Add basic structural test vectors for legacy transactions

The test vectors include explicit values for simple fields like pubkeys
and signatures, and lengths of variable-length composite fields like
Sapling Spends and Sprout JSDescriptions.
This commit is contained in:
Jack Grigg 2022-03-11 14:53:50 +00:00
parent 7acac09230
commit 65f611ae39
6 changed files with 906 additions and 0 deletions

View File

@ -41,6 +41,7 @@ zip_0243 = "zcash_test_vectors.zip_0243:main"
zip_0244 = "zcash_test_vectors.zip_0244:main"
# Transaction format test vectors
transaction_legacy = "zcash_test_vectors.transaction:legacy_test_vectors"
transaction_v5 = "zcash_test_vectors.transaction:v5_test_vectors"
# Transparent test vectors

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -120,6 +120,9 @@ def tv_option_vec_bytes_rust(name, value, pad):
else:
print('%s%s: None,' % (pad, name))
def tv_bool_rust(name, value, pad):
print('%s%s: %s,' % (pad, name, 'true' if value else 'false'))
def tv_int_rust(name, value, pad):
print('%s%s: %d,' % (pad, name, value))
@ -148,6 +151,8 @@ def tv_part_rust(name, value, config, indent=3):
tv_bytes_rust(name, value, pad)
elif config['rust_type'].startswith('Option<'):
tv_option_int_rust(name, value, pad)
elif type(value) == bool:
tv_bool_rust(name, value, pad)
elif type(value) == int:
tv_int_rust(name, value, pad)
elif type(value) == list:

View File

@ -577,6 +577,78 @@ class Transaction(object):
return bytes(self.inner)
def legacy_test_vectors():
from hashlib import sha256
from .output import render_args, render_tv
from .rand import Rand
from .zip_0244 import txid_digest
args = render_args()
from random import Random
rng = Random(0xabad533d)
def randbytes(l):
ret = []
while len(ret) < l:
ret.append(rng.randrange(0, 256))
return bytes(ret)
rand = Rand(randbytes)
test_vectors = []
while len(test_vectors) < 30:
# Generate transactions with versions prior to ZIP 225.
tx = LegacyTransaction(rand, rand.u8() % NU5_TX_VERSION)
tx_bytes = bytes(tx)
txid = sha256(sha256(tx_bytes).digest()).digest()
has_sprout = tx.nVersion >= 2 and len(tx.vJoinSplit) > 0
has_sapling = tx.nVersion == SAPLING_TX_VERSION and not (len(tx.vShieldedSpends) == 0 and len(tx.vShieldedOutputs) == 0)
test_vectors.append({
'tx': tx_bytes,
'txid': txid,
'fOverwintered': tx.fOverwintered,
'version': tx.nVersion,
'nVersionGroupId': tx.nVersionGroupId if tx.fOverwintered else None,
'tx_in_count': len(tx.vin),
'tx_out_count': len(tx.vout),
'lock_time': tx.nLockTime,
'nExpiryHeight': tx.nExpiryHeight if tx.fOverwintered else None,
'valueBalanceSapling': tx.valueBalance if tx.nVersion == SAPLING_TX_VERSION else None,
'nSpendsSapling': len(tx.vShieldedSpends) if tx.nVersion == SAPLING_TX_VERSION else None,
'nOutputsSapling': len(tx.vShieldedOutputs) if tx.nVersion == SAPLING_TX_VERSION else None,
'nJoinSplit': len(tx.vJoinSplit) if tx.nVersion > 2 else None,
'joinSplitPubKey': bytes(tx.joinSplitPubKey) if has_sprout else None,
'joinSplitSig': bytes(tx.joinSplitSig) if has_sprout else None,
'bindingSigSapling': bytes(tx.bindingSig) if has_sapling else None,
})
render_tv(
args,
'transaction_legacy',
(
('tx', {'rust_type': 'Vec<u8>', 'bitcoin_flavoured': False}),
('txid', '[u8; 32]'),
('fOverwintered', 'bool'),
('version', 'u32'),
('nVersionGroupId', 'Option<u32>'),
('tx_in_count', 'usize'),
('tx_out_count', 'usize'),
('lock_time', 'u32'),
('nExpiryHeight', 'Option<u32>'),
('valueBalanceSapling', 'Option<i64>'),
('nSpendsSapling', 'Option<usize>'),
('nOutputsSapling', 'Option<usize>'),
('nJoinSplit', 'usize'),
('joinSplitPubKey', 'Option<[u8; 32]>'),
('joinSplitSig', 'Option<[u8; 64]>'),
('bindingSigSapling', 'Option<[u8; 64]>'),
),
test_vectors,
)
def v5_test_vectors():
from .output import render_args, render_tv
from .rand import Rand