Browse Source

Support 40-character UTF-8 tracking wallet comments

MMGen 7 years ago
parent
commit
d49c8627aa
6 changed files with 31 additions and 33 deletions
  1. 3 4
      mmgen/obj.py
  2. 5 10
      mmgen/rpc.py
  3. 2 2
      mmgen/tool.py
  4. 10 10
      mmgen/tw.py
  5. 1 1
      mmgen/tx.py
  6. 10 6
      test/test.py

+ 3 - 4
mmgen/obj.py

@@ -494,7 +494,7 @@ class TwMMGenID(str,Hilite,InitErrors,MMGenObject):
 		return me
 
 # contains TwMMGenID,TwComment.  Not for display
-class TwLabel(str,InitErrors,MMGenObject):
+class TwLabel(unicode,InitErrors,MMGenObject):
 	def __new__(cls,s,on_fail='die'):
 		if type(s) == cls: return s
 		cls.arg_chk(cls,on_fail)
@@ -502,7 +502,7 @@ class TwLabel(str,InitErrors,MMGenObject):
 			ss = s.split(None,1)
 			mmid = TwMMGenID(ss[0],on_fail='raise')
 			comment = TwComment(ss[1] if len(ss) == 2 else '',on_fail='raise')
-			me = str.__new__(cls,'{}{}'.format(mmid,' {}'.format(comment) if comment else ''))
+			me = unicode.__new__(cls,u'{}{}'.format(mmid,u' {}'.format(comment) if comment else ''))
 			me.mmid = mmid
 			me.comment = comment
 			return me
@@ -671,8 +671,7 @@ class MMGenWalletLabel(MMGenLabel):
 	desc = 'wallet label'
 
 class TwComment(MMGenLabel):
-	max_len = 32
-	allowed = map(unichr,range(32,127))
+	max_len = 40
 	desc = 'tracking wallet comment'
 
 class MMGenTXLabel(MMGenLabel):

+ 5 - 10
mmgen/rpc.py

@@ -103,20 +103,16 @@ class CoinDaemonRPCConnection(object):
 
 		dmsg_rpc('=== request() debug ===')
 		dmsg_rpc('    RPC POST data ==> {}\n'.format(p))
-		caller = self
+
 		class MyJSONEncoder(json.JSONEncoder):
 			def default(self, obj):
 				if isinstance(obj,g.proto.coin_amt):
 					return g.proto.get_rpc_coin_amt_type()(obj)
 				return json.JSONEncoder.default(self, obj)
 
-		# TODO: UTF-8 labels
-		# if type(p) != list and p['method'] == 'importaddress':
-		# 	dump = json.dumps(p,cls=MyJSONEncoder,ensure_ascii=False)
-		# 	print(dump)
-
 		dmsg_rpc('    RPC AUTHORIZATION data ==> raw: [{}]\n{}enc: [Basic {}]\n'.format(
 			self.auth_str,' '*31,base64.b64encode(self.auth_str)))
