Skip to content

Commit 72ca72e

Browse files
committed
Merge #14711: Remove uses of chainActive and mapBlockIndex in wallet code
44de156 Remove remaining chainActive references from CWallet (Russell Yanofsky) db21f02 Convert CWallet::ScanForWalletTransactions and SyncTransaction to the new Chain apis (Russell Yanofsky) 2ffb079 Add findFork and findBlock to the Chain interface (Russell Yanofsky) d93c4c1 Add time methods to the Chain interface (Russell Yanofsky) 700c42b Add height, depth, and hash methods to the Chain interface (Russell Yanofsky) Pull request description: This change removes uses of `chainActive` and `mapBlockIndex` globals in wallet code. It is a refactoring change which does not affect external behavior. This is the next step in the larger #10973 refactoring change, which removes all other accesses to node global variables from wallet code. Doing this is useful to provide a better defined interface between the wallet and node, and necessary to allow wallet and node code to run in separate processes in #10102. Tree-SHA512: 4dcec8a31c458f54e2ea6ecf01e430469b0994c5b41a21a2d150efa67cd209f4c93ae210a101e064b3a87c52c6edfc70b070e979992be0e3a00fd425de6230a8
2 parents 2d790e8 + 44de156 commit 72ca72e

File tree

11 files changed

+486
-215
lines changed

11 files changed

+486
-215
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ BITCOIN_CORE_H = \
146146
netbase.h \
147147
netmessagemaker.h \
148148
noui.h \
149+
optional.h \
149150
outputtype.h \
150151
policy/feerate.h \
151152
policy/fees.h \

src/interfaces/chain.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44

55
#include <interfaces/chain.h>
66

7+
#include <chain.h>
8+
#include <chainparams.h>
9+
#include <primitives/block.h>
710
#include <sync.h>
11+
#include <uint256.h>
812
#include <util/system.h>
913
#include <validation.h>
1014

@@ -16,6 +20,118 @@ namespace {
1620

1721
class LockImpl : public Chain::Lock
1822
{
23+
Optional<int> getHeight() override
24+
{
25+
int height = ::chainActive.Height();
26+
if (height >= 0) {
27+
return height;
28+
}
29+
return nullopt;
30+
}
31+
Optional<int> getBlockHeight(const uint256& hash) override
32+
{
33+
CBlockIndex* block = LookupBlockIndex(hash);
34+
if (block && ::chainActive.Contains(block)) {
35+
return block->nHeight;
36+
}
37+
return nullopt;
38+
}
39+
int getBlockDepth(const uint256& hash) override
40+
{
41+
const Optional<int> tip_height = getHeight();
42+
const Optional<int> height = getBlockHeight(hash);
43+
return tip_height && height ? *tip_height - *height + 1 : 0;
44+
}
45+
uint256 getBlockHash(int height) override
46+
{
47+
CBlockIndex* block = ::chainActive[height];
48+
assert(block != nullptr);
49+
return block->GetBlockHash();
50+
}
51+
int64_t getBlockTime(int height) override
52+
{
53+
CBlockIndex* block = ::chainActive[height];
54+
assert(block != nullptr);
55+
return block->GetBlockTime();
56+
}
57+
int64_t getBlockMedianTimePast(int height) override
58+
{
59+
CBlockIndex* block = ::chainActive[height];
60+
assert(block != nullptr);
61+
return block->GetMedianTimePast();
62+
}
63+
bool haveBlockOnDisk(int height) override
64+
{
65+
CBlockIndex* block = ::chainActive[height];
66+
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
67+
}
68+
Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) override
69+
{
70+
CBlockIndex* block = ::chainActive.FindEarliestAtLeast(time);
71+
if (block) {
72+
if (hash) *hash = block->GetBlockHash();
73+
return block->nHeight;
74+
}
75+
return nullopt;
76+
}
77+
Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height) override
78+
{
79+
// TODO: Could update CChain::FindEarliestAtLeast() to take a height
80+
// parameter and use it with std::lower_bound() to make this
81+
// implementation more efficient and allow combining
82+
// findFirstBlockWithTime and findFirstBlockWithTimeAndHeight into one
83+
// method.
84+
for (CBlockIndex* block = ::chainActive[height]; block; block = ::chainActive.Next(block)) {
85+
if (block->GetBlockTime() >= time) {
86+
return block->nHeight;
87+
}
88+
}
89+
return nullopt;
90+
}
91+
Optional<int> findPruned(int start_height, Optional<int> stop_height) override
92+
{
93+
if (::fPruneMode) {
94+
CBlockIndex* block = stop_height ? ::chainActive[*stop_height] : ::chainActive.Tip();
95+
while (block && block->nHeight >= start_height) {
96+
if ((block->nStatus & BLOCK_HAVE_DATA) == 0) {
97+
return block->nHeight;
98+
}
99+
block = block->pprev;
100+
}
101+
}
102+
return nullopt;
103+
}
104+
Optional<int> findFork(const uint256& hash, Optional<int>* height) override
105+
{
106+
const CBlockIndex* block = LookupBlockIndex(hash);
107+
const CBlockIndex* fork = block ? ::chainActive.FindFork(block) : nullptr;
108+
if (height) {
109+
if (block) {
110+
*height = block->nHeight;
111+
} else {
112+
height->reset();
113+
}
114+
}
115+
if (fork) {
116+
return fork->nHeight;
117+
}
118+
return nullopt;
119+
}
120+
bool isPotentialTip(const uint256& hash) override
121+
{
122+
if (::chainActive.Tip()->GetBlockHash() == hash) return true;
123+
CBlockIndex* block = LookupBlockIndex(hash);
124+
return block && block->GetAncestor(::chainActive.Height()) == ::chainActive.Tip();
125+
}
126+
CBlockLocator getLocator() override { return ::chainActive.GetLocator(); }
127+
Optional<int> findLocatorFork(const CBlockLocator& locator) override
128+
{
129+
LockAnnotation lock(::cs_main);
130+
if (CBlockIndex* fork = FindForkInGlobalIndex(::chainActive, locator)) {
131+
return fork->nHeight;
132+
}
133+
return nullopt;
134+
}
19135
};
20136

