Browse Source

proto.btc.tx.base: `scriptPubKey2addr()` -> `decodeScriptPubKey()`

The MMGen Project 2 months ago
parent
commit
e3dd55e909
4 changed files with 23 additions and 16 deletions
  1. 14 7
      mmgen/proto/btc/tx/base.py
  2. 6 6
      mmgen/proto/btc/tx/completed.py
  3. 2 2
      mmgen/tool/coin.py
  4. 1 1
      test/daemontest_d/ut_tx.py

+ 14 - 7
mmgen/proto/btc/tx/base.py

@@ -31,15 +31,22 @@ def addr2scriptPubKey(proto, addr):
 		'bech32': proto.witness_vernum_hex + '14' + decode_addr(proto, addr)
 		'bech32': proto.witness_vernum_hex + '14' + decode_addr(proto, addr)
 	}[addr.addr_fmt]
 	}[addr.addr_fmt]
 
 
-def scriptPubKey2addr(proto, s):
+def decodeScriptPubKey(proto, s):
+	# src/wallet/rpc/addresses.cpp:
+	#   types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash
+	ret = namedtuple('decoded_scriptPubKey', ['type', 'addr_fmt', 'addr', 'data'])
+
 	if len(s) == 50 and s[:6] == '76a914' and s[-4:] == '88ac':
 	if len(s) == 50 and s[:6] == '76a914' and s[-4:] == '88ac':
-		return proto.pubhash2addr(bytes.fromhex(s[6:-4]), 'p2pkh'), 'p2pkh'
+		return ret('pubkeyhash', 'p2pkh', proto.pubhash2addr(bytes.fromhex(s[6:-4]), 'p2pkh'), None)
+
 	elif len(s) == 46 and s[:4] == 'a914' and s[-2:] == '87':
 	elif len(s) == 46 and s[:4] == 'a914' and s[-2:] == '87':
-		return proto.pubhash2addr(bytes.fromhex(s[4:-2]), 'p2sh'), 'p2sh'
+		return ret('scripthash', 'p2sh', proto.pubhash2addr(bytes.fromhex(s[4:-2]), 'p2sh'), None)
+
 	elif len(s) == 44 and s[:4] == proto.witness_vernum_hex + '14':
 	elif len(s) == 44 and s[:4] == proto.witness_vernum_hex + '14':
-		return proto.pubhash2bech32addr(bytes.fromhex(s[4:])), 'bech32'
+		return ret('witness_v0_keyhash', 'bech32', proto.pubhash2bech32addr(bytes.fromhex(s[4:])), None)
+
 	else:
 	else:
-		raise NotImplementedError(f'Unknown scriptPubKey ({s})')
+		raise NotImplementedError(f'Unrecognized scriptPubKey ({s})')
 
 
 def DeserializeTX(proto, txhex):
 def DeserializeTX(proto, txhex):
 	"""
 	"""
@@ -119,7 +126,7 @@ def DeserializeTX(proto, txhex):
 	} for i in range(d['num_txouts'])])
 	} for i in range(d['num_txouts'])])
 
 
 	for o in d['txouts']:
 	for o in d['txouts']:
-		o['address'] = scriptPubKey2addr(proto, o['scriptPubKey'])[0]
+		o.update(decodeScriptPubKey(proto, o['scriptPubKey'])._asdict())
 
 
 	if has_witness:
 	if has_witness:
 		# https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
 		# https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
@@ -317,7 +324,7 @@ class Base(TxBase.Base):
 
 
 		check_equal(
 		check_equal(
 			'outputs',
 			'outputs',
-			sorted((o['address'], o['amt']) for o in dtx.txouts),
+			sorted((o['addr'], o['amt']) for o in dtx.txouts),
 			sorted((o.addr, o.amt) for o in self.outputs))
 			sorted((o.addr, o.amt) for o in self.outputs))
 
 
 		if str(self.txid) != make_chksum_6(bytes.fromhex(dtx.unsigned_hex)).upper():
 		if str(self.txid) != make_chksum_6(bytes.fromhex(dtx.unsigned_hex)).upper():

+ 6 - 6
mmgen/proto/btc/tx/completed.py

