Add test case for SIGHASH_ALL_ANYONECANPAY in taproot (#4442)

* Add test case for SIGHASH_ALL_ANYONECANPAY in taproot

* Remove spendingTx comment
This commit is contained in:
Chris Stewart 2022-07-01 16:45:41 -05:00 committed by GitHub
parent 3122e1d0f8
commit 0c14fc961b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 16 deletions

View file

@ -561,7 +561,7 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest {
val outputMap: Map[TransactionOutPoint, TransactionOutput] = val outputMap: Map[TransactionOutPoint, TransactionOutput] =
spendingTx.inputs.map(_.previousOutput).zip(Vector(prevOutput)).toMap spendingTx.inputs.map(_.previousOutput).zip(Vector(prevOutput)).toMap
val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, //spendingTx, val taprootTxSigComponent = TaprootTxSigComponent(witnessTx,
inputIndex, inputIndex,
outputMap, outputMap,
Policy.standardFlags) Policy.standardFlags)
@ -616,7 +616,7 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest {
val outputMap: Map[TransactionOutPoint, TransactionOutput] = val outputMap: Map[TransactionOutPoint, TransactionOutput] =
spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap
val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, //spendingTx, val taprootTxSigComponent = TaprootTxSigComponent(witnessTx,
inputIndex, inputIndex,
outputMap, outputMap,
Policy.standardFlags) Policy.standardFlags)
@ -688,7 +688,7 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest {
.toWitnessTx(spendingTx) .toWitnessTx(spendingTx)
.updateWitness(inputIndex.toInt, witness) .updateWitness(inputIndex.toInt, witness)
val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, //spendingTx, val taprootTxSigComponent = TaprootTxSigComponent(witnessTx,
inputIndex, inputIndex,
outputMap, outputMap,
Policy.standardFlags) Policy.standardFlags)
@ -731,7 +731,7 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest {
.toWitnessTx(spendingTx) .toWitnessTx(spendingTx)
.updateWitness(inputIndex.toInt, witness) .updateWitness(inputIndex.toInt, witness)
val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, //spendingTx, val taprootTxSigComponent = TaprootTxSigComponent(witnessTx,
inputIndex, inputIndex,
outputMap, outputMap,
Policy.standardFlags) Policy.standardFlags)
@ -782,7 +782,7 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest {
.toWitnessTx(spendingTx) .toWitnessTx(spendingTx)
.updateWitness(inputIndex.toInt, witness) .updateWitness(inputIndex.toInt, witness)
val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, //spendingTx, val taprootTxSigComponent = TaprootTxSigComponent(witnessTx,
inputIndex, inputIndex,
outputMap, outputMap,
Policy.standardFlags) Policy.standardFlags)
@ -829,7 +829,7 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest {
.toWitnessTx(spendingTx) .toWitnessTx(spendingTx)
.updateWitness(inputIndex.toInt, witness) .updateWitness(inputIndex.toInt, witness)
val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, //spendingTx, val taprootTxSigComponent = TaprootTxSigComponent(witnessTx,
inputIndex, inputIndex,
outputMap, outputMap,
Policy.standardFlags) Policy.standardFlags)
@ -920,7 +920,7 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest {
.toWitnessTx(spendingTx) .toWitnessTx(spendingTx)
.updateWitness(inputIndex.toInt, witness) .updateWitness(inputIndex.toInt, witness)
val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, //spendingTx, val taprootTxSigComponent = TaprootTxSigComponent(witnessTx,
inputIndex, inputIndex,
outputMap, outputMap,
Policy.standardFlags) Policy.standardFlags)
@ -961,7 +961,7 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest {
.toWitnessTx(spendingTx) .toWitnessTx(spendingTx)
.updateWitness(inputIndex.toInt, witness) .updateWitness(inputIndex.toInt, witness)
val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, //spendingTx, val taprootTxSigComponent = TaprootTxSigComponent(witnessTx,
inputIndex, inputIndex,
outputMap, outputMap,
Policy.standardFlags) Policy.standardFlags)
@ -980,4 +980,43 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest {
assert(serialize.toHex == expected) assert(serialize.toHex == expected)
} }
it must "serialize a taproot keyspend SIGHASH_ALL_ANYONECANSPEND" in {
val expected =
"00816c780499da010000a0e6c05b4d684eeb145d9225f15319226c5fd78617f5db646630c0584662a6a3008c033b67f78dfe0867489e0e5a032f24d14ee3c57637c22e71701fd79b64012ad200000094037f010000000022512057c1162a56ec9db80a8eb342634f613c8d990bf305925df7ddb85b356ce8f0bb7138b5c8"
val spendingTxHex =
"6c780499018c033b67f78dfe0867489e0e5a032f24d14ee3c57637c22e71701fd79b64012ad2000000007138b5c80168666e0000000000160014e7f8b1de86947bf379378ebd4368d37361fac307da010000"
val spendingTx = Transaction.fromHex(spendingTxHex)
val inputIndex = UInt32.zero
val prevout = TransactionOutput.fromHex(
"94037f010000000022512057c1162a56ec9db80a8eb342634f613c8d990bf305925df7ddb85b356ce8f0bb")
val prevOutputs = Vector(prevout)
val outputMap: Map[TransactionOutPoint, TransactionOutput] =
spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap
val witnessStackHex = Vector(
"228187c314a903fe94c1c8260c243e0949a3233d404a58f90cd991a44f5dad4d89bd5763525b437a10a973abd8eb99adcfec9e2865fa235fa4d6af82c427f17a81")
val witnessStack = witnessStackHex.map(w => ByteVector.fromValidHex(w))
val witness = TaprootKeyPath.fromStack(witnessStack.reverse)
val witnessTx =
WitnessTransaction
.toWitnessTx(spendingTx)
.updateWitness(inputIndex.toInt, witness)
val taprootTxSigComponent = TaprootTxSigComponent(witnessTx,
inputIndex,
outputMap,
Policy.standardFlags)
val taprootOptions = TaprootSerializationOptions.empty
val serialize = TransactionSignatureSerializer.serializeForSignature(
taprootTxSigComponent,
HashType.sigHashAllAnyoneCanPay,
taprootOptions)
assert(serialize.toHex == expected)
}
} }

View file

@ -248,6 +248,8 @@ sealed abstract class TransactionSignatureSerializer {
val isNotAnyoneCanPay = !HashType.isAnyoneCanPay(hashType) val isNotAnyoneCanPay = !HashType.isAnyoneCanPay(hashType)
val isNotSigHashSingle = !HashType.isSigHashSingle(hashType.num) val isNotSigHashSingle = !HashType.isSigHashSingle(hashType.num)
val isNotSigHashNone = !HashType.isSigHashNone(hashType.num) val isNotSigHashNone = !HashType.isSigHashNone(hashType.num)
val isSigHashAllAnyoneCanPay =
HashType.isSigHashAllAnyoneCanPay(hashType.num)
val extFlag = taprootSigVersion match { val extFlag = taprootSigVersion match {
case SigVersionTaprootKeySpend => 0.toByte case SigVersionTaprootKeySpend => 0.toByte
@ -265,6 +267,7 @@ sealed abstract class TransactionSignatureSerializer {
val b = spendingTransaction.inputs(inputIndex.toInt).previousOutput val b = spendingTransaction.inputs(inputIndex.toInt).previousOutput
b.bytes b.bytes
} }
val amounts = { val amounts = {
if (isNotAnyoneCanPay) { if (isNotAnyoneCanPay) {
val b = BytesUtil.toByteVector(outputs.map(_.value)) val b = BytesUtil.toByteVector(outputs.map(_.value))
@ -282,6 +285,7 @@ sealed abstract class TransactionSignatureSerializer {
b.bytes b.bytes
} }
} }
val sequenceHash: ByteVector = val sequenceHash: ByteVector =
if (isNotAnyoneCanPay) { if (isNotAnyoneCanPay) {
val sequences = spendingTransaction.inputs.map(_.sequence) val sequences = spendingTransaction.inputs.map(_.sequence)
@ -314,7 +318,6 @@ sealed abstract class TransactionSignatureSerializer {
.bytes .bytes
hash hash
} else ByteVector.empty } else ByteVector.empty
val haveAnnex: Boolean = taprootOptions.haveAnnex val haveAnnex: Boolean = taprootOptions.haveAnnex
val annexByte = if (haveAnnex) 1.toByte else 0.toByte val annexByte = if (haveAnnex) 1.toByte else 0.toByte
@ -361,15 +364,24 @@ sealed abstract class TransactionSignatureSerializer {
inputIndexBytes ++ annexBytes ++ tapScriptBytes inputIndexBytes ++ annexBytes ++ tapScriptBytes
} }
} else {
if (isSigHashAllAnyoneCanPay) {
//different ordering if we use SIGHASH_ANYONECANPAY
epoch ++ ByteVector
.fromByte(
hashType.byte) ++ version ++ locktimeBytes ++ outputHash ++
ByteVector.fromByte(
spendType) ++ outPointHash ++ amounts ++ spentSPKs ++
sequenceHash ++ annexBytes ++ tapScriptBytes
} else { } else {
//different ordering if we use SIGHASH_ANYONECANPAY //different ordering if we use SIGHASH_ANYONECANPAY
epoch ++ ByteVector.fromByte( epoch ++ ByteVector.fromByte(
hashType.byte) ++ version ++ locktimeBytes ++ ByteVector.fromByte( hashType.byte) ++ version ++ locktimeBytes ++ ByteVector
spendType) ++ .fromByte(spendType) ++
outPointHash ++ amounts ++ spentSPKs ++ outPointHash ++ amounts ++ spentSPKs ++
sequenceHash ++ annexBytes ++ outputHash ++ tapScriptBytes sequenceHash ++ annexBytes ++ outputHash ++ tapScriptBytes
} }
}
} }
result result
} }