mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-22 14:33:06 +01:00
core: Add Address descriptors from BIP385 (#5935)
This commit is contained in:
parent
62252daff8
commit
959993bed7
6 changed files with 199 additions and 96 deletions
|
@ -386,6 +386,10 @@ class DescriptorTest extends BitcoinSUnitTest {
|
|||
val str2 = "raw(a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87)"
|
||||
val expected2 = "a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"
|
||||
runTest(str2, expected2)
|
||||
|
||||
val str3 = "addr(3PUNyaW7M55oKWJ3kDukwk9bsKvryra15j)"
|
||||
val expected3 = "a914eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee87"
|
||||
runTest(str3, expected3)
|
||||
}
|
||||
|
||||
it must "fail to parse invalid test vectors from BIP385" in {
|
||||
|
@ -467,7 +471,7 @@ class DescriptorTest extends BitcoinSUnitTest {
|
|||
}
|
||||
|
||||
def runTest(descriptor: String, expectedSPK: String): Assertion = {
|
||||
val desc = ScriptDescriptor.fromString(descriptor)
|
||||
val desc = Descriptor.fromString(descriptor)
|
||||
assert(desc.toString == descriptor)
|
||||
assert(desc.scriptPubKey.asmHex == expectedSPK)
|
||||
}
|
||||
|
@ -521,9 +525,9 @@ class DescriptorTest extends BitcoinSUnitTest {
|
|||
|
||||
val p2wpkh = P2WPKHWitnessSPKV0(derivedKey)
|
||||
val spk = desc.expression.descriptorType match {
|
||||
case DescriptorType.WPKH => p2wpkh
|
||||
case DescriptorType.SH => P2SHScriptPubKey(p2wpkh)
|
||||
case DescriptorType.TR =>
|
||||
case ScriptDescriptorType.WPKH => p2wpkh
|
||||
case ScriptDescriptorType.SH => P2SHScriptPubKey(p2wpkh)
|
||||
case ScriptDescriptorType.TR =>
|
||||
val scriptPathTreeExpr =
|
||||
desc.expression.asInstanceOf[ScriptPathTreeExpression]
|
||||
val internalExtKey = parseExtKeyExpression(scriptPathTreeExpr.keyPath)
|
||||
|
@ -576,11 +580,11 @@ class DescriptorTest extends BitcoinSUnitTest {
|
|||
MultiSignatureScriptPubKey(spk.requiredSigs, sortedKeys)
|
||||
val (actual, expected) = {
|
||||
desc.expression.descriptorType match {
|
||||
case DescriptorType.Multi | DescriptorType.SortedMulti =>
|
||||
case ScriptDescriptorType.Multi | ScriptDescriptorType.SortedMulti =>
|
||||
(multisig, MultiSignatureScriptPubKey.fromAsmHex(s))
|
||||
case DescriptorType.SH =>
|
||||
case ScriptDescriptorType.SH =>
|
||||
(P2SHScriptPubKey(multisig), P2SHScriptPubKey.fromAsmHex(s))
|
||||
case DescriptorType.WSH =>
|
||||
case ScriptDescriptorType.WSH =>
|
||||
(P2WSHWitnessSPKV0(multisig), P2WSHWitnessSPKV0.fromAsmHex(s))
|
||||
case x =>
|
||||
sys.error(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.core.consensus.Consensus
|
||||
import org.bitcoins.core.protocol.script.descriptor.DescriptorType
|
||||
import org.bitcoins.core.protocol.script.descriptor.ScriptDescriptorType
|
||||
import org.bitcoins.core.script.ScriptType
|
||||
import org.bitcoins.core.script.bitwise.{OP_EQUAL, OP_EQUALVERIFY}
|
||||
import org.bitcoins.core.script.constant.{BytesToPushOntoStack, *}
|
||||
|
@ -51,7 +51,8 @@ sealed trait P2PKHScriptPubKey extends RawScriptPubKey {
|
|||
def pubKeyHash: Sha256Hash160Digest =
|
||||
Sha256Hash160Digest(asm(asm.length - 3).bytes)
|
||||
|
||||
override def toString = s"${DescriptorType.PK.toString}(${pubKeyHash.hex})"
|
||||
override def toString =
|
||||
s"${ScriptDescriptorType.PK.toString}(${pubKeyHash.hex})"
|
||||
}
|
||||
|
||||
object P2PKHScriptPubKey extends ScriptFactory[P2PKHScriptPubKey] {
|
||||
|
@ -61,7 +62,8 @@ object P2PKHScriptPubKey extends ScriptFactory[P2PKHScriptPubKey] {
|
|||
extends P2PKHScriptPubKey {
|
||||
override val scriptType: ScriptType = ScriptType.PUBKEYHASH
|
||||
|
||||
override def toString = s"${DescriptorType.PKH.toString}(${pubKeyHash.hex})"
|
||||
override def toString =
|
||||
s"${ScriptDescriptorType.PKH.toString}(${pubKeyHash.hex})"
|
||||
}
|
||||
|
||||
def apply(pubKey: ECPublicKey): P2PKHScriptPubKey = {
|
||||
|
@ -189,7 +191,7 @@ sealed trait MultiSignatureScriptPubKey extends RawScriptPubKey {
|
|||
}
|
||||
|
||||
override def toString =
|
||||
s"${DescriptorType.Multi.toString}($requiredSigs,${publicKeys.mkString(",")})"
|
||||
s"${ScriptDescriptorType.Multi.toString}($requiredSigs,${publicKeys.mkString(",")})"
|
||||
}
|
||||
|
||||
object MultiSignatureScriptPubKey
|
||||
|
@ -358,7 +360,8 @@ sealed trait P2SHScriptPubKey extends NonWitnessScriptPubKey {
|
|||
def scriptHash: Sha256Hash160Digest =
|
||||
Sha256Hash160Digest(asm(asm.length - 2).bytes)
|
||||
|
||||
override def toString = s"${DescriptorType.SH.toString}(${scriptHash.hex})"
|
||||
override def toString =
|
||||
s"${ScriptDescriptorType.SH.toString}(${scriptHash.hex})"
|
||||
}
|
||||
|
||||
object P2SHScriptPubKey extends ScriptFactory[P2SHScriptPubKey] {
|
||||
|
@ -413,7 +416,8 @@ sealed trait P2PKScriptPubKey extends RawScriptPubKey {
|
|||
def publicKey: ECPublicKeyBytes =
|
||||
ECPublicKeyBytes(BitcoinScriptUtil.filterPushOps(asm).head.bytes)
|
||||
|
||||
override def toString = s"${DescriptorType.PK.toString}(${publicKey.hex})"
|
||||
override def toString =
|
||||
s"${ScriptDescriptorType.PK.toString}(${publicKey.hex})"
|
||||
|
||||
}
|
||||
|
||||
|
@ -1343,7 +1347,8 @@ object WitnessScriptPubKeyV0 extends ScriptFactory[WitnessScriptPubKeyV0] {
|
|||
*/
|
||||
sealed abstract class P2WPKHWitnessSPKV0 extends WitnessScriptPubKeyV0 {
|
||||
def pubKeyHash: Sha256Hash160Digest = Sha256Hash160Digest(asm(2).bytes)
|
||||
override def toString = s"${DescriptorType.WPKH.toString}(${pubKeyHash.hex})"
|
||||
override def toString =
|
||||
s"${ScriptDescriptorType.WPKH.toString}(${pubKeyHash.hex})"
|
||||
}
|
||||
|
||||
object P2WPKHWitnessSPKV0 extends ScriptFactory[P2WPKHWitnessSPKV0] {
|
||||
|
@ -1395,7 +1400,8 @@ object P2WPKHWitnessSPKV0 extends ScriptFactory[P2WPKHWitnessSPKV0] {
|
|||
*/
|
||||
sealed abstract class P2WSHWitnessSPKV0 extends WitnessScriptPubKeyV0 {
|
||||
def scriptHash: Sha256Digest = Sha256Digest(asm(2).bytes)
|
||||
override def toString = s"${DescriptorType.WSH.toString}(${scriptHash.hex})"
|
||||
override def toString =
|
||||
s"${ScriptDescriptorType.WSH.toString}(${scriptHash.hex})"
|
||||
}
|
||||
|
||||
object P2WSHWitnessSPKV0 extends ScriptFactory[P2WSHWitnessSPKV0] {
|
||||
|
@ -1449,7 +1455,7 @@ case class TaprootScriptPubKey(override val asm: Vector[ScriptToken])
|
|||
XOnlyPubKey.fromBytes(asm(2).bytes)
|
||||
}
|
||||
|
||||
override def toString = s"${DescriptorType.TR.toString}(${pubKey.hex})"
|
||||
override def toString = s"${ScriptDescriptorType.TR.toString}(${pubKey.hex})"
|
||||
}
|
||||
|
||||
object TaprootScriptPubKey extends ScriptFactory[TaprootScriptPubKey] {
|
||||
|
|
|
@ -2,7 +2,7 @@ package org.bitcoins.core.protocol.script.descriptor
|
|||
|
||||
import org.bitcoins.core.config.NetworkParameters
|
||||
import org.bitcoins.core.number.{UInt64, UInt8}
|
||||
import org.bitcoins.core.protocol.Bech32Address
|
||||
import org.bitcoins.core.protocol.{Bech32Address, BitcoinAddress}
|
||||
import org.bitcoins.core.protocol.script.*
|
||||
import org.bitcoins.core.util.Bech32
|
||||
import org.bitcoins.crypto.{ECPrivateKey, PublicKey, StringFactory}
|
||||
|
@ -16,7 +16,7 @@ sealed abstract class Descriptor {
|
|||
|
||||
def expression: DescriptorExpression
|
||||
def checksum: Option[String]
|
||||
|
||||
def scriptPubKey: ScriptPubKey
|
||||
override def toString: String = {
|
||||
val checksumStr = checksum match {
|
||||
case Some(c) => "#" + c
|
||||
|
@ -128,6 +128,14 @@ case class ComboDescriptorCompressed(
|
|||
val p2shp2wpkh: P2SHScriptPubKey = P2SHScriptPubKey(p2wpkh)
|
||||
}
|
||||
|
||||
case class AddressDescriptor(
|
||||
expression: AddressExpression,
|
||||
checksum: Option[String])
|
||||
extends Descriptor {
|
||||
val address: BitcoinAddress = expression.address
|
||||
override val scriptPubKey: ScriptPubKey = address.scriptPubKey
|
||||
}
|
||||
|
||||
sealed abstract class DescriptorFactory[
|
||||
T <: Descriptor,
|
||||
E <: DescriptorExpression,
|
||||
|
@ -167,9 +175,10 @@ sealed abstract class DescriptorFactory[
|
|||
object RawDescriptor
|
||||
extends DescriptorFactory[RawDescriptor,
|
||||
RawScriptExpression,
|
||||
DescriptorType.Raw.type] {
|
||||
ScriptDescriptorType.Raw.type] {
|
||||
|
||||
override val descriptorType: DescriptorType.Raw.type = DescriptorType.Raw
|
||||
override val descriptorType: ScriptDescriptorType.Raw.type =
|
||||
ScriptDescriptorType.Raw
|
||||
|
||||
override protected def parseValidExpression(
|
||||
iter: DescriptorIterator): RawScriptExpression = {
|
||||
|
@ -187,8 +196,9 @@ object RawDescriptor
|
|||
object P2WPKHDescriptor
|
||||
extends DescriptorFactory[P2WPKHDescriptor,
|
||||
P2WPKHExpression,
|
||||
DescriptorType.WPKH.type] {
|
||||
override val descriptorType: DescriptorType.WPKH.type = DescriptorType.WPKH
|
||||
ScriptDescriptorType.WPKH.type] {
|
||||
override val descriptorType: ScriptDescriptorType.WPKH.type =
|
||||
ScriptDescriptorType.WPKH
|
||||
|
||||
override def parseValidExpression(
|
||||
iter: DescriptorIterator): P2WPKHExpression = {
|
||||
|
@ -226,8 +236,9 @@ object P2WPKHDescriptor
|
|||
object P2WSHDescriptor
|
||||
extends DescriptorFactory[P2WSHDescriptor,
|
||||
P2WSHExpression,
|
||||
DescriptorType.WSH.type] {
|
||||
override val descriptorType: DescriptorType.WSH.type = DescriptorType.WSH
|
||||
ScriptDescriptorType.WSH.type] {
|
||||
override val descriptorType: ScriptDescriptorType.WSH.type =
|
||||
ScriptDescriptorType.WSH
|
||||
|
||||
override protected def parseValidExpression(
|
||||
iter: DescriptorIterator): P2WSHExpression = {
|
||||
|
@ -245,8 +256,9 @@ object P2WSHDescriptor
|
|||
object P2PKDescriptor
|
||||
extends DescriptorFactory[P2PKDescriptor[PublicKey],
|
||||
P2PKScriptExpression[PublicKey],
|
||||
DescriptorType.PK.type] {
|
||||
override val descriptorType: DescriptorType.PK.type = DescriptorType.PK
|
||||
ScriptDescriptorType.PK.type] {
|
||||
override val descriptorType: ScriptDescriptorType.PK.type =
|
||||
ScriptDescriptorType.PK
|
||||
|
||||
override protected def parseValidExpression(
|
||||
iter: DescriptorIterator): P2PKScriptExpression[PublicKey] = {
|
||||
|
@ -264,8 +276,9 @@ object P2PKDescriptor
|
|||
object P2PKHDescriptor
|
||||
extends DescriptorFactory[P2PKHDescriptor,
|
||||
P2PKHScriptExpression,
|
||||
DescriptorType.PKH.type] {
|
||||
override val descriptorType: DescriptorType.PKH.type = DescriptorType.PKH
|
||||
ScriptDescriptorType.PKH.type] {
|
||||
override val descriptorType: ScriptDescriptorType.PKH.type =
|
||||
ScriptDescriptorType.PKH
|
||||
|
||||
override protected def parseValidExpression(
|
||||
iter: DescriptorIterator): P2PKHScriptExpression = {
|
||||
|
@ -283,8 +296,9 @@ object P2PKHDescriptor
|
|||
object MultisigDescriptor
|
||||
extends DescriptorFactory[MultisigDescriptor,
|
||||
MultisigExpression,
|
||||
DescriptorType.Multi.type] {
|
||||
override val descriptorType: DescriptorType.Multi.type = DescriptorType.Multi
|
||||
ScriptDescriptorType.Multi.type] {
|
||||
override val descriptorType: ScriptDescriptorType.Multi.type =
|
||||
ScriptDescriptorType.Multi
|
||||
|
||||
override protected def parseValidExpression(
|
||||
iter: DescriptorIterator): MultisigExpression = {
|
||||
|
@ -302,10 +316,10 @@ object MultisigDescriptor
|
|||
object SortedMultisigDescriptor
|
||||
extends DescriptorFactory[SortedMultisigDescriptor,
|
||||
SortedMultisigExpression,
|
||||
DescriptorType.SortedMulti.type] {
|
||||
ScriptDescriptorType.SortedMulti.type] {
|
||||
|
||||
override val descriptorType: DescriptorType.SortedMulti.type =
|
||||
DescriptorType.SortedMulti
|
||||
override val descriptorType: ScriptDescriptorType.SortedMulti.type =
|
||||
ScriptDescriptorType.SortedMulti
|
||||
|
||||
override protected def parseValidExpression(
|
||||
iter: DescriptorIterator): SortedMultisigExpression = {
|
||||
|
@ -323,8 +337,9 @@ object SortedMultisigDescriptor
|
|||
object P2SHDescriptor
|
||||
extends DescriptorFactory[P2SHDescriptor,
|
||||
P2SHExpression,
|
||||
DescriptorType.SH.type] {
|
||||
override val descriptorType: DescriptorType.SH.type = DescriptorType.SH
|
||||
ScriptDescriptorType.SH.type] {
|
||||
override val descriptorType: ScriptDescriptorType.SH.type =
|
||||
ScriptDescriptorType.SH
|
||||
|
||||
override protected def parseValidExpression(
|
||||
iter: DescriptorIterator): P2SHExpression = {
|
||||
|
@ -352,8 +367,9 @@ object P2SHDescriptor
|
|||
object ComboDescriptor
|
||||
extends DescriptorFactory[ComboDescriptor,
|
||||
ComboExpression,
|
||||
DescriptorType.Combo.type] {
|
||||
override val descriptorType: DescriptorType.Combo.type = DescriptorType.Combo
|
||||
ScriptDescriptorType.Combo.type] {
|
||||
override val descriptorType: ScriptDescriptorType.Combo.type =
|
||||
ScriptDescriptorType.Combo
|
||||
|
||||
override protected def parseValidExpression(
|
||||
iter: DescriptorIterator): ComboExpression = {
|
||||
|
@ -372,8 +388,9 @@ object ComboDescriptor
|
|||
object TaprootDescriptor
|
||||
extends DescriptorFactory[TaprootDescriptor,
|
||||
TreeExpression,
|
||||
DescriptorType.TR.type] {
|
||||
override val descriptorType: DescriptorType.TR.type = DescriptorType.TR
|
||||
ScriptDescriptorType.TR.type] {
|
||||
override val descriptorType: ScriptDescriptorType.TR.type =
|
||||
ScriptDescriptorType.TR
|
||||
|
||||
override protected def parseValidExpression(
|
||||
iter: DescriptorIterator): TreeExpression = {
|
||||
|
@ -395,22 +412,22 @@ object ScriptDescriptor extends StringFactory[ScriptDescriptor] {
|
|||
? <: ScriptExpression,
|
||||
? <: DescriptorType]] = {
|
||||
Map(
|
||||
DescriptorType.Raw -> RawDescriptor,
|
||||
DescriptorType.WPKH -> P2WPKHDescriptor,
|
||||
DescriptorType.WSH -> P2WSHDescriptor,
|
||||
DescriptorType.PK -> P2PKDescriptor,
|
||||
DescriptorType.SH -> P2SHDescriptor,
|
||||
DescriptorType.PKH -> P2PKHDescriptor,
|
||||
DescriptorType.Multi -> MultisigDescriptor,
|
||||
DescriptorType.SortedMulti -> SortedMultisigDescriptor,
|
||||
DescriptorType.Combo -> ComboDescriptor,
|
||||
DescriptorType.TR -> TaprootDescriptor
|
||||
ScriptDescriptorType.Raw -> RawDescriptor,
|
||||
ScriptDescriptorType.WPKH -> P2WPKHDescriptor,
|
||||
ScriptDescriptorType.WSH -> P2WSHDescriptor,
|
||||
ScriptDescriptorType.PK -> P2PKDescriptor,
|
||||
ScriptDescriptorType.SH -> P2SHDescriptor,
|
||||
ScriptDescriptorType.PKH -> P2PKHDescriptor,
|
||||
ScriptDescriptorType.Multi -> MultisigDescriptor,
|
||||
ScriptDescriptorType.SortedMulti -> SortedMultisigDescriptor,
|
||||
ScriptDescriptorType.Combo -> ComboDescriptor,
|
||||
ScriptDescriptorType.TR -> TaprootDescriptor
|
||||
)
|
||||
}
|
||||
|
||||
override def fromString(string: String): ScriptDescriptor = {
|
||||
val iter = DescriptorIterator(string)
|
||||
val t = iter.takeDescriptorType()
|
||||
val t = iter.takeScriptDescriptorType()
|
||||
t match {
|
||||
case s: ScriptDescriptorType =>
|
||||
map
|
||||
|
@ -422,6 +439,25 @@ object ScriptDescriptor extends StringFactory[ScriptDescriptor] {
|
|||
}
|
||||
}
|
||||
|
||||
object AddressDescriptor
|
||||
extends DescriptorFactory[AddressDescriptor,
|
||||
AddressExpression,
|
||||
DescriptorType.Addr.type] {
|
||||
|
||||
override def descriptorType: DescriptorType.Addr.type = DescriptorType.Addr
|
||||
|
||||
override protected def parseValidExpression(
|
||||
iter: DescriptorIterator): AddressExpression = {
|
||||
iter.takeAddressExpression()
|
||||
}
|
||||
|
||||
override protected def createDescriptor(
|
||||
e: AddressExpression,
|
||||
checksum: Option[String]): AddressDescriptor = {
|
||||
AddressDescriptor(e, checksum)
|
||||
}
|
||||
}
|
||||
|
||||
object Descriptor extends StringFactory[Descriptor] {
|
||||
|
||||
final val charset: Vector[Char] = {
|
||||
|
@ -440,6 +476,8 @@ object Descriptor extends StringFactory[Descriptor] {
|
|||
t match {
|
||||
case _: ScriptDescriptorType =>
|
||||
ScriptDescriptor.fromString(string)
|
||||
case DescriptorType.Addr =>
|
||||
AddressDescriptor.fromString(string)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,10 @@ import org.bitcoins.core.crypto.{
|
|||
ExtPublicKey
|
||||
}
|
||||
import org.bitcoins.core.hd.{BIP32Node, BIP32Path, HardenedType}
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.script.*
|
||||
import org.bitcoins.core.script.ScriptType
|
||||
import org.bitcoins.crypto._
|
||||
import org.bitcoins.crypto.*
|
||||
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
|
@ -490,7 +491,7 @@ sealed abstract class MultisigScriptExpression
|
|||
|
||||
override def source: MultisigKeyExpression
|
||||
|
||||
def isSorted: Boolean = descriptorType == DescriptorType.SortedMulti
|
||||
def isSorted: Boolean = descriptorType == ScriptDescriptorType.SortedMulti
|
||||
|
||||
}
|
||||
|
||||
|
@ -531,7 +532,8 @@ sealed trait TapscriptTreeExpressionSource extends ExpressionSource {
|
|||
*/
|
||||
case class RawScriptExpression(scriptPubKey: RawScriptPubKey)
|
||||
extends RawSPKScriptExpression {
|
||||
override val descriptorType: DescriptorType.Raw.type = DescriptorType.Raw
|
||||
override val descriptorType: ScriptDescriptorType.Raw.type =
|
||||
ScriptDescriptorType.Raw
|
||||
|
||||
override def toString: String = {
|
||||
s"${descriptorType.toString}(${scriptPubKey.asmHex})"
|
||||
|
@ -541,7 +543,8 @@ case class RawScriptExpression(scriptPubKey: RawScriptPubKey)
|
|||
case class P2PKHScriptExpression(source: SingleECPublicKeyExpression)
|
||||
extends RawSPKScriptExpression
|
||||
with KeyExpressionScriptExpression[ECPublicKey] {
|
||||
override val descriptorType: DescriptorType.PKH.type = DescriptorType.PKH
|
||||
override val descriptorType: ScriptDescriptorType.PKH.type =
|
||||
ScriptDescriptorType.PKH
|
||||
|
||||
override val scriptPubKey: P2PKHScriptPubKey = {
|
||||
val pub = source.key match {
|
||||
|
@ -555,7 +558,8 @@ case class P2PKHScriptExpression(source: SingleECPublicKeyExpression)
|
|||
case class P2PKScriptExpression[T <: PublicKey](source: SingleKeyExpression[T])
|
||||
extends RawSPKScriptExpression
|
||||
with KeyExpressionScriptExpression[T] {
|
||||
override val descriptorType: DescriptorType.PK.type = DescriptorType.PK
|
||||
override val descriptorType: ScriptDescriptorType.PK.type =
|
||||
ScriptDescriptorType.PK
|
||||
|
||||
override val scriptPubKey: P2PKScriptPubKey = {
|
||||
val pub = source match {
|
||||
|
@ -575,7 +579,8 @@ case class P2PKScriptExpression[T <: PublicKey](source: SingleKeyExpression[T])
|
|||
case class P2WPKHExpression(source: SingleECPublicKeyExpression)
|
||||
extends ScriptExpression
|
||||
with KeyExpressionScriptExpression[ECPublicKey] {
|
||||
override val descriptorType: DescriptorType.WPKH.type = DescriptorType.WPKH
|
||||
override val descriptorType: ScriptDescriptorType.WPKH.type =
|
||||
ScriptDescriptorType.WPKH
|
||||
|
||||
override val scriptPubKey: P2WPKHWitnessSPKV0 = {
|
||||
val pubKey = source.key match {
|
||||
|
@ -589,7 +594,8 @@ case class P2WPKHExpression(source: SingleECPublicKeyExpression)
|
|||
case class P2WSHExpression(source: RawSPKScriptExpression)
|
||||
extends ScriptExpression
|
||||
with NestedScriptExpression {
|
||||
override val descriptorType: DescriptorType.WSH.type = DescriptorType.WSH
|
||||
override val descriptorType: ScriptDescriptorType.WSH.type =
|
||||
ScriptDescriptorType.WSH
|
||||
|
||||
override val scriptPubKey: P2WSHWitnessSPKV0 = {
|
||||
P2WSHWitnessSPKV0(source.scriptPubKey)
|
||||
|
@ -599,7 +605,8 @@ case class P2WSHExpression(source: RawSPKScriptExpression)
|
|||
case class P2SHExpression(source: ScriptExpression)
|
||||
extends ScriptExpression
|
||||
with NestedScriptExpression {
|
||||
override val descriptorType: DescriptorType.SH.type = DescriptorType.SH
|
||||
override val descriptorType: ScriptDescriptorType.SH.type =
|
||||
ScriptDescriptorType.SH
|
||||
|
||||
override val scriptPubKey: P2SHScriptPubKey = {
|
||||
source.scriptPubKey match {
|
||||
|
@ -620,7 +627,8 @@ case class P2SHExpression(source: ScriptExpression)
|
|||
case class MultisigExpression(source: MultisigKeyExpression)
|
||||
extends MultisigScriptExpression
|
||||
with KeyExpressionScriptExpression[ECPublicKey] {
|
||||
override val descriptorType: DescriptorType.Multi.type = DescriptorType.Multi
|
||||
override val descriptorType: ScriptDescriptorType.Multi.type =
|
||||
ScriptDescriptorType.Multi
|
||||
|
||||
override val scriptPubKey: MultiSignatureScriptPubKey = {
|
||||
MultiSignatureScriptPubKey(source.numSigsRequired, source.pubKeys)
|
||||
|
@ -643,8 +651,8 @@ case class SortedMultisigExpression(source: MultisigKeyExpression)
|
|||
extends MultisigScriptExpression
|
||||
with KeyExpressionScriptExpression[ECPublicKey] {
|
||||
|
||||
override val descriptorType: DescriptorType.SortedMulti.type =
|
||||
DescriptorType.SortedMulti
|
||||
override val descriptorType: ScriptDescriptorType.SortedMulti.type =
|
||||
ScriptDescriptorType.SortedMulti
|
||||
|
||||
override val scriptPubKey: MultiSignatureScriptPubKey = {
|
||||
MultiSignatureScriptPubKey(source.numSigsRequired, source.sortedPubKeys)
|
||||
|
@ -669,7 +677,7 @@ case class ComboExpression(
|
|||
scriptType: ScriptType = ScriptType.PUBKEYHASH)
|
||||
extends ScriptExpression
|
||||
with KeyExpressionScriptExpression[ECPublicKey] {
|
||||
override val descriptorType: DescriptorType = DescriptorType.Combo
|
||||
override val descriptorType: DescriptorType = ScriptDescriptorType.Combo
|
||||
|
||||
override val scriptPubKey: ScriptPubKey = {
|
||||
scriptType match {
|
||||
|
@ -694,25 +702,27 @@ object ScriptExpressionECKey extends StringFactory[ScriptExpression] {
|
|||
|
||||
override def fromString(string: String): ScriptExpression = {
|
||||
val iter = DescriptorIterator(string)
|
||||
val descriptorType = iter.takeDescriptorType()
|
||||
val descriptorType = iter.takeScriptDescriptorType()
|
||||
val expression: ScriptExpression = descriptorType match {
|
||||
case DescriptorType.PKH =>
|
||||
case ScriptDescriptorType.PKH =>
|
||||
P2PKHScriptExpression(iter.takeSingleECKeyExpression())
|
||||
case DescriptorType.WPKH =>
|
||||
case ScriptDescriptorType.WPKH =>
|
||||
P2WPKHExpression(iter.takeSingleECKeyExpression())
|
||||
case DescriptorType.WSH =>
|
||||
case ScriptDescriptorType.WSH =>
|
||||
P2WSHExpression(iter.takeRawSPKScriptExpression())
|
||||
case DescriptorType.SH => P2SHExpression(iter.takeScriptExpressionECKey())
|
||||
case DescriptorType.Raw => RawScriptExpression(iter.takeRawScriptPubKey())
|
||||
case DescriptorType.PK =>
|
||||
case ScriptDescriptorType.SH =>
|
||||
P2SHExpression(iter.takeScriptExpressionECKey())
|
||||
case ScriptDescriptorType.Raw =>
|
||||
RawScriptExpression(iter.takeRawScriptPubKey())
|
||||
case ScriptDescriptorType.PK =>
|
||||
P2PKScriptExpression(iter.takeSingleECKeyExpression())
|
||||
case DescriptorType.Multi =>
|
||||
case ScriptDescriptorType.Multi =>
|
||||
MultisigExpression(iter.takeMultisigKeyExpression())
|
||||
case DescriptorType.SortedMulti =>
|
||||
case ScriptDescriptorType.SortedMulti =>
|
||||
SortedMultisigExpression(iter.takeMultisigKeyExpression())
|
||||
case DescriptorType.Combo =>
|
||||
case ScriptDescriptorType.Combo =>
|
||||
ComboExpression(iter.takeSingleECKeyExpression())
|
||||
case DescriptorType.TR =>
|
||||
case ScriptDescriptorType.TR =>
|
||||
sys.error(
|
||||
s"Cannot create tapscript expression's with ECPublicKey, got=$string")
|
||||
}
|
||||
|
@ -724,17 +734,19 @@ object ScriptExpressionXOnlyKey extends StringFactory[ScriptExpression] {
|
|||
|
||||
override def fromString(string: String): ScriptExpression = {
|
||||
val iter = DescriptorIterator(string)
|
||||
val descriptorType = iter.takeDescriptorType()
|
||||
val descriptorType = iter.takeScriptDescriptorType()
|
||||
val expression: ScriptExpression = descriptorType match {
|
||||
case DescriptorType.Raw => RawScriptExpression(iter.takeRawScriptPubKey())
|
||||
case DescriptorType.PK =>
|
||||
case ScriptDescriptorType.Raw =>
|
||||
RawScriptExpression(iter.takeRawScriptPubKey())
|
||||
case ScriptDescriptorType.PK =>
|
||||
P2PKScriptExpression(iter.takeSingleXOnlyPubKeyExpression())
|
||||
case DescriptorType.Multi =>
|
||||
case ScriptDescriptorType.Multi =>
|
||||
MultisigExpression(iter.takeMultisigKeyExpression())
|
||||
case DescriptorType.SortedMulti =>
|
||||
case ScriptDescriptorType.SortedMulti =>
|
||||
SortedMultisigExpression(iter.takeMultisigKeyExpression())
|
||||
case x @ (DescriptorType.Combo | DescriptorType.TR | DescriptorType.SH |
|
||||
DescriptorType.WSH | DescriptorType.WPKH | DescriptorType.PKH) =>
|
||||
case x @ (ScriptDescriptorType.Combo | ScriptDescriptorType.TR |
|
||||
ScriptDescriptorType.SH | ScriptDescriptorType.WSH |
|
||||
ScriptDescriptorType.WPKH | ScriptDescriptorType.PKH) =>
|
||||
sys.error(
|
||||
s"Cannot create tapscript descriptor for descriptorType=$x, got=$string")
|
||||
}
|
||||
|
@ -746,7 +758,8 @@ object ScriptExpressionXOnlyKey extends StringFactory[ScriptExpression] {
|
|||
* https://github.com/bitcoin/bips/blob/master/bip-0386.mediawiki
|
||||
*/
|
||||
sealed abstract class TreeExpression extends ScriptExpression {
|
||||
override def descriptorType: DescriptorType.TR.type = DescriptorType.TR
|
||||
override def descriptorType: ScriptDescriptorType.TR.type =
|
||||
ScriptDescriptorType.TR
|
||||
override def scriptPubKey: TaprootScriptPubKey
|
||||
}
|
||||
|
||||
|
@ -782,3 +795,10 @@ case class ScriptPathTreeExpression(
|
|||
s"${descriptorType.toString}(${keyPath.source.toString},${source.toString()})"
|
||||
}
|
||||
}
|
||||
|
||||
case class AddressExpression(address: BitcoinAddress)
|
||||
extends DescriptorExpression {
|
||||
override def toString: String = {
|
||||
s"${DescriptorType.Addr.toString}(${address.toString})"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@ package org.bitcoins.core.protocol.script.descriptor
|
|||
|
||||
import org.bitcoins.core.crypto.{ECPrivateKeyUtil, ExtKey, ExtPublicKey}
|
||||
import org.bitcoins.core.hd.{BIP32Path, HardenedType}
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.script.{
|
||||
MultiSignatureScriptPubKey,
|
||||
RawScriptPubKey
|
||||
}
|
||||
import org.bitcoins.crypto._
|
||||
import org.bitcoins.crypto.*
|
||||
|
||||
case class DescriptorIterator(descriptor: String) {
|
||||
private var index: Int = 0
|
||||
|
@ -20,6 +21,12 @@ case class DescriptorIterator(descriptor: String) {
|
|||
()
|
||||
}
|
||||
|
||||
def takeScriptDescriptorType(): ScriptDescriptorType = {
|
||||
val t = ScriptDescriptorType.fromString(current)
|
||||
skip(t.toString.length)
|
||||
skip(1)
|
||||
t
|
||||
}
|
||||
def takeDescriptorType(): DescriptorType = {
|
||||
val t = DescriptorType.fromString(current)
|
||||
skip(t.toString.length)
|
||||
|
@ -247,4 +254,10 @@ case class DescriptorIterator(descriptor: String) {
|
|||
}
|
||||
expression
|
||||
}
|
||||
|
||||
def takeAddressExpression(): AddressExpression = {
|
||||
val addr = BitcoinAddress.fromString(current)
|
||||
skip(addr.toString.length)
|
||||
AddressExpression(addr)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,19 @@ sealed abstract class ScriptDescriptorType extends DescriptorType {
|
|||
def scriptType: ScriptType
|
||||
}
|
||||
|
||||
object DescriptorType extends StringFactory[DescriptorType] {
|
||||
|
||||
object ScriptDescriptorType extends StringFactory[ScriptDescriptorType] {
|
||||
private[descriptor] val all: Vector[ScriptDescriptorType] = Vector(
|
||||
PK,
|
||||
PKH,
|
||||
WPKH,
|
||||
WSH,
|
||||
TR,
|
||||
Multi,
|
||||
SortedMulti,
|
||||
Raw,
|
||||
SH,
|
||||
Combo
|
||||
)
|
||||
case object PK extends ScriptDescriptorType {
|
||||
override val scriptType: org.bitcoins.core.script.ScriptType.PUBKEY.type =
|
||||
ScriptType.PUBKEY
|
||||
|
@ -78,17 +89,28 @@ object DescriptorType extends StringFactory[DescriptorType] {
|
|||
override val toString: String = "combo"
|
||||
}
|
||||
|
||||
private val all: Vector[DescriptorType] = Vector(
|
||||
PK,
|
||||
PKH,
|
||||
WPKH,
|
||||
WSH,
|
||||
TR,
|
||||
Multi,
|
||||
SortedMulti,
|
||||
Raw,
|
||||
SH,
|
||||
Combo
|
||||
override def fromStringOpt(string: String): Option[ScriptDescriptorType] = {
|
||||
val (dType, _) = string.span(_ != '(')
|
||||
all.find(d => dType == d.toString)
|
||||
}
|
||||
|
||||
override def fromString(string: String): ScriptDescriptorType = {
|
||||
fromStringOpt(string) match {
|
||||
case Some(d) => d
|
||||
case None =>
|
||||
sys.error(s"Could not find descriptor type for string=$string")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object DescriptorType extends StringFactory[DescriptorType] {
|
||||
|
||||
case object Addr extends DescriptorType {
|
||||
override val toString: String = "addr"
|
||||
}
|
||||
|
||||
private val all: Vector[DescriptorType] = ScriptDescriptorType.all ++ Vector(
|
||||
Addr
|
||||
)
|
||||
|
||||
override def fromStringOpt(string: String): Option[DescriptorType] = {
|
||||
|
|
Loading…
Add table
Reference in a new issue