21137
class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
@@ -35,6 +151,32 @@ class ChainImpl : public Chain
35151
return std::move(result);
36152
}
37153
std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); }
154+
bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override
155+
{
156+
CBlockIndex* index;
157+
{
158+
LOCK(cs_main);
159+
index = LookupBlockIndex(hash);
160+
if (!index) {
161+
return false;
162+
}
163+
if (time) {
164+
*time = index->GetBlockTime();
165+
}
166+
if (time_max) {
167+
*time_max = index->GetBlockTimeMax();
168+
}
169+
}
170+
if (block && !ReadBlockFromDisk(*block, index, Params().GetConsensus())) {
171+
block->SetNull();
172+
}
173+
return true;
174+
}
175+
double guessVerificationProgress(const uint256& block_hash) override
176+
{
177+
LOCK(cs_main);
178+
return GuessVerificationProgress(Params().TxData(), LookupBlockIndex(block_hash));
179+
}
38180
};
39181

40182
} // namespace

src/interfaces/chain.h

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@
55
#ifndef BITCOIN_INTERFACES_CHAIN_H
66
#define BITCOIN_INTERFACES_CHAIN_H
77

8+
#include <optional.h>
9+
810
#include <memory>
11+
#include <stdint.h>
912
#include <string>
1013
#include <vector>
1114

15+
class CBlock;
1216
class CScheduler;
17+
class uint256;
18+
struct CBlockLocator;
1319

1420
namespace interfaces {
1521

@@ -28,6 +34,74 @@ class Chain
2834
{
2935
public:
3036
virtual ~Lock() {}
37+
38+
//! Get current chain height, not including genesis block (returns 0 if
39+
//! chain only contains genesis block, nullopt if chain does not contain
40+
//! any blocks).
41+
virtual Optional<int> getHeight() = 0;
42+
43+
//! Get block height above genesis block. Returns 0 for genesis block,
44+
//! 1 for following block, and so on. Returns nullopt for a block not
45+
//! included in the current chain.
46+
virtual Optional<int> getBlockHeight(const uint256& hash) = 0;
47+
48+
//! Get block depth. Returns 1 for chain tip, 2 for preceding block, and
49+
//! so on. Returns 0 for a block not included in the current chain.
50+
virtual int getBlockDepth(const uint256& hash) = 0;
51+
52+
//! Get block hash. Height must be valid or this function will abort.
53+
virtual uint256 getBlockHash(int height) = 0;
54+
55+
//! Get block time. Height must be valid or this function will abort.
56+
virtual int64_t getBlockTime(int height) = 0;
57+
58+
//! Get block median time past. Height must be valid or this function
59+
//! will abort.
60+
virtual int64_t getBlockMedianTimePast(int height) = 0;
61+
62+
//! Check that the block is available on disk (i.e. has not been
63+
//! pruned), and contains transactions.
64+
virtual bool haveBlockOnDisk(int height) = 0;
65+
66+
//! Return height of the first block in the chain with timestamp equal
67+
//! or greater than the given time, or nullopt if there is no block with
68+
//! a high enough timestamp. Also return the block hash as an optional
69+
//! output parameter (to avoid the cost of a second lookup in case this
70+
//! information is needed.)
71+
virtual Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) = 0;
72+
73+
//! Return height of the first block in the chain with timestamp equal
74+
//! or greater than the given time and height equal or greater than the
75+
//! given height, or nullopt if there is no such block.
76+
//!
77+
//! Calling this with height 0 is equivalent to calling
78+
//! findFirstBlockWithTime, but less efficient because it requires a
79+
//! linear instead of a binary search.
80+
virtual Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height) = 0;
81+
82+
//! Return height of last block in the specified range which is pruned, or
83+
//! nullopt if no block in the range is pruned. Range is inclusive.
84+
virtual Optional<int> findPruned(int start_height = 0, Optional<int> stop_height = nullopt) = 0;
85+
86+
//! Return height of the highest block on the chain that is an ancestor
87+
//! of the specified block, or nullopt if no common ancestor is found.
88+
//! Also return the height of the specified block as an optional output
89+
//! parameter (to avoid the cost of a second hash lookup in case this
90+
//! information is desired).
91+
virtual Optional<int> findFork(const uint256& hash, Optional<int>* height) = 0;
92+
93+
//! Return true if block hash points to the current chain tip, or to a
94+
//! possible descendant of the current chain tip that isn't currently
95+
//! connected.
96+
virtual bool isPotentialTip(const uint256& hash) = 0;
97+
98+
//! Get locator for the current chain tip.
99+
virtual CBlockLocator getLocator() = 0;
100+
101+
//! Return height of the latest block common to locator and chain, which
102+
//! is guaranteed to be an ancestor of the block used to create the
103+
//! locator.
104+
virtual Optional<int> findLocatorFork(const CBlockLocator& locator) = 0;
31105
};
32106

