Browse Source

new command: `mmgen-tool rescan_blockchain`

The MMGen Project 2 years ago
parent
commit
c96833c5a2
4 changed files with 74 additions and 1 deletions
  1. 43 1
      mmgen/base_proto/bitcoin/tw/ctl.py
  2. 1 0
      mmgen/main_tool.py
  3. 8 0
      mmgen/tool/rpc.py
  4. 22 0
      test/test_py_d/ts_regtest.py

+ 43 - 1
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')

+ 1 - 0
mmgen/main_tool.py

@@ -161,6 +161,7 @@ mods = {
 		'listaddresses',
 		'remove_address',
 		'remove_label',
+		'rescan_blockchain',
 		'resolve_address',
 		'twview',
 		'txhist',

+ 8 - 0
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

+ 22 - 0
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)