Skip to content

Commit d6eb39a

Browse files
author
BitcoinTsunami
committed
test: add functional test to check transaction time determination during block rescanning
1 parent 07b44f1 commit d6eb39a

File tree

2 files changed

+162
-0
lines changed

2 files changed

+162
-0
lines changed

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
'rpc_rawtransaction.py --legacy-wallet',
176176
'rpc_rawtransaction.py --descriptors',
177177
'wallet_groups.py --legacy-wallet',
178+
'wallet_transactiontime_rescan.py',
178179
'p2p_addrv2_relay.py',
179180
'wallet_groups.py --descriptors',
180181
'p2p_compactblocks_hb.py',
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2018-2019 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Test transaction time during old block rescanning
6+
"""
7+
8+
import time
9+
10+
from test_framework.blocktools import COINBASE_MATURITY
11+
from test_framework.test_framework import BitcoinTestFramework
12+
from test_framework.util import (
13+
assert_equal
14+
)
15+
16+
17+
class TransactionTimeRescanTest(BitcoinTestFramework):
18+
def set_test_params(self):
19+
self.setup_clean_chain = False
20+
self.num_nodes = 3
21+
22+
def skip_test_if_missing_module(self):
23+
self.skip_if_no_wallet()
24+
25+
def run_test(self):
26+
self.log.info('Prepare nodes and wallet')
27+
28+
minernode = self.nodes[0] # node used to mine BTC and create transactions
29+
usernode = self.nodes[1] # user node with correct time
30+
restorenode = self.nodes[2] # node used to restore user wallet and check time determination in ComputeSmartTime (wallet.cpp)
31+
32+
# time constant
33+
cur_time = int(time.time())
34+
ten_days = 10 * 24 * 60 * 60
35+
36+
# synchronize nodes and time
37+
self.sync_all()
38+
minernode.setmocktime(cur_time)
39+
usernode.setmocktime(cur_time)
40+
restorenode.setmocktime(cur_time)
41+
42+
# prepare miner wallet
43+
minernode.createwallet(wallet_name='default')
44+
miner_wallet = minernode.get_wallet_rpc('default')
45+
m1 = miner_wallet.getnewaddress()
46+
47+
# prepare the user wallet with 3 watch only addresses
48+
wo1 = usernode.getnewaddress()
49+
wo2 = usernode.getnewaddress()
50+
wo3 = usernode.getnewaddress()
51+
52+
usernode.createwallet(wallet_name='wo', disable_private_keys=True)
53+
wo_wallet = usernode.get_wallet_rpc('wo')
54+
55+
wo_wallet.importaddress(wo1)
56+
wo_wallet.importaddress(wo2)
57+
wo_wallet.importaddress(wo3)
58+
59+
self.log.info('Start transactions')
60+
61+
# check blockcount
62+
assert_equal(minernode.getblockcount(), 200)
63+
64+
# generate some btc to create transactions and check blockcount
65+
initial_mine = COINBASE_MATURITY + 1
66+
minernode.generatetoaddress(initial_mine, m1)
67+
assert_equal(minernode.getblockcount(), initial_mine + 200)
68+
69+
# synchronize nodes and time
70+
self.sync_all()
71+
minernode.setmocktime(cur_time + ten_days)
72+
usernode.setmocktime(cur_time + ten_days)
73+
restorenode.setmocktime(cur_time + ten_days)
74+
# send 10 btc to user's first watch-only address
75+
self.log.info('Send 10 btc to user')
76+
miner_wallet.sendtoaddress(wo1, 10)
77+
78+
# generate blocks and check blockcount
79+
minernode.generatetoaddress(COINBASE_MATURITY, m1)
80+
assert_equal(minernode.getblockcount(), initial_mine + 300)
81+
82+
# synchronize nodes and time
83+
self.sync_all()
84+
minernode.setmocktime(cur_time + ten_days + ten_days)
85+
usernode.setmocktime(cur_time + ten_days + ten_days)
86+
restorenode.setmocktime(cur_time + ten_days + ten_days)
87+
# send 5 btc to our second watch-only address
88+
self.log.info('Send 5 btc to user')
89+
miner_wallet.sendtoaddress(wo2, 5)
90+
91+
# generate blocks and check blockcount
92+
minernode.generatetoaddress(COINBASE_MATURITY, m1)
93+
assert_equal(minernode.getblockcount(), initial_mine + 400)
94+
95+
# synchronize nodes and time
96+
self.sync_all()
97+
minernode.setmocktime(cur_time + ten_days + ten_days + ten_days)
98+
usernode.setmocktime(cur_time + ten_days + ten_days + ten_days)
99+
restorenode.setmocktime(cur_time + ten_days + ten_days + ten_days)
100+
# send 1 btc to our third watch-only address
101+
self.log.info('Send 1 btc to user')
102+
miner_wallet.sendtoaddress(wo3, 1)
103+
104+
# generate more blocks and check blockcount
105+
minernode.generatetoaddress(COINBASE_MATURITY, m1)
106+
assert_equal(minernode.getblockcount(), initial_mine + 500)
107+
108+
self.log.info('Check user\'s final balance and transaction count')
109+
assert_equal(wo_wallet.getbalance(), 16)
110+
assert_equal(len(wo_wallet.listtransactions()), 3)
111+
112+
self.log.info('Check transaction times')
113+
for tx in wo_wallet.listtransactions():
114+
if tx['address'] == wo1:
115+
assert_equal(tx['blocktime'], cur_time + ten_days)
116+
assert_equal(tx['time'], cur_time + ten_days)
117+
elif tx['address'] == wo2:
118+
assert_equal(tx['blocktime'], cur_time + ten_days + ten_days)
119+
assert_equal(tx['time'], cur_time + ten_days + ten_days)
120+
elif tx['address'] == wo3:
121+
assert_equal(tx['blocktime'], cur_time + ten_days + ten_days + ten_days)
122+
assert_equal(tx['time'], cur_time + ten_days + ten_days + ten_days)
123+
124+
# restore user wallet without rescan
125+
self.log.info('Restore user wallet on another node without rescan')
126+
restorenode.createwallet(wallet_name='wo', disable_private_keys=True)
127+
restorewo_wallet = restorenode.get_wallet_rpc('wo')
128+
129+
restorewo_wallet.importaddress(wo1, rescan=False)
130+
restorewo_wallet.importaddress(wo2, rescan=False)
131+
restorewo_wallet.importaddress(wo3, rescan=False)
132+
133+
# check user has 0 balance and no transactions
134+
assert_equal(restorewo_wallet.getbalance(), 0)
135+
assert_equal(len(restorewo_wallet.listtransactions()), 0)
136+
137+
# proceed to rescan, first with an incomplete one, then with a full rescan
138+
self.log.info('Rescan last history part')
139+
restorewo_wallet.rescanblockchain(initial_mine + 350)
140+
self.log.info('Rescan all history')
141+
restorewo_wallet.rescanblockchain()
142+
143+
self.log.info('Check user\'s final balance and transaction count after restoration')
144+
assert_equal(restorewo_wallet.getbalance(), 16)
145+
assert_equal(len(restorewo_wallet.listtransactions()), 3)
146+
147+
self.log.info('Check transaction times after restoration')
148+
for tx in restorewo_wallet.listtransactions():
149+
if tx['address'] == wo1:
150+
assert_equal(tx['blocktime'], cur_time + ten_days)
151+
assert_equal(tx['time'], cur_time + ten_days)
152+
elif tx['address'] == wo2:
153+
assert_equal(tx['blocktime'], cur_time + ten_days + ten_days)
154+
assert_equal(tx['time'], cur_time + ten_days + ten_days)
155+
elif tx['address'] == wo3:
156+
assert_equal(tx['blocktime'], cur_time + ten_days + ten_days + ten_days)
157+
assert_equal(tx['time'], cur_time + ten_days + ten_days + ten_days)
158+
159+
160+
if __name__ == '__main__':
161+
TransactionTimeRescanTest().main()

0 commit comments

Comments
 (0)