Browse Source

`mmgen-tool tw{export,import}`: support editing of comments fields

The MMGen Project 2 years ago
parent
commit
30b94db2f8

+ 4 - 2
mmgen/base_proto/ethereum/tw/json.py

@@ -87,13 +87,15 @@ class EthereumTwJSON(TwJSON):
 
 		async def do_import(self,batch):
 
+			from ....obj import TwComment
+
 			def gen_data(data):
 				for d in data:
 					if hasattr(d,'address'):
 						if d.amount is None: # Python 3.9: {} | {}
-							yield (d.address, {'mmid':d.mmgen_id,'comment':d.comment})
+							yield (d.address, {'mmid':d.mmgen_id,'comment':TwComment(d.comment)})
 						else:
-							yield (d.address, {'mmid':d.mmgen_id,'comment':d.comment,'balance':d.amount})
+							yield (d.address, {'mmid':d.mmgen_id,'comment':TwComment(d.comment),'balance':d.amount})
 					else:
 						yield ('params', {'symbol':d.symbol,'decimals':d.decimals})
 

+ 1 - 1
mmgen/data/release_date

@@ -1 +1 @@
-June 2022
+July 2022

+ 1 - 1
mmgen/data/version

@@ -1 +1 @@
-13.2.dev8
+13.2.dev9

+ 10 - 4
mmgen/tool/rpc.py

@@ -200,25 +200,31 @@ class tool_cmd(tool_cmd_base):
 		ret = await (await TrackingWallet(self.proto,mode='w')).rescan_blockchain(start_block,stop_block)
 		return True
 
-	async def twexport(self,include_amts=True):
+	async def twexport(self,include_amts=True,pretty=False):
 		"""
 		export a tracking wallet to JSON format
 
-		NOTE:
+		NOTES:
 
 		  If ‘include_amts’ is true (the default), Ethereum balances will be restored
 		  from the dump upon import. For Bitcoin and forks, amount fields in the dump
 		  are ignored.
+
+		  If ‘pretty’ is true, JSON will be dumped in human-readable format to allow
+		  for editing of comment fields.
 		"""
 		from ..tw.json import TwJSON
