mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 10:38:42 +01:00
Merge #15931: Remove GetDepthInMainChain dependency on locked chain interface
36b68de5b2
Remove getBlockDepth method from Chain::interface (Antoine Riard)b66c429c56
Remove locked_chain from GetDepthInMainChain and its callers (Antoine Riard)0ff03871ad
Use CWallet::m_last_block_processed_height in GetDepthInMainChain (Antoine Riard)f77b1de16f
Only return early from BlockUntilSyncedToCurrentChain if current tip is exact match (Antoine Riard)769ff05e48
Refactor some importprunedfunds checks with guard clause (Antoine Riard)5971d3848e
Add block_height field in struct Confirmation (Antoine Riard)9700fcb47f
Replace CWalletTx::SetConf by Confirmation initialization list (Antoine Riard)5aacc3eff1
Add m_last_block_processed_height field in CWallet (Antoine Riard)10b4729e33
Pass block height in Chain::BlockConnected/Chain::BlockDisconnected (Antoine Riard) Pull request description: Work starter to remove Chain::Lock interface by adding m_last_block_processed_height in CWallet and m_block_height in CMerkleTx to avoid GetDepthInMainChain having to keep a lock . Once this one done, it should ease work to wipe out more cs_main locks from wallet code. I think it's ready for a first round of review before to get further. - `BlockUntilSyncedToCurrent` : restrain isPotentialTip to isTip because we want to be sure that wallet see BlockDisconnected callbacks if its height differs from the Chain one. It means during a reorg, an RPC could return before the BlockDisconnected callback had been triggered. This could cause a tx that had been included in the disconnected block to be displayed as confirmed, for example. ~~- `AbandonTransaction` : in case of conflicted tx (nIndex = -1), we set its m_block_height to the one of conflicting blocks, but if this height is superior to CWallet::m_last_block_processed_height, that means tx isn't conflicted anymore so we return 0 as tx is again unconfirmed~~ After #16624, we instead rely on Confirmation. ~~- `AddToWalletIfInvolvingMe`: in case of block disconnected, transactions are added to mempool again, so we need to replace old txn in `mapWallet` with a height set to zero so we remove check on block_hash.IsNull~~ Already done in #16624 ACKs for top commit: jnewbery: @jkczyz you've ACKed an intermediate commit (github annoyingly orders commits in date order, not commit order). Did you mean to ACK the final commit in this branch (36b68de5b2
). jkczyz: > @jkczyz you've ACKed an intermediate commit (github annoyingly orders commits in date order, not commit order). Did you mean to ACK the final commit in this branch ([36b68de
](36b68de5b2
)). meshcollider: utACK36b68de5b2
ryanofsky: Code review ACK36b68de5b2
. Changes since last review: new jkczyz refactor importprunedfunds commit, changed BlockUntilSyncedToCurrentChainChanges commit title and description, changed Confirmation struct field order and line-wrapped comment jnewbery: utACK36b68de5b2
promag: Code review ACK36b68de5b2
. Tree-SHA512: 08b89a0bcc39f67c82a6cb6aee195e6a11697770c788ba737b90986b4893f44e90d1ab9ef87239ea3766508b7e24ea882b7199df41173ab27a3d000328c14644
This commit is contained in:
commit
99ab3a72c5
@ -58,12 +58,6 @@ class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection>
|
|||||||
}
|
}
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
int getBlockDepth(const uint256& hash) override
|
|
||||||
{
|
|
||||||
const Optional<int> tip_height = getHeight();
|
|
||||||
const Optional<int> height = getBlockHeight(hash);
|
|
||||||
return tip_height && height ? *tip_height - *height + 1 : 0;
|
|
||||||
}
|
|
||||||
uint256 getBlockHash(int height) override
|
uint256 getBlockHash(int height) override
|
||||||
{
|
{
|
||||||
LockAssertion lock(::cs_main);
|
LockAssertion lock(::cs_main);
|
||||||
@ -182,11 +176,11 @@ public:
|
|||||||
const CBlockIndex* index,
|
const CBlockIndex* index,
|
||||||
const std::vector<CTransactionRef>& tx_conflicted) override
|
const std::vector<CTransactionRef>& tx_conflicted) override
|
||||||
{
|
{
|
||||||
m_notifications->BlockConnected(*block, tx_conflicted);
|
m_notifications->BlockConnected(*block, tx_conflicted, index->nHeight);
|
||||||
}
|
}
|
||||||
void BlockDisconnected(const std::shared_ptr<const CBlock>& block) override
|
void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
|
||||||
{
|
{
|
||||||
m_notifications->BlockDisconnected(*block);
|
m_notifications->BlockDisconnected(*block, index->nHeight);
|
||||||
}
|
}
|
||||||
void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
|
void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
|
||||||
{
|
{
|
||||||
@ -353,13 +347,11 @@ public:
|
|||||||
{
|
{
|
||||||
return MakeUnique<NotificationsHandlerImpl>(*this, notifications);
|
return MakeUnique<NotificationsHandlerImpl>(*this, notifications);
|
||||||
}
|
}
|
||||||
void waitForNotificationsIfNewBlocksConnected(const uint256& old_tip) override
|
void waitForNotificationsIfTipChanged(const uint256& old_tip) override
|
||||||
{
|
{
|
||||||
if (!old_tip.IsNull()) {
|
if (!old_tip.IsNull()) {
|
||||||
LOCK(::cs_main);
|
LOCK(::cs_main);
|
||||||
if (old_tip == ::ChainActive().Tip()->GetBlockHash()) return;
|
if (old_tip == ::ChainActive().Tip()->GetBlockHash()) return;
|
||||||
CBlockIndex* block = LookupBlockIndex(old_tip);
|
|
||||||
if (block && block->GetAncestor(::ChainActive().Height()) == ::ChainActive().Tip()) return;
|
|
||||||
}
|
}
|
||||||
SyncWithValidationInterfaceQueue();
|
SyncWithValidationInterfaceQueue();
|
||||||
}
|
}
|
||||||
|
@ -76,10 +76,6 @@ public:
|
|||||||
//! included in the current chain.
|
//! included in the current chain.
|
||||||
virtual Optional<int> getBlockHeight(const uint256& hash) = 0;
|
virtual Optional<int> getBlockHeight(const uint256& hash) = 0;
|
||||||
|
|
||||||
//! Get block depth. Returns 1 for chain tip, 2 for preceding block, and
|
|
||||||
//! so on. Returns 0 for a block not included in the current chain.
|
|
||||||
virtual int getBlockDepth(const uint256& hash) = 0;
|
|
||||||
|
|
||||||
//! Get block hash. Height must be valid or this function will abort.
|
//! Get block hash. Height must be valid or this function will abort.
|
||||||
virtual uint256 getBlockHash(int height) = 0;
|
virtual uint256 getBlockHash(int height) = 0;
|
||||||
|
|
||||||
@ -226,8 +222,8 @@ public:
|
|||||||
virtual ~Notifications() {}
|
virtual ~Notifications() {}
|
||||||
virtual void TransactionAddedToMempool(const CTransactionRef& tx) {}
|
virtual void TransactionAddedToMempool(const CTransactionRef& tx) {}
|
||||||
virtual void TransactionRemovedFromMempool(const CTransactionRef& ptx) {}
|
virtual void TransactionRemovedFromMempool(const CTransactionRef& ptx) {}
|
||||||
virtual void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& tx_conflicted) {}
|
virtual void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& tx_conflicted, int height) {}
|
||||||
virtual void BlockDisconnected(const CBlock& block) {}
|
virtual void BlockDisconnected(const CBlock& block, int height) {}
|
||||||
virtual void UpdatedBlockTip() {}
|
virtual void UpdatedBlockTip() {}
|
||||||
virtual void ChainStateFlushed(const CBlockLocator& locator) {}
|
virtual void ChainStateFlushed(const CBlockLocator& locator) {}
|
||||||
};
|
};
|
||||||
@ -236,9 +232,8 @@ public:
|
|||||||
virtual std::unique_ptr<Handler> handleNotifications(Notifications& notifications) = 0;
|
virtual std::unique_ptr<Handler> handleNotifications(Notifications& notifications) = 0;
|
||||||
|
|
||||||
//! Wait for pending notifications to be processed unless block hash points to the current
|
//! Wait for pending notifications to be processed unless block hash points to the current
|
||||||
//! chain tip, or to a possible descendant of the current chain tip that isn't currently
|
//! chain tip.
|
||||||
//! connected.
|
virtual void waitForNotificationsIfTipChanged(const uint256& old_tip) = 0;
|
||||||
virtual void waitForNotificationsIfNewBlocksConnected(const uint256& old_tip) = 0;
|
|
||||||
|
|
||||||
//! Register handler for RPC. Command is not copied, so reference
|
//! Register handler for RPC. Command is not copied, so reference
|
||||||
//! needs to remain valid until Handler is disconnected.
|
//! needs to remain valid until Handler is disconnected.
|
||||||
|
@ -31,7 +31,7 @@ namespace interfaces {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
//! Construct wallet tx struct.
|
//! Construct wallet tx struct.
|
||||||
WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, const CWalletTx& wtx)
|
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
|
||||||
{
|
{
|
||||||
WalletTx result;
|
WalletTx result;
|
||||||
result.tx = wtx.tx;
|
result.tx = wtx.tx;
|
||||||
@ -49,7 +49,7 @@ WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, co
|
|||||||
wallet.IsMine(result.txout_address.back()) :
|
wallet.IsMine(result.txout_address.back()) :
|
||||||
ISMINE_NO);
|
ISMINE_NO);
|
||||||
}
|
}
|
||||||
result.credit = wtx.GetCredit(locked_chain, ISMINE_ALL);
|
result.credit = wtx.GetCredit(ISMINE_ALL);
|
||||||
result.debit = wtx.GetDebit(ISMINE_ALL);
|
result.debit = wtx.GetDebit(ISMINE_ALL);
|
||||||
result.change = wtx.GetChange();
|
result.change = wtx.GetChange();
|
||||||
result.time = wtx.GetTxTime();
|
result.time = wtx.GetTxTime();
|
||||||
@ -63,21 +63,20 @@ WalletTxStatus MakeWalletTxStatus(interfaces::Chain::Lock& locked_chain, const C
|
|||||||
{
|
{
|
||||||
WalletTxStatus result;
|
WalletTxStatus result;
|
||||||
result.block_height = locked_chain.getBlockHeight(wtx.m_confirm.hashBlock).get_value_or(std::numeric_limits<int>::max());
|
result.block_height = locked_chain.getBlockHeight(wtx.m_confirm.hashBlock).get_value_or(std::numeric_limits<int>::max());
|
||||||
result.blocks_to_maturity = wtx.GetBlocksToMaturity(locked_chain);
|
result.blocks_to_maturity = wtx.GetBlocksToMaturity();
|
||||||
result.depth_in_main_chain = wtx.GetDepthInMainChain(locked_chain);
|
result.depth_in_main_chain = wtx.GetDepthInMainChain();
|
||||||
result.time_received = wtx.nTimeReceived;
|
result.time_received = wtx.nTimeReceived;
|
||||||
result.lock_time = wtx.tx->nLockTime;
|
result.lock_time = wtx.tx->nLockTime;
|
||||||
result.is_final = locked_chain.checkFinalTx(*wtx.tx);
|
result.is_final = locked_chain.checkFinalTx(*wtx.tx);
|
||||||
result.is_trusted = wtx.IsTrusted(locked_chain);
|
result.is_trusted = wtx.IsTrusted(locked_chain);
|
||||||
result.is_abandoned = wtx.isAbandoned();
|
result.is_abandoned = wtx.isAbandoned();
|
||||||
result.is_coinbase = wtx.IsCoinBase();
|
result.is_coinbase = wtx.IsCoinBase();
|
||||||
result.is_in_main_chain = wtx.IsInMainChain(locked_chain);
|
result.is_in_main_chain = wtx.IsInMainChain();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Construct wallet TxOut struct.
|
//! Construct wallet TxOut struct.
|
||||||
WalletTxOut MakeWalletTxOut(interfaces::Chain::Lock& locked_chain,
|
WalletTxOut MakeWalletTxOut(CWallet& wallet,
|
||||||
CWallet& wallet,
|
|
||||||
const CWalletTx& wtx,
|
const CWalletTx& wtx,
|
||||||
int n,
|
int n,
|
||||||
int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
||||||
@ -86,7 +85,7 @@ WalletTxOut MakeWalletTxOut(interfaces::Chain::Lock& locked_chain,
|
|||||||
result.txout = wtx.tx->vout[n];
|
result.txout = wtx.tx->vout[n];
|
||||||
result.time = wtx.GetTxTime();
|
result.time = wtx.GetTxTime();
|
||||||
result.depth_in_main_chain = depth;
|
result.depth_in_main_chain = depth;
|
||||||
result.is_spent = wallet.IsSpent(locked_chain, wtx.GetHash(), n);
|
result.is_spent = wallet.IsSpent(wtx.GetHash(), n);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +234,7 @@ public:
|
|||||||
{
|
{
|
||||||
auto locked_chain = m_wallet->chain().lock();
|
auto locked_chain = m_wallet->chain().lock();
|
||||||
LOCK(m_wallet->cs_wallet);
|
LOCK(m_wallet->cs_wallet);
|
||||||
return m_wallet->AbandonTransaction(*locked_chain, txid);
|
return m_wallet->AbandonTransaction(txid);
|
||||||
}
|
}
|
||||||
bool transactionCanBeBumped(const uint256& txid) override
|
bool transactionCanBeBumped(const uint256& txid) override
|
||||||
{
|
{
|
||||||
@ -282,7 +281,7 @@ public:
|
|||||||
LOCK(m_wallet->cs_wallet);
|
LOCK(m_wallet->cs_wallet);
|
||||||
auto mi = m_wallet->mapWallet.find(txid);
|
auto mi = m_wallet->mapWallet.find(txid);
|
||||||
if (mi != m_wallet->mapWallet.end()) {
|
if (mi != m_wallet->mapWallet.end()) {
|
||||||
return MakeWalletTx(*locked_chain, *m_wallet, mi->second);
|
return MakeWalletTx(*m_wallet, mi->second);
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -293,7 +292,7 @@ public:
|
|||||||
std::vector<WalletTx> result;
|
std::vector<WalletTx> result;
|
||||||
result.reserve(m_wallet->mapWallet.size());
|
result.reserve(m_wallet->mapWallet.size());
|
||||||
for (const auto& entry : m_wallet->mapWallet) {
|
for (const auto& entry : m_wallet->mapWallet) {
|
||||||
result.emplace_back(MakeWalletTx(*locked_chain, *m_wallet, entry.second));
|
result.emplace_back(MakeWalletTx(*m_wallet, entry.second));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -338,7 +337,7 @@ public:
|
|||||||
in_mempool = mi->second.InMempool();
|
in_mempool = mi->second.InMempool();
|
||||||
order_form = mi->second.vOrderForm;
|
order_form = mi->second.vOrderForm;
|
||||||
tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
|
tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
|
||||||
return MakeWalletTx(*locked_chain, *m_wallet, mi->second);
|
return MakeWalletTx(*m_wallet, mi->second);
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -407,7 +406,7 @@ public:
|
|||||||
auto& group = result[entry.first];
|
auto& group = result[entry.first];
|
||||||
for (const auto& coin : entry.second) {
|
for (const auto& coin : entry.second) {
|
||||||
group.emplace_back(COutPoint(coin.tx->GetHash(), coin.i),
|
group.emplace_back(COutPoint(coin.tx->GetHash(), coin.i),
|
||||||
MakeWalletTxOut(*locked_chain, *m_wallet, *coin.tx, coin.i, coin.nDepth));
|
MakeWalletTxOut(*m_wallet, *coin.tx, coin.i, coin.nDepth));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -422,9 +421,9 @@ public:
|
|||||||
result.emplace_back();
|
result.emplace_back();
|
||||||
auto it = m_wallet->mapWallet.find(output.hash);
|
auto it = m_wallet->mapWallet.find(output.hash);
|
||||||
if (it != m_wallet->mapWallet.end()) {
|
if (it != m_wallet->mapWallet.end()) {
|
||||||
int depth = it->second.GetDepthInMainChain(*locked_chain);
|
int depth = it->second.GetDepthInMainChain();
|
||||||
if (depth >= 0) {
|
if (depth >= 0) {
|
||||||
result.back() = MakeWalletTxOut(*locked_chain, *m_wallet, it->second, output.n, depth);
|
result.back() = MakeWalletTxOut(*m_wallet, it->second, output.n, depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,10 +139,12 @@ void TestGUI(interfaces::Node& node)
|
|||||||
wallet->LoadWallet(firstRun);
|
wallet->LoadWallet(firstRun);
|
||||||
{
|
{
|
||||||
auto spk_man = wallet->GetLegacyScriptPubKeyMan();
|
auto spk_man = wallet->GetLegacyScriptPubKeyMan();
|
||||||
|
auto locked_chain = wallet->chain().lock();
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
AssertLockHeld(spk_man->cs_wallet);
|
AssertLockHeld(spk_man->cs_wallet);
|
||||||
wallet->SetAddressBook(GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type), "", "receive");
|
wallet->SetAddressBook(GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type), "", "receive");
|
||||||
spk_man->AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
|
spk_man->AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
|
||||||
|
wallet->SetLastBlockProcessed(105, ::ChainActive().Tip()->GetBlockHash());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto locked_chain = wallet->chain().lock();
|
auto locked_chain = wallet->chain().lock();
|
||||||
|
@ -40,9 +40,10 @@ struct TestSubscriber : public CValidationInterface {
|
|||||||
m_expected_tip = block->GetHash();
|
m_expected_tip = block->GetHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockDisconnected(const std::shared_ptr<const CBlock>& block) override
|
void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override
|
||||||
{
|
{
|
||||||
BOOST_CHECK_EQUAL(m_expected_tip, block->GetHash());
|
BOOST_CHECK_EQUAL(m_expected_tip, block->GetHash());
|
||||||
|
BOOST_CHECK_EQUAL(m_expected_tip, pindex->GetBlockHash());
|
||||||
|
|
||||||
m_expected_tip = block->hashPrevBlock;
|
m_expected_tip = block->hashPrevBlock;
|
||||||
}
|
}
|
||||||
|
@ -2458,7 +2458,7 @@ bool CChainState::DisconnectTip(BlockValidationState& state, const CChainParams&
|
|||||||
UpdateTip(pindexDelete->pprev, chainparams);
|
UpdateTip(pindexDelete->pprev, chainparams);
|
||||||
// Let wallets know transactions went from 1-confirmed to
|
// Let wallets know transactions went from 1-confirmed to
|
||||||
// 0-confirmed or conflicted:
|
// 0-confirmed or conflicted:
|
||||||
GetMainSignals().BlockDisconnected(pblock);
|
GetMainSignals().BlockDisconnected(pblock, pindexDelete);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ struct MainSignalsInstance {
|
|||||||
boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
|
boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
|
||||||
boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
|
boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
|
||||||
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef>&)> BlockConnected;
|
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef>&)> BlockConnected;
|
||||||
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
|
boost::signals2::signal<void (const std::shared_ptr<const CBlock>&, const CBlockIndex* pindex)> BlockDisconnected;
|
||||||
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
|
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
|
||||||
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
|
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
|
||||||
boost::signals2::signal<void (const CBlock&, const BlockValidationState&)> BlockChecked;
|
boost::signals2::signal<void (const CBlock&, const BlockValidationState&)> BlockChecked;
|
||||||
@ -92,7 +92,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
|
|||||||
conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(std::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(std::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||||
conns.TransactionAddedToMempool = g_signals.m_internals->TransactionAddedToMempool.connect(std::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, std::placeholders::_1));
|
conns.TransactionAddedToMempool = g_signals.m_internals->TransactionAddedToMempool.connect(std::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, std::placeholders::_1));
|
||||||
conns.BlockConnected = g_signals.m_internals->BlockConnected.connect(std::bind(&CValidationInterface::BlockConnected, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
conns.BlockConnected = g_signals.m_internals->BlockConnected.connect(std::bind(&CValidationInterface::BlockConnected, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||||
conns.BlockDisconnected = g_signals.m_internals->BlockDisconnected.connect(std::bind(&CValidationInterface::BlockDisconnected, pwalletIn, std::placeholders::_1));
|
conns.BlockDisconnected = g_signals.m_internals->BlockDisconnected.connect(std::bind(&CValidationInterface::BlockDisconnected, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
||||||
conns.TransactionRemovedFromMempool = g_signals.m_internals->TransactionRemovedFromMempool.connect(std::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, std::placeholders::_1));
|
conns.TransactionRemovedFromMempool = g_signals.m_internals->TransactionRemovedFromMempool.connect(std::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, std::placeholders::_1));
|
||||||
conns.ChainStateFlushed = g_signals.m_internals->ChainStateFlushed.connect(std::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, std::placeholders::_1));
|
conns.ChainStateFlushed = g_signals.m_internals->ChainStateFlushed.connect(std::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, std::placeholders::_1));
|
||||||
conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
||||||
@ -156,9 +156,10 @@ void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, c
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock) {
|
void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
|
||||||
m_internals->m_schedulerClient.AddToProcessQueue([pblock, this] {
|
{
|
||||||
m_internals->BlockDisconnected(pblock);
|
m_internals->m_schedulerClient.AddToProcessQueue([pblock, pindex, this] {
|
||||||
|
m_internals->BlockDisconnected(pblock, pindex);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ protected:
|
|||||||
*
|
*
|
||||||
* Called on a background thread.
|
* Called on a background thread.
|
||||||
*/
|
*/
|
||||||
virtual void BlockDisconnected(const std::shared_ptr<const CBlock> &block) {}
|
virtual void BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) {}
|
||||||
/**
|
/**
|
||||||
* Notifies listeners of the new active block chain on-disk.
|
* Notifies listeners of the new active block chain on-disk.
|
||||||
*
|
*
|
||||||
@ -178,7 +178,7 @@ public:
|
|||||||
void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
|
void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
|
||||||
void TransactionAddedToMempool(const CTransactionRef &);
|
void TransactionAddedToMempool(const CTransactionRef &);
|
||||||
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
|
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
|
||||||
void BlockDisconnected(const std::shared_ptr<const CBlock> &);
|
void BlockDisconnected(const std::shared_ptr<const CBlock> &, const CBlockIndex* pindex);
|
||||||
void ChainStateFlushed(const CBlockLocator &);
|
void ChainStateFlushed(const CBlockLocator &);
|
||||||
void BlockChecked(const CBlock&, const BlockValidationState&);
|
void BlockChecked(const CBlock&, const BlockValidationState&);
|
||||||
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
|
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
//! Check whether transaction has descendant in wallet or mempool, or has been
|
//! Check whether transaction has descendant in wallet or mempool, or has been
|
||||||
//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
|
//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
|
||||||
static feebumper::Result PreconditionChecks(interfaces::Chain::Lock& locked_chain, const CWallet& wallet, const CWalletTx& wtx, std::vector<std::string>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWalletTx& wtx, std::vector<std::string>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
||||||
{
|
{
|
||||||
if (wallet.HasWalletSpend(wtx.GetHash())) {
|
if (wallet.HasWalletSpend(wtx.GetHash())) {
|
||||||
errors.push_back("Transaction has descendants in the wallet");
|
errors.push_back("Transaction has descendants in the wallet");
|
||||||
@ -30,7 +30,7 @@ static feebumper::Result PreconditionChecks(interfaces::Chain::Lock& locked_chai
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wtx.GetDepthInMainChain(locked_chain) != 0) {
|
if (wtx.GetDepthInMainChain() != 0) {
|
||||||
errors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
|
errors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
|
||||||
return feebumper::Result::WALLET_ERROR;
|
return feebumper::Result::WALLET_ERROR;
|
||||||
}
|
}
|
||||||
@ -146,7 +146,7 @@ bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid)
|
|||||||
if (wtx == nullptr) return false;
|
if (wtx == nullptr) return false;
|
||||||
|
|
||||||
std::vector<std::string> errors_dummy;
|
std::vector<std::string> errors_dummy;
|
||||||
feebumper::Result res = PreconditionChecks(*locked_chain, wallet, *wtx, errors_dummy);
|
feebumper::Result res = PreconditionChecks(wallet, *wtx, errors_dummy);
|
||||||
return res == feebumper::Result::OK;
|
return res == feebumper::Result::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ Result CreateTotalBumpTransaction(const CWallet* wallet, const uint256& txid, co
|
|||||||
}
|
}
|
||||||
const CWalletTx& wtx = it->second;
|
const CWalletTx& wtx = it->second;
|
||||||
|
|
||||||
Result result = PreconditionChecks(*locked_chain, *wallet, wtx, errors);
|
Result result = PreconditionChecks(*wallet, wtx, errors);
|
||||||
if (result != Result::OK) {
|
if (result != Result::OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -291,7 +291,7 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
|
|||||||
}
|
}
|
||||||
const CWalletTx& wtx = it->second;
|
const CWalletTx& wtx = it->second;
|
||||||
|
|
||||||
Result result = PreconditionChecks(*locked_chain, wallet, wtx, errors);
|
Result result = PreconditionChecks(wallet, wtx, errors);
|
||||||
if (result != Result::OK) {
|
if (result != Result::OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -382,7 +382,7 @@ Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransacti
|
|||||||
CWalletTx& oldWtx = it->second;
|
CWalletTx& oldWtx = it->second;
|
||||||
|
|
||||||
// make sure the transaction still has no descendants and hasn't been mined in the meantime
|
// make sure the transaction still has no descendants and hasn't been mined in the meantime
|
||||||
Result result = PreconditionChecks(*locked_chain, wallet, oldWtx, errors);
|
Result result = PreconditionChecks(wallet, oldWtx, errors);
|
||||||
if (result != Result::OK) {
|
if (result != Result::OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -316,7 +316,7 @@ UniValue importaddress(const JSONRPCRequest& request)
|
|||||||
{
|
{
|
||||||
auto locked_chain = pwallet->chain().lock();
|
auto locked_chain = pwallet->chain().lock();
|
||||||
LOCK(pwallet->cs_wallet);
|
LOCK(pwallet->cs_wallet);
|
||||||
pwallet->ReacceptWalletTransactions(*locked_chain);
|
pwallet->ReacceptWalletTransactions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,28 +354,26 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
|
|||||||
//Search partial merkle tree in proof for our transaction and index in valid block
|
//Search partial merkle tree in proof for our transaction and index in valid block
|
||||||
std::vector<uint256> vMatch;
|
std::vector<uint256> vMatch;
|
||||||
std::vector<unsigned int> vIndex;
|
std::vector<unsigned int> vIndex;
|
||||||
unsigned int txnIndex = 0;
|
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) {
|
||||||
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) {
|
|
||||||
|
|
||||||
auto locked_chain = pwallet->chain().lock();
|
|
||||||
if (locked_chain->getBlockHeight(merkleBlock.header.GetHash()) == nullopt) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint256>::const_iterator it;
|
|
||||||
if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx))==vMatch.end()) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof");
|
|
||||||
}
|
|
||||||
|
|
||||||
txnIndex = vIndex[it - vMatch.begin()];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Something wrong with merkleblock");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Something wrong with merkleblock");
|
||||||
}
|
}
|
||||||
|
|
||||||
wtx.SetConf(CWalletTx::Status::CONFIRMED, merkleBlock.header.GetHash(), txnIndex);
|
|
||||||
|
|
||||||
auto locked_chain = pwallet->chain().lock();
|
auto locked_chain = pwallet->chain().lock();
|
||||||
|
Optional<int> height = locked_chain->getBlockHeight(merkleBlock.header.GetHash());
|
||||||
|
if (height == nullopt) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint256>::const_iterator it;
|
||||||
|
if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx)) == vMatch.end()) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int txnIndex = vIndex[it - vMatch.begin()];
|
||||||
|
|
||||||
|
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, *height, merkleBlock.header.GetHash(), txnIndex);
|
||||||
|
wtx.m_confirm = confirm;
|
||||||
|
|
||||||
LOCK(pwallet->cs_wallet);
|
LOCK(pwallet->cs_wallet);
|
||||||
|
|
||||||
if (pwallet->IsMine(*wtx.tx)) {
|
if (pwallet->IsMine(*wtx.tx)) {
|
||||||
@ -507,7 +505,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
|
|||||||
{
|
{
|
||||||
auto locked_chain = pwallet->chain().lock();
|
auto locked_chain = pwallet->chain().lock();
|
||||||
LOCK(pwallet->cs_wallet);
|
LOCK(pwallet->cs_wallet);
|
||||||
pwallet->ReacceptWalletTransactions(*locked_chain);
|
pwallet->ReacceptWalletTransactions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1406,7 +1404,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
|
|||||||
{
|
{
|
||||||
auto locked_chain = pwallet->chain().lock();
|
auto locked_chain = pwallet->chain().lock();
|
||||||
LOCK(pwallet->cs_wallet);
|
LOCK(pwallet->cs_wallet);
|
||||||
pwallet->ReacceptWalletTransactions(*locked_chain);
|
pwallet->ReacceptWalletTransactions();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pwallet->IsAbortingRescan()) {
|
if (pwallet->IsAbortingRescan()) {
|
||||||
|
@ -135,7 +135,7 @@ LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet)
|
|||||||
|
|
||||||
static void WalletTxToJSON(interfaces::Chain& chain, interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx, UniValue& entry)
|
static void WalletTxToJSON(interfaces::Chain& chain, interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx, UniValue& entry)
|
||||||
{
|
{
|
||||||
int confirms = wtx.GetDepthInMainChain(locked_chain);
|
int confirms = wtx.GetDepthInMainChain();
|
||||||
entry.pushKV("confirmations", confirms);
|
entry.pushKV("confirmations", confirms);
|
||||||
if (wtx.IsCoinBase())
|
if (wtx.IsCoinBase())
|
||||||
entry.pushKV("generated", true);
|
entry.pushKV("generated", true);
|
||||||
@ -640,7 +640,7 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
|
|||||||
|
|
||||||
for (const CTxOut& txout : wtx.tx->vout)
|
for (const CTxOut& txout : wtx.tx->vout)
|
||||||
if (txout.scriptPubKey == scriptPubKey)
|
if (txout.scriptPubKey == scriptPubKey)
|
||||||
if (wtx.GetDepthInMainChain(*locked_chain) >= nMinDepth)
|
if (wtx.GetDepthInMainChain() >= nMinDepth)
|
||||||
nAmount += txout.nValue;
|
nAmount += txout.nValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,7 +706,7 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
|
|||||||
{
|
{
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
if (ExtractDestination(txout.scriptPubKey, address) && pwallet->IsMine(address) && setAddress.count(address)) {
|
if (ExtractDestination(txout.scriptPubKey, address) && pwallet->IsMine(address) && setAddress.count(address)) {
|
||||||
if (wtx.GetDepthInMainChain(*locked_chain) >= nMinDepth)
|
if (wtx.GetDepthInMainChain() >= nMinDepth)
|
||||||
nAmount += txout.nValue;
|
nAmount += txout.nValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1063,7 +1063,7 @@ static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, CWallet * co
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nDepth = wtx.GetDepthInMainChain(locked_chain);
|
int nDepth = wtx.GetDepthInMainChain();
|
||||||
if (nDepth < nMinDepth)
|
if (nDepth < nMinDepth)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1320,8 +1320,7 @@ static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* con
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Received
|
// Received
|
||||||
if (listReceived.size() > 0 && wtx.GetDepthInMainChain(locked_chain) >= nMinDepth)
|
if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) {
|
||||||
{
|
|
||||||
for (const COutputEntry& r : listReceived)
|
for (const COutputEntry& r : listReceived)
|
||||||
{
|
{
|
||||||
std::string label;
|
std::string label;
|
||||||
@ -1338,9 +1337,9 @@ static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* con
|
|||||||
MaybePushAddress(entry, r.destination);
|
MaybePushAddress(entry, r.destination);
|
||||||
if (wtx.IsCoinBase())
|
if (wtx.IsCoinBase())
|
||||||
{
|
{
|
||||||
if (wtx.GetDepthInMainChain(locked_chain) < 1)
|
if (wtx.GetDepthInMainChain() < 1)
|
||||||
entry.pushKV("category", "orphan");
|
entry.pushKV("category", "orphan");
|
||||||
else if (wtx.IsImmatureCoinBase(locked_chain))
|
else if (wtx.IsImmatureCoinBase())
|
||||||
entry.pushKV("category", "immature");
|
entry.pushKV("category", "immature");
|
||||||
else
|
else
|
||||||
entry.pushKV("category", "generate");
|
entry.pushKV("category", "generate");
|
||||||
@ -1604,7 +1603,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
|
|||||||
for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
|
for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
|
||||||
CWalletTx tx = pairWtx.second;
|
CWalletTx tx = pairWtx.second;
|
||||||
|
|
||||||
if (depth == -1 || abs(tx.GetDepthInMainChain(*locked_chain)) < depth) {
|
if (depth == -1 || abs(tx.GetDepthInMainChain()) < depth) {
|
||||||
ListTransactions(*locked_chain, pwallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
|
ListTransactions(*locked_chain, pwallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1721,7 +1720,7 @@ static UniValue gettransaction(const JSONRPCRequest& request)
|
|||||||
}
|
}
|
||||||
const CWalletTx& wtx = it->second;
|
const CWalletTx& wtx = it->second;
|
||||||
|
|
||||||
CAmount nCredit = wtx.GetCredit(*locked_chain, filter);
|
CAmount nCredit = wtx.GetCredit(filter);
|
||||||
CAmount nDebit = wtx.GetDebit(filter);
|
CAmount nDebit = wtx.GetDebit(filter);
|
||||||
CAmount nNet = nCredit - nDebit;
|
CAmount nNet = nCredit - nDebit;
|
||||||
CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
|
CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
|
||||||
@ -1785,7 +1784,7 @@ static UniValue abandontransaction(const JSONRPCRequest& request)
|
|||||||
if (!pwallet->mapWallet.count(hash)) {
|
if (!pwallet->mapWallet.count(hash)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
|
||||||
}
|
}
|
||||||
if (!pwallet->AbandonTransaction(*locked_chain, hash)) {
|
if (!pwallet->AbandonTransaction(hash)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2216,7 +2215,7 @@ static UniValue lockunspent(const JSONRPCRequest& request)
|
|||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pwallet->IsSpent(*locked_chain, outpt.hash, outpt.n)) {
|
if (pwallet->IsSpent(outpt.hash, outpt.n)) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,10 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||||||
// Verify ScanForWalletTransactions accommodates a null start block.
|
// Verify ScanForWalletTransactions accommodates a null start block.
|
||||||
{
|
{
|
||||||
CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||||
|
{
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
|
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||||
|
}
|
||||||
AddKey(wallet, coinbaseKey);
|
AddKey(wallet, coinbaseKey);
|
||||||
WalletRescanReserver reserver(&wallet);
|
WalletRescanReserver reserver(&wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
@ -65,6 +69,10 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||||||
// and new block files.
|
// and new block files.
|
||||||
{
|
{
|
||||||
CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||||
|
{
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
|
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||||
|
}
|
||||||
AddKey(wallet, coinbaseKey);
|
AddKey(wallet, coinbaseKey);
|
||||||
WalletRescanReserver reserver(&wallet);
|
WalletRescanReserver reserver(&wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
@ -84,6 +92,10 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||||||
// file.
|
// file.
|
||||||
{
|
{
|
||||||
CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||||
|
{
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
|
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||||
|
}
|
||||||
AddKey(wallet, coinbaseKey);
|
AddKey(wallet, coinbaseKey);
|
||||||
WalletRescanReserver reserver(&wallet);
|
WalletRescanReserver reserver(&wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
@ -102,6 +114,10 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||||||
// Verify ScanForWalletTransactions scans no blocks.
|
// Verify ScanForWalletTransactions scans no blocks.
|
||||||
{
|
{
|
||||||
CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
|
||||||
|
{
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
|
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||||
|
}
|
||||||
AddKey(wallet, coinbaseKey);
|
AddKey(wallet, coinbaseKey);
|
||||||
WalletRescanReserver reserver(&wallet);
|
WalletRescanReserver reserver(&wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
@ -258,18 +274,20 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
|
|||||||
LockAssertion lock(::cs_main);
|
LockAssertion lock(::cs_main);
|
||||||
LOCK(wallet.cs_wallet);
|
LOCK(wallet.cs_wallet);
|
||||||
AssertLockHeld(spk_man->cs_wallet);
|
AssertLockHeld(spk_man->cs_wallet);
|
||||||
|
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||||
|
|
||||||
wtx.SetConf(CWalletTx::Status::CONFIRMED, ::ChainActive().Tip()->GetBlockHash(), 0);
|
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, ::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash(), 0);
|
||||||
|
wtx.m_confirm = confirm;
|
||||||
|
|
||||||
// Call GetImmatureCredit() once before adding the key to the wallet to
|
// Call GetImmatureCredit() once before adding the key to the wallet to
|
||||||
// cache the current immature credit amount, which is 0.
|
// cache the current immature credit amount, which is 0.
|
||||||
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(*locked_chain), 0);
|
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 0);
|
||||||
|
|
||||||
// Invalidate the cached vanue, add the key, and make sure a new immature
|
// Invalidate the cached vanue, add the key, and make sure a new immature
|
||||||
// credit amount is calculated.
|
// credit amount is calculated.
|
||||||
wtx.MarkDirty();
|
wtx.MarkDirty();
|
||||||
BOOST_CHECK(spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()));
|
BOOST_CHECK(spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()));
|
||||||
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(*locked_chain), 50*COIN);
|
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 50*COIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
|
static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
|
||||||
@ -300,7 +318,8 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
|
|||||||
wallet.AddToWallet(wtx);
|
wallet.AddToWallet(wtx);
|
||||||
}
|
}
|
||||||
if (block) {
|
if (block) {
|
||||||
wtx.SetConf(CWalletTx::Status::CONFIRMED, block->GetBlockHash(), 0);
|
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, block->nHeight, block->GetBlockHash(), 0);
|
||||||
|
wtx.m_confirm = confirm;
|
||||||
}
|
}
|
||||||
wallet.AddToWallet(wtx);
|
wallet.AddToWallet(wtx);
|
||||||
return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;
|
return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;
|
||||||
@ -435,6 +454,10 @@ public:
|
|||||||
{
|
{
|
||||||
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
|
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
|
||||||
wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), WalletDatabase::CreateMock());
|
wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), WalletDatabase::CreateMock());
|
||||||
|
{
|
||||||
|
LOCK(wallet->cs_wallet);
|
||||||
|
wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||||
|
}
|
||||||
bool firstRun;
|
bool firstRun;
|
||||||
wallet->LoadWallet(firstRun);
|
wallet->LoadWallet(firstRun);
|
||||||
AddKey(*wallet, coinbaseKey);
|
AddKey(*wallet, coinbaseKey);
|
||||||
@ -473,9 +496,11 @@ public:
|
|||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
|
wallet->SetLastBlockProcessed(wallet->GetLastBlockHeight() + 1, ::ChainActive().Tip()->GetBlockHash());
|
||||||
auto it = wallet->mapWallet.find(tx->GetHash());
|
auto it = wallet->mapWallet.find(tx->GetHash());
|
||||||
BOOST_CHECK(it != wallet->mapWallet.end());
|
BOOST_CHECK(it != wallet->mapWallet.end());
|
||||||
it->second.SetConf(CWalletTx::Status::CONFIRMED, ::ChainActive().Tip()->GetBlockHash(), 1);
|
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, ::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash(), 1);
|
||||||
|
it->second.m_confirm = confirm;
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +452,7 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
|
|||||||
* Outpoint is spent if any non-conflicted transaction
|
* Outpoint is spent if any non-conflicted transaction
|
||||||
* spends it:
|
* spends it:
|
||||||
*/
|
*/
|
||||||
bool CWallet::IsSpent(interfaces::Chain::Lock& locked_chain, const uint256& hash, unsigned int n) const
|
bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
|
||||||
{
|
{
|
||||||
const COutPoint outpoint(hash, n);
|
const COutPoint outpoint(hash, n);
|
||||||
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
|
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
|
||||||
@ -463,7 +463,7 @@ bool CWallet::IsSpent(interfaces::Chain::Lock& locked_chain, const uint256& hash
|
|||||||
const uint256& wtxid = it->second;
|
const uint256& wtxid = it->second;
|
||||||
std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
|
std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
|
||||||
if (mit != mapWallet.end()) {
|
if (mit != mapWallet.end()) {
|
||||||
int depth = mit->second.GetDepthInMainChain(locked_chain);
|
int depth = mit->second.GetDepthInMainChain();
|
||||||
if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
|
if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
|
||||||
return true; // Spent
|
return true; // Spent
|
||||||
}
|
}
|
||||||
@ -768,10 +768,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
|
|||||||
wtx.m_confirm.status = wtxIn.m_confirm.status;
|
wtx.m_confirm.status = wtxIn.m_confirm.status;
|
||||||
wtx.m_confirm.nIndex = wtxIn.m_confirm.nIndex;
|
wtx.m_confirm.nIndex = wtxIn.m_confirm.nIndex;
|
||||||
wtx.m_confirm.hashBlock = wtxIn.m_confirm.hashBlock;
|
wtx.m_confirm.hashBlock = wtxIn.m_confirm.hashBlock;
|
||||||
|
wtx.m_confirm.block_height = wtxIn.m_confirm.block_height;
|
||||||
fUpdated = true;
|
fUpdated = true;
|
||||||
} else {
|
} else {
|
||||||
assert(wtx.m_confirm.nIndex == wtxIn.m_confirm.nIndex);
|
assert(wtx.m_confirm.nIndex == wtxIn.m_confirm.nIndex);
|
||||||
assert(wtx.m_confirm.hashBlock == wtxIn.m_confirm.hashBlock);
|
assert(wtx.m_confirm.hashBlock == wtxIn.m_confirm.hashBlock);
|
||||||
|
assert(wtx.m_confirm.block_height == wtxIn.m_confirm.block_height);
|
||||||
}
|
}
|
||||||
if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
|
if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
|
||||||
{
|
{
|
||||||
@ -822,12 +824,22 @@ void CWallet::LoadToWallet(CWalletTx& wtxIn)
|
|||||||
{
|
{
|
||||||
// If wallet doesn't have a chain (e.g wallet-tool), lock can't be taken.
|
// If wallet doesn't have a chain (e.g wallet-tool), lock can't be taken.
|
||||||
auto locked_chain = LockChain();
|
auto locked_chain = LockChain();
|
||||||
// If tx hasn't been reorged out of chain while wallet being shutdown
|
if (locked_chain) {
|
||||||
// change tx status to UNCONFIRMED and reset hashBlock/nIndex.
|
Optional<int> block_height = locked_chain->getBlockHeight(wtxIn.m_confirm.hashBlock);
|
||||||
if (!wtxIn.m_confirm.hashBlock.IsNull()) {
|
if (block_height) {
|
||||||
if (locked_chain && !locked_chain->getBlockHeight(wtxIn.m_confirm.hashBlock)) {
|
// Update cached block height variable since it not stored in the
|
||||||
|
// serialized transaction.
|
||||||
|
wtxIn.m_confirm.block_height = *block_height;
|
||||||
|
} else if (wtxIn.isConflicted() || wtxIn.isConfirmed()) {
|
||||||
|
// If tx block (or conflicting block) was reorged out of chain
|
||||||
|
// while the wallet was shutdown, change tx status to UNCONFIRMED
|
||||||
|
// and reset block height, hash, and index. ABANDONED tx don't have
|
||||||
|
// associated blocks and don't need to be updated. The case where a
|
||||||
|
// transaction was reorged out while online and then reconfirmed
|
||||||
|
// while offline is covered by the rescan logic.
|
||||||
wtxIn.setUnconfirmed();
|
wtxIn.setUnconfirmed();
|
||||||
wtxIn.m_confirm.hashBlock = uint256();
|
wtxIn.m_confirm.hashBlock = uint256();
|
||||||
|
wtxIn.m_confirm.block_height = 0;
|
||||||
wtxIn.m_confirm.nIndex = 0;
|
wtxIn.m_confirm.nIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -844,25 +856,25 @@ void CWallet::LoadToWallet(CWalletTx& wtxIn)
|
|||||||
if (it != mapWallet.end()) {
|
if (it != mapWallet.end()) {
|
||||||
CWalletTx& prevtx = it->second;
|
CWalletTx& prevtx = it->second;
|
||||||
if (prevtx.isConflicted()) {
|
if (prevtx.isConflicted()) {
|
||||||
MarkConflicted(prevtx.m_confirm.hashBlock, wtx.GetHash());
|
MarkConflicted(prevtx.m_confirm.hashBlock, prevtx.m_confirm.block_height, wtx.GetHash());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Status status, const uint256& block_hash, int posInBlock, bool fUpdate)
|
bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Confirmation confirm, bool fUpdate)
|
||||||
{
|
{
|
||||||
const CTransaction& tx = *ptx;
|
const CTransaction& tx = *ptx;
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet);
|
AssertLockHeld(cs_wallet);
|
||||||
|
|
||||||
if (!block_hash.IsNull()) {
|
if (!confirm.hashBlock.IsNull()) {
|
||||||
for (const CTxIn& txin : tx.vin) {
|
for (const CTxIn& txin : tx.vin) {
|
||||||
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
|
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
|
||||||
while (range.first != range.second) {
|
while (range.first != range.second) {
|
||||||
if (range.first->second != tx.GetHash()) {
|
if (range.first->second != tx.GetHash()) {
|
||||||
WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), block_hash.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
|
WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), confirm.hashBlock.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
|
||||||
MarkConflicted(block_hash, range.first->second);
|
MarkConflicted(confirm.hashBlock, confirm.block_height, range.first->second);
|
||||||
}
|
}
|
||||||
range.first++;
|
range.first++;
|
||||||
}
|
}
|
||||||
@ -890,7 +902,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::St
|
|||||||
|
|
||||||
// Block disconnection override an abandoned tx as unconfirmed
|
// Block disconnection override an abandoned tx as unconfirmed
|
||||||
// which means user may have to call abandontransaction again
|
// which means user may have to call abandontransaction again
|
||||||
wtx.SetConf(status, block_hash, posInBlock);
|
wtx.m_confirm = confirm;
|
||||||
|
|
||||||
return AddToWallet(wtx, false);
|
return AddToWallet(wtx, false);
|
||||||
}
|
}
|
||||||
@ -903,7 +915,7 @@ bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const
|
|||||||
auto locked_chain = chain().lock();
|
auto locked_chain = chain().lock();
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
const CWalletTx* wtx = GetWalletTx(hashTx);
|
const CWalletTx* wtx = GetWalletTx(hashTx);
|
||||||
return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain(*locked_chain) == 0 && !wtx->InMempool();
|
return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() == 0 && !wtx->InMempool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::MarkInputsDirty(const CTransactionRef& tx)
|
void CWallet::MarkInputsDirty(const CTransactionRef& tx)
|
||||||
@ -916,9 +928,9 @@ void CWallet::MarkInputsDirty(const CTransactionRef& tx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::AbandonTransaction(interfaces::Chain::Lock& locked_chain, const uint256& hashTx)
|
bool CWallet::AbandonTransaction(const uint256& hashTx)
|
||||||
{
|
{
|
||||||
auto locked_chain_recursive = chain().lock(); // Temporary. Removed in upcoming lock cleanup
|
auto locked_chain = chain().lock(); // Temporary. Removed in upcoming lock cleanup
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
|
|
||||||
WalletBatch batch(*database, "r+");
|
WalletBatch batch(*database, "r+");
|
||||||
@ -930,7 +942,7 @@ bool CWallet::AbandonTransaction(interfaces::Chain::Lock& locked_chain, const ui
|
|||||||
auto it = mapWallet.find(hashTx);
|
auto it = mapWallet.find(hashTx);
|
||||||
assert(it != mapWallet.end());
|
assert(it != mapWallet.end());
|
||||||
CWalletTx& origtx = it->second;
|
CWalletTx& origtx = it->second;
|
||||||
if (origtx.GetDepthInMainChain(locked_chain) != 0 || origtx.InMempool()) {
|
if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -943,14 +955,13 @@ bool CWallet::AbandonTransaction(interfaces::Chain::Lock& locked_chain, const ui
|
|||||||
auto it = mapWallet.find(now);
|
auto it = mapWallet.find(now);
|
||||||
assert(it != mapWallet.end());
|
assert(it != mapWallet.end());
|
||||||
CWalletTx& wtx = it->second;
|
CWalletTx& wtx = it->second;
|
||||||
int currentconfirm = wtx.GetDepthInMainChain(locked_chain);
|
int currentconfirm = wtx.GetDepthInMainChain();
|
||||||
// If the orig tx was not in block, none of its spends can be
|
// If the orig tx was not in block, none of its spends can be
|
||||||
assert(currentconfirm <= 0);
|
assert(currentconfirm <= 0);
|
||||||
// if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
|
// if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
|
||||||
if (currentconfirm == 0 && !wtx.isAbandoned()) {
|
if (currentconfirm == 0 && !wtx.isAbandoned()) {
|
||||||
// If the orig tx was not in block/mempool, none of its spends can be in mempool
|
// If the orig tx was not in block/mempool, none of its spends can be in mempool
|
||||||
assert(!wtx.InMempool());
|
assert(!wtx.InMempool());
|
||||||
wtx.m_confirm.nIndex = 0;
|
|
||||||
wtx.setAbandoned();
|
wtx.setAbandoned();
|
||||||
wtx.MarkDirty();
|
wtx.MarkDirty();
|
||||||
batch.WriteTx(wtx);
|
batch.WriteTx(wtx);
|
||||||
@ -972,12 +983,12 @@ bool CWallet::AbandonTransaction(interfaces::Chain::Lock& locked_chain, const ui
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
|
void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, const uint256& hashTx)
|
||||||
{
|
{
|
||||||
auto locked_chain = chain().lock();
|
auto locked_chain = chain().lock();
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
|
|
||||||
int conflictconfirms = -locked_chain->getBlockDepth(hashBlock);
|
int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
|
||||||
// If number of conflict confirms cannot be determined, this means
|
// If number of conflict confirms cannot be determined, this means
|
||||||
// that the block is still unknown or not yet part of the main chain,
|
// that the block is still unknown or not yet part of the main chain,
|
||||||
// for example when loading the wallet during a reindex. Do nothing in that
|
// for example when loading the wallet during a reindex. Do nothing in that
|
||||||
@ -1000,12 +1011,13 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
|
|||||||
auto it = mapWallet.find(now);
|
auto it = mapWallet.find(now);
|
||||||
assert(it != mapWallet.end());
|
assert(it != mapWallet.end());
|
||||||
CWalletTx& wtx = it->second;
|
CWalletTx& wtx = it->second;
|
||||||
int currentconfirm = wtx.GetDepthInMainChain(*locked_chain);
|
int currentconfirm = wtx.GetDepthInMainChain();
|
||||||
if (conflictconfirms < currentconfirm) {
|
if (conflictconfirms < currentconfirm) {
|
||||||
// Block is 'more conflicted' than current confirm; update.
|
// Block is 'more conflicted' than current confirm; update.
|
||||||
// Mark transaction as conflicted with this block.
|
// Mark transaction as conflicted with this block.
|
||||||
wtx.m_confirm.nIndex = 0;
|
wtx.m_confirm.nIndex = 0;
|
||||||
wtx.m_confirm.hashBlock = hashBlock;
|
wtx.m_confirm.hashBlock = hashBlock;
|
||||||
|
wtx.m_confirm.block_height = conflicting_height;
|
||||||
wtx.setConflicted();
|
wtx.setConflicted();
|
||||||
wtx.MarkDirty();
|
wtx.MarkDirty();
|
||||||
batch.WriteTx(wtx);
|
batch.WriteTx(wtx);
|
||||||
@ -1024,9 +1036,9 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::SyncTransaction(const CTransactionRef& ptx, CWalletTx::Status status, const uint256& block_hash, int posInBlock, bool update_tx)
|
void CWallet::SyncTransaction(const CTransactionRef& ptx, CWalletTx::Confirmation confirm, bool update_tx)
|
||||||
{
|
{
|
||||||
if (!AddToWalletIfInvolvingMe(ptx, status, block_hash, posInBlock, update_tx))
|
if (!AddToWalletIfInvolvingMe(ptx, confirm, update_tx))
|
||||||
return; // Not one of ours
|
return; // Not one of ours
|
||||||
|
|
||||||
// If a transaction changes 'conflicted' state, that changes the balance
|
// If a transaction changes 'conflicted' state, that changes the balance
|
||||||
@ -1038,7 +1050,8 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, CWalletTx::Status stat
|
|||||||
void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) {
|
void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) {
|
||||||
auto locked_chain = chain().lock();
|
auto locked_chain = chain().lock();
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
SyncTransaction(ptx, CWalletTx::Status::UNCONFIRMED, {} /* block hash */, 0 /* position in block */);
|
CWalletTx::Confirmation confirm(CWalletTx::Status::UNCONFIRMED, /* block_height */ 0, {}, /* nIndex */ 0);
|
||||||
|
SyncTransaction(ptx, confirm);
|
||||||
|
|
||||||
auto it = mapWallet.find(ptx->GetHash());
|
auto it = mapWallet.find(ptx->GetHash());
|
||||||
if (it != mapWallet.end()) {
|
if (it != mapWallet.end()) {
|
||||||
@ -1054,23 +1067,26 @@ void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted) {
|
void CWallet::BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted, int height)
|
||||||
|
{
|
||||||
const uint256& block_hash = block.GetHash();
|
const uint256& block_hash = block.GetHash();
|
||||||
auto locked_chain = chain().lock();
|
auto locked_chain = chain().lock();
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
|
|
||||||
for (size_t i = 0; i < block.vtx.size(); i++) {
|
m_last_block_processed_height = height;
|
||||||
SyncTransaction(block.vtx[i], CWalletTx::Status::CONFIRMED, block_hash, i);
|
m_last_block_processed = block_hash;
|
||||||
TransactionRemovedFromMempool(block.vtx[i]);
|
for (size_t index = 0; index < block.vtx.size(); index++) {
|
||||||
|
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, height, block_hash, index);
|
||||||
|
SyncTransaction(block.vtx[index], confirm);
|
||||||
|
TransactionRemovedFromMempool(block.vtx[index]);
|
||||||
}
|
}
|
||||||
for (const CTransactionRef& ptx : vtxConflicted) {
|
for (const CTransactionRef& ptx : vtxConflicted) {
|
||||||
TransactionRemovedFromMempool(ptx);
|
TransactionRemovedFromMempool(ptx);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_last_block_processed = block_hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::BlockDisconnected(const CBlock& block) {
|
void CWallet::BlockDisconnected(const CBlock& block, int height)
|
||||||
|
{
|
||||||
auto locked_chain = chain().lock();
|
auto locked_chain = chain().lock();
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
|
|
||||||
@ -1078,8 +1094,11 @@ void CWallet::BlockDisconnected(const CBlock& block) {
|
|||||||
// be unconfirmed, whether or not the transaction is added back to the mempool.
|
// be unconfirmed, whether or not the transaction is added back to the mempool.
|
||||||
// User may have to call abandontransaction again. It may be addressed in the
|
// User may have to call abandontransaction again. It may be addressed in the
|
||||||
// future with a stickier abandoned state or even removing abandontransaction call.
|
// future with a stickier abandoned state or even removing abandontransaction call.
|
||||||
|
m_last_block_processed_height = height - 1;
|
||||||
|
m_last_block_processed = block.hashPrevBlock;
|
||||||
for (const CTransactionRef& ptx : block.vtx) {
|
for (const CTransactionRef& ptx : block.vtx) {
|
||||||
SyncTransaction(ptx, CWalletTx::Status::UNCONFIRMED, {} /* block hash */, 0 /* position in block */);
|
CWalletTx::Confirmation confirm(CWalletTx::Status::UNCONFIRMED, /* block_height */ 0, {}, /* nIndex */ 0);
|
||||||
|
SyncTransaction(ptx, confirm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1096,7 +1115,7 @@ void CWallet::BlockUntilSyncedToCurrentChain() {
|
|||||||
// for the queue to drain enough to execute it (indicating we are caught up
|
// for the queue to drain enough to execute it (indicating we are caught up
|
||||||
// at least with the time we entered this function).
|
// at least with the time we entered this function).
|
||||||
uint256 last_block_hash = WITH_LOCK(cs_wallet, return m_last_block_processed);
|
uint256 last_block_hash = WITH_LOCK(cs_wallet, return m_last_block_processed);
|
||||||
chain().waitForNotificationsIfNewBlocksConnected(last_block_hash);
|
chain().waitForNotificationsIfTipChanged(last_block_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1625,7 +1644,8 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
|
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
|
||||||
SyncTransaction(block.vtx[posInBlock], CWalletTx::Status::CONFIRMED, block_hash, posInBlock, fUpdate);
|
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, *block_height, block_hash, posInBlock);
|
||||||
|
SyncTransaction(block.vtx[posInBlock], confirm, fUpdate);
|
||||||
}
|
}
|
||||||
// scan succeeded, record block as most recent successfully scanned
|
// scan succeeded, record block as most recent successfully scanned
|
||||||
result.last_scanned_block = block_hash;
|
result.last_scanned_block = block_hash;
|
||||||
@ -1673,7 +1693,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::ReacceptWalletTransactions(interfaces::Chain::Lock& locked_chain)
|
void CWallet::ReacceptWalletTransactions()
|
||||||
{
|
{
|
||||||
// If transactions aren't being broadcasted, don't let them into local mempool either
|
// If transactions aren't being broadcasted, don't let them into local mempool either
|
||||||
if (!fBroadcastTransactions)
|
if (!fBroadcastTransactions)
|
||||||
@ -1686,7 +1706,7 @@ void CWallet::ReacceptWalletTransactions(interfaces::Chain::Lock& locked_chain)
|
|||||||
CWalletTx& wtx = item.second;
|
CWalletTx& wtx = item.second;
|
||||||
assert(wtx.GetHash() == wtxid);
|
assert(wtx.GetHash() == wtxid);
|
||||||
|
|
||||||
int nDepth = wtx.GetDepthInMainChain(locked_chain);
|
int nDepth = wtx.GetDepthInMainChain();
|
||||||
|
|
||||||
if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {
|
if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {
|
||||||
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
|
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
|
||||||
@ -1697,11 +1717,11 @@ void CWallet::ReacceptWalletTransactions(interfaces::Chain::Lock& locked_chain)
|
|||||||
for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
|
for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
|
||||||
CWalletTx& wtx = *(item.second);
|
CWalletTx& wtx = *(item.second);
|
||||||
std::string unused_err_string;
|
std::string unused_err_string;
|
||||||
wtx.SubmitMemoryPoolAndRelay(unused_err_string, false, locked_chain);
|
wtx.SubmitMemoryPoolAndRelay(unused_err_string, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletTx::SubmitMemoryPoolAndRelay(std::string& err_string, bool relay, interfaces::Chain::Lock& locked_chain)
|
bool CWalletTx::SubmitMemoryPoolAndRelay(std::string& err_string, bool relay)
|
||||||
{
|
{
|
||||||
// Can't relay if wallet is not broadcasting
|
// Can't relay if wallet is not broadcasting
|
||||||
if (!pwallet->GetBroadcastTransactions()) return false;
|
if (!pwallet->GetBroadcastTransactions()) return false;
|
||||||
@ -1711,7 +1731,7 @@ bool CWalletTx::SubmitMemoryPoolAndRelay(std::string& err_string, bool relay, in
|
|||||||
// cause log spam.
|
// cause log spam.
|
||||||
if (IsCoinBase()) return false;
|
if (IsCoinBase()) return false;
|
||||||
// Don't try to submit conflicted or confirmed transactions.
|
// Don't try to submit conflicted or confirmed transactions.
|
||||||
if (GetDepthInMainChain(locked_chain) != 0) return false;
|
if (GetDepthInMainChain() != 0) return false;
|
||||||
|
|
||||||
// Submit transaction to mempool for relay
|
// Submit transaction to mempool for relay
|
||||||
pwallet->WalletLogPrintf("Submitting wtx %s to mempool for relay\n", GetHash().ToString());
|
pwallet->WalletLogPrintf("Submitting wtx %s to mempool for relay\n", GetHash().ToString());
|
||||||
@ -1765,10 +1785,10 @@ CAmount CWalletTx::GetDebit(const isminefilter& filter) const
|
|||||||
return debit;
|
return debit;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount CWalletTx::GetCredit(interfaces::Chain::Lock& locked_chain, const isminefilter& filter) const
|
CAmount CWalletTx::GetCredit(const isminefilter& filter) const
|
||||||
{
|
{
|
||||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||||
if (IsImmatureCoinBase(locked_chain))
|
if (IsImmatureCoinBase())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
CAmount credit = 0;
|
CAmount credit = 0;
|
||||||
@ -1782,16 +1802,16 @@ CAmount CWalletTx::GetCredit(interfaces::Chain::Lock& locked_chain, const ismine
|
|||||||
return credit;
|
return credit;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount CWalletTx::GetImmatureCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache) const
|
CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
|
||||||
{
|
{
|
||||||
if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) {
|
if (IsImmatureCoinBase() && IsInMainChain()) {
|
||||||
return GetCachableAmount(IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache);
|
return GetCachableAmount(IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache, const isminefilter& filter) const
|
CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter) const
|
||||||
{
|
{
|
||||||
if (pwallet == nullptr)
|
if (pwallet == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1800,7 +1820,7 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
|
|||||||
bool allow_cache = (filter & ISMINE_ALL) && (filter & ISMINE_ALL) != ISMINE_ALL;
|
bool allow_cache = (filter & ISMINE_ALL) && (filter & ISMINE_ALL) != ISMINE_ALL;
|
||||||
|
|
||||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||||
if (IsImmatureCoinBase(locked_chain))
|
if (IsImmatureCoinBase())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (fUseCache && allow_cache && m_amounts[AVAILABLE_CREDIT].m_cached[filter]) {
|
if (fUseCache && allow_cache && m_amounts[AVAILABLE_CREDIT].m_cached[filter]) {
|
||||||
@ -1812,7 +1832,7 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
|
|||||||
uint256 hashTx = GetHash();
|
uint256 hashTx = GetHash();
|
||||||
for (unsigned int i = 0; i < tx->vout.size(); i++)
|
for (unsigned int i = 0; i < tx->vout.size(); i++)
|
||||||
{
|
{
|
||||||
if (!pwallet->IsSpent(locked_chain, hashTx, i) && (allow_used_addresses || !pwallet->IsUsedDestination(hashTx, i))) {
|
if (!pwallet->IsSpent(hashTx, i) && (allow_used_addresses || !pwallet->IsUsedDestination(hashTx, i))) {
|
||||||
const CTxOut &txout = tx->vout[i];
|
const CTxOut &txout = tx->vout[i];
|
||||||
nCredit += pwallet->GetCredit(txout, filter);
|
nCredit += pwallet->GetCredit(txout, filter);
|
||||||
if (!MoneyRange(nCredit))
|
if (!MoneyRange(nCredit))
|
||||||
@ -1827,9 +1847,9 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
|
|||||||
return nCredit;
|
return nCredit;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount CWalletTx::GetImmatureWatchOnlyCredit(interfaces::Chain::Lock& locked_chain, const bool fUseCache) const
|
CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const
|
||||||
{
|
{
|
||||||
if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) {
|
if (IsImmatureCoinBase() && IsInMainChain()) {
|
||||||
return GetCachableAmount(IMMATURE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache);
|
return GetCachableAmount(IMMATURE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1860,7 +1880,7 @@ bool CWalletTx::IsTrusted(interfaces::Chain::Lock& locked_chain, std::set<uint25
|
|||||||
{
|
{
|
||||||
// Quick answer in most cases
|
// Quick answer in most cases
|
||||||
if (!locked_chain.checkFinalTx(*tx)) return false;
|
if (!locked_chain.checkFinalTx(*tx)) return false;
|
||||||
int nDepth = GetDepthInMainChain(locked_chain);
|
int nDepth = GetDepthInMainChain();
|
||||||
if (nDepth >= 1) return true;
|
if (nDepth >= 1) return true;
|
||||||
if (nDepth < 0) return false;
|
if (nDepth < 0) return false;
|
||||||
// using wtx's cached debit
|
// using wtx's cached debit
|
||||||
@ -1936,7 +1956,7 @@ void CWallet::ResendWalletTransactions()
|
|||||||
// any confirmed or conflicting txs.
|
// any confirmed or conflicting txs.
|
||||||
if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
|
if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
|
||||||
std::string unused_err_string;
|
std::string unused_err_string;
|
||||||
if (wtx.SubmitMemoryPoolAndRelay(unused_err_string, true, *locked_chain)) ++submitted_tx_count;
|
if (wtx.SubmitMemoryPoolAndRelay(unused_err_string, true)) ++submitted_tx_count;
|
||||||
}
|
}
|
||||||
} // locked_chain and cs_wallet
|
} // locked_chain and cs_wallet
|
||||||
|
|
||||||
@ -1973,9 +1993,9 @@ CWallet::Balance CWallet::GetBalance(const int min_depth, bool avoid_reuse) cons
|
|||||||
{
|
{
|
||||||
const CWalletTx& wtx = entry.second;
|
const CWalletTx& wtx = entry.second;
|
||||||
const bool is_trusted{wtx.IsTrusted(*locked_chain, trusted_parents)};
|
const bool is_trusted{wtx.IsTrusted(*locked_chain, trusted_parents)};
|
||||||
const int tx_depth{wtx.GetDepthInMainChain(*locked_chain)};
|
const int tx_depth{wtx.GetDepthInMainChain()};
|
||||||
const CAmount tx_credit_mine{wtx.GetAvailableCredit(*locked_chain, /* fUseCache */ true, ISMINE_SPENDABLE | reuse_filter)};
|
const CAmount tx_credit_mine{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_SPENDABLE | reuse_filter)};
|
||||||
const CAmount tx_credit_watchonly{wtx.GetAvailableCredit(*locked_chain, /* fUseCache */ true, ISMINE_WATCH_ONLY | reuse_filter)};
|
const CAmount tx_credit_watchonly{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_WATCH_ONLY | reuse_filter)};
|
||||||
if (is_trusted && tx_depth >= min_depth) {
|
if (is_trusted && tx_depth >= min_depth) {
|
||||||
ret.m_mine_trusted += tx_credit_mine;
|
ret.m_mine_trusted += tx_credit_mine;
|
||||||
ret.m_watchonly_trusted += tx_credit_watchonly;
|
ret.m_watchonly_trusted += tx_credit_watchonly;
|
||||||
@ -1984,8 +2004,8 @@ CWallet::Balance CWallet::GetBalance(const int min_depth, bool avoid_reuse) cons
|
|||||||
ret.m_mine_untrusted_pending += tx_credit_mine;
|
ret.m_mine_untrusted_pending += tx_credit_mine;
|
||||||
ret.m_watchonly_untrusted_pending += tx_credit_watchonly;
|
ret.m_watchonly_untrusted_pending += tx_credit_watchonly;
|
||||||
}
|
}
|
||||||
ret.m_mine_immature += wtx.GetImmatureCredit(*locked_chain);
|
ret.m_mine_immature += wtx.GetImmatureCredit();
|
||||||
ret.m_watchonly_immature += wtx.GetImmatureWatchOnlyCredit(*locked_chain);
|
ret.m_watchonly_immature += wtx.GetImmatureWatchOnlyCredit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -2029,10 +2049,10 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wtx.IsImmatureCoinBase(locked_chain))
|
if (wtx.IsImmatureCoinBase())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int nDepth = wtx.GetDepthInMainChain(locked_chain);
|
int nDepth = wtx.GetDepthInMainChain();
|
||||||
if (nDepth < 0)
|
if (nDepth < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -2092,7 +2112,7 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
|
|||||||
if (IsLockedCoin(entry.first, i))
|
if (IsLockedCoin(entry.first, i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (IsSpent(locked_chain, wtxid, i))
|
if (IsSpent(wtxid, i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
isminetype mine = IsMine(wtx.tx->vout[i]);
|
isminetype mine = IsMine(wtx.tx->vout[i]);
|
||||||
@ -2151,7 +2171,7 @@ std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins(interfaces::Ch
|
|||||||
for (const COutPoint& output : lockedCoins) {
|
for (const COutPoint& output : lockedCoins) {
|
||||||
auto it = mapWallet.find(output.hash);
|
auto it = mapWallet.find(output.hash);
|
||||||
if (it != mapWallet.end()) {
|
if (it != mapWallet.end()) {
|
||||||
int depth = it->second.GetDepthInMainChain(locked_chain);
|
int depth = it->second.GetDepthInMainChain();
|
||||||
if (depth >= 0 && output.n < it->second.tx->vout.size() &&
|
if (depth >= 0 && output.n < it->second.tx->vout.size() &&
|
||||||
IsMine(it->second.tx->vout[output.n]) == ISMINE_SPENDABLE) {
|
IsMine(it->second.tx->vout[output.n]) == ISMINE_SPENDABLE) {
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
@ -2891,7 +2911,7 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string err_string;
|
std::string err_string;
|
||||||
if (!wtx.SubmitMemoryPoolAndRelay(err_string, true, *locked_chain)) {
|
if (!wtx.SubmitMemoryPoolAndRelay(err_string, true)) {
|
||||||
WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
|
WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
|
||||||
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
|
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
|
||||||
}
|
}
|
||||||
@ -3111,10 +3131,10 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances(interfaces::Chain:
|
|||||||
if (!wtx.IsTrusted(locked_chain, trusted_parents))
|
if (!wtx.IsTrusted(locked_chain, trusted_parents))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (wtx.IsImmatureCoinBase(locked_chain))
|
if (wtx.IsImmatureCoinBase())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int nDepth = wtx.GetDepthInMainChain(locked_chain);
|
int nDepth = wtx.GetDepthInMainChain();
|
||||||
if (nDepth < (wtx.IsFromMe(ISMINE_ALL) ? 0 : 1))
|
if (nDepth < (wtx.IsFromMe(ISMINE_ALL) ? 0 : 1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -3126,7 +3146,7 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances(interfaces::Chain:
|
|||||||
if(!ExtractDestination(wtx.tx->vout[i].scriptPubKey, addr))
|
if(!ExtractDestination(wtx.tx->vout[i].scriptPubKey, addr))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CAmount n = IsSpent(locked_chain, walletEntry.first, i) ? 0 : wtx.tx->vout[i].nValue;
|
CAmount n = IsSpent(walletEntry.first, i) ? 0 : wtx.tx->vout[i].nValue;
|
||||||
|
|
||||||
if (!balances.count(addr))
|
if (!balances.count(addr))
|
||||||
balances[addr] = 0;
|
balances[addr] = 0;
|
||||||
@ -3785,8 +3805,10 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
|
|||||||
const Optional<int> tip_height = locked_chain->getHeight();
|
const Optional<int> tip_height = locked_chain->getHeight();
|
||||||
if (tip_height) {
|
if (tip_height) {
|
||||||
walletInstance->m_last_block_processed = locked_chain->getBlockHash(*tip_height);
|
walletInstance->m_last_block_processed = locked_chain->getBlockHash(*tip_height);
|
||||||
|
walletInstance->m_last_block_processed_height = *tip_height;
|
||||||
} else {
|
} else {
|
||||||
walletInstance->m_last_block_processed.SetNull();
|
walletInstance->m_last_block_processed.SetNull();
|
||||||
|
walletInstance->m_last_block_processed_height = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tip_height && *tip_height != rescan_height)
|
if (tip_height && *tip_height != rescan_height)
|
||||||
@ -3888,7 +3910,7 @@ void CWallet::postInitProcess()
|
|||||||
|
|
||||||
// Add wallet transactions that aren't already in a block to mempool
|
// Add wallet transactions that aren't already in a block to mempool
|
||||||
// Do this here as mempool requires genesis block to be loaded
|
// Do this here as mempool requires genesis block to be loaded
|
||||||
ReacceptWalletTransactions(*locked_chain);
|
ReacceptWalletTransactions();
|
||||||
|
|
||||||
// Update wallet transactions with current mempool transactions.
|
// Update wallet transactions with current mempool transactions.
|
||||||
chain().requestMempoolTransactions(*this);
|
chain().requestMempoolTransactions(*this);
|
||||||
@ -3914,38 +3936,28 @@ CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn)
|
|||||||
m_pre_split = false;
|
m_pre_split = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWalletTx::SetConf(Status status, const uint256& block_hash, int posInBlock)
|
int CWalletTx::GetDepthInMainChain() const
|
||||||
{
|
|
||||||
// Update tx status
|
|
||||||
m_confirm.status = status;
|
|
||||||
|
|
||||||
// Update the tx's hashBlock
|
|
||||||
m_confirm.hashBlock = block_hash;
|
|
||||||
|
|
||||||
// set the position of the transaction in the block
|
|
||||||
m_confirm.nIndex = posInBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CWalletTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
|
|
||||||
{
|
{
|
||||||
|
assert(pwallet != nullptr);
|
||||||
|
AssertLockHeld(pwallet->cs_wallet);
|
||||||
if (isUnconfirmed() || isAbandoned()) return 0;
|
if (isUnconfirmed() || isAbandoned()) return 0;
|
||||||
|
|
||||||
return locked_chain.getBlockDepth(m_confirm.hashBlock) * (isConflicted() ? -1 : 1);
|
return (pwallet->GetLastBlockHeight() - m_confirm.block_height + 1) * (isConflicted() ? -1 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CWalletTx::GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const
|
int CWalletTx::GetBlocksToMaturity() const
|
||||||
{
|
{
|
||||||
if (!IsCoinBase())
|
if (!IsCoinBase())
|
||||||
return 0;
|
return 0;
|
||||||
int chain_depth = GetDepthInMainChain(locked_chain);
|
int chain_depth = GetDepthInMainChain();
|
||||||
assert(chain_depth >= 0); // coinbase tx should not be conflicted
|
assert(chain_depth >= 0); // coinbase tx should not be conflicted
|
||||||
return std::max(0, (COINBASE_MATURITY+1) - chain_depth);
|
return std::max(0, (COINBASE_MATURITY+1) - chain_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletTx::IsImmatureCoinBase(interfaces::Chain::Lock& locked_chain) const
|
bool CWalletTx::IsImmatureCoinBase() const
|
||||||
{
|
{
|
||||||
// note GetBlocksToMaturity is 0 for non-coinbase tx
|
// note GetBlocksToMaturity is 0 for non-coinbase tx
|
||||||
return GetBlocksToMaturity(locked_chain) > 0;
|
return GetBlocksToMaturity() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outputs, bool single_coin) const {
|
std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outputs, bool single_coin) const {
|
||||||
|
@ -356,14 +356,17 @@ public:
|
|||||||
ABANDONED
|
ABANDONED
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Confirmation includes tx status and a pair of {block hash/tx index in block} at which tx has been confirmed.
|
/* Confirmation includes tx status and a triplet of {block height/block hash/tx index in block}
|
||||||
* This pair is both 0 if tx hasn't confirmed yet. Meaning of these fields changes with CONFLICTED state
|
* at which tx has been confirmed. All three are set to 0 if tx is unconfirmed or abandoned.
|
||||||
* where they instead point to block hash and index of the deepest conflicting tx.
|
* Meaning of these fields changes with CONFLICTED state where they instead point to block hash
|
||||||
|
* and block height of the deepest conflicting tx.
|
||||||
*/
|
*/
|
||||||
struct Confirmation {
|
struct Confirmation {
|
||||||
Status status = UNCONFIRMED;
|
Status status;
|
||||||
uint256 hashBlock = uint256();
|
int block_height;
|
||||||
int nIndex = 0;
|
uint256 hashBlock;
|
||||||
|
int nIndex;
|
||||||
|
Confirmation(Status s = UNCONFIRMED, int b = 0, uint256 h = uint256(), int i = 0) : status(s), block_height(b), hashBlock(h), nIndex(i) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
Confirmation m_confirm;
|
Confirmation m_confirm;
|
||||||
@ -406,7 +409,6 @@ public:
|
|||||||
* compatibility (pre-commit 9ac63d6).
|
* compatibility (pre-commit 9ac63d6).
|
||||||
*/
|
*/
|
||||||
if (serializedIndex == -1 && m_confirm.hashBlock == ABANDON_HASH) {
|
if (serializedIndex == -1 && m_confirm.hashBlock == ABANDON_HASH) {
|
||||||
m_confirm.hashBlock = uint256();
|
|
||||||
setAbandoned();
|
setAbandoned();
|
||||||
} else if (serializedIndex == -1) {
|
} else if (serializedIndex == -1) {
|
||||||
setConflicted();
|
setConflicted();
|
||||||
@ -447,14 +449,14 @@ public:
|
|||||||
|
|
||||||
//! filter decides which addresses will count towards the debit
|
//! filter decides which addresses will count towards the debit
|
||||||
CAmount GetDebit(const isminefilter& filter) const;
|
CAmount GetDebit(const isminefilter& filter) const;
|
||||||
CAmount GetCredit(interfaces::Chain::Lock& locked_chain, const isminefilter& filter) const;
|
CAmount GetCredit(const isminefilter& filter) const;
|
||||||
CAmount GetImmatureCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true) const;
|
CAmount GetImmatureCredit(bool fUseCache = true) const;
|
||||||
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
|
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
|
||||||
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The
|
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The
|
||||||
// annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
|
// annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
|
||||||
// having to resolve the issue of member access into incomplete type CWallet.
|
// having to resolve the issue of member access into incomplete type CWallet.
|
||||||
CAmount GetAvailableCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const NO_THREAD_SAFETY_ANALYSIS;
|
CAmount GetAvailableCredit(bool fUseCache = true, const isminefilter& filter = ISMINE_SPENDABLE) const NO_THREAD_SAFETY_ANALYSIS;
|
||||||
CAmount GetImmatureWatchOnlyCredit(interfaces::Chain::Lock& locked_chain, const bool fUseCache=true) const;
|
CAmount GetImmatureWatchOnlyCredit(const bool fUseCache = true) const;
|
||||||
CAmount GetChange() const;
|
CAmount GetChange() const;
|
||||||
|
|
||||||
// Get the marginal bytes if spending the specified output from this transaction
|
// Get the marginal bytes if spending the specified output from this transaction
|
||||||
@ -481,7 +483,7 @@ public:
|
|||||||
int64_t GetTxTime() const;
|
int64_t GetTxTime() const;
|
||||||
|
|
||||||
// Pass this transaction to node for mempool insertion and relay to peers if flag set to true
|
// Pass this transaction to node for mempool insertion and relay to peers if flag set to true
|
||||||
bool SubmitMemoryPoolAndRelay(std::string& err_string, bool relay, interfaces::Chain::Lock& locked_chain);
|
bool SubmitMemoryPoolAndRelay(std::string& err_string, bool relay);
|
||||||
|
|
||||||
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
|
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
|
||||||
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation
|
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation
|
||||||
@ -491,38 +493,44 @@ public:
|
|||||||
// in place.
|
// in place.
|
||||||
std::set<uint256> GetConflicts() const NO_THREAD_SAFETY_ANALYSIS;
|
std::set<uint256> GetConflicts() const NO_THREAD_SAFETY_ANALYSIS;
|
||||||
|
|
||||||
void SetConf(Status status, const uint256& block_hash, int posInBlock);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return depth of transaction in blockchain:
|
* Return depth of transaction in blockchain:
|
||||||
* <0 : conflicts with a transaction this deep in the blockchain
|
* <0 : conflicts with a transaction this deep in the blockchain
|
||||||
* 0 : in memory pool, waiting to be included in a block
|
* 0 : in memory pool, waiting to be included in a block
|
||||||
* >=1 : this many blocks deep in the main chain
|
* >=1 : this many blocks deep in the main chain
|
||||||
*/
|
*/
|
||||||
int GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const;
|
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
|
||||||
bool IsInMainChain(interfaces::Chain::Lock& locked_chain) const { return GetDepthInMainChain(locked_chain) > 0; }
|
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation
|
||||||
|
// "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to
|
||||||
|
// resolve the issue of member access into incomplete type CWallet. Note
|
||||||
|
// that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)"
|
||||||
|
// in place.
|
||||||
|
int GetDepthInMainChain() const NO_THREAD_SAFETY_ANALYSIS;
|
||||||
|
bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return number of blocks to maturity for this transaction:
|
* @return number of blocks to maturity for this transaction:
|
||||||
* 0 : is not a coinbase transaction, or is a mature coinbase transaction
|
* 0 : is not a coinbase transaction, or is a mature coinbase transaction
|
||||||
* >0 : is a coinbase transaction which matures in this many blocks
|
* >0 : is a coinbase transaction which matures in this many blocks
|
||||||
*/
|
*/
|
||||||
int GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const;
|
int GetBlocksToMaturity() const;
|
||||||
bool isAbandoned() const { return m_confirm.status == CWalletTx::ABANDONED; }
|
bool isAbandoned() const { return m_confirm.status == CWalletTx::ABANDONED; }
|
||||||
void setAbandoned()
|
void setAbandoned()
|
||||||
{
|
{
|
||||||
m_confirm.status = CWalletTx::ABANDONED;
|
m_confirm.status = CWalletTx::ABANDONED;
|
||||||
m_confirm.hashBlock = uint256();
|
m_confirm.hashBlock = uint256();
|
||||||
|
m_confirm.block_height = 0;
|
||||||
m_confirm.nIndex = 0;
|
m_confirm.nIndex = 0;
|
||||||
}
|
}
|
||||||
bool isConflicted() const { return m_confirm.status == CWalletTx::CONFLICTED; }
|
bool isConflicted() const { return m_confirm.status == CWalletTx::CONFLICTED; }
|
||||||
void setConflicted() { m_confirm.status = CWalletTx::CONFLICTED; }
|
void setConflicted() { m_confirm.status = CWalletTx::CONFLICTED; }
|
||||||
bool isUnconfirmed() const { return m_confirm.status == CWalletTx::UNCONFIRMED; }
|
bool isUnconfirmed() const { return m_confirm.status == CWalletTx::UNCONFIRMED; }
|
||||||
void setUnconfirmed() { m_confirm.status = CWalletTx::UNCONFIRMED; }
|
void setUnconfirmed() { m_confirm.status = CWalletTx::UNCONFIRMED; }
|
||||||
|
bool isConfirmed() const { return m_confirm.status == CWalletTx::CONFIRMED; }
|
||||||
void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; }
|
void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; }
|
||||||
const uint256& GetHash() const { return tx->GetHash(); }
|
const uint256& GetHash() const { return tx->GetHash(); }
|
||||||
bool IsCoinBase() const { return tx->IsCoinBase(); }
|
bool IsCoinBase() const { return tx->IsCoinBase(); }
|
||||||
bool IsImmatureCoinBase(interfaces::Chain::Lock& locked_chain) const;
|
bool IsImmatureCoinBase() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class COutput
|
class COutput
|
||||||
@ -642,10 +650,10 @@ private:
|
|||||||
* Abandoned state should probably be more carefully tracked via different
|
* Abandoned state should probably be more carefully tracked via different
|
||||||
* posInBlock signals or by checking mempool presence when necessary.
|
* posInBlock signals or by checking mempool presence when necessary.
|
||||||
*/
|
*/
|
||||||
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, CWalletTx::Status status, const uint256& block_hash, int posInBlock, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, CWalletTx::Confirmation confirm, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
|
|
||||||
/* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */
|
/* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */
|
||||||
void MarkConflicted(const uint256& hashBlock, const uint256& hashTx);
|
void MarkConflicted(const uint256& hashBlock, int conflicting_height, const uint256& hashTx);
|
||||||
|
|
||||||
/* Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed */
|
/* Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed */
|
||||||
void MarkInputsDirty(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void MarkInputsDirty(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
@ -654,7 +662,7 @@ private:
|
|||||||
|
|
||||||
/* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions.
|
/* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions.
|
||||||
* Should be called with non-zero block_hash and posInBlock if this is for a transaction that is included in a block. */
|
* Should be called with non-zero block_hash and posInBlock if this is for a transaction that is included in a block. */
|
||||||
void SyncTransaction(const CTransactionRef& tx, CWalletTx::Status status, const uint256& block_hash, int posInBlock = 0, bool update_tx = true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void SyncTransaction(const CTransactionRef& tx, CWalletTx::Confirmation confirm, bool update_tx = true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
|
|
||||||
std::atomic<uint64_t> m_wallet_flags{0};
|
std::atomic<uint64_t> m_wallet_flags{0};
|
||||||
|
|
||||||
@ -679,12 +687,18 @@ private:
|
|||||||
* The following is used to keep track of how far behind the wallet is
|
* The following is used to keep track of how far behind the wallet is
|
||||||
* from the chain sync, and to allow clients to block on us being caught up.
|
* from the chain sync, and to allow clients to block on us being caught up.
|
||||||
*
|
*
|
||||||
* Note that this is *not* how far we've processed, we may need some rescan
|
* Processed hash is a pointer on node's tip and doesn't imply that the wallet
|
||||||
* to have seen all transactions in the chain, but is only used to track
|
* has scanned sequentially all blocks up to this one.
|
||||||
* live BlockConnected callbacks.
|
|
||||||
*/
|
*/
|
||||||
uint256 m_last_block_processed GUARDED_BY(cs_wallet);
|
uint256 m_last_block_processed GUARDED_BY(cs_wallet);
|
||||||
|
|
||||||
|
/* Height of last block processed is used by wallet to know depth of transactions
|
||||||
|
* without relying on Chain interface beyond asynchronous updates. For safety, we
|
||||||
|
* initialize it to -1. Height is a pointer on node's tip and doesn't imply
|
||||||
|
* that the wallet has scanned sequentially all blocks up to this one.
|
||||||
|
*/
|
||||||
|
int m_last_block_processed_height GUARDED_BY(cs_wallet) = -1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*
|
/*
|
||||||
* Main wallet lock.
|
* Main wallet lock.
|
||||||
@ -794,7 +808,7 @@ public:
|
|||||||
bool SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<OutputGroup> groups,
|
bool SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<OutputGroup> groups,
|
||||||
std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const;
|
std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const;
|
||||||
|
|
||||||
bool IsSpent(interfaces::Chain::Lock& locked_chain, const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
bool IsSpent(const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
|
|
||||||
// Whether this or any UTXO with the same CTxDestination has been spent.
|
// Whether this or any UTXO with the same CTxDestination has been spent.
|
||||||
bool IsUsedDestination(const CTxDestination& dst) const;
|
bool IsUsedDestination(const CTxDestination& dst) const;
|
||||||
@ -855,8 +869,8 @@ public:
|
|||||||
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
|
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
|
||||||
void LoadToWallet(CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void LoadToWallet(CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
void TransactionAddedToMempool(const CTransactionRef& tx) override;
|
void TransactionAddedToMempool(const CTransactionRef& tx) override;
|
||||||
void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted) override;
|
void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted, int height) override;
|
||||||
void BlockDisconnected(const CBlock& block) override;
|
void BlockDisconnected(const CBlock& block, int height) override;
|
||||||
void UpdatedBlockTip() override;
|
void UpdatedBlockTip() override;
|
||||||
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
|
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
|
||||||
|
|
||||||
@ -877,7 +891,7 @@ public:
|
|||||||
};
|
};
|
||||||
ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate);
|
ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate);
|
||||||
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
|
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
|
||||||
void ReacceptWalletTransactions(interfaces::Chain::Lock& locked_chain) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
void ResendWalletTransactions();
|
void ResendWalletTransactions();
|
||||||
struct Balance {
|
struct Balance {
|
||||||
CAmount m_mine_trusted{0}; //!< Trusted, at depth=GetBalance.min_depth or more
|
CAmount m_mine_trusted{0}; //!< Trusted, at depth=GetBalance.min_depth or more
|
||||||
@ -1056,7 +1070,7 @@ public:
|
|||||||
bool TransactionCanBeAbandoned(const uint256& hashTx) const;
|
bool TransactionCanBeAbandoned(const uint256& hashTx) const;
|
||||||
|
|
||||||
/* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
|
/* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
|
||||||
bool AbandonTransaction(interfaces::Chain::Lock& locked_chain, const uint256& hashTx);
|
bool AbandonTransaction(const uint256& hashTx);
|
||||||
|
|
||||||
/** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
|
/** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
|
||||||
bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
|
bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
|
||||||
@ -1129,6 +1143,21 @@ public:
|
|||||||
LegacyScriptPubKeyMan::WatchKeyMap& mapWatchKeys GUARDED_BY(cs_KeyStore) = m_spk_man->mapWatchKeys;
|
LegacyScriptPubKeyMan::WatchKeyMap& mapWatchKeys GUARDED_BY(cs_KeyStore) = m_spk_man->mapWatchKeys;
|
||||||
WalletBatch*& encrypted_batch GUARDED_BY(cs_wallet) = m_spk_man->encrypted_batch;
|
WalletBatch*& encrypted_batch GUARDED_BY(cs_wallet) = m_spk_man->encrypted_batch;
|
||||||
using CryptedKeyMap = LegacyScriptPubKeyMan::CryptedKeyMap;
|
using CryptedKeyMap = LegacyScriptPubKeyMan::CryptedKeyMap;
|
||||||
|
|
||||||
|
/** Get last block processed height */
|
||||||
|
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_wallet);
|
||||||
|
assert(m_last_block_processed_height >= 0);
|
||||||
|
return m_last_block_processed_height;
|
||||||
|
};
|
||||||
|
/** Set last block processed height, currently only use in unit test */
|
||||||
|
void SetLastBlockProcessed(int block_height, uint256 block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_wallet);
|
||||||
|
m_last_block_processed_height = block_height;
|
||||||
|
m_last_block_processed = block_hash;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -185,7 +185,7 @@ void CZMQNotificationInterface::BlockConnected(const std::shared_ptr<const CBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CZMQNotificationInterface::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock)
|
void CZMQNotificationInterface::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected)
|
||||||
{
|
{
|
||||||
for (const CTransactionRef& ptx : pblock->vtx) {
|
for (const CTransactionRef& ptx : pblock->vtx) {
|
||||||
// Do a normal notify for each transaction removed in block disconnection
|
// Do a normal notify for each transaction removed in block disconnection
|
||||||
|
@ -27,7 +27,7 @@ protected:
|
|||||||
// CValidationInterface
|
// CValidationInterface
|
||||||
void TransactionAddedToMempool(const CTransactionRef& tx) override;
|
void TransactionAddedToMempool(const CTransactionRef& tx) override;
|
||||||
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted) override;
|
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted) override;
|
||||||
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
|
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected) override;
|
||||||
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
|
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user