@@ -15,7 +15,7 @@ proto.btc.tx.completed: Bitcoin completed transaction class
 from ....tx import completed as TxBase
 from ....tx import completed as TxBase
 from ....obj import HexStr
 from ....obj import HexStr
 from ....util import msg, die
 from ....util import msg, die
-from .base import Base, scriptPubKey2addr
+from .base import Base, decodeScriptPubKey
 
 
 class Completed(Base, TxBase.Completed):
 class Completed(Base, TxBase.Completed):
 	fn_fee_unit = 'satoshi'
 	fn_fee_unit = 'satoshi'
@@ -45,17 +45,17 @@ class Completed(Base, TxBase.Completed):
 
 
 	def check_pubkey_scripts(self):
 	def check_pubkey_scripts(self):
 		for n, i in enumerate(self.inputs, 1):
 		for n, i in enumerate(self.inputs, 1):
-			addr, fmt = scriptPubKey2addr(self.proto, i.scriptPubKey)
-			if i.addr != addr:
-				if fmt != i.addr.addr_fmt:
+			ds = decodeScriptPubKey(self.proto, i.scriptPubKey)
+			if ds.addr != i.addr:
+				if ds.addr_fmt != i.addr.addr_fmt:
 					m = 'Address format of scriptPubKey ({}) does not match that of address ({}) in input #{}'
 					m = 'Address format of scriptPubKey ({}) does not match that of address ({}) in input #{}'
-					msg(m.format(fmt, i.addr.addr_fmt, n))
+					msg(m.format(ds.addr_fmt, i.addr.addr_fmt, n))
 				m = 'ERROR: Address and scriptPubKey of transaction input #{} do not match!'
 				m = 'ERROR: Address and scriptPubKey of transaction input #{} do not match!'
 				die(3, (m+'\n  {:23}{}'*3).format(
 				die(3, (m+'\n  {:23}{}'*3).format(
 					n,
 					n,
 					'address:',               i.addr,
 					'address:',               i.addr,
 					'scriptPubKey:',          i.scriptPubKey,
 					'scriptPubKey:',          i.scriptPubKey,
-					'scriptPubKey->address:', addr))
+					'scriptPubKey->address:', ds.addr))
 
 
 #	def is_replaceable_from_rpc(self):
 #	def is_replaceable_from_rpc(self):
 #		dec_tx = await self.rpc.call('decoderawtransaction', self.serialized)
 #		dec_tx = await self.rpc.call('decoderawtransaction', self.serialized)

+ 2 - 2
mmgen/tool/coin.py

@@ -184,8 +184,8 @@ class tool_cmd(tool_cmd_base):
 
 
 	def scriptpubkey2addr(self, hexstr: 'sstr'):
 	def scriptpubkey2addr(self, hexstr: 'sstr'):
 		"convert scriptPubKey to coin address"
 		"convert scriptPubKey to coin address"
-		from ..proto.btc.tx.base import scriptPubKey2addr
-		return scriptPubKey2addr(self.proto, hexstr)[0]
+		from ..proto.btc.tx.base import decodeScriptPubKey
+		return decodeScriptPubKey(self.proto, hexstr).addr
 
 
 	def eth_checksummed_addr(self, addr: 'sstr'):
 	def eth_checksummed_addr(self, addr: 'sstr'):
 		"create a checksummed Ethereum address"
 		"create a checksummed Ethereum address"

+ 1 - 1
test/daemontest_d/ut_tx.py

@@ -75,7 +75,7 @@ async def test_tx(tx_proto, tx_hex, desc, n):
 	for i in range(len(a)):
 	for i in range(len(a)):
 		if 'addresses' in a[i]['scriptPubKey']:
 		if 'addresses' in a[i]['scriptPubKey']:
 			A = a[i]['scriptPubKey']['addresses'][0]
 			A = a[i]['scriptPubKey']['addresses'][0]
-			B = b[i]['address']
+			B = b[i]['addr']
 			fs = 'address of output {} does not match\nA: {}\nB: {}'
 			fs = 'address of output {} does not match\nA: {}\nB: {}'
 			assert A == B, fs.format(i, A, B)
 			assert A == B, fs.format(i, A, B)