Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1#!/usr/bin/env python32# Copyright (c) 2018-present The Bitcoin Core developers3# Distributed under the MIT software license, see the accompanying4# file COPYING or http://www.opensource.org/licenses/mit-license.php.5"""Test transaction time during old block rescanning6"""8import time10from test_framework.blocktools import COINBASE_MATURITY11from test_framework.test_framework import BitcoinTestFramework12from test_framework.util import (13assert_equal,14assert_raises_rpc_error,15set_node_times,16)19class TransactionTimeRescanTest(BitcoinTestFramework):20def set_test_params(self):21self.setup_clean_chain = False22self.num_nodes = 323self.extra_args = [["-keypool=400"],24["-keypool=400"],25[]26]28def skip_test_if_missing_module(self):29self.skip_if_no_wallet()31def run_test(self):32self.log.info('Prepare nodes and wallet')34minernode = self.nodes[0] # node used to mine BTC and create transactions35usernode = self.nodes[1] # user node with correct time36restorenode = self.nodes[2] # node used to restore user wallet and check time determination in ComputeSmartTime (wallet.cpp)38# time constant39cur_time = int(time.time())40ten_days = 10 * 24 * 60 * 6042# synchronize nodes and time43self.sync_all()44set_node_times(self.nodes, cur_time)46# prepare miner wallet47minernode.createwallet(wallet_name='default')48miner_wallet = minernode.get_wallet_rpc('default')49m1 = miner_wallet.getnewaddress()51# prepare the user wallet with 3 watch only addresses52wo1 = usernode.getnewaddress()53wo1_desc = usernode.getaddressinfo(wo1)["desc"]54wo2 = usernode.getnewaddress()55wo2_desc = usernode.getaddressinfo(wo2)["desc"]56wo3 = usernode.getnewaddress()57wo3_desc = usernode.getaddressinfo(wo3)["desc"]59usernode.createwallet(wallet_name='wo', disable_private_keys=True)60wo_wallet = usernode.get_wallet_rpc('wo')62import_res = wo_wallet.importdescriptors(63[64{"desc": wo1_desc, "timestamp": "now"},65{"desc": wo2_desc, "timestamp": "now"},66{"desc": wo3_desc, "timestamp": "now"},67]68)69assert_equal(all([r["success"] for r in import_res]), True)71self.log.info('Start transactions')73# check blockcount74assert_equal(minernode.getblockcount(), 200)76# generate some btc to create transactions and check blockcount77initial_mine = COINBASE_MATURITY + 178self.generatetoaddress(minernode, initial_mine, m1)79assert_equal(minernode.getblockcount(), initial_mine + 200)81# synchronize nodes and time82self.sync_all()83set_node_times(self.nodes, cur_time + ten_days)84# send 10 btc to user's first watch-only address85self.log.info('Send 10 btc to user')86miner_wallet.sendtoaddress(wo1, 10)88# generate blocks and check blockcount89self.generatetoaddress(minernode, COINBASE_MATURITY, m1)90assert_equal(minernode.getblockcount(), initial_mine + 300)92# synchronize nodes and time93self.sync_all()94set_node_times(self.nodes, cur_time + ten_days + ten_days)95# send 5 btc to our second watch-only address96self.log.info('Send 5 btc to user')97miner_wallet.sendtoaddress(wo2, 5)99# generate blocks and check blockcount100self.generatetoaddress(minernode, COINBASE_MATURITY, m1)101assert_equal(minernode.getblockcount(), initial_mine + 400)103# synchronize nodes and time104self.sync_all()105set_node_times(self.nodes, cur_time + ten_days + ten_days + ten_days)106# send 1 btc to our third watch-only address107self.log.info('Send 1 btc to user')108miner_wallet.sendtoaddress(wo3, 1)110# generate more blocks and check blockcount111self.generatetoaddress(minernode, COINBASE_MATURITY, m1)112assert_equal(minernode.getblockcount(), initial_mine + 500)114self.log.info('Check user\'s final balance and transaction count')115assert_equal(wo_wallet.getbalance(), 16)116assert_equal(len(wo_wallet.listtransactions()), 3)118self.log.info('Check transaction times')119for tx in wo_wallet.listtransactions():120if tx['address'] == wo1:121assert_equal(tx['blocktime'], cur_time + ten_days)122assert_equal(tx['time'], cur_time + ten_days)123elif tx['address'] == wo2:124assert_equal(tx['blocktime'], cur_time + ten_days + ten_days)125assert_equal(tx['time'], cur_time + ten_days + ten_days)126elif tx['address'] == wo3:127assert_equal(tx['blocktime'], cur_time + ten_days + ten_days + ten_days)128assert_equal(tx['time'], cur_time + ten_days + ten_days + ten_days)130# restore user wallet without rescan131self.log.info('Restore user wallet on another node without rescan')132restorenode.createwallet(wallet_name='wo', disable_private_keys=True)133restorewo_wallet = restorenode.get_wallet_rpc('wo')135# importdescriptors with "timestamp": "now" always rescans136# blocks of the past 2 hours, based on the current MTP timestamp; in order to avoid137# importing the last address (wo3), we advance the time further and generate 10 blocks138set_node_times(self.nodes, cur_time + ten_days + ten_days + ten_days + ten_days)139self.generatetoaddress(minernode, 10, m1)141import_res = restorewo_wallet.importdescriptors(142[143{"desc": wo1_desc, "timestamp": "now"},144{"desc": wo2_desc, "timestamp": "now"},145{"desc": wo3_desc, "timestamp": "now"},146]147)148assert_equal(all([r["success"] for r in import_res]), True)150self.log.info('Testing abortrescan when no rescan is in progress')151assert_equal(restorewo_wallet.getwalletinfo()['scanning'], False)152assert_equal(restorewo_wallet.abortrescan(), False)154# check user has 0 balance and no transactions155assert_equal(restorewo_wallet.getbalance(), 0)156assert_equal(len(restorewo_wallet.listtransactions()), 0)158# proceed to rescan, first with an incomplete one, then with a full rescan159self.log.info('Rescan last history part')160restorewo_wallet.rescanblockchain(initial_mine + 350)161self.log.info('Rescan all history')162restorewo_wallet.rescanblockchain()164self.log.info('Check user\'s final balance and transaction count after restoration')165assert_equal(restorewo_wallet.getbalance(), 16)166assert_equal(len(restorewo_wallet.listtransactions()), 3)168self.log.info('Check transaction times after restoration')169for tx in restorewo_wallet.listtransactions():170if tx['address'] == wo1:171assert_equal(tx['blocktime'], cur_time + ten_days)172assert_equal(tx['time'], cur_time + ten_days)173elif tx['address'] == wo2:174assert_equal(tx['blocktime'], cur_time + ten_days + ten_days)175assert_equal(tx['time'], cur_time + ten_days + ten_days)176elif tx['address'] == wo3:177assert_equal(tx['blocktime'], cur_time + ten_days + ten_days + ten_days)178assert_equal(tx['time'], cur_time + ten_days + ten_days + ten_days)181self.log.info('Test handling of invalid parameters for rescanblockchain')182assert_raises_rpc_error(-8, "Invalid start_height", restorewo_wallet.rescanblockchain, -1, 10)183assert_raises_rpc_error(-8, "Invalid stop_height", restorewo_wallet.rescanblockchain, 1, -1)184assert_raises_rpc_error(-8, "stop_height must be greater than start_height", restorewo_wallet.rescanblockchain, 20, 10)186self.log.info("Test `rescanblockchain` fails when wallet is encrypted and locked")187usernode.createwallet(wallet_name="enc_wallet", passphrase="passphrase")188enc_wallet = usernode.get_wallet_rpc("enc_wallet")189assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", enc_wallet.rescanblockchain)192if __name__ == '__main__':193TransactionTimeRescanTest(__file__).main()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.