From 15b94038a4014e1f2c0e6bc44a456bd1df3c9446 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sun, 29 Sep 2024 11:59:57 +0000 Subject: [PATCH] self.proto.pubhash2addr(): return `CoinAddr` instance --- mmgen/addr.py | 2 +- mmgen/proto/btc/addrgen.py | 17 +++++------------ mmgen/proto/btc/params.py | 23 +++++++++++++---------- mmgen/proto/btc/tx/base.py | 4 ++-- mmgen/proto/eth/addrgen.py | 9 +++------ mmgen/proto/eth/params.py | 10 ++++++---- mmgen/proto/zec/params.py | 4 ++-- mmgen/tool/coin.py | 4 ++-- test/cmdtest_py_d/ct_regtest.py | 4 ++-- 9 files changed, 36 insertions(+), 41 deletions(-) diff --git a/mmgen/addr.py b/mmgen/addr.py index ddcfced6..96a6cc61 100755 --- a/mmgen/addr.py +++ b/mmgen/addr.py @@ -50,7 +50,7 @@ class MMGenAddrType(HiliteStr,InitErrors,MMGenObject): 'C': ati('compressed','std', True, 'p2pkh', 'p2pkh', 'wif', (), 'Compressed P2PKH address'), 'S': ati('segwit', 'std', True, 'segwit', 'p2sh', 'wif', (), 'Segwit P2SH-P2WPKH address'), 'B': ati('bech32', 'std', True, 'bech32', 'bech32', 'wif', (), 'Native Segwit (Bech32) address'), - 'E': ati('ethereum', 'std', False,'ethereum','ethereum','privkey', ('wallet_passwd',),'Ethereum address'), + 'E': ati('ethereum', 'std', False,'ethereum','p2pkh', 'privkey', ('wallet_passwd',),'Ethereum address'), 'Z': ati('zcash_z','zcash_z',False,'zcash_z', 'zcash_z', 'wif', ('viewkey',), 'Zcash z-address'), 'M': ati('monero', 'monero', False,'monero', 'monero', 'spendkey',('viewkey','wallet_passwd'),'Monero address'), } diff --git a/mmgen/proto/btc/addrgen.py b/mmgen/proto/btc/addrgen.py index 3af02519..a8bf02cb 100755 --- a/mmgen/proto/btc/addrgen.py +++ b/mmgen/proto/btc/addrgen.py @@ -13,16 +13,13 @@ proto.btc.addrgen: Bitcoin address generation classes for the MMGen suite """ from ...addrgen import addr_generator, check_data -from ...addr import CoinAddr from .common import hash160 class p2pkh(addr_generator.base): @check_data - def to_addr(self,data): - return CoinAddr( - self.proto, - self.proto.pubhash2addr( hash160(data.pubkey), p2sh=False )) + def to_addr(self, data): + return self.proto.pubhash2addr(hash160(data.pubkey), 'p2pkh') class legacy(p2pkh): pass @@ -34,17 +31,13 @@ class segwit(addr_generator.base): @check_data def to_addr(self,data): - return CoinAddr( - self.proto, - self.proto.pubhash2segwitaddr( hash160(data.pubkey)) ) + return self.proto.pubhash2segwitaddr(hash160(data.pubkey)) def to_segwit_redeem_script(self,data): # NB: returns hex - return self.proto.pubhash2redeem_script( hash160(data.pubkey) ).hex() + return self.proto.pubhash2redeem_script(hash160(data.pubkey)).hex() class bech32(addr_generator.base): @check_data def to_addr(self,data): - return CoinAddr( - self.proto, - self.proto.pubhash2bech32addr( hash160(data.pubkey) )) + return self.proto.pubhash2bech32addr(hash160(data.pubkey)) diff --git a/mmgen/proto/btc/params.py b/mmgen/proto/btc/params.py index 7c2de39b..f9eaa888 100755 --- a/mmgen/proto/btc/params.py +++ b/mmgen/proto/btc/params.py @@ -13,6 +13,7 @@ proto.btc.params: Bitcoin protocol """ from ...protocol import CoinProtocol, decoded_wif, decoded_addr, _finfo, _nw +from ...addr import CoinAddr from .common import b58chk_decode, b58chk_encode, hash160 class mainnet(CoinProtocol.Secp256k1): # chainparams.cpp @@ -90,11 +91,11 @@ class mainnet(CoinProtocol.Secp256k1): # chainparams.cpp return self.decode_addr_bytes(b58chk_decode(addr)) - def pubhash2addr(self, pubhash, p2sh): + def pubhash2addr(self, pubhash, addr_type): assert len(pubhash) == self.addr_len, f'{len(pubhash)}: invalid length for pubkey hash' - return b58chk_encode( - self.addr_fmt_to_ver_bytes[('p2pkh','p2sh')[p2sh]] + pubhash - ) + return CoinAddr( + self, + b58chk_encode(self.addr_fmt_to_ver_bytes[addr_type] + pubhash)) # Segwit: def pubhash2redeem_script(self, pubhash): @@ -104,15 +105,17 @@ class mainnet(CoinProtocol.Secp256k1): # chainparams.cpp return bytes.fromhex(self.witness_vernum_hex + '14') + pubhash def pubhash2segwitaddr(self, pubhash): - return self.pubhash2addr( - hash160( self.pubhash2redeem_script(pubhash) ), - p2sh = True ) + return CoinAddr( + self, + self.pubhash2addr(hash160(self.pubhash2redeem_script(pubhash)), 'p2sh')) def pubhash2bech32addr(self, pubhash): from ...contrib import bech32 - return bech32.bech32_encode( - hrp = self.bech32_hrp, - data = [self.witness_vernum] + bech32.convertbits(list(pubhash),8,5) ) + return CoinAddr( + self, + bech32.bech32_encode( + hrp = self.bech32_hrp, + data = [self.witness_vernum] + bech32.convertbits(list(pubhash),8,5))) class testnet(mainnet): addr_ver_info = { '6f': 'p2pkh', 'c4': 'p2sh' } diff --git a/mmgen/proto/btc/tx/base.py b/mmgen/proto/btc/tx/base.py index ead54f8b..4c73ce46 100755 --- a/mmgen/proto/btc/tx/base.py +++ b/mmgen/proto/btc/tx/base.py @@ -33,9 +33,9 @@ def addr2scriptPubKey(proto,addr): def scriptPubKey2addr(proto,s): if len(s) == 50 and s[:6] == '76a914' and s[-4:] == '88ac': - return proto.pubhash2addr(bytes.fromhex(s[6:-4]), p2sh=False), 'p2pkh' + return proto.pubhash2addr(bytes.fromhex(s[6:-4]), 'p2pkh'), 'p2pkh' elif len(s) == 46 and s[:4] == 'a914' and s[-2:] == '87': - return proto.pubhash2addr(bytes.fromhex(s[4:-2]), p2sh=True), 'p2sh' + return proto.pubhash2addr(bytes.fromhex(s[4:-2]), 'p2sh'), 'p2sh' elif len(s) == 44 and s[:4] == proto.witness_vernum_hex + '14': return proto.pubhash2bech32addr(bytes.fromhex(s[4:])), 'bech32' else: diff --git a/mmgen/proto/eth/addrgen.py b/mmgen/proto/eth/addrgen.py index 97951a3c..8fcfe788 100755 --- a/mmgen/proto/eth/addrgen.py +++ b/mmgen/proto/eth/addrgen.py @@ -12,13 +12,10 @@ proto.eth.addrgen: Ethereum address generation class for the MMGen suite """ -from ...addrgen import addr_generator,check_data -from ...addr import CoinAddr +from ...addrgen import addr_generator, check_data class ethereum(addr_generator.keccak): @check_data - def to_addr(self,data): - return CoinAddr( - self.proto, - self.keccak_256(data.pubkey[1:]).hexdigest()[24:] ) + def to_addr(self, data): + return self.proto.pubhash2addr(self.keccak_256(data.pubkey[1:]).digest()[12:], 'p2pkh') diff --git a/mmgen/proto/eth/params.py b/mmgen/proto/eth/params.py index 60afd387..ccefa576 100755 --- a/mmgen/proto/eth/params.py +++ b/mmgen/proto/eth/params.py @@ -13,6 +13,7 @@ proto.eth.params: Ethereum protocol """ from ...protocol import CoinProtocol,_nw,decoded_addr +from ...addr import CoinAddr from ...util import is_hex_str_lc,Msg class mainnet(CoinProtocol.DummyWIF,CoinProtocol.Secp256k1): @@ -56,7 +57,7 @@ class mainnet(CoinProtocol.DummyWIF,CoinProtocol.Secp256k1): def decode_addr(self, addr): if is_hex_str_lc(addr) and len(addr) == self.addr_len * 2: - return decoded_addr(bytes.fromhex(addr), None, 'ethereum') + return decoded_addr(bytes.fromhex(addr), None, 'p2pkh') if self.cfg.debug: Msg(f'Invalid address: {addr}') return False @@ -65,10 +66,11 @@ class mainnet(CoinProtocol.DummyWIF,CoinProtocol.Secp256k1): h = self.keccak_256(addr.encode()).digest().hex() return ''.join(addr[i].upper() if int(h[i],16) > 7 else addr[i] for i in range(len(addr))) - def pubhash2addr(self,pubhash,p2sh): + def pubhash2addr(self, pubhash, addr_type): assert len(pubhash) == 20, f'{len(pubhash)}: invalid length for {self.name} pubkey hash' - assert not p2sh, f'{self.name} protocol has no P2SH address format' - return pubhash.hex() + assert addr_type == 'p2pkh', ( + f'{addr_type}: bad addr type - {self.name} protocol supports P2PKH address format only') + return CoinAddr(self, pubhash.hex()) class testnet(mainnet): chain_names = ['kovan','goerli','rinkeby'] diff --git a/mmgen/proto/zec/params.py b/mmgen/proto/zec/params.py index c37f65ee..f155fdc0 100755 --- a/mmgen/proto/zec/params.py +++ b/mmgen/proto/zec/params.py @@ -63,10 +63,10 @@ class mainnet(mainnet): else: return super().preprocess_key(sec,pubkey_type) - def pubhash2addr(self,pubhash,p2sh): + def pubhash2addr(self,pubhash, addr_type): hash_len = len(pubhash) if hash_len == 20: - return super().pubhash2addr(pubhash,p2sh) + return super().pubhash2addr(pubhash, addr_type) elif hash_len == 64: raise NotImplementedError('Zcash z-addresses do not support pubhash2addr()') else: diff --git a/mmgen/tool/coin.py b/mmgen/tool/coin.py index e054d51a..b03b1a1d 100755 --- a/mmgen/tool/coin.py +++ b/mmgen/tool/coin.py @@ -156,7 +156,7 @@ class tool_cmd(tool_cmd_base): assert redeem_script_hex[:4] == '0014', f'{redeem_script_hex!r}: invalid redeem script' assert len(redeem_script_hex) == 44, f'{len(redeem_script_hex)//2} bytes: invalid redeem script length' from ..proto.btc.common import hash160 - return self.proto.pubhash2addr(hash160(bytes.fromhex(redeem_script_hex)), p2sh=True) + return self.proto.pubhash2addr(hash160(bytes.fromhex(redeem_script_hex)), 'p2sh') def pubhash2addr(self,pubhashhex:'sstr'): "convert public key hash to address" @@ -166,7 +166,7 @@ class tool_cmd(tool_cmd_base): elif self.mmtype.name == 'bech32': return self.proto.pubhash2bech32addr(pubhash) else: - return self.proto.pubhash2addr(pubhash, self.mmtype.addr_fmt=='p2sh') + return self.proto.pubhash2addr(pubhash, self.mmtype.addr_fmt) def addr2pubhash(self,addr:'sstr'): "convert coin address to public key hash" diff --git a/test/cmdtest_py_d/ct_regtest.py b/test/cmdtest_py_d/ct_regtest.py index 726eace2..25fdf005 100755 --- a/test/cmdtest_py_d/ct_regtest.py +++ b/test/cmdtest_py_d/ct_regtest.py @@ -1591,7 +1591,7 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared): def alice_add_comment_badaddr2(self): # mainnet zero address: - addr = init_proto( cfg, self.proto.coin, network='mainnet' ).pubhash2addr(bytes(20),False) + addr = init_proto(cfg, self.proto.coin, network='mainnet').pubhash2addr(bytes(20), 'p2pkh') return self.alice_add_comment_badaddr( addr, 'invalid address', 2 ) def alice_add_comment_badaddr3(self): @@ -1599,7 +1599,7 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared): return self.alice_add_comment_badaddr( addr, f'MMGen address {addr!r} not found in tracking wallet', 2 ) def alice_add_comment_badaddr4(self): - addr = self.proto.pubhash2addr(bytes(20),False) # regtest (testnet) zero address + addr = self.proto.pubhash2addr(bytes(20), 'p2pkh') # regtest (testnet) zero address return self.alice_add_comment_badaddr( addr, f'Coin address {addr!r} not found in tracking wallet', 2 ) def alice_remove_comment1(self):