Skip to content

Commit df5c643

Browse files
committed
Merge bitcoin/bitcoin#31556: validation: Send correct notification during snapshot completion
bc43eca test: add functional test for balance after snapshot completion (Martin Zumsande) 226d03d validation: Send correct notification during snapshot completion (Martin Zumsande) Pull request description: After AssumeUtxo background sync is completed in a `ActivateBestChain()` call, the `GetRole()` function called with `BlockConnected()` returns `ChainstateRole::NORMAL` instead of `ChainstateRole::BACKGROUND` for this chainstate. This would make the wallet (which ignores `BlockConnected` notifications for the background chainstate) process it, change `m_last_block_processed_height` to the (ancient) snapshot height, and display an incorrect balance. Fix this by caching the chainstate role before calling `ActivateBestChainStep()`. Also contains a test for this situation that fails on master. Fixes #31546 ACKs for top commit: fjahr: re-ACK bc43eca achow101: ACK bc43eca furszy: Code review ACK bc43eca TheCharlatan: lgtm ACK bc43eca Tree-SHA512: c5db677cf3fbab3a33ec127ec6c27c8812299e8368fd3c986bc34d0e515c4eb256f6104479f27829eefc098197de3af75d64ddca636b6b612900a0e21243e4f2
2 parents fa3de03 + bc43eca commit df5c643

File tree

2 files changed

+19
-3
lines changed

2 files changed

+19
-3
lines changed

src/validation.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3529,6 +3529,10 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
35293529

35303530
bool fInvalidFound = false;
35313531
std::shared_ptr<const CBlock> nullBlockPtr;
3532+
// BlockConnected signals must be sent for the original role;
3533+
// in case snapshot validation is completed during ActivateBestChainStep, the
3534+
// result of GetRole() changes from BACKGROUND to NORMAL.
3535+
const ChainstateRole chainstate_role{this->GetRole()};
35323536
if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace)) {
35333537
// A system error occurred
35343538
return false;
@@ -3544,7 +3548,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
35443548
for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
35453549
assert(trace.pblock && trace.pindex);
35463550
if (m_chainman.m_options.signals) {
3547-
m_chainman.m_options.signals->BlockConnected(this->GetRole(), trace.pblock, trace.pindex);
3551+
m_chainman.m_options.signals->BlockConnected(chainstate_role, trace.pblock, trace.pindex);
35483552
}
35493553
}
35503554

test/functional/wallet_assumeutxo.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from test_framework.util import (
1818
assert_equal,
1919
assert_raises_rpc_error,
20+
ensure_for,
2021
)
2122
from test_framework.wallet import MiniWallet
2223

@@ -34,17 +35,18 @@ def add_options(self, parser):
3435

3536
def set_test_params(self):
3637
"""Use the pregenerated, deterministic chain up to height 199."""
37-
self.num_nodes = 2
38+
self.num_nodes = 3
3839
self.rpc_timeout = 120
3940
self.extra_args = [
4041
[],
4142
[],
43+
[],
4244
]
4345

4446
def setup_network(self):
4547
"""Start with the nodes disconnected so that one can generate a snapshot
4648
including blocks the other hasn't yet seen."""
47-
self.add_nodes(2)
49+
self.add_nodes(3)
4850
self.start_nodes(extra_args=self.extra_args)
4951

5052
def run_test(self):
@@ -57,6 +59,7 @@ def run_test(self):
5759
"""
5860
n0 = self.nodes[0]
5961
n1 = self.nodes[1]
62+
n2 = self.nodes[2]
6063

6164
self.mini_wallet = MiniWallet(n0)
6265

@@ -88,6 +91,7 @@ def run_test(self):
8891

8992
# make n1 aware of the new header, but don't give it the block.
9093
n1.submitheader(newblock)
94+
n2.submitheader(newblock)
9195

9296
# Ensure everyone is seeing the same headers.
9397
for n in self.nodes:
@@ -125,6 +129,7 @@ def run_test(self):
125129

126130
assert_equal(n0.getblockcount(), FINAL_HEIGHT)
127131
assert_equal(n1.getblockcount(), START_HEIGHT)
132+
assert_equal(n2.getblockcount(), START_HEIGHT)
128133

129134
assert_equal(n0.getblockchaininfo()["blocks"], FINAL_HEIGHT)
130135

@@ -192,6 +197,13 @@ def run_test(self):
192197
w = n1.get_wallet_rpc("w")
193198
assert_equal(w.getbalance(), 34)
194199

200+
self.log.info("Check balance of a wallet that is active during snapshot completion")
201+
n2.restorewallet("w", "backup_w.dat")
202+
loaded = n2.loadtxoutset(dump_output['path'])
203+
self.connect_nodes(0, 2)
204+
self.wait_until(lambda: len(n2.getchainstates()['chainstates']) == 1)
205+
ensure_for(duration=1, f=lambda: (n2.getbalance() == 34))
206+
195207

196208
if __name__ == '__main__':
197209
AssumeutxoTest(__file__).main()

0 commit comments

Comments
 (0)