mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-15 20:30:17 +01:00
core: Fix TapscriptControlBlock
bugs (#5955)
* core: Fix TapscriptControlBlock bugs where we weren't correctly constructing the TapscriptControlBlock from the merkle path * cleanup if statement
This commit is contained in:
parent
6d240d5c54
commit
fb49548e21
3 changed files with 38 additions and 18 deletions
|
@ -142,6 +142,7 @@ class TaprootWitnessTest extends BitcoinSUnitTest {
|
||||||
it must "have a correct constructor" in {
|
it must "have a correct constructor" in {
|
||||||
val x = TapscriptControlBlock.apply(controlBlock.leafVersion,
|
val x = TapscriptControlBlock.apply(controlBlock.leafVersion,
|
||||||
controlBlock.p,
|
controlBlock.p,
|
||||||
|
controlBlock.parity,
|
||||||
leafHashes = controlBlock.hashes)
|
leafHashes = controlBlock.hashes)
|
||||||
assert(x.bytes.toHex == controlBlock.bytes.toHex)
|
assert(x.bytes.toHex == controlBlock.bytes.toHex)
|
||||||
assert(x == controlBlock)
|
assert(x == controlBlock)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package org.bitcoins.core.protocol.script
|
package org.bitcoins.core.protocol.script
|
||||||
|
|
||||||
import org.bitcoins.crypto.{Factory, NetworkElement, Sha256Digest, XOnlyPubKey}
|
import org.bitcoins.crypto.*
|
||||||
import scodec.bits.ByteVector
|
import scodec.bits.ByteVector
|
||||||
|
|
||||||
/** Control block as defined by BIP341
|
/** Control block as defined by BIP341
|
||||||
|
@ -38,6 +38,11 @@ sealed abstract class ControlBlock extends NetworkElement {
|
||||||
case class TapscriptControlBlock(bytes: ByteVector) extends ControlBlock {
|
case class TapscriptControlBlock(bytes: ByteVector) extends ControlBlock {
|
||||||
require(TapscriptControlBlock.isValid(bytes),
|
require(TapscriptControlBlock.isValid(bytes),
|
||||||
s"Invalid tapscript control block, got=$bytes")
|
s"Invalid tapscript control block, got=$bytes")
|
||||||
|
|
||||||
|
def parity: KeyParity = {
|
||||||
|
if ((bytes.head & 1) == 1) OddParity
|
||||||
|
else EvenParity
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control block that does not have a leaf version defined as per BIP342 This
|
/** A control block that does not have a leaf version defined as per BIP342 This
|
||||||
|
@ -87,22 +92,32 @@ object TapscriptControlBlock extends Factory[TapscriptControlBlock] {
|
||||||
new TapscriptControlBlock(bytes)
|
new TapscriptControlBlock(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
def fromLeaves(
|
|
||||||
leafVersion: LeafVersion,
|
|
||||||
internalKey: XOnlyPubKey,
|
|
||||||
leafs: Vector[TapLeaf]): TapscriptControlBlock = {
|
|
||||||
TapscriptControlBlock(leafVersion, internalKey, leafs.map(_.sha256))
|
|
||||||
}
|
|
||||||
|
|
||||||
def apply(
|
def apply(
|
||||||
leafVersion: LeafVersion,
|
leafVersion: LeafVersion,
|
||||||
internalKey: XOnlyPubKey,
|
internalKey: XOnlyPubKey,
|
||||||
|
parity: KeyParity,
|
||||||
leafHashes: Vector[Sha256Digest]): TapscriptControlBlock = {
|
leafHashes: Vector[Sha256Digest]): TapscriptControlBlock = {
|
||||||
|
val parityByte: Byte = parity match {
|
||||||
|
case OddParity => 0x01
|
||||||
|
case EvenParity => 0x0
|
||||||
|
}
|
||||||
val bytes =
|
val bytes =
|
||||||
((leafVersion.toByte | 0x1).toByte +: internalKey.bytes) ++ ByteVector
|
((parityByte | leafVersion.toByte).toByte +: internalKey.bytes) ++ ByteVector
|
||||||
.concat(leafHashes.map(_.bytes))
|
.concat(leafHashes.map(_.bytes))
|
||||||
TapscriptControlBlock(bytes)
|
TapscriptControlBlock(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Constructs a tapscript control block for the case where we have one single
|
||||||
|
* [[TapLeaf]] in the entire tree In this case, we don't have any elements in
|
||||||
|
* the control block besides the internal key, leaf version and parity of the
|
||||||
|
* output xonly pubkey
|
||||||
|
*/
|
||||||
|
def fromSingleLeaf(
|
||||||
|
leafVersion: LeafVersion,
|
||||||
|
internalKey: XOnlyPubKey,
|
||||||
|
parity: KeyParity): TapscriptControlBlock = {
|
||||||
|
TapscriptControlBlock(leafVersion, internalKey, parity, Vector.empty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object UnknownControlBlock extends Factory[UnknownControlBlock] {
|
object UnknownControlBlock extends Factory[UnknownControlBlock] {
|
||||||
|
|
|
@ -6,17 +6,11 @@ import org.bitcoins.core.currency.{Bitcoins, CurrencyUnit, CurrencyUnits}
|
||||||
import org.bitcoins.core.hd.{HDChainType, HDCoinType, SegWitHDPath}
|
import org.bitcoins.core.hd.{HDChainType, HDCoinType, SegWitHDPath}
|
||||||
import org.bitcoins.core.number.{Int32, UInt32}
|
import org.bitcoins.core.number.{Int32, UInt32}
|
||||||
import org.bitcoins.core.protocol.Bech32mAddress
|
import org.bitcoins.core.protocol.Bech32mAddress
|
||||||
import org.bitcoins.core.protocol.script._
|
import org.bitcoins.core.protocol.script.*
|
||||||
import org.bitcoins.core.protocol.transaction._
|
import org.bitcoins.core.protocol.transaction.*
|
||||||
import org.bitcoins.core.psbt.PSBT
|
import org.bitcoins.core.psbt.PSBT
|
||||||
import org.bitcoins.core.wallet.utxo.TxoState
|
import org.bitcoins.core.wallet.utxo.TxoState
|
||||||
import org.bitcoins.crypto.{
|
import org.bitcoins.crypto.*
|
||||||
DoubleSha256Digest,
|
|
||||||
DoubleSha256DigestBE,
|
|
||||||
ECPrivateKey,
|
|
||||||
ECPublicKey,
|
|
||||||
ECPublicKeyBytes
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Created by chris on 2/12/16.
|
/** Created by chris on 2/12/16.
|
||||||
*/
|
*/
|
||||||
|
@ -257,6 +251,16 @@ trait TransactionTestUtil {
|
||||||
EmptyTransaction.lockTime
|
EmptyTransaction.lockTime
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def testWitnessTransaction: WitnessTransaction = {
|
||||||
|
WitnessTransaction(
|
||||||
|
EmptyTransaction.version,
|
||||||
|
Vector(EmptyTransactionInput),
|
||||||
|
Vector.empty,
|
||||||
|
EmptyTransaction.lockTime,
|
||||||
|
EmptyWitness.fromN(1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/** Builds a dummy transaction that sends money to the given output */
|
/** Builds a dummy transaction that sends money to the given output */
|
||||||
def buildTransactionTo(output: TransactionOutput): Transaction = {
|
def buildTransactionTo(output: TransactionOutput): Transaction = {
|
||||||
BaseTransaction(
|
BaseTransaction(
|
||||||
|
|
Loading…
Add table
Reference in a new issue