self.proto.pubhash2addr(): return CoinAddr instance

This commit is contained in:
The MMGen Project 2024-09-29 11:59:57 +00:00
commit 15b94038a4
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
9 changed files with 36 additions and 41 deletions

View file

@ -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'),
}

View file

@ -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))

View file

@ -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' }

View file

@ -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:

View file

@ -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')

View file

@ -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']

View file

@ -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:

View file

@ -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"

View file

@ -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):