mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 10:38:42 +01:00
refactor: Get rid of more redundant chain methods
This just drops three interfaces::Chain methods replacing them with other calls. Motivation for removing these chain methods: - Need to get rid of findFirstBlockWithTimeAndHeight for #10102, which doesn't support overloaded methods - Followup from https://github.com/bitcoin/bitcoin/pull/16426#discussion_r412487403 - phantomcircuit comments about findNextBlock test http://www.erisian.com.au/bitcoin-core-dev/log-2020-06-06.html#l-214 Behavior is not changing in any way here. A TODO comment in ScanForWalletTransactions was removed, but just because it was invalid (see https://github.com/bitcoin/bitcoin/pull/19195#discussion_r448020762), not because it was implemented.
This commit is contained in:
parent
5c4911e7e7
commit
3fbbb9a640
@ -44,6 +44,10 @@ public:
|
||||
FoundBlock& time(int64_t& time) { m_time = &time; return *this; }
|
||||
FoundBlock& maxTime(int64_t& max_time) { m_max_time = &max_time; return *this; }
|
||||
FoundBlock& mtpTime(int64_t& mtp_time) { m_mtp_time = &mtp_time; return *this; }
|
||||
//! Return whether block is in the active (most-work) chain.
|
||||
FoundBlock& inActiveChain(bool& in_active_chain) { m_in_active_chain = &in_active_chain; return *this; }
|
||||
//! Return next block in the active chain if current block is in the active chain.
|
||||
FoundBlock& nextBlock(const FoundBlock& next_block) { m_next_block = &next_block; return *this; }
|
||||
//! Read block data from disk. If the block exists but doesn't have data
|
||||
//! (for example due to pruning), the CBlock variable will be set to null.
|
||||
FoundBlock& data(CBlock& data) { m_data = &data; return *this; }
|
||||
@ -53,6 +57,8 @@ public:
|
||||
int64_t* m_time = nullptr;
|
||||
int64_t* m_max_time = nullptr;
|
||||
int64_t* m_mtp_time = nullptr;
|
||||
bool* m_in_active_chain = nullptr;
|
||||
const FoundBlock* m_next_block = nullptr;
|
||||
CBlock* m_data = nullptr;
|
||||
};
|
||||
|
||||
@ -77,9 +83,9 @@ public:
|
||||
//! wallet cache it, fee estimation being driven by node mempool, wallet
|
||||
//! should be the consumer.
|
||||
//!
|
||||
//! * The `guessVerificationProgress`, `getBlockHeight`, `getBlockHash`, etc
|
||||
//! methods can go away if rescan logic is moved on the node side, and wallet
|
||||
//! only register rescan request.
|
||||
//! * `guessVerificationProgress` and similar methods can go away if rescan
|
||||
//! logic moves out of the wallet, and the wallet just requests scans from the
|
||||
//! node (https://github.com/bitcoin/bitcoin/issues/11756)
|
||||
class Chain
|
||||
{
|
||||
public:
|
||||
@ -90,11 +96,6 @@ public:
|
||||
//! any blocks)
|
||||
virtual Optional<int> getHeight() = 0;
|
||||
|
||||
//! Get block height above genesis block. Returns 0 for genesis block,
|
||||
//! 1 for following block, and so on. Returns nullopt for a block not
|
||||
//! included in the current chain.
|
||||
virtual Optional<int> getBlockHeight(const uint256& hash) = 0;
|
||||
|
||||
//! Get block hash. Height must be valid or this function will abort.
|
||||
virtual uint256 getBlockHash(int height) = 0;
|
||||
|
||||
@ -102,13 +103,6 @@ public:
|
||||
//! pruned), and contains transactions.
|
||||
virtual bool haveBlockOnDisk(int height) = 0;
|
||||
|
||||
//! Return height of the first block in the chain with timestamp equal
|
||||
//! or greater than the given time and height equal or greater than the
|
||||
//! given height, or nullopt if there is no block with a high enough
|
||||
//! timestamp and height. Also return the block hash as an optional output parameter
|
||||
//! (to avoid the cost of a second lookup in case this information is needed.)
|
||||
virtual Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) = 0;
|
||||
|
||||
//! Get locator for the current chain tip.
|
||||
virtual CBlockLocator getTipLocator() = 0;
|
||||
|
||||
@ -130,11 +124,6 @@ public:
|
||||
//! information.
|
||||
virtual bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block={}) = 0;
|
||||
|
||||
//! Find next block if block is part of current chain. Also flag if
|
||||
//! there was a reorg and the specified block hash is no longer in the
|
||||
//! current chain, and optionally return block information.
|
||||
virtual bool findNextBlock(const uint256& block_hash, int block_height, const FoundBlock& next={}, bool* reorg=nullptr) = 0;
|
||||
|
||||
//! Find ancestor of block at specified height and optionally return
|
||||
//! ancestor information.
|
||||
virtual bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out={}) = 0;
|
||||
|
@ -311,6 +311,8 @@ bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<Rec
|
||||
if (block.m_time) *block.m_time = index->GetBlockTime();
|
||||
if (block.m_max_time) *block.m_max_time = index->GetBlockTimeMax();
|
||||
if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast();
|
||||
if (block.m_in_active_chain) *block.m_in_active_chain = ChainActive()[index->nHeight] == index;
|
||||
if (block.m_next_block) FillBlock(ChainActive()[index->nHeight] == index ? ChainActive()[index->nHeight + 1] : nullptr, *block.m_next_block, lock);
|
||||
if (block.m_data) {
|
||||
REVERSE_LOCK(lock);
|
||||
if (!ReadBlockFromDisk(*block.m_data, index, Params().GetConsensus())) block.m_data->SetNull();
|
||||
@ -419,15 +421,6 @@ public:
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
Optional<int> getBlockHeight(const uint256& hash) override
|
||||
{
|
||||
LOCK(::cs_main);
|
||||
CBlockIndex* block = LookupBlockIndex(hash);
|
||||
if (block && ::ChainActive().Contains(block)) {
|
||||
return block->nHeight;
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
uint256 getBlockHash(int height) override
|
||||
{
|
||||
LOCK(::cs_main);
|
||||
@ -441,16 +434,6 @@ public:
|
||||
CBlockIndex* block = ::ChainActive()[height];
|
||||
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
|
||||
}
|
||||
Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override
|
||||
{
|
||||
LOCK(cs_main);
|
||||
CBlockIndex* block = ::ChainActive().FindEarliestAtLeast(time, height);
|
||||
if (block) {
|
||||
if (hash) *hash = block->GetBlockHash();
|
||||
return block->nHeight;
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
CBlockLocator getTipLocator() override
|
||||
{
|
||||
LOCK(cs_main);
|
||||
@ -479,13 +462,6 @@ public:
|
||||
WAIT_LOCK(cs_main, lock);
|
||||
return FillBlock(ChainActive().FindEarliestAtLeast(min_time, min_height), block, lock);
|
||||
}
|
||||
bool findNextBlock(const uint256& block_hash, int block_height, const FoundBlock& next, bool* reorg) override {
|
||||
WAIT_LOCK(cs_main, lock);
|
||||
CBlockIndex* block = ChainActive()[block_height];
|
||||
if (block && block->GetBlockHash() != block_hash) block = nullptr;
|
||||
if (reorg) *reorg = !block;
|
||||
return FillBlock(block ? ChainActive()[block_height + 1] : nullptr, next, lock);
|
||||
}
|
||||
bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override
|
||||
{
|
||||
WAIT_LOCK(cs_main, lock);
|
||||
|
@ -44,6 +44,18 @@ BOOST_AUTO_TEST_CASE(findBlock)
|
||||
BOOST_CHECK(chain->findBlock(active[60]->GetBlockHash(), FoundBlock().mtpTime(mtp_time)));
|
||||
BOOST_CHECK_EQUAL(mtp_time, active[60]->GetMedianTimePast());
|
||||
|
||||
bool cur_active{false}, next_active{false};
|
||||
uint256 next_hash;
|
||||
BOOST_CHECK_EQUAL(active.Height(), 100);
|
||||
BOOST_CHECK(chain->findBlock(active[99]->GetBlockHash(), FoundBlock().inActiveChain(cur_active).nextBlock(FoundBlock().inActiveChain(next_active).hash(next_hash))));
|
||||
BOOST_CHECK(cur_active);
|
||||
BOOST_CHECK(next_active);
|
||||
BOOST_CHECK_EQUAL(next_hash, active[100]->GetBlockHash());
|
||||
cur_active = next_active = false;
|
||||
BOOST_CHECK(chain->findBlock(active[100]->GetBlockHash(), FoundBlock().inActiveChain(cur_active).nextBlock(FoundBlock().inActiveChain(next_active))));
|
||||
BOOST_CHECK(cur_active);
|
||||
BOOST_CHECK(!next_active);
|
||||
|
||||
BOOST_CHECK(!chain->findBlock({}, FoundBlock()));
|
||||
}
|
||||
|
||||
@ -59,21 +71,6 @@ BOOST_AUTO_TEST_CASE(findFirstBlockWithTimeAndHeight)
|
||||
BOOST_CHECK(!chain->findFirstBlockWithTimeAndHeight(/* min_time= */ active.Tip()->GetBlockTimeMax() + 1, /* min_height= */ 0));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(findNextBlock)
|
||||
{
|
||||
auto chain = interfaces::MakeChain(m_node);
|
||||
auto& active = ChainActive();
|
||||
bool reorg;
|
||||
uint256 hash;
|
||||
BOOST_CHECK(chain->findNextBlock(active[20]->GetBlockHash(), 20, FoundBlock().hash(hash), &reorg));
|
||||
BOOST_CHECK_EQUAL(hash, active[21]->GetBlockHash());
|
||||
BOOST_CHECK_EQUAL(reorg, false);
|
||||
BOOST_CHECK(!chain->findNextBlock(uint256(), 20, {}, &reorg));
|
||||
BOOST_CHECK_EQUAL(reorg, true);
|
||||
BOOST_CHECK(!chain->findNextBlock(active.Tip()->GetBlockHash(), active.Height(), {}, &reorg));
|
||||
BOOST_CHECK_EQUAL(reorg, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(findAncestorByHeight)
|
||||
{
|
||||
auto chain = interfaces::MakeChain(m_node);
|
||||
|
@ -946,11 +946,12 @@ bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx
|
||||
}
|
||||
// If wallet doesn't have a chain (e.g wallet-tool), don't bother to update txn.
|
||||
if (HaveChain()) {
|
||||
Optional<int> block_height = chain().getBlockHeight(wtx.m_confirm.hashBlock);
|
||||
if (block_height) {
|
||||
bool active;
|
||||
int height;
|
||||
if (chain().findBlock(wtx.m_confirm.hashBlock, FoundBlock().inActiveChain(active).height(height)) && active) {
|
||||
// Update cached block height variable since it not stored in the
|
||||
// serialized transaction.
|
||||
wtx.m_confirm.block_height = *block_height;
|
||||
wtx.m_confirm.block_height = height;
|
||||
} else if (wtx.isConflicted() || wtx.isConfirmed()) {
|
||||
// If tx block (or conflicting block) was reorged out of chain
|
||||
// while the wallet was shutdown, change tx status to UNCONFIRMED
|
||||
@ -1771,18 +1772,22 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
|
||||
WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
|
||||
}
|
||||
|
||||
// Read block data
|
||||
CBlock block;
|
||||
bool next_block;
|
||||
chain().findBlock(block_hash, FoundBlock().data(block));
|
||||
|
||||
// Find next block separately from reading data above, because reading
|
||||
// is slow and there might be a reorg while it is read.
|
||||
bool block_still_active = false;
|
||||
bool next_block = false;
|
||||
uint256 next_block_hash;
|
||||
bool reorg = false;
|
||||
if (chain().findBlock(block_hash, FoundBlock().data(block)) && !block.IsNull()) {
|
||||
chain().findBlock(block_hash, FoundBlock().inActiveChain(block_still_active).nextBlock(FoundBlock().inActiveChain(next_block).hash(next_block_hash)));
|
||||
|
||||
if (!block.IsNull()) {
|
||||
LOCK(cs_wallet);
|
||||
next_block = chain().findNextBlock(block_hash, block_height, FoundBlock().hash(next_block_hash), &reorg);
|
||||
if (reorg) {
|
||||
if (!block_still_active) {
|
||||
// Abort scan if current block is no longer active, to prevent
|
||||
// marking transactions as coming from the wrong block.
|
||||
// TODO: This should return success instead of failure, see
|
||||
// https://github.com/bitcoin/bitcoin/pull/14711#issuecomment-458342518
|
||||
result.last_failed_block = block_hash;
|
||||
result.status = ScanResult::FAILURE;
|
||||
break;
|
||||
@ -1797,13 +1802,12 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
|
||||
// could not scan block, keep scanning but record this block as the most recent failure
|
||||
result.last_failed_block = block_hash;
|
||||
result.status = ScanResult::FAILURE;
|
||||
next_block = chain().findNextBlock(block_hash, block_height, FoundBlock().hash(next_block_hash), &reorg);
|
||||
}
|
||||
if (max_height && block_height >= *max_height) {
|
||||
break;
|
||||
}
|
||||
{
|
||||
if (!next_block || reorg) {
|
||||
if (!next_block) {
|
||||
// break successfully when rescan has reached the tip, or
|
||||
// previous block is no longer on the chain due to a reorg
|
||||
break;
|
||||
@ -4058,9 +4062,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
|
||||
if (!time_first_key || time < *time_first_key) time_first_key = time;
|
||||
}
|
||||
if (time_first_key) {
|
||||
if (Optional<int> first_block = chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, nullptr)) {
|
||||
rescan_height = *first_block;
|
||||
}
|
||||
chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, FoundBlock().height(rescan_height));
|
||||
}
|
||||
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user