Skip to content

Commit 2ffb079

Browse files
ryanofskyEmpact
andcommitted
Add findFork and findBlock 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 d93c4c1 commit 2ffb079

File tree

4 files changed

+75
-19
lines changed

4 files changed

+75
-19
lines changed

src/interfaces/chain.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <interfaces/chain.h>
66

77
#include <chain.h>
8+
#include <chainparams.h>
9+
#include <primitives/block.h>
810
#include <sync.h>
911
#include <uint256.h>
1012
#include <util/system.h>
@@ -58,6 +60,22 @@ class LockImpl : public Chain::Lock
5860
assert(block != nullptr);
5961
return block->GetMedianTimePast();
6062
}
63+
Optional<int> findFork(const uint256& hash, Optional<int>* height) override
64+
{
65+
const CBlockIndex* block = LookupBlockIndex(hash);
66+
const CBlockIndex* fork = block ? ::chainActive.FindFork(block) : nullptr;
67+
if (height) {
68+
if (block) {
69+
*height = block->nHeight;
70+
} else {
71+
height->reset();
72+
}
73+
}
74+
if (fork) {
75+
return fork->nHeight;
76+
}
77+
return nullopt;
78+
}
6179
};
6280

6381
class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
@@ -77,6 +95,27 @@ class ChainImpl : public Chain
7795
return std::move(result);
7896
}
7997
std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); }
98+
bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override
99+
{
100+
CBlockIndex* index;
101+
{
102+
LOCK(cs_main);
103+
index = LookupBlockIndex(hash);
104+
if (!index) {
105+
return false;
106+
}
107+
if (time) {
108+
*time = index->GetBlockTime();
109+
}
110+
if (time_max) {
111+
*time_max = index->GetBlockTimeMax();
112+
}
113+
}
114+
if (block && !ReadBlockFromDisk(*block, index, Params().GetConsensus())) {
115+
block->SetNull();
116+
}
117+
return true;
118+
}
80119
};
81120

82121
} // namespace

src/interfaces/chain.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <string>
1313
#include <vector>
1414

15+
class CBlock;
1516
class CScheduler;
1617
class uint256;
1718

@@ -56,6 +57,13 @@ class Chain
5657
//! Get block median time past. Height must be valid or this function
5758
//! will abort.
5859
virtual int64_t getBlockMedianTimePast(int height) = 0;
60+
61+
//! Return height of the highest block on the chain that is an ancestor
62+
//! of the specified block, or nullopt if no common ancestor is found.
63+
//! Also return the height of the specified block as an optional output
64+
//! parameter (to avoid the cost of a second hash lookup in case this
65+
//! information is desired).
66+
virtual Optional<int> findFork(const uint256& hash, Optional<int>* height) = 0;
5967
};
6068

6169
//! Return Lock interface. Chain is locked when this is called, and
@@ -66,6 +74,17 @@ class Chain
6674
//! method is temporary and is only used in a few places to avoid changing
6775
//! behavior while code is transitioned to use the Chain::Lock interface.
6876
virtual std::unique_ptr<Lock> assumeLocked() = 0;
77+
78+
//! Return whether node has the block and optionally return block metadata
79+
//! or contents.
80+
//!
81+
//! If a block pointer is provided to retrieve the block contents, and the
82+
//! block exists but doesn't have data (for example due to pruning), the
83+
//! block will be empty and all fields set to null.
84+
virtual bool findBlock(const uint256& hash,
85+
CBlock* block = nullptr,
86+
int64_t* time = nullptr,
87+
int64_t* max_time = nullptr) = 0;
6988
};
7089

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

