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)
 	}[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':
-		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':
-		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':
-		return proto.pubhash2bech32addr(bytes.fromhex(s[4:])), 'bech32'
+		return ret('witness_v0_keyhash', 'bech32', proto.pubhash2bech32addr(bytes.fromhex(s[4:])), None)
+
 	else:
-		raise NotImplementedError(f'Unknown scriptPubKey ({s})')
+		raise NotImplementedError(f'Unrecognized scriptPubKey ({s})')
 
 def DeserializeTX(proto, txhex):
 	"""
@@ -119,7 +126,7 @@ def DeserializeTX(proto, txhex):
 	} for i in range(d['num_txouts'])])
 
 	for o in d['txouts']:
-		o['address'] = scriptPubKey2addr(proto, o['scriptPubKey'])[0]
+		o.update(decodeScriptPubKey(proto, o['scriptPubKey'])._asdict())
 
 	if has_witness:
 		# https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
@@ -317,7 +324,7 @@ class Base(TxBase.Base):
 
 		check_equal(
 			'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))
 
 		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 ....obj import HexStr
 from ....util import msg, die
-from .base import Base, scriptPubKey2addr
+from .base import Base, decodeScriptPubKey
 
 class Completed(Base, TxBase.Completed):
 	fn_fee_unit = 'satoshi'
@@ -45,17 +45,17 @@ class Completed(Base, TxBase.Completed):
 
 	def check_pubkey_scripts(self):
 		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 #{}'
-					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!'
 				die(3, (m+'\n  {:23}{}'*3).format(
 					n,
 					'address:',               i.addr,
 					'scriptPubKey:',          i.scriptPubKey,
-					'scriptPubKey->address:', addr))
+					'scriptPubKey->address:', ds.addr))
 
 #	def is_replaceable_from_rpc(self):
 #		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'):
 		"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'):
 		"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)):
 		if 'addresses' in a[i]['scriptPubKey']:
 			A = a[i]['scriptPubKey']['addresses'][0]
-			B = b[i]['address']
+			B = b[i]['addr']
 			fs = 'address of output {} does not match\nA: {}\nB: {}'
 			assert A == B, fs.format(i, A, B)