+
 		try:
 			hc.request('POST', '/', json.dumps(p,cls=MyJSONEncoder), {
 				'Host': self.host,
@@ -146,15 +142,14 @@ class CoinDaemonRPCConnection(object):
 				e2 = str(e1)
 			return do_fail(r,1,e2)
 
-		r2 = r.read()
+		r2 = r.read().decode('utf8')
 
-		dmsg_rpc('    RPC REPLY data ==> {}\n'.format(r2))
+		dmsg_rpc(u'    RPC REPLY data ==> {}\n'.format(r2))
 
 		if not r2:
 			return do_fail(r,2,'Error: empty reply')
 
-#		from decimal import Decimal
-		r3 = json.loads(r2.decode('utf8'), parse_float=Decimal)
+		r3 = json.loads(r2,parse_float=Decimal)
 		ret = []
 
 		for resp in r3 if cf['batch'] else [r3]:

+ 2 - 2
mmgen/tool.py

@@ -725,7 +725,7 @@ def Listaddresses(addrs='',minconf=1,
 
 	out = ([],[green('Chain: {}'.format(g.chain.upper()))])[g.chain in ('testnet','regtest')]
 
-	fs = '{{mid}}{} {{cmt}} {{amt}}{}'.format(('',' {addr}')[showbtcaddrs],('',' {age}')[show_age])
+	fs = u'{{mid}}{} {{cmt}} {{amt}}{}'.format(('',' {addr}')[showbtcaddrs],('',' {age}')[show_age])
 	mmaddrs = [k for k in addrs.keys() if k.type == 'mmgen']
 	max_mmid_len = max(len(k) for k in mmaddrs) + 2 if mmaddrs else 10
 	max_cmt_len  = max(max(len(v['lbl'].comment) for v in addrs.values()),7)
@@ -835,6 +835,6 @@ def Twview(pager=False,reverse=False,wide=False,minconf=1,sort='age',show_days=T
 def Add_label(mmaddr_or_coin_addr,label):
 	rpc_init()
 	from mmgen.tw import MMGenTrackingWallet
-	MMGenTrackingWallet.add_label(mmaddr_or_coin_addr,label) # dies on failure
+	MMGenTrackingWallet.add_label(mmaddr_or_coin_addr,label,on_fail='raise')
 
 def Remove_label(mmaddr_or_coin_addr): Add_label(mmaddr_or_coin_addr,'')

+ 10 - 10
mmgen/tw.py

@@ -162,7 +162,7 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
 		out  = [hdr_fmt.format(' '.join(self.sort_info()),g.coin,self.total.hl())]
 		if g.chain in ('testnet','regtest'):
 			out += [green('Chain: {}'.format(g.chain.upper()))]
-		fs = ' {:%s} {:%s} {:2} {} {} {:<}' % (col1_w,tx_w)
+		fs = u' {:%s} {:%s} {:2} {} {} {:<}' % (col1_w,tx_w)
 		out += [fs.format('Num',
 				'TXid'.ljust(tx_w - 5) + ' Vout', '',
 				'Address'.ljust(addr_w),
@@ -175,10 +175,10 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
 				else i.twmmid if i.twmmid.type=='mmgen'
 					else 'Non-{}'.format(g.proj_name),width=mmid_w,color=True)
 			if self.show_mmid:
-				addr_out = '{} {}'.format(
+				addr_out = u'{} {}'.format(
 					type(i.addr).fmtc(addr_dots,width=btaddr_w,color=True) if i.skip == 'addr' \
 							else i.addr.fmt(width=btaddr_w,color=True),
-					'{} {}'.format(mmid_disp,i.label.fmt(width=label_w,color=True) \
+					u'{} {}'.format(mmid_disp,i.label.fmt(width=label_w,color=True) \
 							if label_w > 0 else ''))
 			else:
 				addr_out = type(i.addr).fmtc(addr_dots,width=addr_w,color=True) \
@@ -280,10 +280,10 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
 				idx,lbl = self.get_idx_and_label_from_user()
 				if idx:
 					e = self.unspent[idx-1]
-					if type(self).add_label(e.twmmid,lbl,addr=e.addr):
+					if type(self).add_label(e.twmmid,lbl.decode('utf8'),addr=e.addr):
 						self.get_unspent_data()
 						self.do_sort()
-						msg('{}\n{}\n{}'.format(self.fmt_display,prompt,p))
+						msg(u'{}\n{}\n{}'.format(self.fmt_display,prompt,p))
 					else:
 						msg('Label could not be added\n{}\n{}'.format(prompt,p))
 			elif reply == 'M': self.do_sort('twmmid'); self.show_mmid = True
@@ -314,7 +314,7 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
 
 	# returns on failure
 	@classmethod
-	def add_label(cls,arg1,label='',addr=None,silent=False):
+	def add_label(cls,arg1,label='',addr=None,silent=False,on_fail='return'):
 		from mmgen.tx import is_mmgen_id,is_coin_addr
 		mmaddr,coinaddr = None,None
 		if is_coin_addr(addr or arg1):
@@ -345,10 +345,10 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
 
 		mmaddr = TwMMGenID(mmaddr)
 
-		cmt = TwComment(label,on_fail='return')
+		cmt = TwComment(label,on_fail=on_fail)
 		if cmt in (False,None): return False
 
-		lbl = TwLabel(mmaddr + ('',' '+cmt)[bool(cmt)]) # label is ASCII for now
+		lbl = TwLabel(mmaddr + ('',' '+cmt)[bool(cmt)],on_fail=on_fail)
 
 		# NOTE: this works because importaddress() removes the old account before
 		# associating the new account with the address.
@@ -366,8 +366,8 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
 			m = mmaddr.type.replace('mmg','MMG')
 			a = mmaddr.replace(g.proto.base_coin.lower()+':','')
 			s = '{} address {} in tracking wallet'.format(m,a)
-			if label: msg("Added label '{}' to {}".format(label,s))
-			else:     msg('Removed label from {}'.format(s))
+			if label: msg(u"Added label '{}' to {}".format(label,s))
+			else:     msg(u'Removed label from {}'.format(s))
 			return True
 
 	@classmethod

+ 1 - 1
mmgen/tx.py

@@ -949,7 +949,7 @@ class MMGenTX(MMGenObject):
 						('','confirmations:','{} (around {} days)'.format(confs,days) if blockcount!=None else '')
 					] if ip else icommon + [
 						('','change:',green('True') if e.is_chg else '')]
-					io_out += '\n'.join([('{:>3} {:<8} {}'.format(*d)) for d in items if d[2]]) + '\n\n'
+					io_out += '\n'.join([(u'{:>3} {:<8} {}'.format(*d)) for d in items if d[2]]) + '\n\n'
 			return io_out
 
 		hdr_fs = (

+ 10 - 6
test/test.py

@@ -2713,9 +2713,9 @@ class MMGenTestSuite(object):
 		sid = self.regtest_user_sid('alice')
 		return self.regtest_user_remove_label(name,'alice',sid+':C:1')
 
-	def regtest_user_chk_label(self,name,user,addr,label):
+	def regtest_user_chk_label(self,name,user,addr,label,label_pat=None):
 		t = MMGenExpect(name,'mmgen-tool',['--'+user,'listaddresses','all_labels=1'])
-		t.expect('{}\s+\S{{30}}\S+\s+{}\s+'.format(addr,label),regex=True)
+		t.expect(ur'{}\s+\S{{30}}\S+\s+{}\s+'.format(addr,label_pat or label),regex=True)
 		t.ok()
 
 	def regtest_alice_chk_label1(self,name):
@@ -2726,9 +2726,16 @@ class MMGenTestSuite(object):
 		sid = self.regtest_user_sid('alice')
 		return self.regtest_user_chk_label(name,'alice',sid+':C:1','Replacement Label')
 
+	utf8_label     =  u'Edited label (40 characters, UTF8) α-β-γ'
+	utf8_label_pat = ur'Edited label \(40 characters, UTF8\) ..-..-..'
+
+	def regtest_alice_edit_label1(self,name):
+		return self.regtest_user_edit_label(name,'alice','1',self.utf8_label)
+
 	def regtest_alice_chk_label3(self,name):
 		sid = self.regtest_user_sid('alice')
-		return self.regtest_user_chk_label(name,'alice',sid+':C:1','Edited Label')
+		return self.regtest_user_chk_label(name,'alice',sid+':C:1',self.utf8_label,
+					label_pat=self.utf8_label_pat)
 
 	def regtest_alice_chk_label4(self,name):
 		sid = self.regtest_user_sid('alice')
@@ -2743,9 +2750,6 @@ class MMGenTestSuite(object):
 		t.expect(r"'q'=quit view, .*?:.",'q',regex=True)
 		t.ok()
 
-	def regtest_alice_edit_label1(self,name):
-		return self.regtest_user_edit_label(name,'alice','1','Edited Label')
-
 	def regtest_stop(self,name):
 		t = MMGenExpect(name,'mmgen-regtest',['stop'])
 		t.ok()