33107
//! Return Lock interface. Chain is locked when this is called, and
@@ -38,6 +112,21 @@ class Chain
38112
//! method is temporary and is only used in a few places to avoid changing
39113
//! behavior while code is transitioned to use the Chain::Lock interface.
40114
virtual std::unique_ptr<Lock> assumeLocked() = 0;
115+
116+
//! Return whether node has the block and optionally return block metadata
117+
//! or contents.
118+
//!
119+
//! If a block pointer is provided to retrieve the block contents, and the
120+
//! block exists but doesn't have data (for example due to pruning), the
121+
//! block will be empty and all fields set to null.
122+
virtual bool findBlock(const uint256& hash,
123+
CBlock* block = nullptr,
124+
int64_t* time = nullptr,
125+
int64_t* max_time = nullptr) = 0;
126+
127+
//! Estimate fraction of total transactions verified if blocks up to
128+
//! the specified block hash are verified.
129+
virtual double guessVerificationProgress(const uint256& block_hash) = 0;
41130
};
42131

43132
//! Interface to let node manage chain clients (wallets, or maybe tools for

src/interfaces/wallet.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,13 @@ class WalletImpl : public Wallet
333333
if (mi == m_wallet.mapWallet.end()) {
334334
return false;
335335
}
336-
num_blocks = ::chainActive.Height();
337-
block_time = ::chainActive.Tip()->GetBlockTime();
336+
if (Optional<int> height = locked_chain->getHeight()) {
337+
num_blocks = *height;
338+
block_time = locked_chain->getBlockTime(*height);
339+
} else {
340+
num_blocks = -1;
341+
block_time = -1;
342+
}
338343
tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
339344
return true;
340345
}
@@ -348,7 +353,7 @@ class WalletImpl : public Wallet
348353
LOCK(m_wallet.cs_wallet);
349354
auto mi = m_wallet.mapWallet.find(txid);
350355
if (mi != m_wallet.mapWallet.end()) {
351-
num_blocks = ::chainActive.Height();
356+
num_blocks = locked_chain->getHeight().value_or(-1);
352357
in_mempool = mi->second.InMempool();
353358
order_form = mi->second.vOrderForm;
354359
tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
@@ -379,7 +384,7 @@ class WalletImpl : public Wallet
379384
return false;
380385
}
381386
balances = getBalances();
382-
num_blocks = ::chainActive.Height();
387+
num_blocks = locked_chain->getHeight().value_or(-1);
383388
return true;
384389
}
385390
CAmount getBalance() override { return m_wallet.GetBalance(); }

src/optional.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) 2017 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_OPTIONAL_H
6+
#define BITCOIN_OPTIONAL_H
7+
8+
#include <boost/optional.hpp>
9+
10+
//! Substitute for C++17 std::optional
11+
template <typename T>
12+
using Optional = boost::optional<T>;
13+
14+
//! Substitute for C++17 std::nullopt
15+
static auto& nullopt = boost::none;
16+
17+
#endif // BITCOIN_OPTIONAL_H

src/qt/test/wallettests.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <qt/test/wallettests.h>
22
#include <qt/test/util.h>
33

4+
#include <init.h>
45
#include <interfaces/chain.h>
56
#include <interfaces/node.h>
67
#include <base58.h>
@@ -146,13 +147,10 @@ void TestGUI()
146147
auto locked_chain = wallet->chain().lock();
147148
WalletRescanReserver reserver(wallet.get());
148149
reserver.reserve();
149-
const CBlockIndex* const null_block = nullptr;
150-
const CBlockIndex *stop_block, *failed_block;
151-
QCOMPARE(
152-
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block, true /* fUpdate */),
153-
CWallet::ScanResult::SUCCESS);
154-
QCOMPARE(stop_block, chainActive.Tip());
155-
QCOMPARE(failed_block, null_block);
150+
CWallet::ScanResult result = wallet->ScanForWalletTransactions(locked_chain->getBlockHash(0), {} /* stop_block */, reserver, true /* fUpdate */);
151+
QCOMPARE(result.status, CWallet::ScanResult::SUCCESS);
152+
QCOMPARE(result.stop_block, chainActive.Tip()->GetBlockHash());
153+
QVERIFY(result.failed_block.IsNull());
156154
}
157155
wallet->SetBroadcastTransactions(true);
158156

0 commit comments

Comments
 (0)