mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-13 11:35:40 +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 {
|
||||
val x = TapscriptControlBlock.apply(controlBlock.leafVersion,
|
||||
controlBlock.p,
|
||||
controlBlock.parity,
|
||||
leafHashes = controlBlock.hashes)
|
||||
assert(x.bytes.toHex == controlBlock.bytes.toHex)
|
||||
assert(x == controlBlock)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.crypto.{Factory, NetworkElement, Sha256Digest, XOnlyPubKey}
|
||||
import org.bitcoins.crypto.*
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/** Control block as defined by BIP341
|
||||
|
@ -38,6 +38,11 @@ sealed abstract class ControlBlock extends NetworkElement {
|
|||
case class TapscriptControlBlock(bytes: ByteVector) extends ControlBlock {
|
||||
require(TapscriptControlBlock.isValid(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
|
||||
|
@ -87,22 +92,32 @@ object TapscriptControlBlock extends Factory[TapscriptControlBlock] {
|
|||
new TapscriptControlBlock(bytes)
|
||||
}
|
||||
|
||||
def fromLeaves(
|
||||
leafVersion: LeafVersion,
|
||||
internalKey: XOnlyPubKey,
|
||||
leafs: Vector[TapLeaf]): TapscriptControlBlock = {
|
||||
TapscriptControlBlock(leafVersion, internalKey, leafs.map(_.sha256))
|
||||
}
|
||||
|
||||
def apply(
|
||||
leafVersion: LeafVersion,
|
||||
internalKey: XOnlyPubKey,
|
||||
parity: KeyParity,
|
||||
leafHashes: Vector[Sha256Digest]): TapscriptControlBlock = {
|
||||
val parityByte: Byte = parity match {
|
||||
case OddParity => 0x01
|
||||
case EvenParity => 0x0
|
||||
}
|
||||
val bytes =
|
||||
((leafVersion.toByte | 0x1).toByte +: internalKey.bytes) ++ ByteVector
|
||||
((parityByte | leafVersion.toByte).toByte +: internalKey.bytes) ++ ByteVector
|
||||
.concat(leafHashes.map(_.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] {
|
||||
|
|
|
@ -6,17 +6,11 @@ import org.bitcoins.core.currency.{Bitcoins, CurrencyUnit, CurrencyUnits}
|
|||
import org.bitcoins.core.hd.{HDChainType, HDCoinType, SegWitHDPath}
|
||||
import org.bitcoins.core.number.{Int32, UInt32}
|
||||
import org.bitcoins.core.protocol.Bech32mAddress
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.transaction._
|
||||
import org.bitcoins.core.protocol.script.*
|
||||
import org.bitcoins.core.protocol.transaction.*
|
||||
import org.bitcoins.core.psbt.PSBT
|
||||
import org.bitcoins.core.wallet.utxo.TxoState
|
||||
import org.bitcoins.crypto.{
|
||||
DoubleSha256Digest,
|
||||
DoubleSha256DigestBE,
|
||||
ECPrivateKey,
|
||||
ECPublicKey,
|
||||
ECPublicKeyBytes
|
||||
}
|
||||
import org.bitcoins.crypto.*
|
||||
|
||||
/** Created by chris on 2/12/16.
|
||||
*/
|
||||
|
@ -257,6 +251,16 @@ trait TransactionTestUtil {
|
|||
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 */
|
||||
def buildTransactionTo(output: TransactionOutput): Transaction = {
|
||||
BaseTransaction(
|
||||
|
|
Loading…
Add table
Reference in a new issue