-		await TwJSON.Export( self.proto, include_amts=include_amts )
+		await TwJSON.Export( self.proto, include_amts=include_amts, pretty=pretty )
 		return True
 
 	async def twimport(self,filename:str,ignore_checksum=False,batch=False):
 		"""
 		restore a tracking wallet from a JSON dump created by ‘twexport’
 
-		NOTE:
+		NOTES:
+
+		  If comment fields in the JSON dump have been edited, ‘ignore_checksum’ must
+		  be set to true.
 
 		  The restored tracking wallet will have correct balances but no record of
 		  historical transactions.  These may be restored by running ‘mmgen-tool

+ 14 - 6
mmgen/tw/json.py

@@ -50,8 +50,13 @@ class TwJSON:
 		def dump_fn(self):
 			return f'{self.fn_pfx}-{self.coin}-{self.network}.json'
 
-		def json_dump(self,data):
-			return json.dumps( data, cls=json_encoder, separators=(',', ':'), sort_keys=True )
+		def json_dump(self,data,pretty=False):
+			return json.dumps(
+				data,
+				cls        = json_encoder,
+				sort_keys  = True,
+				separators = None if pretty else (',', ':'),
+				indent     = 4 if pretty else None )
 
 		def make_chksum(self,data):
 			return make_chksum_8( self.json_dump(data).encode() ).lower()
@@ -128,7 +133,7 @@ class TwJSON:
 
 	class Export(Base,metaclass=AsyncInit):
 
-		async def __init__(self,proto,include_amts=True):
+		async def __init__(self,proto,include_amts=True,pretty=False):
 
 			super().__init__(proto)
 
@@ -156,7 +161,10 @@ class TwJSON:
 			from ..fileutil import write_data_to_file
 			write_data_to_file(
 				outfile = self.dump_fn,
-				data = self.json_dump({
-					'checksum': self.make_chksum(data),
-					'data': data }),
+				data = self.json_dump(
+					{
+						'checksum': self.make_chksum(data),
+						'data': data
+					},
+					pretty = pretty ),
 				desc = f'tracking wallet JSON data' )

+ 27 - 2
test/test_py_d/ts_ethdev.py

@@ -317,6 +317,12 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
 		('twmove',             'moving the tracking wallet'),
 		('twimport',           'importing the tracking wallet'),
 		('twcompare',          'comparing imported tracking wallet with original'),
+		('edit_json_twdump',   'editing the tracking wallet JSON dump'),
+		('twmove',             'moving the tracking wallet'),
+		('twimport_nochksum',  'importing the edited tracking wallet JSON dump (ignore_checksum=1)'),
+
+		('token_listaddresses3','listaddresses --token=mm1 showempty=1'),
+		('token_listaddresses4','listaddresses --token=mm2 showempty=1'),
 		('twview9',            'twview (check balance)'),
 
 		('stop',               'stopping daemon'),
@@ -1143,6 +1149,10 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
 		return self.listaddresses(args=['--token=mm1'])
 	def token_listaddresses2(self):
 		return self.listaddresses(args=['--token=mm1'],tool_args=['showempty=1'])
+	def token_listaddresses3(self):
+		return self.listaddresses(args=['--token=mm1'],tool_args=['showempty=1'])
+	def token_listaddresses4(self):
+		return self.listaddresses(args=['--token=mm2'],tool_args=['showempty=1'])
 
 	def twview_cached_balances(self):
 		return self.twview(args=['--cached-balances'])
@@ -1279,14 +1289,19 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
 		os.rename( tw.tw_fn, tw.tw_fn+'.bak.json' )
 		return 'ok'
 
-	def twimport(self,add_args=[]):
+	def twimport(self,add_args=[],expect_str=None):
 		from mmgen.tw.json import TwJSON
 		fn = joinpath( self.tmpdir, TwJSON.Base(self.proto).dump_fn )
-		t = self.spawn('mmgen-tool',self.eth_args + ['twimport',fn] + add_args)
+		t = self.spawn('mmgen-tool',self.eth_args_noquiet + ['twimport',fn] + add_args)
 		t.expect('(y/N): ','y')
+		if expect_str:
+			t.expect(expect_str)
 		t.written_to_file('tracking wallet data')
 		return t
 
+	def twimport_nochksum(self):
+		return self.twimport(add_args=['ignore_checksum=true'],expect_str='ignoring incorrect checksum')
+
 	def tw_chktotal(self):
 		self.spawn('',msg_only=True)
 		from mmgen.tw.json import TwJSON
@@ -1305,6 +1320,16 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
 		cmp_or_die(*data,'tracking wallets')
 		return 'ok'
 
+	def edit_json_twdump(self):
+		self.spawn('',msg_only=True)
+		from mmgen.tw.json import TwJSON
+		fn = TwJSON.Base(self.proto).dump_fn
+		text = json.loads(self.read_from_tmpfile(fn))
+		token_addr = self.read_from_tmpfile('token_addr2').strip()
+		text['data']['entries']['tokens'][token_addr][2][3] = f'edited comment [фубар] [{gr_uc}]'
+		self.write_to_tmpfile( fn, json.dumps(text,indent=4) )
+		return 'ok'
+
 	def stop(self):
 		self.spawn('',msg_only=True)
 		if not opt.no_daemon_stop:

+ 29 - 2
test/test_py_d/ts_regtest.py

@@ -209,6 +209,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 		('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_twexport',             'exporting a tracking wallet to JSON'),
 		('carol_twimport',           'importing a tracking wallet JSON dump'),
 		('carol_delete_wallet',      'unloading and deleting Carol’s tracking wallet'),
@@ -216,6 +217,12 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 		('carol_twimport_nochksum',  'importing a tracking wallet JSON dump (ignore_checksum=1)'),
 		('carol_delete_wallet',      'unloading and deleting Carol’s tracking wallet'),
 		('carol_twimport_batch',     'importing a tracking wallet JSON dump (batch=1)'),
+		('bob_twexport_pretty',      'exporting a tracking wallet to JSON (pretty=1)'),
+		('bob_edit_json_twdump',     'editing a tracking wallet JSON dump'),
+		('carol_delete_wallet',      'unloading and deleting Carol’s tracking wallet'),
+		('carol_twimport_pretty',    'importing an edited tracking wallet JSON dump (ignore_checksum=1)'),
+		('carol_listaddresses',      'viewing Carol’s tracking wallet'),
+
 		('bob_split2',               "splitting Bob's funds"),
 		('bob_0conf0_getbalance',    "Bob's balance (unconfirmed, minconf=0)"),
 		('bob_0conf1_getbalance',    "Bob's balance (unconfirmed, minconf=1)"),
@@ -986,12 +993,26 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 	def bob_twexport_noamt(self):
 		return self.bob_twexport(add_args=['include_amts=0'])
 
-	def carol_twimport(self,add_args=[]):
+	def bob_twexport_pretty(self):
+		return self.bob_twexport(add_args=['pretty=1'])
+
+	def bob_edit_json_twdump(self):
+		self.spawn('',msg_only=True)
+		from mmgen.tw.json import TwJSON
+		fn = TwJSON.Base(self.proto).dump_fn
+		text = json.loads(self.read_from_tmpfile(fn))
+		text['data']['entries'][3][3] = f'edited comment [фубар] [{gr_uc}]'
+		self.write_to_tmpfile( fn, json.dumps(text,indent=4) )
+		return 'ok'
+
+	def carol_twimport(self,add_args=[],expect_str=None):
 		from mmgen.tw.json import TwJSON
 		fn = joinpath( self.tmpdir, TwJSON.Base(self.proto).dump_fn )
 		t = self.spawn('mmgen-tool',['--carol','twimport',fn] + add_args)
 		t.expect('(y/N): ','y')
-		if 'batch=true' in add_args:
+		if expect_str:
+			t.expect(expect_str)
+		elif 'batch=true' in add_args:
 			t.expect('{} addresses imported'.format(15 if self.proto.coin == 'BCH' else 25))
 		else:
 			t.expect('import completed OK')
@@ -1004,6 +1025,12 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 	def carol_twimport_batch(self):
 		return self.carol_twimport(add_args=['batch=true'])
 
+	def carol_twimport_pretty(self):
+		return self.carol_twimport(add_args=['ignore_checksum=true'],expect_str='ignoring incorrect checksum')
+
+	def carol_listaddresses(self):
+		return self.spawn('mmgen-tool',['--carol','listaddresses','showempty=1'])
+
 	async def carol_delete_wallet(self):
 		imsg(f'Unloading Carol’s tracking wallet')
 		t = self.spawn('mmgen-regtest',['cli','unloadwallet','carol'])