Skip to content

Commit 700c42b

Browse files
ryanofskyEmpact
andcommitted
Add height, depth, and hash methods to the Chain interface
And use them to remove uses of chainActive and mapBlockIndex in wallet code This commit does not change behavior. Co-authored-by: Ben Woosley <[email protected]>
1 parent eb2aecf commit 700c42b

File tree

10 files changed

+96
-35
lines changed

10 files changed

+96
-35
lines changed

src/Makefile.am

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

src/interfaces/chain.cpp

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

55
#include <interfaces/chain.h>
66

7+
#include <chain.h>
78
#include <sync.h>
9+
#include <uint256.h>
810
#include <util/system.h>
911
#include <validation.h>
1012

@@ -16,6 +18,34 @@ namespace {
1618

1719
class LockImpl : public Chain::Lock
1820
{
21+
Optional<int> getHeight() override
22+
{
23+
int height = ::chainActive.Height();
24+
if (height >= 0) {
25+
return height;
26+
}
27+
return nullopt;
28+
}
29+
Optional<int> getBlockHeight(const uint256& hash) override
30+
{
31+
CBlockIndex* block = LookupBlockIndex(hash);
32+
if (block && ::chainActive.Contains(block)) {
33+
return block->nHeight;
34+
}
35+
return nullopt;
36+
}
37+
int getBlockDepth(const uint256& hash) override
38+
{
39+
const Optional<int> tip_height = getHeight();
40+
const Optional<int> height = getBlockHeight(hash);
41+
return tip_height && height ? *tip_height - *height + 1 : 0;
42+
}
43+
uint256 getBlockHash(int height) override
44+
{
45+
CBlockIndex* block = ::chainActive[height];
46+
assert(block != nullptr);
47+
return block->GetBlockHash();
48+
}
1949
};
2050

2151
class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>

src/interfaces/chain.h

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

8+
#include <optional.h>
9+
810
#include <memory>
911
#include <string>
1012
#include <vector>
1113

1214
class CScheduler;
15+
class uint256;
1316

1417
namespace interfaces {
1518

@@ -28,6 +31,23 @@ class Chain
2831
{
2932
public:
3033
virtual ~Lock() {}
34+
35+
//! Get current chain height, not including genesis block (returns 0 if
36+
//! chain only contains genesis block, nullopt if chain does not contain
37+
//! any blocks).
38+
virtual Optional<int> getHeight() = 0;
39+
40+
//! Get block height above genesis block. Returns 0 for genesis block,
41+
//! 1 for following block, and so on. Returns nullopt for a block not
42+
//! included in the current chain.
43+
virtual Optional<int> getBlockHeight(const uint256& hash) = 0;
44+
45+
//! Get block depth. Returns 1 for chain tip, 2 for preceding block, and
46+
//! so on. Returns 0 for a block not included in the current chain.
47+
virtual int getBlockDepth(const uint256& hash) = 0;
48+
49+
//! Get block hash. Height must be valid or this function will abort.
50+
virtual uint256 getBlockHash(int height) = 0;
3151
};
3252

3353
//! Return Lock interface. Chain is locked when this is called, and

src/interfaces/wallet.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ class WalletImpl : public Wallet
333333
if (mi == m_wallet.mapWallet.end()) {
334334
return false;
335335
}
336-
num_blocks = ::chainActive.Height();
336+
num_blocks = locked_chain->getHeight().value_or(-1);
337337
block_time = ::chainActive.Tip()->GetBlockTime();
338338
tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
339339
return true;
@@ -348,7 +348,7 @@ class WalletImpl : public Wallet
348348
LOCK(m_wallet.cs_wallet);
349349
auto mi = m_wallet.mapWallet.find(txid);
350350
if (mi != m_wallet.mapWallet.end()) {
351-
num_blocks = ::chainActive.Height();
351+
num_blocks = locked_chain->getHeight().value_or(-1);
352352
in_mempool = mi->second.InMempool();
353353
order_form = mi->second.vOrderForm;
354354
tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
@@ -379,7 +379,7 @@ class WalletImpl : public Wallet
379379
return false;
380380
}
381381
balances = getBalances();
382-
num_blocks = ::chainActive.Height();
382+
num_blocks = locked_chain->getHeight().value_or(-1);
383383
return true;
384384
}
385385
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/wallet/rpcdump.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
379379
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) {
380380

381381
auto locked_chain = pwallet->chain().lock();
382-
const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash());
383-
if (!pindex || !chainActive.Contains(pindex)) {
382+
if (locked_chain->getBlockHeight(merkleBlock.header.GetHash()) == nullopt) {
384383
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
385384
}
386385

@@ -773,7 +772,8 @@ UniValue dumpwallet(const JSONRPCRequest& request)
773772
// produce output
774773
file << strprintf("# Wallet dump created by Bitcoin %s\n", CLIENT_BUILD);
775774
file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime()));
776-
file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
775+
const Optional<int> tip_height = locked_chain->getHeight();
776+
file << strprintf("# * Best block at time of backup was %i (%s),\n", tip_height.value_or(-1), tip_height ? locked_chain->getBlockHash(*tip_height).ToString() : "(missing block hash)");
777777
file << strprintf("# mined on %s\n", FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()));
778778
file << "\n";
779779

src/wallet/rpcwallet.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,7 +1607,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
16071607

16081608
bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
16091609

1610-
int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
1610+
const Optional<int> tip_height = locked_chain->getHeight();
1611+
int depth = tip_height && pindex ? (1 + *tip_height - pindex->nHeight) : -1;
16111612

16121613
UniValue transactions(UniValue::VARR);
16131614

@@ -1638,8 +1639,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
16381639
paltindex = paltindex->pprev;
16391640
}
16401641

1641-
CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1642-
uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
1642+
int last_height = tip_height ? *tip_height + 1 - target_confirms : -1;
1643+
uint256 lastblock = last_height >= 0 ? locked_chain->getBlockHash(last_height) : uint256();
16431644

16441645
UniValue ret(UniValue::VOBJ);
16451646
ret.pushKV("transactions", transactions);

src/wallet/test/wallet_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
276276

277277
CWalletTx wtx(&wallet, MakeTransactionRef(tx));
278278
if (block) {
279-
wtx.SetMerkleBranch(block, 0);
279+
wtx.SetMerkleBranch(block->GetBlockHash(), 0);
280280
}
281281
{
282282
LOCK(cs_main);
@@ -372,7 +372,7 @@ class ListCoinsTestingSetup : public TestChain100Setup
372372
LOCK(wallet->cs_wallet);
373373
auto it = wallet->mapWallet.find(tx->GetHash());
374374
BOOST_CHECK(it != wallet->mapWallet.end());
375-
it->second.SetMerkleBranch(chainActive.Tip(), 1);
375+
it->second.SetMerkleBranch(chainActive.Tip()->GetBlockHash(), 1);
376376
return it->second;
377377
}
378378

src/wallet/wallet.cpp

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -935,19 +935,19 @@ void CWallet::LoadToWallet(const CWalletTx& wtxIn)
935935
}
936936
}
937937

938-
bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
938+
bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const uint256& block_hash, int posInBlock, bool fUpdate)
939939
{
940940
const CTransaction& tx = *ptx;
941941
{
942942
AssertLockHeld(cs_wallet);
943943

944-
if (pIndex != nullptr) {
944+
if (!block_hash.IsNull()) {
945945
for (const CTxIn& txin : tx.vin) {
946946
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
947947
while (range.first != range.second) {
948948
if (range.first->second != tx.GetHash()) {
949-
WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pIndex->GetBlockHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
950-
MarkConflicted(pIndex->GetBlockHash(), range.first->second);
949+
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);
950+
MarkConflicted(block_hash, range.first->second);
951951
}
952952
range.first++;
953953
}
@@ -983,8 +983,8 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockI
983983
CWalletTx wtx(this, ptx);
984984

985985
// Get merkle branch if transaction was found in a block
986-
if (pIndex != nullptr)
987-
wtx.SetMerkleBranch(pIndex, posInBlock);
986+
if (!block_hash.IsNull())
987+
wtx.SetMerkleBranch(block_hash, posInBlock);
988988

989989
return AddToWallet(wtx, false);
990990
}
@@ -1071,11 +1071,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
10711071
auto locked_chain = chain().lock();
10721072
LOCK(cs_wallet);
10731073

1074-
int conflictconfirms = 0;
1075-
CBlockIndex* pindex = LookupBlockIndex(hashBlock);
1076-
if (pindex && chainActive.Contains(pindex)) {
1077-
conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
1078-
}
1074+
int conflictconfirms = -locked_chain->getBlockDepth(hashBlock);
10791075
// If number of conflict confirms cannot be determined, this means
10801076
// that the block is still unknown or not yet part of the main chain,
10811077
// for example when loading the wallet during a reindex. Do nothing in that
@@ -1122,7 +1118,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
11221118
}
11231119

11241120
void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pindex, int posInBlock, bool update_tx) {
1125-
if (!AddToWalletIfInvolvingMe(ptx, pindex, posInBlock, update_tx))
1121+
if (!AddToWalletIfInvolvingMe(ptx, pindex->GetBlockHash(), posInBlock, update_tx))
11261122
return; // Not one of ours
11271123

11281124
// If a transaction changes 'conflicted' state, that changes the balance
@@ -2573,6 +2569,7 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain)
25732569
*/
25742570
static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_chain)
25752571
{
2572+
uint32_t const height = locked_chain.getHeight().value_or(-1);
25762573
uint32_t locktime;
25772574
// Discourage fee sniping.
25782575
//
@@ -2595,7 +2592,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_cha
25952592
// now we ensure code won't be written that makes assumptions about
25962593
// nLockTime that preclude a fix later.
25972594
if (IsCurrentForAntiFeeSniping(locked_chain)) {
2598-
locktime = chainActive.Height();
2595+
locktime = height;
25992596

26002597
// Secondly occasionally randomly pick a nLockTime even further back, so
26012598
// that transactions that are delayed after signing for whatever reason,
@@ -2609,7 +2606,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_cha
26092606
// unique "nLockTime fingerprint", set nLockTime to a constant.
26102607
locktime = 0;
26112608
}
2612-
assert(locktime <= (unsigned int)chainActive.Height());
2609+
assert(locktime <= height);
26132610
assert(locktime < LOCKTIME_THRESHOLD);
26142611
return locktime;
26152612
}
@@ -4282,10 +4279,10 @@ CWalletKey::CWalletKey(int64_t nExpires)
42824279
nTimeExpires = nExpires;
42834280
}
42844281

4285-
void CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)
4282+
void CMerkleTx::SetMerkleBranch(const uint256& block_hash, int posInBlock)
42864283
{
42874284
// Update the tx's hashBlock
4288-
hashBlock = pindex->GetBlockHash();
4285+
hashBlock = block_hash;
42894286

42904287
// set the position of the transaction in the block
42914288
nIndex = posInBlock;
@@ -4298,12 +4295,7 @@ int CMerkleTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
42984295

42994296
AssertLockHeld(cs_main);
43004297

4301-
// Find the block it claims to be in
4302-
CBlockIndex* pindex = LookupBlockIndex(hashBlock);
4303-
if (!pindex || !chainActive.Contains(pindex))
4304-
return 0;
4305-
4306-
return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1);
4298+
return locked_chain.getBlockDepth(hashBlock) * (nIndex == -1 ? -1 : 1);
43074299
}
43084300

43094301
int CMerkleTx::GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const

src/wallet/wallet.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ class CMerkleTx
287287
READWRITE(nIndex);
288288
}
289289

290-
void SetMerkleBranch(const CBlockIndex* pIndex, int posInBlock);
290+
void SetMerkleBranch(const uint256& block_hash, int posInBlock);
291291

292292
/**
293293
* Return depth of transaction in blockchain:
@@ -667,7 +667,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
667667
* Abandoned state should probably be more carefully tracked via different
668668
* posInBlock signals or by checking mempool presence when necessary.
669669
*/
670-
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
670+
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const uint256& block_hash, int posInBlock, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
671671

672672
/* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */
673673
void MarkConflicted(const uint256& hashBlock, const uint256& hashTx);

0 commit comments

Comments
 (0)