message signing: cleanups, default to base cls if proto cls missing
This commit is contained in:
parent
cda6e2c3ce
commit
b84e68d486
8 changed files with 56 additions and 57 deletions
|
|
@ -16,20 +16,16 @@ from ...msg import coin_msg
|
|||
|
||||
class coin_msg(coin_msg):
|
||||
|
||||
class base(coin_msg.base): pass
|
||||
include_pubhash = True
|
||||
sigdata_pfx = None
|
||||
msghash_types = ('raw',) # first-listed is the default
|
||||
|
||||
class new(base,coin_msg.new): pass
|
||||
|
||||
class completed(base,coin_msg.completed): pass
|
||||
|
||||
class unsigned(completed,coin_msg.unsigned):
|
||||
class unsigned(coin_msg.unsigned):
|
||||
|
||||
async def do_sign(self,wif,message,msghash_type):
|
||||
return await self.rpc.call( 'signmessagewithprivkey', wif, message )
|
||||
|
||||
class signed(completed,coin_msg.signed): pass
|
||||
|
||||
class signed_online(signed,coin_msg.signed_online):
|
||||
class signed_online(coin_msg.signed_online):
|
||||
|
||||
async def do_verify(self,addr,sig,message,msghash_type):
|
||||
return await self.rpc.call( 'verifymessage', addr, sig, message )
|
||||
|
|
|
|||
|
|
@ -16,21 +16,17 @@ from ...msg import coin_msg
|
|||
|
||||
class coin_msg(coin_msg):
|
||||
|
||||
class base(coin_msg.base): pass
|
||||
include_pubhash = False
|
||||
sigdata_pfx = '0x'
|
||||
msghash_types = ('eth_sign','raw') # first-listed is the default
|
||||
|
||||
class new(base,coin_msg.new): pass
|
||||
|
||||
class completed(base,coin_msg.completed): pass
|
||||
|
||||
class unsigned(completed,coin_msg.unsigned):
|
||||
class unsigned(coin_msg.unsigned):
|
||||
|
||||
async def do_sign(self,wif,message,msghash_type):
|
||||
from .misc import ec_sign_message_with_privkey
|
||||
return ec_sign_message_with_privkey( message, bytes.fromhex(wif), msghash_type )
|
||||
|
||||
class signed(completed,coin_msg.signed): pass
|
||||
|
||||
class signed_online(signed,coin_msg.signed_online):
|
||||
class signed_online(coin_msg.signed_online):
|
||||
|
||||
async def do_verify(self,addr,sig,message,msghash_type):
|
||||
from ...tool.coin import tool_cmd
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class MsgOps:
|
|||
network = proto.network,
|
||||
message = msg,
|
||||
addrlists = addr_specs,
|
||||
msghash_type = opt.msghash_type or proto.msghash_types[0]
|
||||
msghash_type = opt.msghash_type
|
||||
).write_to_file( ask_overwrite=False )
|
||||
|
||||
class sign(metaclass=AsyncInit):
|
||||
|
|
|
|||
39
mmgen/msg.py
39
mmgen/msg.py
|
|
@ -49,12 +49,11 @@ class MMGenIDRange(str,Hilite,InitErrors,MMGenObject):
|
|||
|
||||
class coin_msg:
|
||||
|
||||
supported_base_protos = ('Bitcoin','Ethereum')
|
||||
|
||||
class base(MMGenObject):
|
||||
|
||||
ext = 'rawmsg.json'
|
||||
signed = False
|
||||
chksum_keys = ('addrlists','message','msghash_type','network')
|
||||
|
||||
@property
|
||||
def desc(self):
|
||||
|
|
@ -64,7 +63,7 @@ class coin_msg:
|
|||
def chksum(self):
|
||||
return make_chksum_6(
|
||||
json.dumps(
|
||||
{k:v for k,v in self.data.items() if k in ('addrlists','message','network','msghash_type')},
|
||||
{k:self.data[k] for k in self.chksum_keys},
|
||||
sort_keys = True,
|
||||
separators = (',', ':')
|
||||
))
|
||||
|
|
@ -107,7 +106,8 @@ class coin_msg:
|
|||
class new(base):
|
||||
|
||||
def __init__(self,message,addrlists,msghash_type,*args,**kwargs):
|
||||
if msghash_type not in self.proto.msghash_types:
|
||||
msghash_type = msghash_type or self.msg_cls.msghash_types[0]
|
||||
if msghash_type not in self.msg_cls.msghash_types:
|
||||
die(2,f'msghash_type {msghash_type!r} not supported for {self.proto.base_proto} protocol')
|
||||
self.data = {
|
||||
'network': '{}_{}'.format( self.proto.coin.lower(), self.proto.network ),
|
||||
|
|
@ -181,7 +181,7 @@ class coin_msg:
|
|||
'failed_sids': ('Failed Seed IDs:', lambda v: red(fmt_list(v,fmt='bare')) ),
|
||||
}
|
||||
|
||||
if len(self.proto.msghash_types) == 1:
|
||||
if len(self.msg_cls.msghash_types) == 1:
|
||||
del hdr_data['msghash_type']
|
||||
|
||||
if req_addr or type(self).__name__ == 'exported_sigs':
|
||||
|
|
@ -193,7 +193,7 @@ class coin_msg:
|
|||
fs1 = '{:%s} {}' % max(len(v[0]) for v in hdr_data.values())
|
||||
fs2 = '{:%s} %s{}' % (
|
||||
max(len(labels[k]) for v in self.sigs.values() for k in v.keys()),
|
||||
'0x' if self.proto.base_proto == 'Ethereum' else ''
|
||||
self.msg_cls.sigdata_pfx or ''
|
||||
)
|
||||
|
||||
if req_addr:
|
||||
|
|
@ -229,7 +229,7 @@ class coin_msg:
|
|||
'addr': e.addr,
|
||||
'sig': sig,
|
||||
}
|
||||
if self.proto.base_proto != 'Ethereum':
|
||||
if self.msg_cls.include_pubhash:
|
||||
data.update({ 'pubhash': self.proto.parse_addr(e.addr_p2pkh or e.addr).bytes.hex() })
|
||||
|
||||
if e.addr_p2pkh:
|
||||
|
|
@ -319,8 +319,9 @@ class coin_msg:
|
|||
|
||||
def get_json_for_export(self,addr=None):
|
||||
sigs = list( self.get_sigs(addr).values() )
|
||||
if self.proto.base_proto == 'Ethereum':
|
||||
sigs = [{k:'0x'+v for k,v in e.items()} for e in sigs]
|
||||
pfx = self.msg_cls.sigdata_pfx
|
||||
if pfx:
|
||||
sigs = [{k:pfx+v for k,v in e.items()} for e in sigs]
|
||||
return json.dumps(
|
||||
{
|
||||
'message': self.data['message'],
|
||||
|
|
@ -342,9 +343,10 @@ class coin_msg:
|
|||
desc = self.desc )
|
||||
)
|
||||
|
||||
pfx = self.msg_cls.sigdata_pfx
|
||||
self.sigs = {sig_data['addr']:sig_data for sig_data in (
|
||||
[{k:v[2:] for k,v in e.items()} for e in self.data['signatures']] # remove '0x' prefix
|
||||
if self.proto.base_proto == 'Ethereum' else
|
||||
[{k:v[len(pfx):] for k,v in e.items()} for e in self.data['signatures']]
|
||||
if pfx else
|
||||
self.data['signatures']
|
||||
)}
|
||||
|
||||
|
|
@ -362,14 +364,15 @@ def _get_obj(clsname,coin=None,network='mainnet',infile=None,data=None,*args,**k
|
|||
init_proto( coin=coin, network=network ) if coin else
|
||||
coin_msg.base().get_proto_from_file(infile) )
|
||||
|
||||
if proto.base_proto not in coin_msg.supported_base_protos:
|
||||
die(f'Message signing operations not supported for {proto.base_proto} protocol')
|
||||
try:
|
||||
msg_cls = getattr(
|
||||
importlib.import_module(f'mmgen.base_proto.{proto.base_proto.lower()}.msg'),
|
||||
'coin_msg' )
|
||||
except:
|
||||
die(1,f'Message signing operations not supported for {proto.base_proto} protocol')
|
||||
|
||||
cls = getattr(
|
||||
getattr(importlib.import_module(f'mmgen.base_proto.{proto.base_proto.lower()}.msg'),'coin_msg'),
|
||||
clsname )
|
||||
|
||||
me = MMGenObject.__new__(cls)
|
||||
me = MMGenObject.__new__(getattr( msg_cls, clsname, getattr(coin_msg,clsname) ))
|
||||
me.msg_cls = msg_cls
|
||||
me.proto = proto
|
||||
|
||||
me.__init__(infile=infile,data=data,*args,**kwargs)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ class mainnet(CoinProtocol.Secp256k1): # chainparams.cpp
|
|||
witness_vernum = int(witness_vernum_hex,16)
|
||||
bech32_hrp = 'bc'
|
||||
sign_mode = 'daemon'
|
||||
msghash_types = ('raw',) # first-listed is the default
|
||||
avg_bdi = int(9.7 * 60) # average block discovery interval (historical)
|
||||
halving_interval = 210000
|
||||
max_halvings = 64
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ class mainnet(CoinProtocol.DummyWIF,CoinProtocol.Secp256k1):
|
|||
max_tx_fee = '0.005'
|
||||
chain_names = ['ethereum','foundation']
|
||||
sign_mode = 'standalone'
|
||||
msghash_types = ('eth_sign','raw') # first-listed is the default
|
||||
caps = ('token',)
|
||||
mmcaps = ('key','addr','rpc','tx')
|
||||
base_proto = 'Ethereum'
|
||||
|
|
|
|||
|
|
@ -712,9 +712,10 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
|
|||
t.written_to_file('Signed message data')
|
||||
return t
|
||||
|
||||
def msgverify(self,fn=None):
|
||||
def msgverify(self,fn=None,msghash_type='eth_sign'):
|
||||
fn = fn or get_file_with_ext(self.tmpdir,'sigmsg.json')
|
||||
t = self.spawn('mmgen-msg', self.eth_args_noquiet + [ 'verify', fn ])
|
||||
t.expect(msghash_type)
|
||||
t.expect('1 signature verified')
|
||||
return t
|
||||
|
||||
|
|
@ -725,25 +726,28 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
|
|||
return t
|
||||
|
||||
def msgverify_export(self):
|
||||
return self.msgverify( fn=os.path.join(self.tmpdir,'signatures.json') )
|
||||
return self.msgverify(
|
||||
fn = os.path.join(self.tmpdir,'signatures.json') )
|
||||
|
||||
def msgcreate_raw(self):
|
||||
get_file_with_ext(self.tmpdir,'rawmsg.json',delete_all=True)
|
||||
return self.msgcreate(add_args=['--msghash-type=raw'])
|
||||
|
||||
def msgsign_raw(self,*args,**kwargs):
|
||||
def msgsign_raw(self):
|
||||
get_file_with_ext(self.tmpdir,'sigmsg.json',delete_all=True)
|
||||
return self.msgsign(*args,**kwargs)
|
||||
return self.msgsign()
|
||||
|
||||
def msgverify_raw(self,*args,**kwargs):
|
||||
return self.msgverify(*args,**kwargs)
|
||||
def msgverify_raw(self):
|
||||
return self.msgverify(msghash_type='raw')
|
||||
|
||||
def msgexport_raw(self,*args,**kwargs):
|
||||
def msgexport_raw(self):
|
||||
get_file_with_ext(self.tmpdir,'signatures.json',no_dot=True,delete_all=True)
|
||||
return self.msgexport(*args,**kwargs)
|
||||
return self.msgexport()
|
||||
|
||||
def msgverify_export_raw(self,*args,**kwargs):
|
||||
return self.msgverify_export(*args,**kwargs)
|
||||
def msgverify_export_raw(self):
|
||||
return self.msgverify(
|
||||
fn = os.path.join(self.tmpdir,'signatures.json'),
|
||||
msghash_type = 'raw' )
|
||||
|
||||
def txcreate4(self):
|
||||
return self.txcreate(
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ def get_obj(coin,network,msghash_type):
|
|||
addrlists = addrlists,
|
||||
msghash_type = msghash_type )
|
||||
|
||||
async def run_test(network_id,msghash_type='raw'):
|
||||
async def run_test(network_id,chksum,msghash_type='raw'):
|
||||
|
||||
coin,network = CoinProtocol.Base.parse_network_id(network_id)
|
||||
|
||||
|
|
@ -48,6 +48,8 @@ async def run_test(network_id,msghash_type='raw'):
|
|||
|
||||
os.makedirs(tmpdir,exist_ok=True)
|
||||
|
||||
assert m.chksum.upper() == chksum, f'{m.chksum.upper()} != {chksum}'
|
||||
|
||||
m.write_to_file(
|
||||
outdir = tmpdir,
|
||||
ask_overwrite = False )
|
||||
|
|
@ -122,22 +124,22 @@ class unit_tests:
|
|||
altcoin_deps = ('ltc','bch','eth','eth_raw')
|
||||
|
||||
def btc(self,name,ut):
|
||||
return run_test('btc')
|
||||
return run_test('btc','AA0DB5')
|
||||
|
||||
def btc_tn(self,name,ut):
|
||||
return run_test('btc_tn')
|
||||
return run_test('btc_tn','A88E1D')
|
||||
|
||||
def btc_rt(self,name,ut):
|
||||
return run_test('btc_rt')
|
||||
return run_test('btc_rt','578018')
|
||||
|
||||
def ltc(self,name,ut):
|
||||
return run_test('ltc')
|
||||
return run_test('ltc','BA7549')
|
||||
|
||||
def bch(self,name,ut):
|
||||
return run_test('bch')
|
||||
return run_test('bch','1B8065')
|
||||
|
||||
def eth(self,name,ut):
|
||||
return run_test('eth',msghash_type='eth_sign')
|
||||
return run_test('eth','35BAD9',msghash_type='eth_sign')
|
||||
|
||||
def eth_raw(self,name,ut):
|
||||
return run_test('eth')
|
||||
return run_test('eth','9D900C')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue