test: Fix SignatureHash RPC test helper
- Check validity of inIdx. - ZIP 143 and 243 support.
This commit is contained in:
parent
bbed3ecc3c
commit
030a685392
|
@ -19,9 +19,11 @@ if sys.version > '3':
|
|||
bchr = lambda x: bytes([x])
|
||||
bord = lambda x: x
|
||||
|
||||
from pyblake2 import blake2b
|
||||
import struct
|
||||
|
||||
from test_framework import bignum
|
||||
from test_framework.mininode import (CTransaction, CTxOut, hash256, ser_string, ser_uint256)
|
||||
|
||||
MAX_SCRIPT_SIZE = 10000
|
||||
MAX_SCRIPT_ELEMENT_SIZE = 520
|
||||
|
@ -820,17 +822,116 @@ SIGHASH_NONE = 2
|
|||
SIGHASH_SINGLE = 3
|
||||
SIGHASH_ANYONECANPAY = 0x80
|
||||
|
||||
def getHashPrevouts(tx):
|
||||
digest = blake2b(digest_size=32, person=b'ZcashPrevoutHash')
|
||||
for x in tx.vin:
|
||||
digest.update(x.prevout.serialize())
|
||||
return digest.digest()
|
||||
|
||||
def SignatureHash(script, txTo, inIdx, hashtype):
|
||||
"""Consensus-correct SignatureHash
|
||||
def getHashSequence(tx):
|
||||
digest = blake2b(digest_size=32, person=b'ZcashSequencHash')
|
||||
for x in tx.vin:
|
||||
digest.update(struct.pack('<I', x.nSequence))
|
||||
return digest.digest()
|
||||
|
||||
Returns (hash, err) to precisely match the consensus-critical behavior of
|
||||
the SIGHASH_SINGLE bug. (inIdx is *not* checked for validity)
|
||||
"""
|
||||
HASH_ONE = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
def getHashOutputs(tx):
|
||||
digest = blake2b(digest_size=32, person=b'ZcashOutputsHash')
|
||||
for x in tx.vout:
|
||||
digest.update(x.serialize())
|
||||
return digest.digest()
|
||||
|
||||
def getHashJoinSplits(tx):
|
||||
digest = blake2b(digest_size=32, person=b'ZcashJSplitsHash')
|
||||
for jsdesc in tx.vJoinSplit:
|
||||
digest.update(jsdesc.serialize())
|
||||
digest.update(tx.joinSplitPubKey)
|
||||
return digest.digest()
|
||||
|
||||
def getHashShieldedSpends(tx):
|
||||
digest = blake2b(digest_size=32, person=b'ZcashSSpendsHash')
|
||||
for desc in tx.shieldedSpends:
|
||||
# We don't pass in serialized form of desc as spendAuthSig is not part of the hash
|
||||
digest.update(ser_uint256(desc.cv))
|
||||
digest.update(ser_uint256(desc.anchor))
|
||||
digest.update(ser_uint256(desc.nullifier))
|
||||
digest.update(ser_uint256(desc.rk))
|
||||
digest.update(desc.proof)
|
||||
return digest.digest()
|
||||
|
||||
def getHashShieldedOutputs(tx):
|
||||
digest = blake2b(digest_size=32, person=b'ZcashSOutputHash')
|
||||
for desc in tx.shieldedOutputs:
|
||||
digest.update(desc.serialize())
|
||||
return digest.digest()
|
||||
|
||||
|
||||
def SignatureHash(script, txTo, inIdx, hashtype, amount, consensusBranchId):
|
||||
"""Consensus-correct SignatureHash"""
|
||||
if inIdx >= len(txTo.vin):
|
||||
return (HASH_ONE, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin)))
|
||||
raise ValueError("inIdx %d out of range (%d)" % (inIdx, len(txTo.vin)))
|
||||
|
||||
if consensusBranchId != 0:
|
||||
# ZIP 243
|
||||
hashPrevouts = b'\x00'*32
|
||||
hashSequence = b'\x00'*32
|
||||
hashOutputs = b'\x00'*32
|
||||
hashJoinSplits = b'\x00'*32
|
||||
hashShieldedSpends = b'\x00'*32
|
||||
hashShieldedOutputs = b'\x00'*32
|
||||
|
||||
if not (hashtype & SIGHASH_ANYONECANPAY):
|
||||
hashPrevouts = getHashPrevouts(txTo)
|
||||
|
||||
if (not (hashtype & SIGHASH_ANYONECANPAY)) and \
|
||||
(hashtype & 0x1f) != SIGHASH_SINGLE and \
|
||||
(hashtype & 0x1f) != SIGHASH_NONE:
|
||||
hashSequence = getHashSequence(txTo)
|
||||
|
||||
if (hashtype & 0x1f) != SIGHASH_SINGLE and \
|
||||
(hashtype & 0x1f) != SIGHASH_NONE:
|
||||
hashOutputs = getHashOutputs(txTo)
|
||||
elif (hashtype & 0x1f) == SIGHASH_SINGLE and \
|
||||
0 <= inIdx and inIdx < len(txTo.vout):
|
||||
digest = blake2b(digest_size=32, person=b'ZcashOutputsHash')
|
||||
digest.update(txTo.vout[inIdx].serialize())
|
||||
hashOutputs = digest.digest()
|
||||
|
||||
if len(txTo.vJoinSplit) > 0:
|
||||
hashJoinSplits = getHashJoinSplits(txTo)
|
||||
|
||||
if len(txTo.shieldedSpends) > 0:
|
||||
hashShieldedSpends = getHashShieldedSpends(txTo)
|
||||
|
||||
if len(txTo.shieldedOutputs) > 0:
|
||||
hashShieldedOutputs = getHashShieldedOutputs(txTo)
|
||||
|
||||
digest = blake2b(
|
||||
digest_size=32,
|
||||
person=b'ZcashSigHash' + struct.pack('<I', consensusBranchId),
|
||||
)
|
||||
|
||||
digest.update(struct.pack('<I', (int(txTo.fOverwintered)<<31) | txTo.nVersion))
|
||||
digest.update(struct.pack('<I', txTo.nVersionGroupId))
|
||||
digest.update(hashPrevouts)
|
||||
digest.update(hashSequence)
|
||||
digest.update(hashOutputs)
|
||||
digest.update(hashJoinSplits)
|
||||
digest.update(hashShieldedSpends)
|
||||
digest.update(hashShieldedOutputs)
|
||||
digest.update(struct.pack('<I', txTo.nLockTime))
|
||||
digest.update(struct.pack('<I', txTo.nExpiryHeight))
|
||||
digest.update(struct.pack('<Q', txTo.valueBalance))
|
||||
digest.update(struct.pack('<I', hashtype))
|
||||
|
||||
if inIdx is not None:
|
||||
digest.update(txTo.vin[inIdx].prevout.serialize())
|
||||
digest.update(ser_string(script))
|
||||
digest.update(struct.pack('<Q', amount))
|
||||
digest.update(struct.pack('<I', txTo.vin[inIdx].nSequence))
|
||||
|
||||
return (digest.digest(), None)
|
||||
else:
|
||||
# Pre-Overwinter
|
||||
txtmp = CTransaction(txTo)
|
||||
|
||||
for txin in txtmp.vin:
|
||||
|
@ -847,7 +948,7 @@ def SignatureHash(script, txTo, inIdx, hashtype):
|
|||
elif (hashtype & 0x1f) == SIGHASH_SINGLE:
|
||||
outIdx = inIdx
|
||||
if outIdx >= len(txtmp.vout):
|
||||
return (HASH_ONE, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout)))
|
||||
raise ValueError("outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout)))
|
||||
|
||||
tmp = txtmp.vout[outIdx]
|
||||
txtmp.vout = []
|
||||
|
|
Loading…
Reference in New Issue