diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -179,6 +179,12 @@ virtual bool findBlock(const BlockHash &hash, const FoundBlock &block = {}) = 0; + //! Return whether block descends from a specified ancestor, and + //! optionally return ancestor information. + virtual bool findAncestorByHash(const BlockHash &block_hash, + const BlockHash &ancestor_hash, + const FoundBlock &ancestor_out = {}) = 0; + //! Look up unspent output information. Returns coins in the mempool and in //! the current chain UTXO set. Iterates through all the keys in the map and //! populates the values. diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -289,6 +289,18 @@ WAIT_LOCK(cs_main, lock); return FillBlock(LookupBlockIndex(hash), block, lock); } + bool findAncestorByHash(const BlockHash &block_hash, + const BlockHash &ancestor_hash, + const FoundBlock &ancestor_out) override { + WAIT_LOCK(cs_main, lock); + const CBlockIndex *block = LookupBlockIndex(block_hash); + const CBlockIndex *ancestor = LookupBlockIndex(ancestor_hash); + if (block && ancestor && + block->GetAncestor(ancestor->nHeight) != ancestor) { + ancestor = nullptr; + } + return FillBlock(ancestor, ancestor_out, lock); + } void findCoins(std::map &coins) override { return FindCoins(coins); } diff --git a/src/test/interfaces_tests.cpp b/src/test/interfaces_tests.cpp --- a/src/test/interfaces_tests.cpp +++ b/src/test/interfaces_tests.cpp @@ -50,4 +50,16 @@ BOOST_CHECK(!chain->findBlock(BlockHash(), FoundBlock())); } +BOOST_AUTO_TEST_CASE(findAncestorByHash) { + auto chain = interfaces::MakeChain(m_node, Params()); + auto &active = ChainActive(); + int height = -1; + BOOST_CHECK(chain->findAncestorByHash(active[20]->GetBlockHash(), + active[10]->GetBlockHash(), + FoundBlock().height(height))); + BOOST_CHECK_EQUAL(height, 10); + BOOST_CHECK(!chain->findAncestorByHash(active[10]->GetBlockHash(), + active[20]->GetBlockHash())); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -26,6 +26,8 @@ #include #include +using interfaces::FoundBlock; + static std::string EncodeDumpString(const std::string &str) { std::stringstream ret; for (const uint8_t c : str) { @@ -425,9 +427,11 @@ } auto locked_chain = pwallet->chain().lock(); - Optional height = - locked_chain->getBlockHeight(merkleBlock.header.GetHash()); - if (height == nullopt) { + LOCK(pwallet->cs_wallet); + int height; + if (!pwallet->chain().findAncestorByHash(pwallet->GetLastBlockHash(), + merkleBlock.header.GetHash(), + FoundBlock().height(height))) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); } @@ -440,12 +444,10 @@ size_t txnIndex = vIndex[it - vMatch.begin()]; - CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, *height, + CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, height, merkleBlock.header.GetHash(), txnIndex); wtx.m_confirm = confirm; - LOCK(pwallet->cs_wallet); - if (pwallet->IsMine(*wtx.tx)) { pwallet->AddToWallet(wtx, false); return NullUniValue;