mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-13 11:35:40 +01:00
core: Add ADT for LeafVersion
This commit is contained in:
parent
aeca55f5ef
commit
b407141146
10 changed files with 69 additions and 53 deletions
|
@ -1,9 +1,9 @@
|
||||||
package org.bitcoins.core.protocol.transaction
|
package org.bitcoins.core.protocol.transaction
|
||||||
|
|
||||||
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.crypto.{Sha256Digest, XOnlyPubKey}
|
import org.bitcoins.crypto.{Sha256Digest, XOnlyPubKey}
|
||||||
import upickle.default._
|
import upickle.default.*
|
||||||
|
|
||||||
case class Given(internalPubkey: XOnlyPubKey, treeOpt: Option[TapscriptTree]) {
|
case class Given(internalPubkey: XOnlyPubKey, treeOpt: Option[TapscriptTree]) {
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ object TaprootWalletTestCase {
|
||||||
else if (`given`.objOpt.isDefined) {
|
else if (`given`.objOpt.isDefined) {
|
||||||
val givenObj = `given`.obj
|
val givenObj = `given`.obj
|
||||||
val script = ScriptPubKey.fromAsmHex(givenObj("script").str)
|
val script = ScriptPubKey.fromAsmHex(givenObj("script").str)
|
||||||
val leafVersion = givenObj("leafVersion").num.toByte
|
val leafVersion = LeafVersion.fromByte(givenObj("leafVersion").num.toByte)
|
||||||
val leaf = TapLeaf(leafVersion, script)
|
val leaf = TapLeaf(leafVersion, script)
|
||||||
Some(leaf)
|
Some(leaf)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -50,7 +50,7 @@ class TaprootWitnessTest extends BitcoinSUnitTest {
|
||||||
"7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac"
|
"7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac"
|
||||||
val spk = ScriptPubKey.fromAsmHex(asmHex)
|
val spk = ScriptPubKey.fromAsmHex(asmHex)
|
||||||
assert(asmHex == spk.asmHex)
|
assert(asmHex == spk.asmHex)
|
||||||
val leaf = TapLeaf(0xc0.toByte, spk)
|
val leaf = TapLeaf(LeafVersion.Tapscript, spk)
|
||||||
val hash = TaprootScriptPath.computeTapleafHash(leaf)
|
val hash = TaprootScriptPath.computeTapleafHash(leaf)
|
||||||
assert(hash.hex == expected)
|
assert(hash.hex == expected)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package org.bitcoins.core.protocol.script.descriptor
|
package org.bitcoins.core.protocol.script.descriptor
|
||||||
|
|
||||||
import org.bitcoins.core.protocol.script._
|
import org.bitcoins.core.protocol.script.*
|
||||||
import org.bitcoins.crypto.{ECPrivateKey, ECPublicKey}
|
import org.bitcoins.crypto.{ECPrivateKey, ECPublicKey}
|
||||||
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
|
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
|
||||||
import org.scalatest.Assertion
|
import org.scalatest.Assertion
|
||||||
|
@ -536,7 +536,7 @@ class DescriptorTest extends BitcoinSUnitTest {
|
||||||
case pub: ECPublicKey => pub.toXOnly
|
case pub: ECPublicKey => pub.toXOnly
|
||||||
}
|
}
|
||||||
val tree =
|
val tree =
|
||||||
TapLeaf(TapLeaf.leafVersion, P2PKScriptPubKey(derivedKey.toXOnly))
|
TapLeaf(LeafVersion.Tapscript, P2PKScriptPubKey(derivedKey.toXOnly))
|
||||||
val (_, spk) =
|
val (_, spk) =
|
||||||
TaprootScriptPubKey.fromInternalKeyTapscriptTree(internal, tree)
|
TaprootScriptPubKey.fromInternalKeyTapscriptTree(internal, tree)
|
||||||
spk
|
spk
|
||||||
|
|
|
@ -22,11 +22,11 @@ sealed abstract class ControlBlock extends NetworkElement {
|
||||||
XOnlyPubKey.fromBytes(bytes.slice(1, 33))
|
XOnlyPubKey.fromBytes(bytes.slice(1, 33))
|
||||||
}
|
}
|
||||||
|
|
||||||
val leafVersion: Byte =
|
val leafVersion: LeafVersion =
|
||||||
(bytes.head & TaprootScriptPath.TAPROOT_LEAF_MASK).toByte
|
LeafVersion.fromByte((bytes.head & LeafVersion.TAPROOT_LEAF_MASK).toByte)
|
||||||
|
|
||||||
val isTapLeafMask: Boolean = {
|
val isTapLeafMask: Boolean = {
|
||||||
(bytes.head & TaprootScriptPath.TAPROOT_LEAF_MASK).toByte == TaprootScriptPath.TAPROOT_LEAF_TAPSCRIPT
|
(bytes.head & LeafVersion.TAPROOT_LEAF_MASK).toByte == LeafVersion.Tapscript.toByte
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Leaf or branch hashes embedded in the control block */
|
/** Leaf or branch hashes embedded in the control block */
|
||||||
|
@ -71,7 +71,8 @@ object TapscriptControlBlock extends Factory[TapscriptControlBlock] {
|
||||||
if (bytes.isEmpty) {
|
if (bytes.isEmpty) {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
TapLeaf.knownLeafVersions.contains(bytes.head) &&
|
LeafVersion.knownLeafVersions.contains(
|
||||||
|
LeafVersion.fromMaskedByte(bytes.head)) &&
|
||||||
ControlBlock.isValid(bytes) &&
|
ControlBlock.isValid(bytes) &&
|
||||||
XOnlyPubKey.fromBytesT(bytes.slice(1, 33)).isSuccess
|
XOnlyPubKey.fromBytesT(bytes.slice(1, 33)).isSuccess
|
||||||
}
|
}
|
||||||
|
@ -79,7 +80,7 @@ object TapscriptControlBlock extends Factory[TapscriptControlBlock] {
|
||||||
|
|
||||||
/** Creates a control block with no scripts, just an internal key */
|
/** Creates a control block with no scripts, just an internal key */
|
||||||
def fromXOnlyPubKey(internalKey: XOnlyPubKey): TapscriptControlBlock = {
|
def fromXOnlyPubKey(internalKey: XOnlyPubKey): TapscriptControlBlock = {
|
||||||
fromBytes(TapLeaf.leafVersion +: internalKey.bytes)
|
fromBytes(LeafVersion.Tapscript.toByte +: internalKey.bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def fromBytes(bytes: ByteVector): TapscriptControlBlock = {
|
override def fromBytes(bytes: ByteVector): TapscriptControlBlock = {
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package org.bitcoins.core.protocol.script
|
||||||
|
|
||||||
|
sealed abstract class LeafVersion {
|
||||||
|
def toByte: Byte
|
||||||
|
}
|
||||||
|
|
||||||
|
object LeafVersion {
|
||||||
|
|
||||||
|
/** BIP342 specifies validity rules that apply for leaf version 0xc0, but
|
||||||
|
* future proposals can introduce rules for other leaf versions.
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#rationale
|
||||||
|
*/
|
||||||
|
case object Tapscript extends LeafVersion {
|
||||||
|
override def toByte: Byte = 0xc0.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
case class UnknownLeafVersion(toByte: Byte) extends LeafVersion
|
||||||
|
|
||||||
|
val knownLeafVersions: Vector[LeafVersion] = Vector(
|
||||||
|
Tapscript /*, 0xc1.toByte*/ )
|
||||||
|
|
||||||
|
final val TAPROOT_LEAF_MASK: Byte = 0xfe.toByte
|
||||||
|
|
||||||
|
def fromByte(byte: Byte): LeafVersion = {
|
||||||
|
knownLeafVersions
|
||||||
|
.find(_.toByte == byte)
|
||||||
|
.getOrElse(UnknownLeafVersion(byte))
|
||||||
|
}
|
||||||
|
|
||||||
|
def fromMaskedByte(byte: Byte): LeafVersion = {
|
||||||
|
fromByte((TAPROOT_LEAF_MASK & byte).toByte)
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import org.bitcoins.core.serializers.script.{
|
||||||
ScriptParser
|
ScriptParser
|
||||||
}
|
}
|
||||||
import org.bitcoins.core.util.{BitcoinScriptUtil, BytesUtil}
|
import org.bitcoins.core.util.{BitcoinScriptUtil, BytesUtil}
|
||||||
import org.bitcoins.crypto._
|
import org.bitcoins.crypto.*
|
||||||
import scodec.bits.ByteVector
|
import scodec.bits.ByteVector
|
||||||
|
|
||||||
/** Created by chris on 11/10/16. The witness used to evaluate a
|
/** Created by chris on 11/10/16. The witness used to evaluate a
|
||||||
|
@ -416,10 +416,6 @@ object TaprootScriptPath extends Factory[TaprootScriptPath] {
|
||||||
final val TAPROOT_CONTROL_MAX_SIZE: Int = {
|
final val TAPROOT_CONTROL_MAX_SIZE: Int = {
|
||||||
TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT
|
TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT
|
||||||
}
|
}
|
||||||
|
|
||||||
final val TAPROOT_LEAF_MASK: Byte = 0xfe.toByte
|
|
||||||
final val TAPROOT_LEAF_TAPSCRIPT: Byte = 0xc0.toByte
|
|
||||||
|
|
||||||
override def fromBytes(bytes: ByteVector): TaprootScriptPath = {
|
override def fromBytes(bytes: ByteVector): TaprootScriptPath = {
|
||||||
RawScriptWitnessParser.read(bytes) match {
|
RawScriptWitnessParser.read(bytes) match {
|
||||||
case t: TaprootScriptPath => t
|
case t: TaprootScriptPath => t
|
||||||
|
@ -485,7 +481,8 @@ object TaprootScriptPath extends Factory[TaprootScriptPath] {
|
||||||
*/
|
*/
|
||||||
def computeTapleafHash(leaf: TapLeaf): Sha256Digest = {
|
def computeTapleafHash(leaf: TapLeaf): Sha256Digest = {
|
||||||
val bytes =
|
val bytes =
|
||||||
ByteVector.fromInt(i = leaf.leafVersion, size = 1) ++ leaf.spk.bytes
|
ByteVector.fromInt(i = leaf.leafVersion.toByte,
|
||||||
|
size = 1) ++ leaf.spk.bytes
|
||||||
CryptoUtil.tapLeafHash(bytes)
|
CryptoUtil.tapLeafHash(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,11 @@ case class TapBranch(tree1: TapscriptTree, tree2: TapscriptTree)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TapLeaf(leafVersion: Byte, spk: ScriptPubKey) extends TapscriptTree {
|
case class TapLeaf(leafVersion: LeafVersion, spk: ScriptPubKey)
|
||||||
|
extends TapscriptTree {
|
||||||
|
|
||||||
override val bytes: ByteVector =
|
override val bytes: ByteVector =
|
||||||
ByteVector.fromInt(leafVersion, 1) ++ spk.bytes
|
ByteVector.fromInt(leafVersion.toByte, 1) ++ spk.bytes
|
||||||
val sha256: Sha256Digest = CryptoUtil.tapLeafHash(bytes)
|
val sha256: Sha256Digest = CryptoUtil.tapLeafHash(bytes)
|
||||||
override val leafs: Vector[TapLeaf] = Vector(this)
|
override val leafs: Vector[TapLeaf] = Vector(this)
|
||||||
|
|
||||||
|
@ -41,18 +42,6 @@ case class TapLeaf(leafVersion: Byte, spk: ScriptPubKey) extends TapscriptTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object TapLeaf {
|
|
||||||
val leafVersion: Byte = 0xc0.toByte
|
|
||||||
|
|
||||||
/** BIP342 specifies validity rules that apply for leaf version 0xc0, but
|
|
||||||
* future proposals can introduce rules for other leaf versions.
|
|
||||||
*
|
|
||||||
* @see
|
|
||||||
* https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#rationale
|
|
||||||
*/
|
|
||||||
val knownLeafVersions: Vector[Byte] = Vector(leafVersion, 0xc1.toByte)
|
|
||||||
}
|
|
||||||
|
|
||||||
object TapscriptTree {
|
object TapscriptTree {
|
||||||
|
|
||||||
def buildTapscriptTree(leafs: Vector[TapLeaf]): TapscriptTree = {
|
def buildTapscriptTree(leafs: Vector[TapLeaf]): TapscriptTree = {
|
||||||
|
|
|
@ -386,7 +386,7 @@ case class TapscriptLeafExpression(source: RawSPKScriptExpression)
|
||||||
private def scriptPubKey: ScriptPubKey = source.scriptPubKey
|
private def scriptPubKey: ScriptPubKey = source.scriptPubKey
|
||||||
|
|
||||||
override def tree: TapLeaf =
|
override def tree: TapLeaf =
|
||||||
TapLeaf(TapLeaf.leafVersion, scriptPubKey)
|
TapLeaf(LeafVersion.Tapscript, scriptPubKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
object SingleECPublicKeyExpression
|
object SingleECPublicKeyExpression
|
||||||
|
|
|
@ -4,7 +4,7 @@ import org.bitcoins.core.crypto.ExtPublicKey
|
||||||
import org.bitcoins.core.hd.BIP32Path
|
import org.bitcoins.core.hd.BIP32Path
|
||||||
import org.bitcoins.core.number.{Int32, UInt32, UInt64}
|
import org.bitcoins.core.number.{Int32, UInt32, UInt64}
|
||||||
import org.bitcoins.core.protocol.CompactSizeUInt
|
import org.bitcoins.core.protocol.CompactSizeUInt
|
||||||
import org.bitcoins.core.protocol.script._
|
import org.bitcoins.core.protocol.script.*
|
||||||
import org.bitcoins.core.protocol.transaction.{
|
import org.bitcoins.core.protocol.transaction.{
|
||||||
BaseTransaction,
|
BaseTransaction,
|
||||||
NonWitnessTransaction,
|
NonWitnessTransaction,
|
||||||
|
@ -13,7 +13,7 @@ import org.bitcoins.core.protocol.transaction.{
|
||||||
}
|
}
|
||||||
import org.bitcoins.core.serializers.script.RawScriptWitnessParser
|
import org.bitcoins.core.serializers.script.RawScriptWitnessParser
|
||||||
import org.bitcoins.core.util.BytesUtil
|
import org.bitcoins.core.util.BytesUtil
|
||||||
import org.bitcoins.crypto.{HashType, _}
|
import org.bitcoins.crypto.*
|
||||||
import scodec.bits.ByteVector
|
import scodec.bits.ByteVector
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
@ -59,7 +59,7 @@ sealed trait GlobalPSBTRecord extends PSBTRecord {
|
||||||
}
|
}
|
||||||
|
|
||||||
object GlobalPSBTRecord extends Factory[GlobalPSBTRecord] {
|
object GlobalPSBTRecord extends Factory[GlobalPSBTRecord] {
|
||||||
import org.bitcoins.core.psbt.PSBTGlobalKeyId._
|
import org.bitcoins.core.psbt.PSBTGlobalKeyId.*
|
||||||
|
|
||||||
case class UnsignedTransaction(transaction: NonWitnessTransaction)
|
case class UnsignedTransaction(transaction: NonWitnessTransaction)
|
||||||
extends GlobalPSBTRecord {
|
extends GlobalPSBTRecord {
|
||||||
|
@ -107,7 +107,7 @@ object GlobalPSBTRecord extends Factory[GlobalPSBTRecord] {
|
||||||
}
|
}
|
||||||
|
|
||||||
override def fromBytes(bytes: ByteVector): GlobalPSBTRecord = {
|
override def fromBytes(bytes: ByteVector): GlobalPSBTRecord = {
|
||||||
import org.bitcoins.core.psbt.PSBTGlobalKeyId._
|
import org.bitcoins.core.psbt.PSBTGlobalKeyId.*
|
||||||
|
|
||||||
val (key, value) = PSBTRecord.fromBytes(bytes)
|
val (key, value) = PSBTRecord.fromBytes(bytes)
|
||||||
PSBTGlobalKeyId.fromByte(key.head) match {
|
PSBTGlobalKeyId.fromByte(key.head) match {
|
||||||
|
@ -141,7 +141,7 @@ sealed trait InputPSBTRecord extends PSBTRecord {
|
||||||
}
|
}
|
||||||
|
|
||||||
object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
||||||
import org.bitcoins.core.psbt.PSBTInputKeyId._
|
import org.bitcoins.core.psbt.PSBTInputKeyId.*
|
||||||
|
|
||||||
case class NonWitnessOrUnknownUTXO(transactionSpent: Transaction)
|
case class NonWitnessOrUnknownUTXO(transactionSpent: Transaction)
|
||||||
extends InputPSBTRecord {
|
extends InputPSBTRecord {
|
||||||
|
@ -352,7 +352,7 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
||||||
case class TRLeafScript(
|
case class TRLeafScript(
|
||||||
controlBlock: ControlBlock,
|
controlBlock: ControlBlock,
|
||||||
script: RawScriptPubKey,
|
script: RawScriptPubKey,
|
||||||
leafVersion: Byte)
|
leafVersion: LeafVersion)
|
||||||
extends InputPSBTRecord {
|
extends InputPSBTRecord {
|
||||||
override type KeyId = TRLeafScriptKeyId.type
|
override type KeyId = TRLeafScriptKeyId.type
|
||||||
|
|
||||||
|
@ -361,7 +361,7 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
||||||
}
|
}
|
||||||
|
|
||||||
override val value: ByteVector = {
|
override val value: ByteVector = {
|
||||||
script.asmBytes ++ ByteVector.fromByte(leafVersion)
|
script.asmBytes ++ ByteVector.fromByte(leafVersion.toByte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +411,7 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
||||||
}
|
}
|
||||||
|
|
||||||
override def fromBytes(bytes: ByteVector): InputPSBTRecord = {
|
override def fromBytes(bytes: ByteVector): InputPSBTRecord = {
|
||||||
import org.bitcoins.core.psbt.PSBTInputKeyId._
|
import org.bitcoins.core.psbt.PSBTInputKeyId.*
|
||||||
|
|
||||||
val (key, value) = PSBTRecord.fromBytes(bytes)
|
val (key, value) = PSBTRecord.fromBytes(bytes)
|
||||||
PSBTInputKeyId.fromByte(key.head) match {
|
PSBTInputKeyId.fromByte(key.head) match {
|
||||||
|
@ -530,7 +530,7 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
||||||
|
|
||||||
val script = RawScriptPubKey.fromAsmBytes(value.init)
|
val script = RawScriptPubKey.fromAsmBytes(value.init)
|
||||||
|
|
||||||
TRLeafScript(controlBlock, script, value.last)
|
TRLeafScript(controlBlock, script, LeafVersion.fromByte(value.last))
|
||||||
case TRBIP32DerivationPathKeyId =>
|
case TRBIP32DerivationPathKeyId =>
|
||||||
val pubKey = XOnlyPubKey(key.tail)
|
val pubKey = XOnlyPubKey(key.tail)
|
||||||
val numHashes = CompactSizeUInt.fromBytes(value)
|
val numHashes = CompactSizeUInt.fromBytes(value)
|
||||||
|
@ -575,7 +575,7 @@ sealed trait OutputPSBTRecord extends PSBTRecord {
|
||||||
}
|
}
|
||||||
|
|
||||||
object OutputPSBTRecord extends Factory[OutputPSBTRecord] {
|
object OutputPSBTRecord extends Factory[OutputPSBTRecord] {
|
||||||
import org.bitcoins.core.psbt.PSBTOutputKeyId._
|
import org.bitcoins.core.psbt.PSBTOutputKeyId.*
|
||||||
|
|
||||||
case class RedeemScript(redeemScript: ScriptPubKey) extends OutputPSBTRecord {
|
case class RedeemScript(redeemScript: ScriptPubKey) extends OutputPSBTRecord {
|
||||||
override type KeyId = RedeemScriptKeyId.type
|
override type KeyId = RedeemScriptKeyId.type
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
package org.bitcoins.core.script
|
package org.bitcoins.core.script
|
||||||
|
|
||||||
import org.bitcoins.core.crypto._
|
import org.bitcoins.core.crypto.*
|
||||||
import org.bitcoins.core.number.UInt32
|
import org.bitcoins.core.number.UInt32
|
||||||
import org.bitcoins.core.protocol.script.{
|
import org.bitcoins.core.protocol.script.*
|
||||||
TapLeaf,
|
import org.bitcoins.core.script.constant.*
|
||||||
TaprootKeyPath,
|
|
||||||
TaprootScriptPath,
|
|
||||||
TaprootUnknownPath,
|
|
||||||
TaprootWitness
|
|
||||||
}
|
|
||||||
import org.bitcoins.core.script.constant._
|
|
||||||
import org.bitcoins.core.script.control.{OP_ELSE, OP_ENDIF, OP_IF, OP_NOTIF}
|
import org.bitcoins.core.script.control.{OP_ELSE, OP_ENDIF, OP_IF, OP_NOTIF}
|
||||||
import org.bitcoins.core.script.flag.ScriptFlag
|
import org.bitcoins.core.script.flag.ScriptFlag
|
||||||
import org.bitcoins.core.script.result._
|
import org.bitcoins.core.script.result.*
|
||||||
import org.bitcoins.core.util.BitcoinScriptUtil
|
import org.bitcoins.core.util.BitcoinScriptUtil
|
||||||
import org.bitcoins.crypto.Sha256Digest
|
import org.bitcoins.crypto.Sha256Digest
|
||||||
|
|
||||||
|
@ -91,7 +85,7 @@ sealed trait ScriptProgram {
|
||||||
*/
|
*/
|
||||||
def tapLeafHashOpt: Option[Sha256Digest] = {
|
def tapLeafHashOpt: Option[Sha256Digest] = {
|
||||||
getTapscriptOpt.map { sp =>
|
getTapscriptOpt.map { sp =>
|
||||||
val leaf = TapLeaf(TaprootScriptPath.TAPROOT_LEAF_TAPSCRIPT, sp.script)
|
val leaf = TapLeaf(LeafVersion.Tapscript, sp.script)
|
||||||
val hash = TaprootScriptPath.computeTapleafHash(leaf)
|
val hash = TaprootScriptPath.computeTapleafHash(leaf)
|
||||||
hash
|
hash
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue