new command: mmgen-tool rescan_address
- updates an address balance using the `scantxoutset` RPC call
This commit is contained in:
parent
c96833c5a2
commit
5488c51353
4 changed files with 80 additions and 1 deletions
|
|
@ -14,7 +14,7 @@ base_proto.bitcoin.twctl: Bitcoin base protocol tracking wallet control class
|
|||
|
||||
from ....globalvars import g
|
||||
from ....tw.ctl import TrackingWallet
|
||||
from ....util import msg,msg_r,rmsg,die,write_mode
|
||||
from ....util import msg,msg_r,rmsg,vmsg,die,suf,fmt_list,write_mode
|
||||
|
||||
class BitcoinTrackingWallet(TrackingWallet):
|
||||
|
||||
|
|
@ -88,3 +88,68 @@ class BitcoinTrackingWallet(TrackingWallet):
|
|||
tip = await self.rpc.call('getblockcount')
|
||||
|
||||
msg('Done')
|
||||
|
||||
@write_mode
|
||||
async def rescan_address(self,addrspec):
|
||||
res = await self.resolve_address(addrspec,None)
|
||||
if not res:
|
||||
return False
|
||||
return await self.rescan_addresses([res.coinaddr])
|
||||
|
||||
@write_mode
|
||||
async def rescan_addresses(self,coin_addrs):
|
||||
|
||||
import asyncio
|
||||
|
||||
async def do_scan():
|
||||
return await self.rpc.call(
|
||||
'scantxoutset',
|
||||
'start',
|
||||
[f'addr({a})' for a in coin_addrs],
|
||||
timeout = 720 ) # call may take several minutes to complete
|
||||
|
||||
async def do_status():
|
||||
m = f'{CR}Scanning UTXO set: '
|
||||
msg_r(m)
|
||||
while True:
|
||||
await asyncio.sleep(2)
|
||||
res = await self.rpc.call('scantxoutset','status')
|
||||
if res:
|
||||
msg_r(m + f'{res["progress"]}% completed ')
|
||||
if task1.done():
|
||||
msg('')
|
||||
return
|
||||
|
||||
CR = '\r'
|
||||
|
||||
if self.rpc.backend.name == 'aiohttp':
|
||||
task1 = asyncio.create_task( do_scan() )
|
||||
task2 = asyncio.create_task( do_status() )
|
||||
res = await task1
|
||||
await task2
|
||||
else:
|
||||
msg_r(f'Scanning UTXO set, this could take several minutes...')
|
||||
res = await do_scan()
|
||||
msg('done')
|
||||
|
||||
if not res['success']:
|
||||
msg('UTXO scanning failed or was interrupted')
|
||||
return False
|
||||
elif res['unspents']:
|
||||
blocks = sorted({ i['height'] for i in res['unspents'] })
|
||||
msg('Found {} unspent output{} in {} block{}'.format(
|
||||
len(res['unspents']),
|
||||
suf(res['unspents']),
|
||||
len(blocks),
|
||||
suf(blocks) ))
|
||||
vmsg(f'Blocks to rescan: {fmt_list(blocks,fmt="bare")}')
|
||||
for n,block in enumerate(blocks):
|
||||
msg_r(f'{CR}Rescanning block: {block} ({n+1}/{len(blocks)})')
|
||||
# httplib seems to require fresh connection here, so specify timeout
|
||||
await self.rpc.call('rescanblockchain',block,block,timeout=60)
|
||||
msg('\nRescan completed OK')
|
||||
return True
|
||||
else:
|
||||
msg('Imported address has no balance' if len(coin_addrs) == 1 else
|
||||
'Imported addresses have no balances' )
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ mods = {
|
|||
'listaddresses',
|
||||
'remove_address',
|
||||
'remove_label',
|
||||
'rescan_address',
|
||||
'rescan_blockchain',
|
||||
'resolve_address',
|
||||
'twview',
|
||||
|
|
|
|||
|
|
@ -179,6 +179,11 @@ class tool_cmd(tool_cmd_base):
|
|||
else:
|
||||
return False
|
||||
|
||||
async def rescan_address(self,mmgen_or_coin_addr:str):
|
||||
"rescan an address in the tracking wallet to update its balance"
|
||||
from ..tw.ctl import TrackingWallet
|
||||
return await (await TrackingWallet(self.proto,mode='w')).rescan_address( mmgen_or_coin_addr )
|
||||
|
||||
async def rescan_blockchain(self,
|
||||
start_block: int = None,
|
||||
stop_block: int = None ):
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@ 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_addr', 'rescanning an address'),
|
||||
('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)'),
|
||||
|
|
@ -931,6 +932,13 @@ 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_addr(self):
|
||||
sid = self._user_sid('bob')
|
||||
t = self.spawn('mmgen-tool',['--bob','rescan_address',f'{sid}:C:1'])
|
||||
t.expect('Found 1 unspent output')
|
||||
t.expect('completed OK')
|
||||
return t
|
||||
|
||||
def bob_rescan_blockchain(self,add_args,expect):
|
||||
t = self.spawn('mmgen-tool',['--bob','rescan_blockchain'] + add_args)
|
||||
t.expect(f'Scanning blocks {expect}')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue