From c96833c5a2791901eef9a4abe6e6b9321b5ba1bb Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Thu, 26 May 2022 16:07:21 +0000 Subject: [PATCH] new command: `mmgen-tool rescan_blockchain` --- mmgen/base_proto/bitcoin/tw/ctl.py | 44 +++++++++++++++++++++++++++++- mmgen/main_tool.py | 1 + mmgen/tool/rpc.py | 8 ++++++ test/test_py_d/ts_regtest.py | 22 +++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/mmgen/base_proto/bitcoin/tw/ctl.py b/mmgen/base_proto/bitcoin/tw/ctl.py index 2090efd4..f4440001 100755 --- a/mmgen/base_proto/bitcoin/tw/ctl.py +++ b/mmgen/base_proto/bitcoin/tw/ctl.py @@ -12,8 +12,9 @@ base_proto.bitcoin.twctl: Bitcoin base protocol tracking wallet control class """ +from ....globalvars import g from ....tw.ctl import TrackingWallet -from ....util import rmsg,write_mode +from ....util import msg,msg_r,rmsg,die,write_mode class BitcoinTrackingWallet(TrackingWallet): @@ -46,3 +47,44 @@ class BitcoinTrackingWallet(TrackingWallet): except Exception as e: rmsg(e.args[0]) return False + + @write_mode + async def rescan_blockchain(self,start,stop): + + start = start or 0 + endless = stop == None + CR = '\n' if g.test_suite else '\r' + + if not ( start >= 0 and (stop if stop is not None else start) >= start ): + die(1,f'{start} {stop}: invalid range') + + async def do_scan(chunks,tip): + res = None + for a,b in chunks: + msg_r(f'{CR}Scanning blocks {a}-{b} ') + res = await self.rpc.call('rescanblockchain',a,b,timeout=7200) + if res['start_height'] != a or res['stop_height'] != b: + die(1,f'\nAn error occurred in block range {a}-{b}') + msg('') + return b if res else tip + + def gen_chunks(start,stop,tip): + n = start + if endless: + stop = tip + elif stop > tip: + die(1,f'{stop}: stop value is higher than chain tip') + + while n <= stop: + yield ( n, min(n+99,stop) ) + n += 100 + + last_block = await do_scan(gen_chunks(start,stop,self.rpc.blockcount),self.rpc.blockcount) + + if endless: + tip = await self.rpc.call('getblockcount') + while last_block < tip: + last_block = await do_scan(gen_chunks(last_block+1,tip),tip) + tip = await self.rpc.call('getblockcount') + + msg('Done') diff --git a/mmgen/main_tool.py b/mmgen/main_tool.py index f8f5e6e1..1d927247 100755 --- a/mmgen/main_tool.py +++ b/mmgen/main_tool.py @@ -161,6 +161,7 @@ mods = { 'listaddresses', 'remove_address', 'remove_label', + 'rescan_blockchain', 'resolve_address', 'twview', 'txhist', diff --git a/mmgen/tool/rpc.py b/mmgen/tool/rpc.py index 596c0b63..4de03297 100755 --- a/mmgen/tool/rpc.py +++ b/mmgen/tool/rpc.py @@ -178,3 +178,11 @@ class tool_cmd(tool_cmd_base): return ret.mmaddr if is_coin_addr(self.proto,mmgen_or_coin_addr) else ret.coinaddr else: return False + + async def rescan_blockchain(self, + start_block: int = None, + stop_block: int = None ): + "rescan the blockchain to update historical transactions in the tracking wallet" + from ..tw.ctl import TrackingWallet + ret = await (await TrackingWallet(self.proto,mode='w')).rescan_blockchain(start_block,stop_block) + return True diff --git a/test/test_py_d/ts_regtest.py b/test/test_py_d/ts_regtest.py index fc6be211..35c03ead 100755 --- a/test/test_py_d/ts_regtest.py +++ b/test/test_py_d/ts_regtest.py @@ -203,6 +203,10 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared): ('bob_import_list', 'importing flat address list'), ('bob_import_list_rescan', 'importing flat address list with --rescan'), ('bob_resolve_addr', 'resolving an address in the tracking wallet'), + ('bob_rescan_blockchain_all','rescanning the blockchain (full rescan)'), + ('bob_rescan_blockchain_gb', 'rescanning the blockchain (Genesis block)'), + ('bob_rescan_blockchain_one','rescanning the blockchain (single block)'), + ('bob_rescan_blockchain_ss', 'rescanning the blockchain (range of blocks)'), ('bob_split2', "splitting Bob's funds"), ('bob_0conf0_getbalance', "Bob's balance (unconfirmed, minconf=0)"), ('bob_0conf1_getbalance', "Bob's balance (unconfirmed, minconf=1)"), @@ -927,6 +931,24 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared): addrfile = joinpath(self.tmpdir,'non-mmgen.addrs') return self.user_import('bob',['--quiet','--rescan','--addrlist',addrfile],nAddr=5) + def bob_rescan_blockchain(self,add_args,expect): + t = self.spawn('mmgen-tool',['--bob','rescan_blockchain'] + add_args) + t.expect(f'Scanning blocks {expect}') + t.expect('Done') + return t + + def bob_rescan_blockchain_all(self): + return self.bob_rescan_blockchain([],'400-400') + + def bob_rescan_blockchain_gb(self): + return self.bob_rescan_blockchain(['start_block=0','stop_block=0'],'0-0') + + def bob_rescan_blockchain_one(self): + return self.bob_rescan_blockchain(['start_block=300','stop_block=300'],'300-300') + + def bob_rescan_blockchain_ss(self): + return self.bob_rescan_blockchain(['start_block=300','stop_block=302'],'300-302') + def bob_split2(self): addrs = self.read_from_tmpfile('non-mmgen.addrs').split() amts = (1.12345678,2.87654321,3.33443344,4.00990099,5.43214321)