mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-13 11:35:40 +01:00
core: Add ADT for LeafVersion
(#5952)
* core: Add ADT for LeafVersion * Use LeafVersion.fromMaskedByte()
This commit is contained in:
parent
aeca55f5ef
commit
32eaf31e48
10 changed files with 69 additions and 53 deletions
|
@ -1,9 +1,9 @@
|
|||
package org.bitcoins.core.protocol.transaction
|
||||
|
||||
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 upickle.default._
|
||||
import upickle.default.*
|
||||
|
||||
case class Given(internalPubkey: XOnlyPubKey, treeOpt: Option[TapscriptTree]) {
|
||||
|
||||
|
@ -74,7 +74,7 @@ object TaprootWalletTestCase {
|
|||
else if (`given`.objOpt.isDefined) {
|
||||
val givenObj = `given`.obj
|
||||
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)
|
||||
Some(leaf)
|
||||
} else {
|
||||
|
|
|
@ -50,7 +50,7 @@ class TaprootWitnessTest extends BitcoinSUnitTest {
|
|||
"7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac"
|
||||
val spk = ScriptPubKey.fromAsmHex(asmHex)
|
||||
assert(asmHex == spk.asmHex)
|
||||
val leaf = TapLeaf(0xc0.toByte, spk)
|
||||
val leaf = TapLeaf(LeafVersion.Tapscript, spk)
|
||||
val hash = TaprootScriptPath.computeTapleafHash(leaf)
|
||||
assert(hash.hex == expected)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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.testkitcore.util.BitcoinSUnitTest
|
||||
import org.scalatest.Assertion
|
||||
|
@ -536,7 +536,7 @@ class DescriptorTest extends BitcoinSUnitTest {
|
|||
case pub: ECPublicKey => pub.toXOnly
|
||||
}
|
||||
val tree =
|
||||
TapLeaf(TapLeaf.leafVersion, P2PKScriptPubKey(derivedKey.toXOnly))
|
||||
TapLeaf(LeafVersion.Tapscript, P2PKScriptPubKey(derivedKey.toXOnly))
|
||||
val (_, spk) =
|
||||
TaprootScriptPubKey.fromInternalKeyTapscriptTree(internal, tree)
|
||||
spk
|
||||
|
|
|
@ -22,11 +22,11 @@ sealed abstract class ControlBlock extends NetworkElement {
|
|||
XOnlyPubKey.fromBytes(bytes.slice(1, 33))
|
||||
}
|
||||
|
||||
val leafVersion: Byte =
|
||||
(bytes.head & TaprootScriptPath.TAPROOT_LEAF_MASK).toByte
|
||||
val leafVersion: LeafVersion =
|
||||
LeafVersion.fromMaskedByte(bytes.head)
|
||||
|
||||
val isTapLeafMask: Boolean = {
|
||||
(bytes.head & TaprootScriptPath.TAPROOT_LEAF_MASK).toByte == TaprootScriptPath.TAPROOT_LEAF_TAPSCRIPT
|
||||
leafVersion == LeafVersion.Tapscript
|
||||
}
|
||||
|
||||
/** Leaf or branch hashes embedded in the control block */
|
||||
|
@ -71,7 +71,8 @@ object TapscriptControlBlock extends Factory[TapscriptControlBlock] {
|
|||
if (bytes.isEmpty) {
|
||||
false
|
||||
} else {
|
||||
TapLeaf.knownLeafVersions.contains(bytes.head) &&
|
||||
LeafVersion.knownLeafVersions.contains(
|
||||
LeafVersion.fromMaskedByte(bytes.head)) &&
|
||||
ControlBlock.isValid(bytes) &&
|
||||
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 */
|
||||
def fromXOnlyPubKey(internalKey: XOnlyPubKey): TapscriptControlBlock = {
|
||||
fromBytes(TapLeaf.leafVersion +: internalKey.bytes)
|
||||
fromBytes(LeafVersion.Tapscript.toByte +: internalKey.bytes)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
import org.bitcoins.core.util.{BitcoinScriptUtil, BytesUtil}
|
||||
import org.bitcoins.crypto._
|
||||
import org.bitcoins.crypto.*
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/** 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 = {
|
||||
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 = {
|
||||
RawScriptWitnessParser.read(bytes) match {
|
||||
case t: TaprootScriptPath => t
|
||||
|
@ -485,7 +481,8 @@ object TaprootScriptPath extends Factory[TaprootScriptPath] {
|
|||
*/
|
||||
def computeTapleafHash(leaf: TapLeaf): Sha256Digest = {
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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 =
|
||||
ByteVector.fromInt(leafVersion, 1) ++ spk.bytes
|
||||
ByteVector.fromInt(leafVersion.toByte, 1) ++ spk.bytes
|
||||
val sha256: Sha256Digest = CryptoUtil.tapLeafHash(bytes)
|
||||
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 {
|
||||
|
||||
def buildTapscriptTree(leafs: Vector[TapLeaf]): TapscriptTree = {
|
||||
|
|
|
@ -386,7 +386,7 @@ case class TapscriptLeafExpression(source: RawSPKScriptExpression)
|
|||
private def scriptPubKey: ScriptPubKey = source.scriptPubKey
|
||||
|
||||
override def tree: TapLeaf =
|
||||
TapLeaf(TapLeaf.leafVersion, scriptPubKey)
|
||||
TapLeaf(LeafVersion.Tapscript, scriptPubKey)
|
||||
}
|
||||
|
||||
object SingleECPublicKeyExpression
|
||||
|
|
|
@ -4,7 +4,7 @@ import org.bitcoins.core.crypto.ExtPublicKey
|
|||
import org.bitcoins.core.hd.BIP32Path
|
||||
import org.bitcoins.core.number.{Int32, UInt32, UInt64}
|
||||
import org.bitcoins.core.protocol.CompactSizeUInt
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.script.*
|
||||
import org.bitcoins.core.protocol.transaction.{
|
||||
BaseTransaction,
|
||||
NonWitnessTransaction,
|
||||
|
@ -13,7 +13,7 @@ import org.bitcoins.core.protocol.transaction.{
|
|||
}
|
||||
import org.bitcoins.core.serializers.script.RawScriptWitnessParser
|
||||
import org.bitcoins.core.util.BytesUtil
|
||||
import org.bitcoins.crypto.{HashType, _}
|
||||
import org.bitcoins.crypto.*
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
@ -59,7 +59,7 @@ sealed trait GlobalPSBTRecord extends PSBTRecord {
|
|||
}
|
||||
|
||||
object GlobalPSBTRecord extends Factory[GlobalPSBTRecord] {
|
||||
import org.bitcoins.core.psbt.PSBTGlobalKeyId._
|
||||
import org.bitcoins.core.psbt.PSBTGlobalKeyId.*
|
||||
|
||||
case class UnsignedTransaction(transaction: NonWitnessTransaction)
|
||||
extends GlobalPSBTRecord {
|
||||
|
@ -107,7 +107,7 @@ object GlobalPSBTRecord extends Factory[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)
|
||||
PSBTGlobalKeyId.fromByte(key.head) match {
|
||||
|
@ -141,7 +141,7 @@ sealed trait InputPSBTRecord extends PSBTRecord {
|
|||
}
|
||||
|
||||
object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
||||
import org.bitcoins.core.psbt.PSBTInputKeyId._
|
||||
import org.bitcoins.core.psbt.PSBTInputKeyId.*
|
||||
|
||||
case class NonWitnessOrUnknownUTXO(transactionSpent: Transaction)
|
||||
extends InputPSBTRecord {
|
||||
|
@ -352,7 +352,7 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
|||
case class TRLeafScript(
|
||||
controlBlock: ControlBlock,
|
||||
script: RawScriptPubKey,
|
||||
leafVersion: Byte)
|
||||
leafVersion: LeafVersion)
|
||||
extends InputPSBTRecord {
|
||||
override type KeyId = TRLeafScriptKeyId.type
|
||||
|
||||
|
@ -361,7 +361,7 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
|||
}
|
||||
|
||||
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 = {
|
||||
import org.bitcoins.core.psbt.PSBTInputKeyId._
|
||||
import org.bitcoins.core.psbt.PSBTInputKeyId.*
|
||||
|
||||
val (key, value) = PSBTRecord.fromBytes(bytes)
|
||||
PSBTInputKeyId.fromByte(key.head) match {
|
||||
|
@ -530,7 +530,7 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
|||
|
||||
val script = RawScriptPubKey.fromAsmBytes(value.init)
|
||||
|
||||
TRLeafScript(controlBlock, script, value.last)
|
||||
TRLeafScript(controlBlock, script, LeafVersion.fromByte(value.last))
|
||||
case TRBIP32DerivationPathKeyId =>
|
||||
val pubKey = XOnlyPubKey(key.tail)
|
||||
val numHashes = CompactSizeUInt.fromBytes(value)
|
||||
|
@ -575,7 +575,7 @@ sealed trait OutputPSBTRecord extends PSBTRecord {
|
|||
}
|
||||
|
||||
object OutputPSBTRecord extends Factory[OutputPSBTRecord] {
|
||||
import org.bitcoins.core.psbt.PSBTOutputKeyId._
|
||||
import org.bitcoins.core.psbt.PSBTOutputKeyId.*
|
||||
|
||||
case class RedeemScript(redeemScript: ScriptPubKey) extends OutputPSBTRecord {
|
||||
override type KeyId = RedeemScriptKeyId.type
|
||||
|
|
|
@ -1,18 +1,12 @@
|
|||
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.protocol.script.{
|
||||
TapLeaf,
|
||||
TaprootKeyPath,
|
||||
TaprootScriptPath,
|
||||
TaprootUnknownPath,
|
||||
TaprootWitness
|
||||
}
|
||||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.protocol.script.*
|
||||
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.flag.ScriptFlag
|
||||
import org.bitcoins.core.script.result._
|
||||
import org.bitcoins.core.script.result.*
|
||||
import org.bitcoins.core.util.BitcoinScriptUtil
|
||||
import org.bitcoins.crypto.Sha256Digest
|
||||
|
||||
|
@ -91,7 +85,7 @@ sealed trait ScriptProgram {
|
|||
*/
|
||||
def tapLeafHashOpt: Option[Sha256Digest] = {
|
||||
getTapscriptOpt.map { sp =>
|
||||
val leaf = TapLeaf(TaprootScriptPath.TAPROOT_LEAF_TAPSCRIPT, sp.script)
|
||||
val leaf = TapLeaf(LeafVersion.Tapscript, sp.script)
|
||||
val hash = TaprootScriptPath.computeTapleafHash(leaf)
|
||||
hash
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue