feat(core): Support external inputs in TxWeightCalculator.

pull/1918/head
Andrew Kozlik 3 years ago committed by Andrew Kozlik
parent f9f0b517e2
commit 56ac799626

@ -92,7 +92,7 @@ def verify_nonownership(
# Verify the BIP-322 SignatureProof. # Verify the BIP-322 SignatureProof.
proof_body = proof[: r.offset] proof_body = memoryview(proof)[: r.offset]
sighash = hashlib.sha256(proof_body) sighash = hashlib.sha256(proof_body)
sighash.update(script_pubkey) sighash.update(script_pubkey)
if commitment_data: if commitment_data:
@ -110,6 +110,26 @@ def verify_nonownership(
return not_owned return not_owned
def read_scriptsig_witness(ownership_proof: bytes) -> tuple[memoryview, memoryview]:
try:
r = utils.BufferReader(ownership_proof)
if r.read_memoryview(4) != _VERSION_MAGIC:
raise wire.DataError("Unknown format of proof of ownership")
flags = r.get()
if flags & 0b1111_1110:
raise wire.DataError("Unknown flags in proof of ownership")
# Skip ownership IDs.
id_count = read_bitcoin_varint(r)
r.read_memoryview(_OWNERSHIP_ID_LEN * id_count)
return read_bip322_signature_proof(r)
except (ValueError, EOFError):
raise wire.DataError("Invalid proof of ownership")
def get_identifier(script_pubkey: bytes, keychain: Keychain) -> bytes: def get_identifier(script_pubkey: bytes, keychain: Keychain) -> bytes:
# k = Key(m/"SLIP-0019"/"Ownership identification key") # k = Key(m/"SLIP-0019"/"Ownership identification key")
node = keychain.derive_slip21(_OWNERSHIP_ID_KEY_PATH) node = keychain.derive_slip21(_OWNERSHIP_ID_KEY_PATH)

@ -10,7 +10,7 @@ from micropython import const
from trezor import wire from trezor import wire
from trezor.enums import InputScriptType from trezor.enums import InputScriptType
from .. import common from .. import common, ownership
if False: if False:
from trezor.messages import TxInput from trezor.messages import TxInput
@ -87,6 +87,24 @@ class TxWeightCalculator:
else: else:
self.counter += 4 # empty script_sig (1 byte) self.counter += 4 # empty script_sig (1 byte)
self.counter += 1 + input_script_size # discounted witness self.counter += 1 + input_script_size # discounted witness
elif i.script_type == InputScriptType.EXTERNAL:
if i.ownership_proof:
script_sig, witness = ownership.read_scriptsig_witness(
i.ownership_proof
)
script_sig_size = len(script_sig)
witness_size = len(witness)
else:
script_sig_size = len(i.script_sig or b"")
witness_size = len(i.witness or b"")
if witness_size > 1:
self.segwit_inputs_count += 1
self.counter += 4 * (self.varint_size(script_sig_size) + script_sig_size)
self.counter += witness_size
else:
raise wire.DataError("Invalid script type")
def add_output(self, script: bytes) -> None: def add_output(self, script: bytes) -> None:
self.outputs_count += 1 self.outputs_count += 1

@ -304,5 +304,59 @@ class TestCalculateTxWeight(unittest.TestCase):
# average length, so the caculator should estimate 285 bytes of witness data. # average length, so the caculator should estimate 285 bytes of witness data.
self.assertEqual(calculator.get_total(), 4*477 + 285) self.assertEqual(calculator.get_total(), 4*477 + 285)
def test_external_txweight(self):
coin = coins.by_name('Testnet')
inp1 = TxInput(
amount=100000,
prev_hash=unhexlify('e5b7e21b5ba720e81efd6bfa9f854ababdcddc75a43bfa60bf0fe069cfd1bb8a'),
prev_index=0,
script_type=InputScriptType.EXTERNAL,
script_pubkey=unhexlify('00149c02608d469160a92f40fdf8c6ccced029493088'),
ownership_proof=unhexlify(
'534c001900016b2055d8190244b2ed2d46513c40658a574d3bc2deb6969c0535bb818b44d2c40002483045022100d4ad0374c922848c71d913fba59c81b9075e0d33e884d953f0c4b4806b8ffd0c022024740e6717a2b6a5aa03148c3a28b02c713b4e30fc8aeae67fa69eb20e8ddcd9012103505f0d82bbdd251511591b34f36ad5eea37d3220c2b81a1189084431ddb3aa3d'
),
)
inp2 = TxInput(
address_n=[84 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 0, 0],
prev_hash=unhexlify('70f9871eb03a38405cfd7a01e0e1448678132d815e2c9f552ad83ae23969509e'),
prev_index=0,
amount=100000,
script_type=InputScriptType.SPENDWITNESS,
)
inp3 = TxInput(
# tb1qldlynaqp0hy4zc2aag3pkenzvxy65saesxw3wd
# address_n=parse_path("m/84h/1h/0h/0/1"),
prev_hash=unhexlify('65b768dacccfb209eebd95a1fb80a04f1dd6a3abc6d7b41d5e9d9f91605b37d9'),
prev_index=0,
amount=10000,
script_type=InputScriptType.EXTERNAL,
script_pubkey=unhexlify('0014fb7e49f4017dc951615dea221b66626189aa43b9'),
script_sig=bytes(0),
witness=unhexlify(
'024730440220432ac60461de52713ad543cbb1484f7eca1a72c615d539b3f42f5668da4501d2022063786a6d6940a5c1ed9c2d2fd02cef90b6c01ddd84829c946561e15be6c0aae1012103dcf3bc936ecb2ec57b8f468050abce8c8756e75fd74273c9977744b1a0be7d03'
),
)
out1 = TxOutput(
address="tb1qnspxpr2xj9s2jt6qlhuvdnxw6q55jvygcf89r2",
amount=100000 + 100000 + 10000,
script_type=OutputScriptType.PAYTOWITNESS,
)
calculator = TxWeightCalculator()
calculator.add_input(inp1)
calculator.add_input(inp2)
calculator.add_input(inp3)
calculator.add_output(output_derive_script(out1.address, coin))
self.assertEqual(calculator.get_total(), 4*164 + 325)
# non-segwit: header, inputs, outputs, locktime 4*(4+1+3*41+1+31+4) = 4*164
# segwit: segwit header, 2x estimated witness (including stack item count)
# and 1x exact witness (including stack item count) 1*(2+108+108+107) = 325
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

Loading…
Cancel
Save