src/wallet/rpcwallet.cpp

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,10 @@ static void WalletTxToJSON(interfaces::Chain& chain, interfaces::Chain::Lock& lo
102102
{
103103
entry.pushKV("blockhash", wtx.hashBlock.GetHex());
104104
entry.pushKV("blockindex", wtx.nIndex);
105-
entry.pushKV("blocktime", LookupBlockIndex(wtx.hashBlock)->GetBlockTime());
105+
int64_t block_time;
106+
bool found_block = chain.findBlock(wtx.hashBlock, nullptr /* block */, &block_time);
107+
assert(found_block);
108+
entry.pushKV("blocktime", block_time);
106109
} else {
107110
entry.pushKV("trusted", wtx.IsTrusted(locked_chain));
108111
}
@@ -1573,24 +1576,18 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
15731576
auto locked_chain = pwallet->chain().lock();
15741577
LOCK(pwallet->cs_wallet);
15751578

1576-
const CBlockIndex* pindex = nullptr; // Block index of the specified block or the common ancestor, if the block provided was in a deactivated chain.
1577-
const CBlockIndex* paltindex = nullptr; // Block index of the specified block, even if it's in a deactivated chain.
1579+
Optional<int> height; // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
1580+
Optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
15781581
int target_confirms = 1;
15791582
isminefilter filter = ISMINE_SPENDABLE;
15801583

1584+
uint256 blockId;
15811585
if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
1582-
uint256 blockId(ParseHashV(request.params[0], "blockhash"));
1583-
1584-
paltindex = pindex = LookupBlockIndex(blockId);
1585-
if (!pindex) {
1586+
blockId = ParseHashV(request.params[0], "blockhash");
1587+
height = locked_chain->findFork(blockId, &altheight);
1588+
if (!height) {
15861589
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
15871590
}
1588-
if (chainActive[pindex->nHeight] != pindex) {
1589-
// the block being asked for is a part of a deactivated chain;
1590-
// we don't want to depend on its perceived height in the block
1591-
// chain, we want to instead use the last common ancestor
1592-
pindex = chainActive.FindFork(pindex);
1593-
}
15941591
}
15951592

15961593
if (!request.params[1].isNull()) {
@@ -1608,7 +1605,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
16081605
bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
16091606

16101607
const Optional<int> tip_height = locked_chain->getHeight();
1611-
int depth = tip_height && pindex ? (1 + *tip_height - pindex->nHeight) : -1;
1608+
int depth = tip_height && height ? (1 + *tip_height - *height) : -1;
16121609

16131610
UniValue transactions(UniValue::VARR);
16141611

@@ -1623,9 +1620,9 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
16231620
// when a reorg'd block is requested, we also list any relevant transactions
16241621
// in the blocks of the chain that was detached
16251622
UniValue removed(UniValue::VARR);
1626-
while (include_removed && paltindex && paltindex != pindex) {
1623+
while (include_removed && altheight && *altheight > *height) {
16271624
CBlock block;
1628-
if (!ReadBlockFromDisk(block, paltindex, Params().GetConsensus())) {
1625+
if (!pwallet->chain().findBlock(blockId, &block) || block.IsNull()) {
16291626
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
16301627
}
16311628
for (const CTransactionRef& tx : block.vtx) {
@@ -1636,7 +1633,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
16361633
ListTransactions(*locked_chain, pwallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
16371634
}
16381635
}
1639-
paltindex = paltindex->pprev;
1636+
blockId = block.hashPrevBlock;
1637+
--*altheight;
16401638
}
16411639

16421640
int last_height = tip_height ? *tip_height + 1 - target_confirms : -1;

src/wallet/wallet.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3775,7 +3775,8 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
37753775
{
37763776
unsigned int nTimeSmart = wtx.nTimeReceived;
37773777
if (!wtx.hashUnset()) {
3778-
if (const CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock)) {
3778+
int64_t blocktime;
3779+
if (chain().findBlock(wtx.hashBlock, nullptr /* block */, &blocktime)) {
37793780
int64_t latestNow = wtx.nTimeReceived;
37803781
int64_t latestEntry = 0;
37813782

@@ -3801,7 +3802,6 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
38013802
}
38023803
}
38033804

3804-
int64_t blocktime = pindex->GetBlockTime();
38053805
nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
38063806
} else {
38073807
WalletLogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), wtx.hashBlock.ToString());

0 commit comments

Comments
 (0)