mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-03 10:46:42 +01:00
Fixes some Scaladocs (#286)
* Fixes some Scaladocs * ran scalafmt * ran test:scalafmt
This commit is contained in:
parent
a50c6c15b3
commit
abcd7c5d6d
19 changed files with 790 additions and 482 deletions
|
@ -10,7 +10,8 @@ import scala.util.{Failure, Success, Try}
|
|||
|
||||
/**
|
||||
* Created by chris on 4/6/16.
|
||||
* Represents a transaction whose input is being checked against the spending conditions of a [[ScriptPubKey]]
|
||||
* Represents a transaction whose input is being checked against the spending conditions of a
|
||||
* [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]]
|
||||
*/
|
||||
sealed abstract class TxSigComponent {
|
||||
|
||||
|
@ -31,7 +32,7 @@ sealed abstract class TxSigComponent {
|
|||
/** The scriptPubKey for which the input is being checked against */
|
||||
def scriptPubKey: ScriptPubKey = output.scriptPubKey
|
||||
|
||||
/** The amount of [[CurrencyUnit]] we are spending in this TxSigComponent */
|
||||
/** The amount of [[org.bitcoins.core.currency.CurrencyUnit CurrencyUnit]] we are spending in this TxSigComponent */
|
||||
def amount: CurrencyUnit = output.value
|
||||
|
||||
/** The flags that are needed to verify if the signature is correct */
|
||||
|
@ -42,19 +43,24 @@ sealed abstract class TxSigComponent {
|
|||
}
|
||||
|
||||
/**
|
||||
* The [[TxSigComponent]] used to evaluate the the original Satoshi transaction digest algorithm.
|
||||
* Basically this is every spk that is not a [[WitnessScriptPubKey]] EXCEPT in the case of a
|
||||
* P2SH(witness script) [[ScriptPubKey]]
|
||||
* The [[org.bitcoins.core.crypto.TxSigComponent TxSigComponent]]
|
||||
* used to evaluate the the original Satoshi transaction digest algorithm.
|
||||
* Basically this is every spk that is not a
|
||||
* [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] EXCEPT in the case of a
|
||||
* P2SH(witness script) [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]]
|
||||
*/
|
||||
sealed abstract class BaseTxSigComponent extends TxSigComponent {
|
||||
override def sigVersion = SigVersionBase
|
||||
}
|
||||
|
||||
/**
|
||||
* The [[TxSigComponent]] used to represent all the components necessarily for BIP143
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki]]
|
||||
* Examples of these [[ScriptPubKey]]'s are [[P2WPKHWitnessSPKV0]],
|
||||
* [[P2WSHWitnessSPKV0]], and P2SH(witness script)
|
||||
* The [[org.bitcoins.core.crypto.TxSigComponent TxSigComponent]]
|
||||
* used to represent all the components necessarily for
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki BIP143]].
|
||||
* Examples of these [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]]'s
|
||||
* are [[org.bitcoins.core.protocol.script.P2WPKHWitnessV0 P2WPKHWitnessSPKV0]],
|
||||
* [[org.bitcoins.core.protocol.script.P2WSHWitnessSPKV0 P2WSHWitnessSPKV0]],
|
||||
* and P2SH(witness script)
|
||||
*/
|
||||
sealed abstract class WitnessTxSigComponent extends TxSigComponent {
|
||||
|
||||
|
@ -67,7 +73,9 @@ sealed abstract class WitnessTxSigComponent extends TxSigComponent {
|
|||
override def sigVersion = SigVersionWitnessV0
|
||||
}
|
||||
|
||||
/** This represents checking the [[WitnessTransaction]] against a [[P2WPKHWitnessSPKV0]] or a [[P2WSHWitnessSPKV0]] */
|
||||
/** This represents checking the [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]]
|
||||
* against a [[org.bitcoins.core.protocol.script.P2WPKHWitnessSPKV0 P2WPKHWitnessSPKV0]] or a
|
||||
* [[org.bitcoins.core.protocol.script.P2WSHWitnessSPKV0 P2WSHWitnessSPKV0]] */
|
||||
sealed abstract class WitnessTxSigComponentRaw extends WitnessTxSigComponent {
|
||||
override def scriptPubKey: WitnessScriptPubKey =
|
||||
output.scriptPubKey.asInstanceOf[WitnessScriptPubKey]
|
||||
|
@ -77,7 +85,8 @@ sealed abstract class WitnessTxSigComponentRaw extends WitnessTxSigComponent {
|
|||
}
|
||||
}
|
||||
|
||||
/** This represents checking the [[WitnessTransaction]] against a P2SH(P2WSH) or P2SH(P2WPKH) scriptPubKey */
|
||||
/** This represents checking the [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]]
|
||||
* against a P2SH(P2WSH) or P2SH(P2WPKH) scriptPubKey */
|
||||
sealed abstract class WitnessTxSigComponentP2SH extends WitnessTxSigComponent {
|
||||
override def scriptPubKey: P2SHScriptPubKey =
|
||||
output.scriptPubKey.asInstanceOf[P2SHScriptPubKey]
|
||||
|
@ -97,8 +106,8 @@ sealed abstract class WitnessTxSigComponentP2SH extends WitnessTxSigComponent {
|
|||
case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey |
|
||||
_: MultiSignatureScriptPubKey | _: P2SHScriptPubKey |
|
||||
_: CSVScriptPubKey | _: CLTVScriptPubKey |
|
||||
_: NonStandardScriptPubKey |
|
||||
_: WitnessCommitment | EmptyScriptPubKey) =>
|
||||
_: NonStandardScriptPubKey | _: WitnessCommitment |
|
||||
EmptyScriptPubKey) =>
|
||||
Failure(new IllegalArgumentException(
|
||||
"Must have a witness scriptPubKey as redeemScript for P2SHScriptPubKey in WitnessTxSigComponentP2SH, got: " + x))
|
||||
|
||||
|
@ -114,10 +123,14 @@ sealed abstract class WitnessTxSigComponentP2SH extends WitnessTxSigComponent {
|
|||
}
|
||||
|
||||
/**
|
||||
* This represents a 'rebuilt' [[ScriptPubKey]] that was constructed from [[WitnessScriptPubKey]]
|
||||
* After the [[ScriptPubKey]] is rebuilt, we need to use that rebuilt scriptpubkey to evaluate the [[ScriptSignature]]
|
||||
* See BIP141 for more info on rebuilding P2WSH and P2WPKH scriptpubkeys
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program]]
|
||||
* This represents a 'rebuilt' [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]]
|
||||
* that was constructed from [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]]
|
||||
* After the
|
||||
* [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] is rebuilt, we need to use that rebuilt
|
||||
* scriptpubkey to evaluate the [[org.bitcoins.core.protocol.script.ScriptSignature ScriptSignature]]
|
||||
* See
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program BIP141]]
|
||||
* for more info on rebuilding P2WSH and P2WPKH scriptpubkeys
|
||||
*/
|
||||
sealed abstract class WitnessTxSigComponentRebuilt extends TxSigComponent {
|
||||
override def transaction: WitnessTransaction
|
||||
|
@ -194,8 +207,7 @@ object WitnessTxSigComponentRaw {
|
|||
case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey |
|
||||
_: MultiSignatureScriptPubKey | _: P2SHScriptPubKey |
|
||||
_: LockTimeScriptPubKey | _: NonStandardScriptPubKey |
|
||||
_: WitnessCommitment |
|
||||
EmptyScriptPubKey) =>
|
||||
_: WitnessCommitment | EmptyScriptPubKey) =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Cannot create a WitnessTxSigComponentRaw with a spk of $x")
|
||||
}
|
||||
|
@ -222,8 +234,8 @@ object WitnessTxSigComponentP2SH {
|
|||
WitnessTxSigComponentP2SHImpl(transaction, inputIndex, output, flags)
|
||||
case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey |
|
||||
_: MultiSignatureScriptPubKey | _: LockTimeScriptPubKey |
|
||||
_: NonStandardScriptPubKey |
|
||||
_: WitnessCommitment | _: WitnessScriptPubKey | EmptyScriptPubKey) =>
|
||||
_: NonStandardScriptPubKey | _: WitnessCommitment |
|
||||
_: WitnessScriptPubKey | EmptyScriptPubKey) =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Cannot create a WitnessTxSigComponentP2SH with a spk of $x")
|
||||
}
|
||||
|
|
|
@ -223,9 +223,8 @@ object Bech32Address extends AddressFactory[Bech32Address] {
|
|||
case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey |
|
||||
_: MultiSignatureScriptPubKey | _: P2SHScriptPubKey |
|
||||
_: LockTimeScriptPubKey | _: WitnessScriptPubKey |
|
||||
_: NonStandardScriptPubKey |
|
||||
_: WitnessCommitment | _: UnassignedWitnessScriptPubKey |
|
||||
EmptyScriptPubKey) =>
|
||||
_: NonStandardScriptPubKey | _: WitnessCommitment |
|
||||
_: UnassignedWitnessScriptPubKey | EmptyScriptPubKey) =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Cannot create a address for the scriptPubKey: " + x))
|
||||
|
@ -328,9 +327,8 @@ object P2PKHAddress extends AddressFactory[P2PKHAddress] {
|
|||
case p2pkh: P2PKHScriptPubKey => Success(P2PKHAddress(p2pkh, np))
|
||||
case x @ (_: P2PKScriptPubKey | _: MultiSignatureScriptPubKey |
|
||||
_: P2SHScriptPubKey | _: LockTimeScriptPubKey | _: WitnessScriptPubKey |
|
||||
_: NonStandardScriptPubKey |
|
||||
_: WitnessCommitment | _: UnassignedWitnessScriptPubKey |
|
||||
EmptyScriptPubKey) =>
|
||||
_: NonStandardScriptPubKey | _: WitnessCommitment |
|
||||
_: UnassignedWitnessScriptPubKey | EmptyScriptPubKey) =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Cannot create a address for the scriptPubKey: " + x))
|
||||
|
@ -398,9 +396,9 @@ object P2SHAddress extends AddressFactory[P2SHAddress] {
|
|||
case p2sh: P2SHScriptPubKey => Success(P2SHAddress(p2sh, np))
|
||||
case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey |
|
||||
_: MultiSignatureScriptPubKey | _: LockTimeScriptPubKey |
|
||||
_: WitnessScriptPubKey |
|
||||
_: NonStandardScriptPubKey | _: WitnessCommitment |
|
||||
_: UnassignedWitnessScriptPubKey | EmptyScriptPubKey) =>
|
||||
_: WitnessScriptPubKey | _: NonStandardScriptPubKey |
|
||||
_: WitnessCommitment | _: UnassignedWitnessScriptPubKey |
|
||||
EmptyScriptPubKey) =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Cannot create a address for the scriptPubKey: " + x))
|
||||
|
@ -439,9 +437,9 @@ object BitcoinAddress extends AddressFactory[BitcoinAddress] {
|
|||
case p2sh: P2SHScriptPubKey => Success(P2SHAddress(p2sh, np))
|
||||
case witSPK: WitnessScriptPubKey => Success(Bech32Address(witSPK, np))
|
||||
case x @ (_: P2PKScriptPubKey | _: MultiSignatureScriptPubKey |
|
||||
_: LockTimeScriptPubKey |
|
||||
_: NonStandardScriptPubKey | _: WitnessCommitment |
|
||||
_: UnassignedWitnessScriptPubKey | EmptyScriptPubKey) =>
|
||||
_: LockTimeScriptPubKey | _: NonStandardScriptPubKey |
|
||||
_: WitnessCommitment | _: UnassignedWitnessScriptPubKey |
|
||||
EmptyScriptPubKey) =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Cannot create a address for the scriptPubKey: " + x))
|
||||
|
|
|
@ -106,11 +106,10 @@ sealed abstract class ChainParams {
|
|||
val const = ScriptConstant(timestampBytes)
|
||||
|
||||
val asm = {
|
||||
List(
|
||||
BytesToPushOntoStack(4),
|
||||
ScriptConstant("ffff001d"),
|
||||
BytesToPushOntoStack(1),
|
||||
ScriptConstant("04")) ++
|
||||
List(BytesToPushOntoStack(4),
|
||||
ScriptConstant("ffff001d"),
|
||||
BytesToPushOntoStack(1),
|
||||
ScriptConstant("04")) ++
|
||||
BitcoinScriptUtil.calculatePushOp(const) ++
|
||||
List(const)
|
||||
}
|
||||
|
|
|
@ -10,15 +10,16 @@ import scala.math._
|
|||
|
||||
/**
|
||||
* Created by chris on 8/7/16.
|
||||
* Represents a subset of known txids inside of a [[Block]]
|
||||
* Represents a subset of known txids inside of a [[org.bitcoins.core.protocol.blockchain.Block Block]]
|
||||
* in a way that allows recovery of the txids & merkle root
|
||||
* without having to store them all explicitly.
|
||||
* See BIP37 for more details
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#partial-merkle-branch-format]]
|
||||
* See
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#partial-merkle-branch-format BIP37]]
|
||||
* for more details
|
||||
*
|
||||
* Encoding procedure:
|
||||
* [[https://bitcoin.org/en/developer-reference#creating-a-merkleblock-message]]
|
||||
* [[https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L78]]
|
||||
* [[https://bitcoin.org/en/developer-reference#creating-a-merkleblock-message "Bitcoin.org: creating a merkleblock message"]]
|
||||
* [[https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L78 "Bitcoin Core: merkleblock.cpp"]]
|
||||
* Traverse the tree in depth first order, storing a bit for each traversal.
|
||||
* This bit signifies if the node is a parent of at least one
|
||||
* matched leaf txid (or a matched leaf txid) itself.
|
||||
|
@ -27,8 +28,8 @@ import scala.math._
|
|||
* Otherwise no hash is stored, but we recurse all of this node's child branches.
|
||||
*
|
||||
* Decoding procedure:
|
||||
* [[https://bitcoin.org/en/developer-reference#parsing-a-merkleblock-message]]
|
||||
* [[https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L96]]
|
||||
* [[https://bitcoin.org/en/developer-reference#parsing-a-merkleblock-message "Bitcoin.org: parsing a merkleblock message"]]
|
||||
* [[https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L96 "Bitcoin Core: merkleblock.cpp"]]
|
||||
* The same depth first decoding procedure is performed, but we consume the
|
||||
* bits and hashes that we used during encoding
|
||||
*/
|
||||
|
@ -37,10 +38,10 @@ sealed trait PartialMerkleTree extends BitcoinSLogger {
|
|||
/** The total number of transactions in this block */
|
||||
def transactionCount: UInt32
|
||||
|
||||
/** The actual scala integer representation for [[transactionCount]] */
|
||||
/** The actual scala integer representation for `transactionCount` */
|
||||
private def numTransactions: Int = transactionCount.toInt
|
||||
|
||||
/** Maximum height of the [[tree]] */
|
||||
/** Maximum height of the `tree` */
|
||||
private def maxHeight = PartialMerkleTree.calcMaxHeight(numTransactions)
|
||||
|
||||
/** The actual tree used to represent this partial merkle tree*/
|
||||
|
@ -154,8 +155,10 @@ object PartialMerkleTree {
|
|||
|
||||
/**
|
||||
* @param txMatches indicates whether the given txid matches the bloom filter, the full merkle branch needs
|
||||
* to be included inside of the [[PartialMerkleTree]]
|
||||
* @return the binary tree that represents the partial merkle tree, the bits needed to reconstruct this partial merkle tree, and the hashes needed to be inserted
|
||||
* to be included inside of the
|
||||
* [[org.bitcoins.core.protocol.blockchain.PartialMerkleTree PartialMerkleTree]]
|
||||
* @return the binary tree that represents the partial merkle tree, the bits needed to reconstruct this partial
|
||||
* merkle tree, and the hashes needed to be inserted
|
||||
* according to the flags inside of bits
|
||||
*/
|
||||
private def build(txMatches: Seq[(Boolean, DoubleSha256Digest)]): (
|
||||
|
@ -164,7 +167,7 @@ object PartialMerkleTree {
|
|||
val maxHeight = calcMaxHeight(txMatches.size)
|
||||
|
||||
/**
|
||||
* This loops through our merkle tree building [[bits]] so we can instruct another node how to create the partial merkle tree
|
||||
* This loops through our merkle tree building `bits` so we can instruct another node how to create the partial merkle tree
|
||||
* [[https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L78]]
|
||||
* @param bits the accumulator for bits indicating how to reconsctruct the partial merkle tree
|
||||
* @param hashes the relevant hashes used with bits to reconstruct the merkle tree
|
||||
|
@ -261,13 +264,13 @@ object PartialMerkleTree {
|
|||
}
|
||||
|
||||
/**
|
||||
* This constructor creates a partial from this given [[BinaryTree]]
|
||||
* You probably don't want to use this constructor, unless you manually constructed [[bits]] and the [[tree]]
|
||||
* This constructor creates a partial from this given [[org.bitcoins.core.util.BinaryTree BinaryTree]]
|
||||
* You probably don't want to use this constructor, unless you manually constructed `bits` and the `tree`
|
||||
* by hand
|
||||
* @param tree the partial merkle tree -- note this is NOT the full merkle tree
|
||||
* @param transactionCount the number of transactions there initially was in the full merkle tree
|
||||
* @param bits the path to the matches in the partial merkle tree
|
||||
* @param hashes the hashes used to reconstruct the binary tree according to [[bits]]
|
||||
* @param hashes the hashes used to reconstruct the binary tree according to `bits`
|
||||
*/
|
||||
def apply(
|
||||
tree: BinaryTree[DoubleSha256Digest],
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
|
||||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.core.protocol.{ CompactSizeUInt, NetworkElement }
|
||||
import org.bitcoins.core.protocol.{CompactSizeUInt, NetworkElement}
|
||||
import org.bitcoins.core.script.constant.ScriptToken
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
|
||||
/** This is meant to be a super type for
|
||||
* scripts in the bitcoin protocol. This gives us
|
||||
* access to the asm representation, and how to serialize the script
|
||||
|
@ -34,4 +32,4 @@ abstract class Script extends NetworkElement {
|
|||
/** The full byte serialization for a script on the network */
|
||||
override val bytes: ByteVector = compactSizeUInt.bytes ++ asmBytes
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,11 @@ import scodec.bits.ByteVector
|
|||
trait ScriptFactory[T <: Script] extends Factory[T] {
|
||||
|
||||
/** Builds a script from the given asm with the given constructor if the invariant holds true, else throws an error */
|
||||
def buildScript(asm: Vector[ScriptToken], constructor: Vector[ScriptToken] => T,
|
||||
invariant: Seq[ScriptToken] => Boolean, errorMsg: String): T = {
|
||||
def buildScript(
|
||||
asm: Vector[ScriptToken],
|
||||
constructor: Vector[ScriptToken] => T,
|
||||
invariant: Seq[ScriptToken] => Boolean,
|
||||
errorMsg: String): T = {
|
||||
if (invariant(asm)) {
|
||||
constructor(asm)
|
||||
} else throw new IllegalArgumentException(errorMsg)
|
||||
|
@ -22,9 +25,7 @@ trait ScriptFactory[T <: Script] extends Factory[T] {
|
|||
def fromAsm(asm: Seq[ScriptToken]): T
|
||||
|
||||
def fromBytes(bytes: ByteVector): T = {
|
||||
BitcoinScriptUtil.parseScript(
|
||||
bytes = bytes,
|
||||
f = fromAsm)
|
||||
BitcoinScriptUtil.parseScript(bytes = bytes, f = fromAsm)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,4 +51,4 @@ trait ScriptFactory[T <: Script] extends Factory[T] {
|
|||
def fromAsmHex(hex: String): T = {
|
||||
fromAsmBytes(BitcoinSUtil.decodeHex(hex))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,16 @@ import org.bitcoins.core.crypto._
|
|||
import org.bitcoins.core.script.bitwise.{OP_EQUAL, OP_EQUALVERIFY}
|
||||
import org.bitcoins.core.script.constant.{BytesToPushOntoStack, _}
|
||||
import org.bitcoins.core.script.control.OP_RETURN
|
||||
import org.bitcoins.core.script.crypto.{OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY, OP_CHECKSIG, OP_HASH160}
|
||||
import org.bitcoins.core.script.locktime.{OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY}
|
||||
import org.bitcoins.core.script.crypto.{
|
||||
OP_CHECKMULTISIG,
|
||||
OP_CHECKMULTISIGVERIFY,
|
||||
OP_CHECKSIG,
|
||||
OP_HASH160
|
||||
}
|
||||
import org.bitcoins.core.script.locktime.{
|
||||
OP_CHECKLOCKTIMEVERIFY,
|
||||
OP_CHECKSEQUENCEVERIFY
|
||||
}
|
||||
import org.bitcoins.core.script.reserved.UndefinedOP_NOP
|
||||
import org.bitcoins.core.script.stack.{OP_DROP, OP_DUP}
|
||||
import org.bitcoins.core.util._
|
||||
|
@ -19,16 +27,21 @@ import scala.util.{Failure, Success, Try}
|
|||
sealed abstract class ScriptPubKey extends Script
|
||||
|
||||
/**
|
||||
* Represents a pay-to-pubkey hash script pubkey
|
||||
* https://bitcoin.org/en/developer-guide#pay-to-public-key-hash-p2pkh
|
||||
* Format: OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
|
||||
* Represents a
|
||||
* [[https://bitcoin.org/en/developer-guide#pay-to-public-key-hash-p2pkh pay-to-pubkey hash script pubkey]]
|
||||
*
|
||||
* Format: `OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG`
|
||||
*/
|
||||
sealed trait P2PKHScriptPubKey extends ScriptPubKey {
|
||||
def pubKeyHash: Sha256Hash160Digest = Sha256Hash160Digest(asm(asm.length - 3).bytes)
|
||||
|
||||
def pubKeyHash: Sha256Hash160Digest =
|
||||
Sha256Hash160Digest(asm(asm.length - 3).bytes)
|
||||
}
|
||||
|
||||
object P2PKHScriptPubKey extends ScriptFactory[P2PKHScriptPubKey] {
|
||||
private case class P2PKHScriptPubKeyImpl(override val asm: Vector[ScriptToken]) extends P2PKHScriptPubKey {
|
||||
private case class P2PKHScriptPubKeyImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends P2PKHScriptPubKey {
|
||||
override def toString = "P2PKHScriptPubKeyImpl(" + hex + ")"
|
||||
}
|
||||
|
||||
|
@ -39,20 +52,33 @@ object P2PKHScriptPubKey extends ScriptFactory[P2PKHScriptPubKey] {
|
|||
|
||||
def apply(hash: Sha256Hash160Digest): P2PKHScriptPubKey = {
|
||||
val pushOps = BitcoinScriptUtil.calculatePushOp(hash.bytes)
|
||||
val asm = Seq(OP_DUP, OP_HASH160) ++ pushOps ++ Seq(ScriptConstant(hash.bytes), OP_EQUALVERIFY, OP_CHECKSIG)
|
||||
val asm = Seq(OP_DUP, OP_HASH160) ++ pushOps ++ Seq(
|
||||
ScriptConstant(hash.bytes),
|
||||
OP_EQUALVERIFY,
|
||||
OP_CHECKSIG)
|
||||
P2PKHScriptPubKey(asm)
|
||||
}
|
||||
|
||||
def fromAsm(asm: Seq[ScriptToken]): P2PKHScriptPubKey = {
|
||||
buildScript(asm.toVector, P2PKHScriptPubKeyImpl(_), isP2PKHScriptPubKey(_), "Given asm was not a p2pkh scriptPubKey, got: " + asm)
|
||||
buildScript(asm.toVector,
|
||||
P2PKHScriptPubKeyImpl(_),
|
||||
isP2PKHScriptPubKey(_),
|
||||
"Given asm was not a p2pkh scriptPubKey, got: " + asm)
|
||||
}
|
||||
|
||||
def apply(asm: Seq[ScriptToken]): P2PKHScriptPubKey = fromAsm(asm)
|
||||
|
||||
/** Checks if the given asm matches the pattern for [[P2PKHScriptPubKey]] */
|
||||
/** Checks if the given asm matches the pattern for
|
||||
* [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey P2PKHScriptPubKey]] */
|
||||
def isP2PKHScriptPubKey(asm: Seq[ScriptToken]): Boolean = {
|
||||
asm match {
|
||||
case Seq(OP_DUP, OP_HASH160, _: BytesToPushOntoStack, _: ScriptConstant, OP_EQUALVERIFY, OP_CHECKSIG) => true
|
||||
case Seq(OP_DUP,
|
||||
OP_HASH160,
|
||||
_: BytesToPushOntoStack,
|
||||
_: ScriptConstant,
|
||||
OP_EQUALVERIFY,
|
||||
OP_CHECKSIG) =>
|
||||
true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
@ -68,16 +94,23 @@ sealed trait MultiSignatureScriptPubKey extends ScriptPubKey {
|
|||
/** Returns the amount of required signatures for this multisignature script pubkey output */
|
||||
def requiredSigs: Int = {
|
||||
val asmWithoutPushOps = asm.filterNot(_.isInstanceOf[BytesToPushOntoStack])
|
||||
val opCheckMultiSigIndex = if (asm.indexOf(OP_CHECKMULTISIG) != -1) asmWithoutPushOps.indexOf(OP_CHECKMULTISIG) else asmWithoutPushOps.indexOf(OP_CHECKMULTISIGVERIFY)
|
||||
val opCheckMultiSigIndex =
|
||||
if (asm.indexOf(OP_CHECKMULTISIG) != -1)
|
||||
asmWithoutPushOps.indexOf(OP_CHECKMULTISIG)
|
||||
else asmWithoutPushOps.indexOf(OP_CHECKMULTISIGVERIFY)
|
||||
//magic number 2 represents the maxSig operation and the OP_CHECKMULTISIG operation at the end of the asm
|
||||
val numSigsRequired = asmWithoutPushOps(opCheckMultiSigIndex - maxSigs.toInt - 2)
|
||||
val numSigsRequired = asmWithoutPushOps(
|
||||
opCheckMultiSigIndex - maxSigs.toInt - 2)
|
||||
numSigsRequired match {
|
||||
case x: ScriptNumber => x.toInt
|
||||
case c: ScriptConstant if ScriptNumber(c.hex).toLong <= Consensus.maxPublicKeysPerMultiSig =>
|
||||
case c: ScriptConstant
|
||||
if ScriptNumber(c.hex).toLong <= Consensus.maxPublicKeysPerMultiSig =>
|
||||
ScriptNumber(c.hex).toInt
|
||||
case _ => throw new RuntimeException("The first element of the multisignature pubkey must be a script number operation\n" +
|
||||
"operation: " + numSigsRequired +
|
||||
"\nscriptPubKey: " + this)
|
||||
case _ =>
|
||||
throw new RuntimeException(
|
||||
"The first element of the multisignature pubkey must be a script number operation\n" +
|
||||
"operation: " + numSigsRequired +
|
||||
"\nscriptPubKey: " + this)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,35 +122,51 @@ sealed trait MultiSignatureScriptPubKey extends ScriptPubKey {
|
|||
} else {
|
||||
asm(checkMultiSigIndex - 1) match {
|
||||
case x: ScriptNumber => x.toInt
|
||||
case c: ScriptConstant if ScriptNumber(c.hex).toLong <= Consensus.maxPublicKeysPerMultiSig =>
|
||||
case c: ScriptConstant
|
||||
if ScriptNumber(c.hex).toLong <= Consensus.maxPublicKeysPerMultiSig =>
|
||||
ScriptNumber(c.hex).toInt
|
||||
case x => throw new RuntimeException("The element preceding a OP_CHECKMULTISIG operation in a multisignature pubkey must be a script number operation, got: " + x)
|
||||
case x =>
|
||||
throw new RuntimeException(
|
||||
"The element preceding a OP_CHECKMULTISIG operation in a multisignature pubkey must be a script number operation, got: " + x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Gives the OP_CHECKMULTISIG or OP_CHECKMULTISIGVERIFY index inside of asm */
|
||||
/** Gives the `OP_CHECKMULTISIG` or `OP_CHECKMULTISIGVERIFY` index inside of asm */
|
||||
private def checkMultiSigIndex: Int = {
|
||||
if (asm.indexOf(OP_CHECKMULTISIG) != -1) asm.indexOf(OP_CHECKMULTISIG) else asm.indexOf(OP_CHECKMULTISIGVERIFY)
|
||||
if (asm.indexOf(OP_CHECKMULTISIG) != -1) asm.indexOf(OP_CHECKMULTISIG)
|
||||
else asm.indexOf(OP_CHECKMULTISIGVERIFY)
|
||||
}
|
||||
|
||||
/** Returns the public keys encoded into the scriptPubKey */
|
||||
/** Returns the public keys encoded into the `scriptPubKey` */
|
||||
def publicKeys: Seq[ECPublicKey] = {
|
||||
asm.filter(_.isInstanceOf[ScriptConstant]).slice(1, maxSigs + 1).map(key => ECPublicKey(key.hex))
|
||||
asm
|
||||
.filter(_.isInstanceOf[ScriptConstant])
|
||||
.slice(1, maxSigs + 1)
|
||||
.map(key => ECPublicKey(key.hex))
|
||||
}
|
||||
}
|
||||
|
||||
object MultiSignatureScriptPubKey extends ScriptFactory[MultiSignatureScriptPubKey] {
|
||||
object MultiSignatureScriptPubKey
|
||||
extends ScriptFactory[MultiSignatureScriptPubKey] {
|
||||
|
||||
private case class MultiSignatureScriptPubKeyImpl(override val asm: Vector[ScriptToken]) extends MultiSignatureScriptPubKey {
|
||||
private case class MultiSignatureScriptPubKeyImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends MultiSignatureScriptPubKey {
|
||||
override def toString = "MultiSignatureScriptPubKeyImpl(" + hex + ")"
|
||||
}
|
||||
|
||||
def apply(requiredSigs: Int, pubKeys: Seq[ECPublicKey]): MultiSignatureScriptPubKey = {
|
||||
require(requiredSigs <= Consensus.maxPublicKeysPerMultiSig, "We cannot have more required signatures than: " +
|
||||
Consensus.maxPublicKeysPerMultiSig + " got: " + requiredSigs)
|
||||
require(pubKeys.length <= Consensus.maxPublicKeysPerMultiSig, "We cannot have more public keys than " +
|
||||
Consensus.maxPublicKeysPerMultiSig + " got: " + pubKeys.length)
|
||||
def apply(
|
||||
requiredSigs: Int,
|
||||
pubKeys: Seq[ECPublicKey]): MultiSignatureScriptPubKey = {
|
||||
require(
|
||||
requiredSigs <= Consensus.maxPublicKeysPerMultiSig,
|
||||
"We cannot have more required signatures than: " +
|
||||
Consensus.maxPublicKeysPerMultiSig + " got: " + requiredSigs
|
||||
)
|
||||
require(pubKeys.length <= Consensus.maxPublicKeysPerMultiSig,
|
||||
"We cannot have more public keys than " +
|
||||
Consensus.maxPublicKeysPerMultiSig + " got: " + pubKeys.length)
|
||||
|
||||
val required = ScriptNumberOperation.fromNumber(requiredSigs) match {
|
||||
case Some(scriptNumOp) => Seq(scriptNumOp)
|
||||
|
@ -138,28 +187,34 @@ object MultiSignatureScriptPubKey extends ScriptFactory[MultiSignatureScriptPubK
|
|||
pushOps = BitcoinScriptUtil.calculatePushOp(pubKey.bytes)
|
||||
constant = ScriptConstant(pubKey.bytes)
|
||||
} yield pushOps ++ Seq(constant)
|
||||
val asm: Seq[ScriptToken] = required ++ pubKeysWithPushOps.flatten ++ possible ++ Seq(OP_CHECKMULTISIG)
|
||||
val asm: Seq[ScriptToken] = required ++ pubKeysWithPushOps.flatten ++ possible ++ Seq(
|
||||
OP_CHECKMULTISIG)
|
||||
MultiSignatureScriptPubKey(asm)
|
||||
}
|
||||
|
||||
def fromAsm(asm: Seq[ScriptToken]): MultiSignatureScriptPubKey = {
|
||||
buildScript(asm.toVector, MultiSignatureScriptPubKeyImpl(_), isMultiSignatureScriptPubKey(_), "Given asm was not a MultSignatureScriptPubKey, got: " + asm)
|
||||
buildScript(asm.toVector,
|
||||
MultiSignatureScriptPubKeyImpl(_),
|
||||
isMultiSignatureScriptPubKey(_),
|
||||
"Given asm was not a MultSignatureScriptPubKey, got: " + asm)
|
||||
}
|
||||
|
||||
def apply(asm: Seq[ScriptToken]): MultiSignatureScriptPubKey = fromAsm(asm)
|
||||
|
||||
/** Determines if the given script tokens are a multisignature scriptPubKey */
|
||||
/** Determines if the given script tokens are a multisignature `scriptPubKey` */
|
||||
def isMultiSignatureScriptPubKey(asm: Seq[ScriptToken]): Boolean = {
|
||||
val isNotEmpty = asm.size > 0
|
||||
val containsMultiSigOp = asm.contains(OP_CHECKMULTISIG) || asm.contains(OP_CHECKMULTISIGVERIFY)
|
||||
val containsMultiSigOp = asm.contains(OP_CHECKMULTISIG) || asm.contains(
|
||||
OP_CHECKMULTISIGVERIFY)
|
||||
//we need either the first or second asm operation to indicate how many signatures are required
|
||||
val hasRequiredSignaturesTry = Try {
|
||||
asm.headOption match {
|
||||
case None => false
|
||||
case None => false
|
||||
case Some(token) =>
|
||||
//this is for the case that we have more than 16 public keys, the
|
||||
//first operation will be a push op, the second operation being the actual number of keys
|
||||
if (token.isInstanceOf[BytesToPushOntoStack]) isValidPubKeyNumber(asm.tail.head)
|
||||
if (token.isInstanceOf[BytesToPushOntoStack])
|
||||
isValidPubKeyNumber(asm.tail.head)
|
||||
else isValidPubKeyNumber(token)
|
||||
}
|
||||
}
|
||||
|
@ -170,8 +225,11 @@ object MultiSignatureScriptPubKey extends ScriptFactory[MultiSignatureScriptPubK
|
|||
}
|
||||
}
|
||||
|
||||
val standardOps = asm.filter(op => op.isInstanceOf[ScriptNumber] || op == OP_CHECKMULTISIG ||
|
||||
op == OP_CHECKMULTISIGVERIFY || op.isInstanceOf[ScriptConstant] || op.isInstanceOf[BytesToPushOntoStack])
|
||||
val standardOps = asm.filter(
|
||||
op =>
|
||||
op.isInstanceOf[ScriptNumber] || op == OP_CHECKMULTISIG ||
|
||||
op == OP_CHECKMULTISIGVERIFY || op.isInstanceOf[ScriptConstant] || op
|
||||
.isInstanceOf[BytesToPushOntoStack])
|
||||
(hasRequiredSignaturesTry, hasMaximumSignaturesTry) match {
|
||||
case (Success(hasRequiredSignatures), Success(hasMaximumSignatures)) =>
|
||||
val result = isNotEmpty && containsMultiSigOp && hasRequiredSignatures &&
|
||||
|
@ -185,28 +243,32 @@ object MultiSignatureScriptPubKey extends ScriptFactory[MultiSignatureScriptPubK
|
|||
|
||||
/**
|
||||
* Checks that the given script token is with the range of the maximum amount of
|
||||
* public keys we can have in a [[MultiSignatureScriptPubKey]]
|
||||
* public keys we can have in a
|
||||
* [[org.bitcoins.core.protocol.script.MultiSignatureScriptPubKey MultiSignatureScriptPubKey]]
|
||||
*/
|
||||
private def isValidPubKeyNumber(token: ScriptToken): Boolean = token match {
|
||||
case constant: ScriptConstant =>
|
||||
constant.isInstanceOf[ScriptNumber] ||
|
||||
ScriptNumber(constant.bytes) <= ScriptNumber(Consensus.maxPublicKeysPerMultiSig)
|
||||
ScriptNumber(constant.bytes) <= ScriptNumber(
|
||||
Consensus.maxPublicKeysPerMultiSig)
|
||||
case _: ScriptToken => false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a pay-to-scripthash public key
|
||||
* https://bitcoin.org/en/developer-guide#pay-to-script-hash-p2sh
|
||||
* Format: OP_HASH160 <Hash160(redeemScript)> OP_EQUAL
|
||||
* Represents a [[https://bitcoin.org/en/developer-guide#pay-to-script-hash-p2sh pay-to-scripthash public key]]
|
||||
* Format: `OP_HASH160 <Hash160(redeemScript)> OP_EQUAL`
|
||||
*/
|
||||
sealed trait P2SHScriptPubKey extends ScriptPubKey {
|
||||
|
||||
/** The hash of the script for which this scriptPubKey is being created from */
|
||||
def scriptHash: Sha256Hash160Digest = Sha256Hash160Digest(asm(asm.length - 2).bytes)
|
||||
def scriptHash: Sha256Hash160Digest =
|
||||
Sha256Hash160Digest(asm(asm.length - 2).bytes)
|
||||
}
|
||||
|
||||
object P2SHScriptPubKey extends ScriptFactory[P2SHScriptPubKey] {
|
||||
private case class P2SHScriptPubKeyImpl(override val asm: Vector[ScriptToken]) extends P2SHScriptPubKey {
|
||||
private case class P2SHScriptPubKeyImpl(override val asm: Vector[ScriptToken])
|
||||
extends P2SHScriptPubKey {
|
||||
override def toString = "P2SHScriptPubKeyImpl(" + hex + ")"
|
||||
}
|
||||
|
||||
|
@ -217,35 +279,46 @@ object P2SHScriptPubKey extends ScriptFactory[P2SHScriptPubKey] {
|
|||
|
||||
def apply(hash: Sha256Hash160Digest): P2SHScriptPubKey = {
|
||||
val pushOps = BitcoinScriptUtil.calculatePushOp(hash.bytes)
|
||||
val asm = Seq(OP_HASH160) ++ pushOps ++ Seq(ScriptConstant(hash.bytes), OP_EQUAL)
|
||||
val asm = Seq(OP_HASH160) ++ pushOps ++ Seq(ScriptConstant(hash.bytes),
|
||||
OP_EQUAL)
|
||||
P2SHScriptPubKey(asm)
|
||||
}
|
||||
|
||||
/** Checks if the given asm matches the pattern for [[P2SHScriptPubKey]] */
|
||||
/** Checks if the given asm matches the pattern for
|
||||
* [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] */
|
||||
def isP2SHScriptPubKey(asm: Seq[ScriptToken]): Boolean = asm match {
|
||||
case Seq(OP_HASH160, _: BytesToPushOntoStack, _: ScriptConstant, OP_EQUAL) => true
|
||||
case Seq(OP_HASH160,
|
||||
_: BytesToPushOntoStack,
|
||||
_: ScriptConstant,
|
||||
OP_EQUAL) =>
|
||||
true
|
||||
case _ => false
|
||||
}
|
||||
|
||||
def fromAsm(asm: Seq[ScriptToken]): P2SHScriptPubKey = {
|
||||
buildScript(asm.toVector, P2SHScriptPubKeyImpl(_), isP2SHScriptPubKey(_), "Given asm was not a p2sh scriptPubkey, got: " + asm)
|
||||
buildScript(asm.toVector,
|
||||
P2SHScriptPubKeyImpl(_),
|
||||
isP2SHScriptPubKey(_),
|
||||
"Given asm was not a p2sh scriptPubkey, got: " + asm)
|
||||
}
|
||||
|
||||
def apply(asm: Seq[ScriptToken]): P2SHScriptPubKey = fromAsm(asm)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a pay to public key script public key
|
||||
* https://bitcoin.org/en/developer-guide#pubkey
|
||||
* Format: <pubkey> OP_CHECKSIG
|
||||
* Represents a [[https://bitcoin.org/en/developer-guide#pubkey pay to public key script public key]]
|
||||
* Format: `<pubkey> OP_CHECKSIG`
|
||||
*/
|
||||
sealed trait P2PKScriptPubKey extends ScriptPubKey {
|
||||
def publicKey: ECPublicKey = ECPublicKey(BitcoinScriptUtil.filterPushOps(asm).head.bytes)
|
||||
|
||||
def publicKey: ECPublicKey =
|
||||
ECPublicKey(BitcoinScriptUtil.filterPushOps(asm).head.bytes)
|
||||
}
|
||||
|
||||
object P2PKScriptPubKey extends ScriptFactory[P2PKScriptPubKey] {
|
||||
|
||||
private case class P2PKScriptPubKeyImpl(override val asm: Vector[ScriptToken]) extends P2PKScriptPubKey {
|
||||
private case class P2PKScriptPubKeyImpl(override val asm: Vector[ScriptToken])
|
||||
extends P2PKScriptPubKey {
|
||||
override def toString = "P2PKScriptPubKeyImpl(" + hex + ")"
|
||||
}
|
||||
|
||||
|
@ -256,25 +329,30 @@ object P2PKScriptPubKey extends ScriptFactory[P2PKScriptPubKey] {
|
|||
}
|
||||
|
||||
def fromAsm(asm: Seq[ScriptToken]): P2PKScriptPubKey = {
|
||||
buildScript(asm.toVector, P2PKScriptPubKeyImpl(_), isP2PKScriptPubKey(_), "Given asm was not a p2pk scriptPubKey, got: " + asm)
|
||||
buildScript(asm.toVector,
|
||||
P2PKScriptPubKeyImpl(_),
|
||||
isP2PKScriptPubKey(_),
|
||||
"Given asm was not a p2pk scriptPubKey, got: " + asm)
|
||||
}
|
||||
|
||||
def apply(asm: Seq[ScriptToken]): P2PKScriptPubKey = fromAsm(asm)
|
||||
|
||||
/** Sees if the given asm matches the [[P2PKHScriptPubKey]] pattern */
|
||||
/** Sees if the given asm matches the
|
||||
* [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey P2PKHScriptPubKey]] pattern */
|
||||
def isP2PKScriptPubKey(asm: Seq[ScriptToken]): Boolean = asm match {
|
||||
case Seq(_: BytesToPushOntoStack, _: ScriptConstant, OP_CHECKSIG) => true
|
||||
case _ => false
|
||||
case _ => false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sealed trait LockTimeScriptPubKey extends ScriptPubKey {
|
||||
/** Determines the nested ScriptPubKey inside the LockTimeScriptPubKey */
|
||||
|
||||
/** Determines the nested `ScriptPubKey` inside the `LockTimeScriptPubKey` */
|
||||
def nestedScriptPubKey: ScriptPubKey = {
|
||||
val bool: Boolean = asm.head.isInstanceOf[ScriptNumberOperation]
|
||||
bool match {
|
||||
case true => ScriptPubKey(asm.slice(3, asm.length))
|
||||
case true => ScriptPubKey(asm.slice(3, asm.length))
|
||||
case false => ScriptPubKey(asm.slice(4, asm.length))
|
||||
}
|
||||
}
|
||||
|
@ -282,12 +360,14 @@ sealed trait LockTimeScriptPubKey extends ScriptPubKey {
|
|||
/** The relative locktime value (i.e. the amount of time the output should remain unspendable) */
|
||||
def locktime: ScriptNumber = {
|
||||
asm.head match {
|
||||
case scriptNumOp: ScriptNumberOperation => ScriptNumber(scriptNumOp.toLong)
|
||||
case scriptNumOp: ScriptNumberOperation =>
|
||||
ScriptNumber(scriptNumOp.toLong)
|
||||
case _: BytesToPushOntoStack => ScriptNumber(asm(1).hex)
|
||||
case _: ScriptConstant | _: ScriptOperation =>
|
||||
throw new IllegalArgumentException("In a LockTimeScriptPubKey, " +
|
||||
"the first asm must be either a ScriptNumberOperation (i.e. OP_5), or the BytesToPushOntoStack " +
|
||||
"for the proceeding ScriptConstant.")
|
||||
throw new IllegalArgumentException(
|
||||
"In a LockTimeScriptPubKey, " +
|
||||
"the first asm must be either a ScriptNumberOperation (i.e. OP_5), or the BytesToPushOntoStack " +
|
||||
"for the proceeding ScriptConstant.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -298,42 +378,52 @@ object LockTimeScriptPubKey extends ScriptFactory[LockTimeScriptPubKey] {
|
|||
require(isValidLockTimeScriptPubKey(asm))
|
||||
if (asm.contains(OP_CHECKLOCKTIMEVERIFY)) CLTVScriptPubKey(asm)
|
||||
else if (asm.contains(OP_CHECKSEQUENCEVERIFY)) CSVScriptPubKey(asm)
|
||||
else throw new IllegalArgumentException("Given asm was not a LockTimeScriptPubKey, got: " + asm)
|
||||
else
|
||||
throw new IllegalArgumentException(
|
||||
"Given asm was not a LockTimeScriptPubKey, got: " + asm)
|
||||
}
|
||||
|
||||
def isValidLockTimeScriptPubKey(asm: Seq[ScriptToken]): Boolean = {
|
||||
CLTVScriptPubKey.isCLTVScriptPubKey(asm) || CSVScriptPubKey.isCSVScriptPubKey(asm)
|
||||
CLTVScriptPubKey.isCLTVScriptPubKey(asm) || CSVScriptPubKey
|
||||
.isCSVScriptPubKey(asm)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a scriptPubKey that contains OP_CHECKLOCKTIMEVERIFY.
|
||||
* Represents a scriptPubKey that contains `OP_CHECKLOCKTIMEVERIFY.`
|
||||
* Adds an absolute/defined locktime condition to any scriptPubKey.
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki]]
|
||||
* Format: <locktime> OP_CLTV OP_DROP <scriptPubKey>
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki BIP65]]
|
||||
* Format: `<locktime> OP_CLTV OP_DROP <scriptPubKey>`
|
||||
*/
|
||||
sealed trait CLTVScriptPubKey extends LockTimeScriptPubKey
|
||||
|
||||
object CLTVScriptPubKey extends ScriptFactory[CLTVScriptPubKey] {
|
||||
private case class CLTVScriptPubKeyImpl(override val asm: Vector[ScriptToken]) extends CLTVScriptPubKey {
|
||||
private case class CLTVScriptPubKeyImpl(override val asm: Vector[ScriptToken])
|
||||
extends CLTVScriptPubKey {
|
||||
override def toString = "CLTVScriptPubKeyImpl(" + hex + ")"
|
||||
}
|
||||
|
||||
def fromAsm(asm: Seq[ScriptToken]): CLTVScriptPubKey = {
|
||||
buildScript(asm.toVector, CLTVScriptPubKeyImpl(_), isCLTVScriptPubKey(_), "Given asm was not a CLTVScriptPubKey, got: " + asm)
|
||||
buildScript(asm.toVector,
|
||||
CLTVScriptPubKeyImpl(_),
|
||||
isCLTVScriptPubKey(_),
|
||||
"Given asm was not a CLTVScriptPubKey, got: " + asm)
|
||||
}
|
||||
|
||||
def apply(asm: Seq[ScriptToken]): CLTVScriptPubKey = fromAsm(asm)
|
||||
|
||||
def apply(locktime: ScriptNumber, scriptPubKey: ScriptPubKey): CLTVScriptPubKey = {
|
||||
def apply(
|
||||
locktime: ScriptNumber,
|
||||
scriptPubKey: ScriptPubKey): CLTVScriptPubKey = {
|
||||
val scriptOp = BitcoinScriptUtil.minimalScriptNumberRepresentation(locktime)
|
||||
|
||||
val scriptNum: Seq[ScriptToken] = if (scriptOp.isInstanceOf[ScriptNumberOperation]) {
|
||||
Seq(scriptOp)
|
||||
} else {
|
||||
val pushOpsLockTime = BitcoinScriptUtil.calculatePushOp(locktime.bytes)
|
||||
pushOpsLockTime ++ Seq(ScriptConstant(locktime.bytes))
|
||||
}
|
||||
val scriptNum: Seq[ScriptToken] =
|
||||
if (scriptOp.isInstanceOf[ScriptNumberOperation]) {
|
||||
Seq(scriptOp)
|
||||
} else {
|
||||
val pushOpsLockTime = BitcoinScriptUtil.calculatePushOp(locktime.bytes)
|
||||
pushOpsLockTime ++ Seq(ScriptConstant(locktime.bytes))
|
||||
}
|
||||
|
||||
val cltvAsm = Seq(OP_CHECKLOCKTIMEVERIFY, OP_DROP)
|
||||
val scriptPubKeyAsm = scriptPubKey.asm
|
||||
|
@ -344,15 +434,20 @@ object CLTVScriptPubKey extends ScriptFactory[CLTVScriptPubKey] {
|
|||
def isCLTVScriptPubKey(asm: Seq[ScriptToken]): Boolean = {
|
||||
if (asm.head.isInstanceOf[BytesToPushOntoStack]) {
|
||||
val tailTokens = asm.slice(4, asm.length)
|
||||
if (P2SHScriptPubKey.isP2SHScriptPubKey(tailTokens) || tailTokens.contains(OP_CHECKLOCKTIMEVERIFY)) return false
|
||||
if (P2SHScriptPubKey.isP2SHScriptPubKey(tailTokens) || tailTokens
|
||||
.contains(OP_CHECKLOCKTIMEVERIFY)) return false
|
||||
asm.slice(0, 4) match {
|
||||
case Seq(_: BytesToPushOntoStack, _: ScriptConstant, OP_CHECKLOCKTIMEVERIFY, OP_DROP) =>
|
||||
case Seq(_: BytesToPushOntoStack,
|
||||
_: ScriptConstant,
|
||||
OP_CHECKLOCKTIMEVERIFY,
|
||||
OP_DROP) =>
|
||||
validScriptAfterLockTime(tailTokens)
|
||||
case _ => false
|
||||
}
|
||||
} else {
|
||||
val tailTokens = asm.slice(3, asm.length)
|
||||
if (P2SHScriptPubKey.isP2SHScriptPubKey(tailTokens) || tailTokens.contains(OP_CHECKLOCKTIMEVERIFY)) return false
|
||||
if (P2SHScriptPubKey.isP2SHScriptPubKey(tailTokens) || tailTokens
|
||||
.contains(OP_CHECKLOCKTIMEVERIFY)) return false
|
||||
asm.slice(0, 3) match {
|
||||
case Seq(_: ScriptNumberOperation, OP_CHECKLOCKTIMEVERIFY, OP_DROP) =>
|
||||
validScriptAfterLockTime(tailTokens)
|
||||
|
@ -364,12 +459,14 @@ object CLTVScriptPubKey extends ScriptFactory[CLTVScriptPubKey] {
|
|||
/**
|
||||
* We need this check because sometimes we can get very lucky in having a non valid
|
||||
* lock time script that has the first 4 bytes as a valid locktime script
|
||||
* and then the bytes after the first 4 bytes gets lucky and is parsed by our [[org.bitcoins.core.serializers.script.ScriptParser]]
|
||||
* and then the bytes after the first 4 bytes gets lucky and is parsed by our
|
||||
* [[org.bitcoins.core.serializers.script.ScriptParser ScriptParser]]
|
||||
* A good way to see if this is _actually_ a valid script is by checking if we have any
|
||||
* [[UndefinedOP_NOP]] in the script, which means we definitely don't have a valid locktime script
|
||||
* See this example of what happened before we added this check:
|
||||
* [[org.bitcoins.core.script.reserved.UndefinedOP_NOP UndefinedOP_NOP]] in the script,
|
||||
* which means we definitely don't have a valid locktime script
|
||||
*
|
||||
* [[https://travis-ci.org/bitcoin-s/bitcoin-s-core/builds/201652191#L2526]]
|
||||
* See this example of what happened before we added this check:
|
||||
* [[https://travis-ci.org/bitcoin-s/bitcoin-s-core/builds/201652191#L2526 Travis CI]]
|
||||
*/
|
||||
def validScriptAfterLockTime(asm: Seq[ScriptToken]): Boolean = {
|
||||
!asm.exists(_.isInstanceOf[UndefinedOP_NOP])
|
||||
|
@ -377,33 +474,43 @@ object CLTVScriptPubKey extends ScriptFactory[CLTVScriptPubKey] {
|
|||
}
|
||||
|
||||
/**
|
||||
* Represents a scriptPubKey that contains OP_CHECKSEQUENCEVERIFY.
|
||||
* Adds a relative lockTime condition to any scriptPubKey.
|
||||
* https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki
|
||||
* Format: <locktime> OP_CSV OP_DROP <scriptPubKey>
|
||||
* Represents a scriptPubKey that contains
|
||||
* [[org.bitcoins.core.script.locktime.OP_CHECKSEQUENCEVERIFY OP_CHECKSEQUENCEVERIFY]]
|
||||
* Adds a relative lockTime condition to any `scriptPubKey`.
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki BIP112]]
|
||||
* Format: `<locktime> OP_CSV OP_DROP <scriptPubKey>`
|
||||
*/
|
||||
sealed trait CSVScriptPubKey extends LockTimeScriptPubKey
|
||||
|
||||
object CSVScriptPubKey extends ScriptFactory[CSVScriptPubKey] {
|
||||
private case class CSVScriptPubKeyImpl(override val asm: Vector[ScriptToken]) extends CSVScriptPubKey {
|
||||
private case class CSVScriptPubKeyImpl(override val asm: Vector[ScriptToken])
|
||||
extends CSVScriptPubKey {
|
||||
override def toString = "CSVScriptPubKeyImpl(" + hex + ")"
|
||||
}
|
||||
|
||||
def fromAsm(asm: Seq[ScriptToken]): CSVScriptPubKey = {
|
||||
buildScript(asm.toVector, CSVScriptPubKeyImpl(_), isCSVScriptPubKey(_), "Given asm was not a CSVScriptPubKey, got: " + asm)
|
||||
buildScript(asm.toVector,
|
||||
CSVScriptPubKeyImpl(_),
|
||||
isCSVScriptPubKey(_),
|
||||
"Given asm was not a CSVScriptPubKey, got: " + asm)
|
||||
}
|
||||
|
||||
def apply(asm: Seq[ScriptToken]): CSVScriptPubKey = fromAsm(asm)
|
||||
|
||||
def apply(relativeLockTime: ScriptNumber, scriptPubKey: ScriptPubKey): CSVScriptPubKey = {
|
||||
val scriptOp = BitcoinScriptUtil.minimalScriptNumberRepresentation(relativeLockTime)
|
||||
def apply(
|
||||
relativeLockTime: ScriptNumber,
|
||||
scriptPubKey: ScriptPubKey): CSVScriptPubKey = {
|
||||
val scriptOp =
|
||||
BitcoinScriptUtil.minimalScriptNumberRepresentation(relativeLockTime)
|
||||
|
||||
val scriptNum: Seq[ScriptToken] = if (scriptOp.isInstanceOf[ScriptNumberOperation]) {
|
||||
Seq(scriptOp)
|
||||
} else {
|
||||
val pushOpsLockTime = BitcoinScriptUtil.calculatePushOp(relativeLockTime.bytes)
|
||||
pushOpsLockTime ++ Seq(ScriptConstant(relativeLockTime.bytes))
|
||||
}
|
||||
val scriptNum: Seq[ScriptToken] =
|
||||
if (scriptOp.isInstanceOf[ScriptNumberOperation]) {
|
||||
Seq(scriptOp)
|
||||
} else {
|
||||
val pushOpsLockTime =
|
||||
BitcoinScriptUtil.calculatePushOp(relativeLockTime.bytes)
|
||||
pushOpsLockTime ++ Seq(ScriptConstant(relativeLockTime.bytes))
|
||||
}
|
||||
|
||||
val csvAsm = Seq(OP_CHECKSEQUENCEVERIFY, OP_DROP)
|
||||
val scriptPubKeyAsm = scriptPubKey.asm
|
||||
|
@ -414,15 +521,20 @@ object CSVScriptPubKey extends ScriptFactory[CSVScriptPubKey] {
|
|||
def isCSVScriptPubKey(asm: Seq[ScriptToken]): Boolean = {
|
||||
if (asm.head.isInstanceOf[BytesToPushOntoStack]) {
|
||||
val tailTokens = asm.slice(4, asm.length)
|
||||
if (P2SHScriptPubKey.isP2SHScriptPubKey(tailTokens) || tailTokens.contains(OP_CHECKSEQUENCEVERIFY)) return false
|
||||
if (P2SHScriptPubKey.isP2SHScriptPubKey(tailTokens) || tailTokens
|
||||
.contains(OP_CHECKSEQUENCEVERIFY)) return false
|
||||
asm.slice(0, 4) match {
|
||||
case Seq(_: BytesToPushOntoStack, _: ScriptConstant, OP_CHECKSEQUENCEVERIFY, OP_DROP) =>
|
||||
case Seq(_: BytesToPushOntoStack,
|
||||
_: ScriptConstant,
|
||||
OP_CHECKSEQUENCEVERIFY,
|
||||
OP_DROP) =>
|
||||
CLTVScriptPubKey.validScriptAfterLockTime(tailTokens)
|
||||
case _ => false
|
||||
}
|
||||
} else {
|
||||
val tailTokens = asm.slice(3, asm.length)
|
||||
if (P2SHScriptPubKey.isP2SHScriptPubKey(tailTokens) || tailTokens.contains(OP_CHECKSEQUENCEVERIFY)) return false
|
||||
if (P2SHScriptPubKey.isP2SHScriptPubKey(tailTokens) || tailTokens
|
||||
.contains(OP_CHECKSEQUENCEVERIFY)) return false
|
||||
asm.slice(0, 3) match {
|
||||
case Seq(_: ScriptNumberOperation, OP_CHECKSEQUENCEVERIFY, OP_DROP) =>
|
||||
CLTVScriptPubKey.validScriptAfterLockTime(tailTokens)
|
||||
|
@ -436,13 +548,17 @@ object CSVScriptPubKey extends ScriptFactory[CSVScriptPubKey] {
|
|||
sealed trait NonStandardScriptPubKey extends ScriptPubKey
|
||||
|
||||
object NonStandardScriptPubKey extends ScriptFactory[NonStandardScriptPubKey] {
|
||||
private case class NonStandardScriptPubKeyImpl(override val asm: Vector[ScriptToken]) extends NonStandardScriptPubKey {
|
||||
private case class NonStandardScriptPubKeyImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends NonStandardScriptPubKey {
|
||||
override def toString = "NonStandardScriptPubKeyImpl(" + hex + ")"
|
||||
}
|
||||
|
||||
def fromAsm(asm: Seq[ScriptToken]): NonStandardScriptPubKey = {
|
||||
//everything can be a NonStandardScriptPubkey, thus the trivially true function
|
||||
buildScript(asm.toVector, NonStandardScriptPubKeyImpl(_), { _ => true }, "")
|
||||
buildScript(asm.toVector, NonStandardScriptPubKeyImpl(_), { _ =>
|
||||
true
|
||||
}, "")
|
||||
}
|
||||
|
||||
def apply(asm: Seq[ScriptToken]): NonStandardScriptPubKey = fromAsm(asm)
|
||||
|
@ -453,53 +569,82 @@ case object EmptyScriptPubKey extends ScriptPubKey {
|
|||
override def asm: Seq[ScriptToken] = Vector.empty
|
||||
}
|
||||
|
||||
/** Factory companion object used to create ScriptPubKey objects */
|
||||
/** Factory companion object used to create
|
||||
* [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] objects */
|
||||
object ScriptPubKey extends ScriptFactory[ScriptPubKey] {
|
||||
def empty: ScriptPubKey = fromAsm(Nil)
|
||||
|
||||
/** Creates a scriptPubKey from its asm representation */
|
||||
/** Creates a `scriptPubKey` from its asm representation */
|
||||
def fromAsm(asm: Seq[ScriptToken]): ScriptPubKey = asm match {
|
||||
case Nil => EmptyScriptPubKey
|
||||
case _ if P2PKHScriptPubKey.isP2PKHScriptPubKey(asm) => P2PKHScriptPubKey(asm)
|
||||
case _ if P2PKHScriptPubKey.isP2PKHScriptPubKey(asm) =>
|
||||
P2PKHScriptPubKey(asm)
|
||||
case _ if P2SHScriptPubKey.isP2SHScriptPubKey(asm) => P2SHScriptPubKey(asm)
|
||||
case _ if P2PKScriptPubKey.isP2PKScriptPubKey(asm) => P2PKScriptPubKey(asm)
|
||||
case _ if MultiSignatureScriptPubKey.isMultiSignatureScriptPubKey(asm) => MultiSignatureScriptPubKey(asm)
|
||||
case _ if MultiSignatureScriptPubKey.isMultiSignatureScriptPubKey(asm) =>
|
||||
MultiSignatureScriptPubKey(asm)
|
||||
case _ if CLTVScriptPubKey.isCLTVScriptPubKey(asm) => CLTVScriptPubKey(asm)
|
||||
case _ if CSVScriptPubKey.isCSVScriptPubKey(asm) => CSVScriptPubKey(asm)
|
||||
case _ if WitnessScriptPubKey.isWitnessScriptPubKey(asm) => WitnessScriptPubKey(asm).get
|
||||
case _ if WitnessCommitment.isWitnessCommitment(asm) => WitnessCommitment(asm)
|
||||
case _ if CSVScriptPubKey.isCSVScriptPubKey(asm) => CSVScriptPubKey(asm)
|
||||
case _ if WitnessScriptPubKey.isWitnessScriptPubKey(asm) =>
|
||||
WitnessScriptPubKey(asm).get
|
||||
case _ if WitnessCommitment.isWitnessCommitment(asm) =>
|
||||
WitnessCommitment(asm)
|
||||
case _ => NonStandardScriptPubKey(asm)
|
||||
}
|
||||
|
||||
def apply(asm: Seq[ScriptToken]): ScriptPubKey = fromAsm(asm)
|
||||
}
|
||||
|
||||
/** This type represents a [[ScriptPubKey]] to evaluate a [[ScriptWitness]] */
|
||||
/** This type represents a
|
||||
* [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] to evaluate a
|
||||
* [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] */
|
||||
sealed trait WitnessScriptPubKey extends ScriptPubKey {
|
||||
def witnessProgram: Seq[ScriptToken]
|
||||
def witnessVersion = WitnessVersion(asm.head)
|
||||
}
|
||||
|
||||
object WitnessScriptPubKey {
|
||||
/** Witness scripts must begin with one of these operations, see BIP141 */
|
||||
val validWitVersions: Seq[ScriptNumberOperation] = Seq(OP_0, OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_7, OP_8,
|
||||
OP_9, OP_10, OP_11, OP_12, OP_13, OP_14, OP_15, OP_16)
|
||||
|
||||
/** Witness scripts must begin with one of these operations, see
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP141]] */
|
||||
val validWitVersions: Seq[ScriptNumberOperation] = Seq(OP_0,
|
||||
OP_1,
|
||||
OP_2,
|
||||
OP_3,
|
||||
OP_4,
|
||||
OP_5,
|
||||
OP_6,
|
||||
OP_7,
|
||||
OP_8,
|
||||
OP_9,
|
||||
OP_10,
|
||||
OP_11,
|
||||
OP_12,
|
||||
OP_13,
|
||||
OP_14,
|
||||
OP_15,
|
||||
OP_16)
|
||||
|
||||
val unassignedWitVersions = validWitVersions.tail
|
||||
|
||||
def apply(asm: Seq[ScriptToken]): Option[WitnessScriptPubKey] = fromAsm(asm)
|
||||
|
||||
def fromAsm(asm: Seq[ScriptToken]): Option[WitnessScriptPubKey] = asm match {
|
||||
case _ if P2WPKHWitnessSPKV0.isValid(asm) => Some(P2WPKHWitnessSPKV0.fromAsm(asm))
|
||||
case _ if P2WSHWitnessSPKV0.isValid(asm) => Some(P2WSHWitnessSPKV0.fromAsm(asm))
|
||||
case _ if WitnessScriptPubKey.isWitnessScriptPubKey(asm) => Some(UnassignedWitnessScriptPubKey(asm))
|
||||
case _ if P2WPKHWitnessSPKV0.isValid(asm) =>
|
||||
Some(P2WPKHWitnessSPKV0.fromAsm(asm))
|
||||
case _ if P2WSHWitnessSPKV0.isValid(asm) =>
|
||||
Some(P2WSHWitnessSPKV0.fromAsm(asm))
|
||||
case _ if WitnessScriptPubKey.isWitnessScriptPubKey(asm) =>
|
||||
Some(UnassignedWitnessScriptPubKey(asm))
|
||||
case _ => None
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given asm is a valid [[org.bitcoins.core.protocol.script.WitnessScriptPubKey]]
|
||||
* Mimics this function inside of Bitcoin Core
|
||||
* [[https://github.com/bitcoin/bitcoin/blob/14d01309bed59afb08651f2b701ff90371b15b20/src/script/script.cpp#L223-L237]]
|
||||
* Checks if the given asm is a valid
|
||||
* [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]]
|
||||
* Mimics
|
||||
* [[https://github.com/bitcoin/bitcoin/blob/14d01309bed59afb08651f2b701ff90371b15b20/src/script/script.cpp#L223-L237 this function]]
|
||||
* inside of Bitcoin Core
|
||||
*/
|
||||
def isWitnessScriptPubKey(asm: Seq[ScriptToken]): Boolean = {
|
||||
|
||||
|
@ -512,7 +657,8 @@ object WitnessScriptPubKey {
|
|||
|
||||
//we can also have a LockTimeScriptPubKey with a nested 0 public key multisig script, need to check that as well
|
||||
val bytes = BitcoinSUtil.toByteVector(asm)
|
||||
val isMultiSig = MultiSignatureScriptPubKey.isMultiSignatureScriptPubKey(asm)
|
||||
val isMultiSig =
|
||||
MultiSignatureScriptPubKey.isMultiSignatureScriptPubKey(asm)
|
||||
val isLockTimeSPK = {
|
||||
LockTimeScriptPubKey.isValidLockTimeScriptPubKey(asm)
|
||||
}
|
||||
|
@ -526,7 +672,8 @@ object WitnessScriptPubKey {
|
|||
}
|
||||
}
|
||||
|
||||
/** Represents a [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program]] */
|
||||
/** Represents a
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program BIP141 Witness program]] */
|
||||
sealed abstract class WitnessScriptPubKeyV0 extends WitnessScriptPubKey {
|
||||
override def witnessProgram: Seq[ScriptToken] = asm.tail.tail
|
||||
}
|
||||
|
@ -534,20 +681,23 @@ sealed abstract class WitnessScriptPubKeyV0 extends WitnessScriptPubKey {
|
|||
object WitnessScriptPubKeyV0 {
|
||||
|
||||
/**
|
||||
* Mimics the function to determine if a [[ScriptPubKey]] contains a witness
|
||||
* A witness program is any valid [[ScriptPubKey]] that consists of a 1 byte push op and then a data push
|
||||
* Mimics the function to determine if a
|
||||
* [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] contains a witness
|
||||
* A witness program is any valid
|
||||
* [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] that consists of a 1 byte push op and then a data push
|
||||
* between 2 and 40 bytes
|
||||
* Verison 0 witness program need to have an OP_0 as the first operation
|
||||
* [[https://github.com/bitcoin/bitcoin/blob/449f9b8debcceb61a92043bc7031528a53627c47/src/script/script.cpp#L215-L229]]
|
||||
*/
|
||||
def isValid(asm: Seq[ScriptToken]): Boolean = {
|
||||
WitnessScriptPubKey.isWitnessScriptPubKey(asm) && asm.headOption == Some(OP_0)
|
||||
WitnessScriptPubKey.isWitnessScriptPubKey(asm) && asm.headOption == Some(
|
||||
OP_0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the pay-to-witness-pubkeyhash script pubkey type as defined in BIP141
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#P2WPKH]]
|
||||
* Represents the pay-to-witness-pubkeyhash script pubkey type as defined in
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#P2WPKH BIP141]]
|
||||
*/
|
||||
sealed abstract class P2WPKHWitnessSPKV0 extends WitnessScriptPubKeyV0 {
|
||||
def pubKeyHash: Sha256Hash160Digest = Sha256Hash160Digest(asm(2).bytes)
|
||||
|
@ -555,16 +705,21 @@ sealed abstract class P2WPKHWitnessSPKV0 extends WitnessScriptPubKeyV0 {
|
|||
}
|
||||
|
||||
object P2WPKHWitnessSPKV0 extends ScriptFactory[P2WPKHWitnessSPKV0] {
|
||||
private case class P2WPKHWitnessSPKV0Impl(override val asm: Vector[ScriptToken]) extends P2WPKHWitnessSPKV0
|
||||
private case class P2WPKHWitnessSPKV0Impl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends P2WPKHWitnessSPKV0
|
||||
|
||||
override def fromAsm(asm: Seq[ScriptToken]): P2WPKHWitnessSPKV0 = {
|
||||
buildScript(asm.toVector, P2WPKHWitnessSPKV0Impl(_), isValid(_), s"Given asm was not a P2WPKHWitnessSPKV0, got $asm")
|
||||
buildScript(asm.toVector,
|
||||
P2WPKHWitnessSPKV0Impl(_),
|
||||
isValid(_),
|
||||
s"Given asm was not a P2WPKHWitnessSPKV0, got $asm")
|
||||
}
|
||||
|
||||
def isValid(asm: Seq[ScriptToken]): Boolean = {
|
||||
val asmBytes = BitcoinSUtil.toByteVector(asm)
|
||||
WitnessScriptPubKeyV0.isValid(asm) &&
|
||||
asmBytes.size == 22
|
||||
asmBytes.size == 22
|
||||
}
|
||||
|
||||
def fromHash(hash: Sha256Hash160Digest): P2WPKHWitnessSPKV0 = {
|
||||
|
@ -575,7 +730,9 @@ object P2WPKHWitnessSPKV0 extends ScriptFactory[P2WPKHWitnessSPKV0] {
|
|||
/** Creates a P2WPKH witness script pubkey */
|
||||
def apply(pubKey: ECPublicKey): P2WPKHWitnessSPKV0 = {
|
||||
//https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#restrictions-on-public-key-type
|
||||
require(pubKey.isCompressed, s"Public key must be compressed to be used in a segwit script, see BIP143")
|
||||
require(
|
||||
pubKey.isCompressed,
|
||||
s"Public key must be compressed to be used in a segwit script, see BIP143")
|
||||
val hash = CryptoUtil.sha256Hash160(pubKey.bytes)
|
||||
val pushop = BitcoinScriptUtil.calculatePushOp(hash.bytes)
|
||||
fromAsm(Seq(OP_0) ++ pushop ++ Seq(ScriptConstant(hash.bytes)))
|
||||
|
@ -583,8 +740,8 @@ object P2WPKHWitnessSPKV0 extends ScriptFactory[P2WPKHWitnessSPKV0] {
|
|||
}
|
||||
|
||||
/**
|
||||
* Reprents the pay-to-witness-scripthash script pubkey type as defined in BIP141
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wsh]]
|
||||
* Reprents the pay-to-witness-scripthash script pubkey type as defined in
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wsh BIP141]]
|
||||
*/
|
||||
sealed abstract class P2WSHWitnessSPKV0 extends WitnessScriptPubKeyV0 {
|
||||
def scriptHash: Sha256Digest = Sha256Digest(asm(3).bytes)
|
||||
|
@ -592,16 +749,21 @@ sealed abstract class P2WSHWitnessSPKV0 extends WitnessScriptPubKeyV0 {
|
|||
}
|
||||
|
||||
object P2WSHWitnessSPKV0 extends ScriptFactory[P2WSHWitnessSPKV0] {
|
||||
private case class P2WSHWitnessSPKV0Impl(override val asm: Vector[ScriptToken]) extends P2WSHWitnessSPKV0
|
||||
private case class P2WSHWitnessSPKV0Impl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends P2WSHWitnessSPKV0
|
||||
|
||||
override def fromAsm(asm: Seq[ScriptToken]): P2WSHWitnessSPKV0 = {
|
||||
buildScript(asm.toVector, P2WSHWitnessSPKV0Impl(_), isValid(_), s"Given asm was not a P2WSHWitnessSPKV0, got $asm")
|
||||
buildScript(asm.toVector,
|
||||
P2WSHWitnessSPKV0Impl(_),
|
||||
isValid(_),
|
||||
s"Given asm was not a P2WSHWitnessSPKV0, got $asm")
|
||||
}
|
||||
|
||||
def isValid(asm: Seq[ScriptToken]): Boolean = {
|
||||
val asmBytes = BitcoinSUtil.toByteVector(asm)
|
||||
WitnessScriptPubKeyV0.isValid(asm) &&
|
||||
asmBytes.size == 34
|
||||
asmBytes.size == 34
|
||||
}
|
||||
|
||||
def fromHash(hash: Sha256Digest): P2WSHWitnessSPKV0 = {
|
||||
|
@ -610,26 +772,37 @@ object P2WSHWitnessSPKV0 extends ScriptFactory[P2WSHWitnessSPKV0] {
|
|||
}
|
||||
|
||||
def apply(spk: ScriptPubKey): P2WSHWitnessSPKV0 = {
|
||||
require(BitcoinScriptUtil.isOnlyCompressedPubKey(spk), s"Public key must be compressed to be used in a segwit script, see BIP143")
|
||||
require(
|
||||
BitcoinScriptUtil.isOnlyCompressedPubKey(spk),
|
||||
s"Public key must be compressed to be used in a segwit script, see BIP143")
|
||||
val hash = CryptoUtil.sha256(spk.asmBytes)
|
||||
val pushop = BitcoinScriptUtil.calculatePushOp(hash.bytes)
|
||||
fromAsm(Seq(OP_0) ++ pushop ++ Seq(ScriptConstant(hash.bytes)))
|
||||
}
|
||||
}
|
||||
|
||||
/** Type to represent all [[org.bitcoins.core.protocol.script.WitnessScriptPubKey]]s we have not used yet in the bitcoin protocol */
|
||||
/** Type to represent all
|
||||
* [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]]s
|
||||
* we have not used yet in the bitcoin protocol */
|
||||
sealed trait UnassignedWitnessScriptPubKey extends WitnessScriptPubKey {
|
||||
override def witnessProgram: Seq[ScriptToken] = asm.tail.tail
|
||||
}
|
||||
|
||||
object UnassignedWitnessScriptPubKey extends ScriptFactory[UnassignedWitnessScriptPubKey] {
|
||||
private case class UnassignedWitnessScriptPubKeyImpl(override val asm: Vector[ScriptToken]) extends UnassignedWitnessScriptPubKey {
|
||||
object UnassignedWitnessScriptPubKey
|
||||
extends ScriptFactory[UnassignedWitnessScriptPubKey] {
|
||||
private case class UnassignedWitnessScriptPubKeyImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends UnassignedWitnessScriptPubKey {
|
||||
override def toString = "UnassignedWitnessScriptPubKeyImpl(" + hex + ")"
|
||||
}
|
||||
|
||||
override def fromAsm(asm: Seq[ScriptToken]): UnassignedWitnessScriptPubKey = {
|
||||
buildScript(asm.toVector, UnassignedWitnessScriptPubKeyImpl(_), WitnessScriptPubKey.isWitnessScriptPubKey(_),
|
||||
"Given asm was not a valid witness script pubkey: " + asm)
|
||||
buildScript(
|
||||
asm.toVector,
|
||||
UnassignedWitnessScriptPubKeyImpl(_),
|
||||
WitnessScriptPubKey.isWitnessScriptPubKey(_),
|
||||
"Given asm was not a valid witness script pubkey: " + asm
|
||||
)
|
||||
}
|
||||
def apply(asm: Seq[ScriptToken]): UnassignedWitnessScriptPubKey = fromAsm(asm)
|
||||
}
|
||||
|
@ -637,35 +810,51 @@ object UnassignedWitnessScriptPubKey extends ScriptFactory[UnassignedWitnessScri
|
|||
/**
|
||||
* This trait represents the witness commitment found in the coinbase transaction
|
||||
* This is needed to commit to the wtxids of all of the witness transactions, since the merkle tree
|
||||
* does not commit to the witnesses for all [[org.bitcoins.core.protocol.transaction.WitnessTransaction]]
|
||||
* does not commit to the witnesses for all
|
||||
* [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]]
|
||||
* See BIP141 for more info
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure]]
|
||||
*/
|
||||
sealed trait WitnessCommitment extends ScriptPubKey {
|
||||
/** The commitment to the [[WitnessTransaction]]s in the [[Block]] */
|
||||
def witnessRootHash: DoubleSha256Digest = DoubleSha256Digest(asm(2).bytes.splitAt(4)._2)
|
||||
|
||||
/** The commitment to the
|
||||
* [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]]s in the
|
||||
* [[org.bitcoins.core.protocol.blockchain.Block Block]] */
|
||||
def witnessRootHash: DoubleSha256Digest =
|
||||
DoubleSha256Digest(asm(2).bytes.splitAt(4)._2)
|
||||
}
|
||||
|
||||
object WitnessCommitment extends ScriptFactory[WitnessCommitment] {
|
||||
private case class WitnessCommitmentImpl(override val asm: Vector[ScriptToken]) extends WitnessCommitment {
|
||||
private case class WitnessCommitmentImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends WitnessCommitment {
|
||||
override def toString = "WitnessCommitmentImpl(" + hex + ")"
|
||||
}
|
||||
|
||||
/** Every witness commitment must start with this header, see BIP141 for details */
|
||||
/** Every witness commitment must start with this header, see
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141]]
|
||||
* for details */
|
||||
private val commitmentHeader = "aa21a9ed"
|
||||
|
||||
def apply(asm: Seq[ScriptToken]): WitnessCommitment = fromAsm(asm)
|
||||
|
||||
override def fromAsm(asm: Seq[ScriptToken]): WitnessCommitment = {
|
||||
buildScript(asm.toVector, WitnessCommitmentImpl(_), isWitnessCommitment(_), "Given asm was not a valid witness commitment, got: " + asm)
|
||||
buildScript(asm.toVector,
|
||||
WitnessCommitmentImpl(_),
|
||||
isWitnessCommitment(_),
|
||||
"Given asm was not a valid witness commitment, got: " + asm)
|
||||
}
|
||||
|
||||
def apply(hash: DoubleSha256Digest): WitnessCommitment = {
|
||||
WitnessCommitment(Seq(OP_RETURN, BytesToPushOntoStack(36), ScriptConstant(commitmentHeader + hash.hex)))
|
||||
WitnessCommitment(
|
||||
Seq(OP_RETURN,
|
||||
BytesToPushOntoStack(36),
|
||||
ScriptConstant(commitmentHeader + hash.hex)))
|
||||
}
|
||||
|
||||
/**
|
||||
* This determines if the given asm has the correct witness structure according to BIP141
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure]]
|
||||
* This determines if the given asm has the correct witness structure according to
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure BIP141]]
|
||||
*/
|
||||
def isWitnessCommitment(asm: Seq[ScriptToken]): Boolean = {
|
||||
if (asm.size < 3) false
|
||||
|
@ -674,7 +863,7 @@ object WitnessCommitment extends ScriptFactory[WitnessCommitment] {
|
|||
val asmBytes = BitcoinSUtil.toByteVector(asm)
|
||||
val Seq(opReturn, pushOp, constant) = asm.take(3)
|
||||
opReturn == OP_RETURN && pushOp == BytesToPushOntoStack(36) &&
|
||||
constant.hex.take(8) == commitmentHeader && asmBytes.size >= minCommitmentSize
|
||||
constant.hex.take(8) == commitmentHeader && asmBytes.size >= minCommitmentSize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,15 +29,19 @@ sealed trait NonStandardScriptSignature extends ScriptSignature {
|
|||
override def toString = "NonStandardScriptSignature(" + hex + ")"
|
||||
}
|
||||
|
||||
object NonStandardScriptSignature extends ScriptFactory[NonStandardScriptSignature] {
|
||||
private case class NonStandardScriptSignatureImpl(override val asm: Vector[ScriptToken]) extends NonStandardScriptSignature
|
||||
object NonStandardScriptSignature
|
||||
extends ScriptFactory[NonStandardScriptSignature] {
|
||||
private case class NonStandardScriptSignatureImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends NonStandardScriptSignature
|
||||
|
||||
def fromAsm(asm: Seq[ScriptToken]): NonStandardScriptSignature = {
|
||||
buildScript(
|
||||
asm = asm.toVector,
|
||||
constructor = NonStandardScriptSignatureImpl(_),
|
||||
invariant = { _ => true },
|
||||
errorMsg = "")
|
||||
buildScript(asm = asm.toVector,
|
||||
constructor = NonStandardScriptSignatureImpl(_),
|
||||
invariant = { _ =>
|
||||
true
|
||||
},
|
||||
errorMsg = "")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,32 +68,42 @@ sealed trait P2PKHScriptSignature extends ScriptSignature {
|
|||
}
|
||||
|
||||
object P2PKHScriptSignature extends ScriptFactory[P2PKHScriptSignature] {
|
||||
private case class P2PKHScriptSignatureImpl(override val asm: Vector[ScriptToken]) extends P2PKHScriptSignature
|
||||
private case class P2PKHScriptSignatureImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends P2PKHScriptSignature
|
||||
|
||||
def fromAsm(asm: Seq[ScriptToken]): P2PKHScriptSignature = {
|
||||
buildScript(
|
||||
asm = asm.toVector,
|
||||
constructor = P2PKHScriptSignatureImpl(_),
|
||||
invariant = isP2PKHScriptSig(_),
|
||||
errorMsg = s"Given asm was not a P2PKHScriptSignature, got: $asm")
|
||||
errorMsg = s"Given asm was not a P2PKHScriptSignature, got: $asm"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a script signature from a digital signature and a public key
|
||||
* this is a pay to public key hash script sig
|
||||
*/
|
||||
def apply(signature: ECDigitalSignature, pubKey: ECPublicKey): P2PKHScriptSignature = {
|
||||
val signatureBytesToPushOntoStack = BitcoinScriptUtil.calculatePushOp(signature.bytes)
|
||||
val pubKeyBytesToPushOntoStack = BitcoinScriptUtil.calculatePushOp(pubKey.bytes)
|
||||
val asm: Seq[ScriptToken] = signatureBytesToPushOntoStack ++ Seq(ScriptConstant(signature.hex)) ++
|
||||
def apply(
|
||||
signature: ECDigitalSignature,
|
||||
pubKey: ECPublicKey): P2PKHScriptSignature = {
|
||||
val signatureBytesToPushOntoStack =
|
||||
BitcoinScriptUtil.calculatePushOp(signature.bytes)
|
||||
val pubKeyBytesToPushOntoStack =
|
||||
BitcoinScriptUtil.calculatePushOp(pubKey.bytes)
|
||||
val asm: Seq[ScriptToken] = signatureBytesToPushOntoStack ++ Seq(
|
||||
ScriptConstant(signature.hex)) ++
|
||||
pubKeyBytesToPushOntoStack ++ Seq(ScriptConstant(pubKey.hex))
|
||||
fromAsm(asm)
|
||||
}
|
||||
|
||||
/** Determines if the given asm matches a [[P2PKHScriptSignature]] */
|
||||
def isP2PKHScriptSig(asm: Seq[ScriptToken]): Boolean = asm match {
|
||||
case Seq(_: BytesToPushOntoStack, _: ScriptConstant, _: BytesToPushOntoStack,
|
||||
z: ScriptConstant) =>
|
||||
case Seq(_: BytesToPushOntoStack,
|
||||
_: ScriptConstant,
|
||||
_: BytesToPushOntoStack,
|
||||
z: ScriptConstant) =>
|
||||
if (ECPublicKey.isFullyValid(z.bytes)) true
|
||||
else !P2SHScriptSignature.isRedeemScript(z)
|
||||
case _ => false
|
||||
|
@ -108,7 +122,7 @@ sealed trait P2SHScriptSignature extends ScriptSignature {
|
|||
def redeemScript: ScriptPubKey = {
|
||||
val scriptSig = scriptSignatureNoRedeemScript
|
||||
if (scriptSig == EmptyScriptSignature &&
|
||||
WitnessScriptPubKey.isWitnessScriptPubKey(asm.tail)) {
|
||||
WitnessScriptPubKey.isWitnessScriptPubKey(asm.tail)) {
|
||||
//if we have an EmptyScriptSignature, we need to check if the rest of the asm
|
||||
//is a Witness script. It is not necessarily a witness script, since this code
|
||||
//path might be used for signing a normal p2sh spk in TransactionSignatureSerializer
|
||||
|
@ -128,17 +142,19 @@ sealed trait P2SHScriptSignature extends ScriptSignature {
|
|||
val asmWithoutRedeemScriptAndPushOp: Try[Seq[ScriptToken]] = Try {
|
||||
asm(asm.size - 2) match {
|
||||
case _: BytesToPushOntoStack => asm.dropRight(2)
|
||||
case _ => asm.dropRight(3)
|
||||
case _ => asm.dropRight(3)
|
||||
}
|
||||
}
|
||||
val script = asmWithoutRedeemScriptAndPushOp.getOrElse(EmptyScriptSignature.asm)
|
||||
val script =
|
||||
asmWithoutRedeemScriptAndPushOp.getOrElse(EmptyScriptSignature.asm)
|
||||
ScriptSignature.fromAsm(script)
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the public keys for the p2sh scriptSignature */
|
||||
def publicKeys: Seq[ECPublicKey] = {
|
||||
val pubKeys: Seq[ScriptToken] = redeemScript.asm.filter(_.isInstanceOf[ScriptConstant])
|
||||
val pubKeys: Seq[ScriptToken] = redeemScript.asm
|
||||
.filter(_.isInstanceOf[ScriptConstant])
|
||||
.filterNot(_.isInstanceOf[ScriptNumberOperation])
|
||||
pubKeys.map(k => ECPublicKey(k.hex))
|
||||
}
|
||||
|
@ -146,8 +162,8 @@ sealed trait P2SHScriptSignature extends ScriptSignature {
|
|||
/** The digital signatures inside of the scriptSig */
|
||||
def signatures: Seq[ECDigitalSignature] = {
|
||||
val sigs = {
|
||||
scriptSignatureNoRedeemScript
|
||||
.asm.filter(_.isInstanceOf[ScriptConstant])
|
||||
scriptSignatureNoRedeemScript.asm
|
||||
.filter(_.isInstanceOf[ScriptConstant])
|
||||
.filterNot(_.isInstanceOf[ScriptNumberOperation])
|
||||
.filterNot(_.hex.length < 100)
|
||||
}
|
||||
|
@ -167,13 +183,18 @@ sealed trait P2SHScriptSignature extends ScriptSignature {
|
|||
}
|
||||
|
||||
object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] {
|
||||
private case class P2SHScriptSignatureImpl(override val asm: Vector[ScriptToken]) extends P2SHScriptSignature
|
||||
private case class P2SHScriptSignatureImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends P2SHScriptSignature
|
||||
|
||||
def apply(scriptSig: ScriptSignature, redeemScript: ScriptPubKey): P2SHScriptSignature = {
|
||||
def apply(
|
||||
scriptSig: ScriptSignature,
|
||||
redeemScript: ScriptPubKey): P2SHScriptSignature = {
|
||||
//we need to calculate the size of the redeemScript and add the corresponding push op
|
||||
val serializedRedeemScript = ScriptConstant(redeemScript.asmBytes)
|
||||
val pushOps = BitcoinScriptUtil.calculatePushOp(serializedRedeemScript)
|
||||
val asm: Seq[ScriptToken] = scriptSig.asm ++ pushOps ++ Seq(serializedRedeemScript)
|
||||
val asm: Seq[ScriptToken] = scriptSig.asm ++ pushOps ++ Seq(
|
||||
serializedRedeemScript)
|
||||
fromAsm(asm)
|
||||
}
|
||||
|
||||
|
@ -187,18 +208,20 @@ object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] {
|
|||
//we have a P2SHScriptPubKey
|
||||
//previously P2SHScriptSignature's redeem script had to be standard scriptPubKey's, this
|
||||
//was removed in 0.11 or 0.12 of Bitcoin Core
|
||||
buildScript(
|
||||
asm = asm.toVector,
|
||||
constructor = P2SHScriptSignatureImpl(_),
|
||||
invariant = { _ => true },
|
||||
errorMsg = s"Given asm tokens are not a p2sh scriptSig, got: $asm")
|
||||
buildScript(asm = asm.toVector,
|
||||
constructor = P2SHScriptSignatureImpl(_),
|
||||
invariant = { _ =>
|
||||
true
|
||||
},
|
||||
errorMsg =
|
||||
s"Given asm tokens are not a p2sh scriptSig, got: $asm")
|
||||
}
|
||||
|
||||
/** Tests if the given asm tokens are a [[P2SHScriptSignature]] */
|
||||
def isP2SHScriptSig(asm: Seq[ScriptToken]): Boolean = asm match {
|
||||
case _ if asm.size > 1 && isRedeemScript(asm.last) => true
|
||||
case _ if asm.size > 1 && isRedeemScript(asm.last) => true
|
||||
case _ if WitnessScriptPubKey.isWitnessScriptPubKey(asm) => true
|
||||
case _ => false
|
||||
case _ => false
|
||||
}
|
||||
|
||||
/** Detects if the given script token is a redeem script */
|
||||
|
@ -207,12 +230,13 @@ object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] {
|
|||
redeemScriptTry match {
|
||||
case Success(redeemScript) =>
|
||||
redeemScript match {
|
||||
case _: P2PKHScriptPubKey | _: MultiSignatureScriptPubKey
|
||||
| _: P2SHScriptPubKey | _: P2PKScriptPubKey
|
||||
| _: CLTVScriptPubKey | _: CSVScriptPubKey
|
||||
| _: WitnessScriptPubKeyV0 | _: UnassignedWitnessScriptPubKey => true
|
||||
case _: P2PKHScriptPubKey | _: MultiSignatureScriptPubKey |
|
||||
_: P2SHScriptPubKey | _: P2PKScriptPubKey | _: CLTVScriptPubKey |
|
||||
_: CSVScriptPubKey | _: WitnessScriptPubKeyV0 |
|
||||
_: UnassignedWitnessScriptPubKey =>
|
||||
true
|
||||
case _: NonStandardScriptPubKey | _: WitnessCommitment => false
|
||||
case EmptyScriptPubKey => false
|
||||
case EmptyScriptPubKey => false
|
||||
}
|
||||
case Failure(_) => false
|
||||
}
|
||||
|
@ -236,18 +260,23 @@ sealed trait MultiSignatureScriptSignature extends ScriptSignature {
|
|||
|
||||
/** The digital signatures inside of the scriptSig */
|
||||
def signatures: Seq[ECDigitalSignature] = {
|
||||
asm.tail.filter(_.isInstanceOf[ScriptConstant])
|
||||
asm.tail
|
||||
.filter(_.isInstanceOf[ScriptConstant])
|
||||
.map(sig => ECDigitalSignature(sig.hex))
|
||||
}
|
||||
|
||||
override def toString = "MultiSignatureScriptSignature(" + hex + ")"
|
||||
}
|
||||
|
||||
object MultiSignatureScriptSignature extends ScriptFactory[MultiSignatureScriptSignature] {
|
||||
object MultiSignatureScriptSignature
|
||||
extends ScriptFactory[MultiSignatureScriptSignature] {
|
||||
|
||||
private case class MultiSignatureScriptSignatureImpl(override val asm: Vector[ScriptToken]) extends MultiSignatureScriptSignature
|
||||
private case class MultiSignatureScriptSignatureImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends MultiSignatureScriptSignature
|
||||
|
||||
def apply(signatures: Seq[ECDigitalSignature]): MultiSignatureScriptSignature = {
|
||||
def apply(
|
||||
signatures: Seq[ECDigitalSignature]): MultiSignatureScriptSignature = {
|
||||
val sigsPushOpsPairs: Seq[Seq[ScriptToken]] = for {
|
||||
sig <- signatures
|
||||
constant = ScriptConstant(sig.bytes)
|
||||
|
@ -264,7 +293,9 @@ object MultiSignatureScriptSignature extends ScriptFactory[MultiSignatureScriptS
|
|||
asm = asm.toVector,
|
||||
constructor = MultiSignatureScriptSignatureImpl(_),
|
||||
invariant = isMultiSignatureScriptSignature(_),
|
||||
errorMsg = s"The given asm tokens were not a multisignature script sig: $asm")
|
||||
errorMsg =
|
||||
s"The given asm tokens were not a multisignature script sig: $asm"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -274,15 +305,21 @@ object MultiSignatureScriptSignature extends ScriptFactory[MultiSignatureScriptS
|
|||
* @param asm the asm to check if it falls in the multisignature script sig format
|
||||
* @return boolean indicating if the scriptsignature is a multisignature script signature
|
||||
*/
|
||||
def isMultiSignatureScriptSignature(asm: Seq[ScriptToken]): Boolean = asm.isEmpty match {
|
||||
case true => false
|
||||
//case false if (asm.size == 1) => false
|
||||
case false =>
|
||||
val firstTokenIsScriptNumberOperation = asm.head.isInstanceOf[ScriptNumberOperation]
|
||||
val restOfScriptIsPushOpsOrScriptConstants = asm.tail.map(
|
||||
token => token.isInstanceOf[ScriptConstant] || StackPushOperationFactory.isPushOperation(token)).exists(_ == false)
|
||||
firstTokenIsScriptNumberOperation && !restOfScriptIsPushOpsOrScriptConstants
|
||||
}
|
||||
def isMultiSignatureScriptSignature(asm: Seq[ScriptToken]): Boolean =
|
||||
asm.isEmpty match {
|
||||
case true => false
|
||||
//case false if (asm.size == 1) => false
|
||||
case false =>
|
||||
val firstTokenIsScriptNumberOperation =
|
||||
asm.head.isInstanceOf[ScriptNumberOperation]
|
||||
val restOfScriptIsPushOpsOrScriptConstants = asm.tail
|
||||
.map(
|
||||
token =>
|
||||
token.isInstanceOf[ScriptConstant] || StackPushOperationFactory
|
||||
.isPushOperation(token))
|
||||
.exists(_ == false)
|
||||
firstTokenIsScriptNumberOperation && !restOfScriptIsPushOpsOrScriptConstants
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -304,7 +341,9 @@ sealed trait P2PKScriptSignature extends ScriptSignature {
|
|||
}
|
||||
|
||||
object P2PKScriptSignature extends ScriptFactory[P2PKScriptSignature] {
|
||||
private case class P2PKScriptSignatureImpl(override val asm: Vector[ScriptToken]) extends P2PKScriptSignature
|
||||
private case class P2PKScriptSignatureImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends P2PKScriptSignature
|
||||
|
||||
def apply(signature: ECDigitalSignature): P2PKScriptSignature = {
|
||||
val pushOps = BitcoinScriptUtil.calculatePushOp(signature.bytes)
|
||||
|
@ -314,14 +353,16 @@ object P2PKScriptSignature extends ScriptFactory[P2PKScriptSignature] {
|
|||
}
|
||||
|
||||
def fromAsm(asm: Seq[ScriptToken]): P2PKScriptSignature = {
|
||||
buildScript(asm.toVector, P2PKScriptSignatureImpl(_), isP2PKScriptSignature(_),
|
||||
"The given asm tokens were not a p2pk script sig: " + asm)
|
||||
buildScript(asm.toVector,
|
||||
P2PKScriptSignatureImpl(_),
|
||||
isP2PKScriptSignature(_),
|
||||
"The given asm tokens were not a p2pk script sig: " + asm)
|
||||
}
|
||||
|
||||
/** P2PK scriptSigs always have the pattern [pushop, digitalSignature] */
|
||||
def isP2PKScriptSignature(asm: Seq[ScriptToken]): Boolean = asm match {
|
||||
case Seq(_: BytesToPushOntoStack, _: ScriptConstant) => true
|
||||
case _ => false
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,14 +383,17 @@ sealed trait CLTVScriptSignature extends LockTimeScriptSignature {
|
|||
* [[CLTVScriptPubKey]] does not manipulate the stack
|
||||
*/
|
||||
object CLTVScriptSignature extends ScriptFactory[CLTVScriptSignature] {
|
||||
private case class CLTVScriptSignatureImpl(override val asm: Vector[ScriptToken]) extends CLTVScriptSignature
|
||||
private case class CLTVScriptSignatureImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends CLTVScriptSignature
|
||||
|
||||
override def fromAsm(asm: Seq[ScriptToken]): CLTVScriptSignature = {
|
||||
buildScript(
|
||||
asm = asm.toVector,
|
||||
constructor = CLTVScriptSignatureImpl(_),
|
||||
invariant = { _ => true },
|
||||
errorMsg = s"Given asm was not a CLTVScriptSignature $asm")
|
||||
buildScript(asm = asm.toVector,
|
||||
constructor = CLTVScriptSignatureImpl(_),
|
||||
invariant = { _ =>
|
||||
true
|
||||
},
|
||||
errorMsg = s"Given asm was not a CLTVScriptSignature $asm")
|
||||
}
|
||||
|
||||
override def fromHex(hex: String): CLTVScriptSignature = {
|
||||
|
@ -366,14 +410,17 @@ sealed trait CSVScriptSignature extends LockTimeScriptSignature {
|
|||
}
|
||||
|
||||
object CSVScriptSignature extends ScriptFactory[CSVScriptSignature] {
|
||||
private case class CSVScriptSignatureImpl(override val asm: Vector[ScriptToken]) extends CSVScriptSignature
|
||||
private case class CSVScriptSignatureImpl(
|
||||
override val asm: Vector[ScriptToken])
|
||||
extends CSVScriptSignature
|
||||
|
||||
override def fromAsm(asm: Seq[ScriptToken]): CSVScriptSignature = {
|
||||
buildScript(
|
||||
asm = asm.toVector,
|
||||
constructor = CSVScriptSignatureImpl(_),
|
||||
invariant = { _ => true },
|
||||
errorMsg = s"Given asm was not a CLTVScriptSignature $asm")
|
||||
buildScript(asm = asm.toVector,
|
||||
constructor = CSVScriptSignatureImpl(_),
|
||||
invariant = { _ =>
|
||||
true
|
||||
},
|
||||
errorMsg = s"Given asm was not a CLTVScriptSignature $asm")
|
||||
}
|
||||
|
||||
override def fromHex(hex: String): CSVScriptSignature = {
|
||||
|
@ -399,12 +446,18 @@ object ScriptSignature extends ScriptFactory[ScriptSignature] {
|
|||
/** Creates a scriptSignature from the list of script tokens */
|
||||
def fromAsm(tokens: Seq[ScriptToken]): ScriptSignature = tokens match {
|
||||
case Nil => EmptyScriptSignature
|
||||
case _ if (tokens.size > 1 && P2SHScriptSignature.isRedeemScript(tokens.last)) =>
|
||||
case _
|
||||
if (tokens.size > 1 && P2SHScriptSignature.isRedeemScript(
|
||||
tokens.last)) =>
|
||||
P2SHScriptSignature.fromAsm(tokens)
|
||||
case _ if (MultiSignatureScriptSignature.isMultiSignatureScriptSignature(tokens)) =>
|
||||
case _
|
||||
if (MultiSignatureScriptSignature.isMultiSignatureScriptSignature(
|
||||
tokens)) =>
|
||||
MultiSignatureScriptSignature.fromAsm(tokens)
|
||||
case _ if P2PKHScriptSignature.isP2PKHScriptSig(tokens) => P2PKHScriptSignature.fromAsm(tokens)
|
||||
case _ if P2PKScriptSignature.isP2PKScriptSignature(tokens) => P2PKScriptSignature.fromAsm(tokens)
|
||||
case _ if P2PKHScriptSignature.isP2PKHScriptSig(tokens) =>
|
||||
P2PKHScriptSignature.fromAsm(tokens)
|
||||
case _ if P2PKScriptSignature.isP2PKScriptSignature(tokens) =>
|
||||
P2PKScriptSignature.fromAsm(tokens)
|
||||
case _ => NonStandardScriptSignature.fromAsm(tokens)
|
||||
}
|
||||
|
||||
|
@ -414,21 +467,32 @@ object ScriptSignature extends ScriptFactory[ScriptSignature] {
|
|||
* @param scriptPubKey the scriptPubKey which the script signature is trying to spend
|
||||
* @return
|
||||
*/
|
||||
def fromScriptPubKey(tokens: Seq[ScriptToken], scriptPubKey: ScriptPubKey): Try[ScriptSignature] = scriptPubKey match {
|
||||
case _: P2SHScriptPubKey => Try(P2SHScriptSignature.fromAsm(tokens))
|
||||
def fromScriptPubKey(
|
||||
tokens: Seq[ScriptToken],
|
||||
scriptPubKey: ScriptPubKey): Try[ScriptSignature] = scriptPubKey match {
|
||||
case _: P2SHScriptPubKey => Try(P2SHScriptSignature.fromAsm(tokens))
|
||||
case _: P2PKHScriptPubKey => Try(P2PKHScriptSignature.fromAsm(tokens))
|
||||
case _: P2PKScriptPubKey => Try(P2PKScriptSignature.fromAsm(tokens))
|
||||
case _: MultiSignatureScriptPubKey => Try(MultiSignatureScriptSignature.fromAsm(tokens))
|
||||
case _: NonStandardScriptPubKey => Try(NonStandardScriptSignature.fromAsm(tokens))
|
||||
case _: P2PKScriptPubKey => Try(P2PKScriptSignature.fromAsm(tokens))
|
||||
case _: MultiSignatureScriptPubKey =>
|
||||
Try(MultiSignatureScriptSignature.fromAsm(tokens))
|
||||
case _: NonStandardScriptPubKey =>
|
||||
Try(NonStandardScriptSignature.fromAsm(tokens))
|
||||
case s: CLTVScriptPubKey => fromScriptPubKey(tokens, s.nestedScriptPubKey)
|
||||
case s: CSVScriptPubKey => fromScriptPubKey(tokens, s.nestedScriptPubKey)
|
||||
case _: WitnessScriptPubKeyV0 | _: UnassignedWitnessScriptPubKey => Success(EmptyScriptSignature)
|
||||
case s: CSVScriptPubKey => fromScriptPubKey(tokens, s.nestedScriptPubKey)
|
||||
case _: WitnessScriptPubKeyV0 | _: UnassignedWitnessScriptPubKey =>
|
||||
Success(EmptyScriptSignature)
|
||||
case EmptyScriptPubKey =>
|
||||
if (tokens.isEmpty) Success(EmptyScriptSignature) else Try(NonStandardScriptSignature.fromAsm(tokens))
|
||||
case _: WitnessCommitment => Failure(new IllegalArgumentException("Cannot spend witness commitment scriptPubKey"))
|
||||
if (tokens.isEmpty) Success(EmptyScriptSignature)
|
||||
else Try(NonStandardScriptSignature.fromAsm(tokens))
|
||||
case _: WitnessCommitment =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Cannot spend witness commitment scriptPubKey"))
|
||||
}
|
||||
|
||||
def apply(tokens: Seq[ScriptToken], scriptPubKey: ScriptPubKey): Try[ScriptSignature] = {
|
||||
def apply(
|
||||
tokens: Seq[ScriptToken],
|
||||
scriptPubKey: ScriptPubKey): Try[ScriptSignature] = {
|
||||
fromScriptPubKey(tokens, scriptPubKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,10 +71,9 @@ object P2WPKHWitnessV0 {
|
|||
scriptSig match {
|
||||
case p2pkh: P2PKHScriptSignature =>
|
||||
P2WPKHWitnessV0(p2pkh.publicKey, p2pkh.signature)
|
||||
case x @ (_: LockTimeScriptSignature |
|
||||
_: MultiSignatureScriptSignature | _: NonStandardScriptSignature |
|
||||
_: P2PKScriptSignature | _: P2SHScriptSignature |
|
||||
EmptyScriptSignature) =>
|
||||
case x @ (_: LockTimeScriptSignature | _: MultiSignatureScriptSignature |
|
||||
_: NonStandardScriptSignature | _: P2PKScriptSignature |
|
||||
_: P2SHScriptSignature | EmptyScriptSignature) =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Expected P2PKHScriptSignature, got $x")
|
||||
}
|
||||
|
|
|
@ -96,8 +96,7 @@ sealed abstract class ScriptInterpreter {
|
|||
case _: P2PKHScriptPubKey | _: P2PKScriptPubKey |
|
||||
_: MultiSignatureScriptPubKey | _: CSVScriptPubKey |
|
||||
_: CLTVScriptPubKey | _: NonStandardScriptPubKey |
|
||||
_: WitnessCommitment |
|
||||
EmptyScriptPubKey =>
|
||||
_: WitnessCommitment | EmptyScriptPubKey =>
|
||||
scriptPubKeyExecutedProgram
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,13 +13,12 @@ trait RawScriptPubKeyParser extends RawBitcoinSerializer[ScriptPubKey] {
|
|||
override def read(bytes: ByteVector): ScriptPubKey = {
|
||||
if (bytes.isEmpty) EmptyScriptPubKey
|
||||
else {
|
||||
BitcoinScriptUtil.parseScript(
|
||||
bytes = bytes,
|
||||
f = ScriptPubKey.fromAsm)
|
||||
BitcoinScriptUtil.parseScript(bytes = bytes, f = ScriptPubKey.fromAsm)
|
||||
}
|
||||
}
|
||||
|
||||
override def write(scriptPubKey: ScriptPubKey): ByteVector = scriptPubKey.bytes
|
||||
override def write(scriptPubKey: ScriptPubKey): ByteVector =
|
||||
scriptPubKey.bytes
|
||||
}
|
||||
|
||||
object RawScriptPubKeyParser extends RawScriptPubKeyParser
|
||||
object RawScriptPubKeyParser extends RawScriptPubKeyParser
|
||||
|
|
|
@ -8,18 +8,17 @@ import scodec.bits.ByteVector
|
|||
/**
|
||||
* Created by chris on 1/12/16.
|
||||
*/
|
||||
sealed abstract class RawScriptSignatureParser extends RawBitcoinSerializer[ScriptSignature] {
|
||||
sealed abstract class RawScriptSignatureParser
|
||||
extends RawBitcoinSerializer[ScriptSignature] {
|
||||
|
||||
def read(bytes: ByteVector): ScriptSignature = {
|
||||
if (bytes.isEmpty) EmptyScriptSignature
|
||||
else {
|
||||
BitcoinScriptUtil.parseScript(
|
||||
bytes = bytes,
|
||||
f = ScriptSignature.fromAsm)
|
||||
BitcoinScriptUtil.parseScript(bytes = bytes, f = ScriptSignature.fromAsm)
|
||||
}
|
||||
}
|
||||
|
||||
def write(scriptSig: ScriptSignature): ByteVector = scriptSig.bytes
|
||||
}
|
||||
|
||||
object RawScriptSignatureParser extends RawScriptSignatureParser
|
||||
object RawScriptSignatureParser extends RawScriptSignatureParser
|
||||
|
|
|
@ -4,12 +4,29 @@ import org.bitcoins.core.consensus.Consensus
|
|||
import org.bitcoins.core.crypto._
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.protocol.CompactSizeUInt
|
||||
import org.bitcoins.core.protocol.script.{CLTVScriptPubKey, CSVScriptPubKey, EmptyScriptPubKey, _}
|
||||
import org.bitcoins.core.protocol.script.{
|
||||
CLTVScriptPubKey,
|
||||
CSVScriptPubKey,
|
||||
EmptyScriptPubKey,
|
||||
_
|
||||
}
|
||||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.crypto.{OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY, OP_CHECKSIG, OP_CHECKSIGVERIFY}
|
||||
import org.bitcoins.core.script.crypto.{
|
||||
OP_CHECKMULTISIG,
|
||||
OP_CHECKMULTISIGVERIFY,
|
||||
OP_CHECKSIG,
|
||||
OP_CHECKSIGVERIFY
|
||||
}
|
||||
import org.bitcoins.core.script.flag.{ScriptFlag, ScriptFlagUtil}
|
||||
import org.bitcoins.core.script.result.{ScriptError, ScriptErrorPubKeyType, ScriptErrorWitnessPubKeyType}
|
||||
import org.bitcoins.core.script.{ExecutionInProgressScriptProgram, ScriptProgram}
|
||||
import org.bitcoins.core.script.result.{
|
||||
ScriptError,
|
||||
ScriptErrorPubKeyType,
|
||||
ScriptErrorWitnessPubKeyType
|
||||
}
|
||||
import org.bitcoins.core.script.{
|
||||
ExecutionInProgressScriptProgram,
|
||||
ScriptProgram
|
||||
}
|
||||
import org.bitcoins.core.serializers.script.ScriptParser
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
|
@ -390,7 +407,8 @@ trait BitcoinScriptUtil extends BitcoinSLogger {
|
|||
}
|
||||
case _: P2PKHScriptPubKey | _: P2PKScriptPubKey |
|
||||
_: MultiSignatureScriptPubKey | _: NonStandardScriptPubKey |
|
||||
_: CLTVScriptPubKey | _: CSVScriptPubKey | _: WitnessCommitment | EmptyScriptPubKey =>
|
||||
_: CLTVScriptPubKey | _: CSVScriptPubKey | _: WitnessCommitment |
|
||||
EmptyScriptPubKey =>
|
||||
script
|
||||
}
|
||||
|
||||
|
@ -507,12 +525,15 @@ trait BitcoinScriptUtil extends BitcoinSLogger {
|
|||
}
|
||||
}
|
||||
|
||||
def parseScript[T <: Script](bytes: ByteVector, f: Vector[ScriptToken] => T): T = {
|
||||
def parseScript[T <: Script](
|
||||
bytes: ByteVector,
|
||||
f: Vector[ScriptToken] => T): T = {
|
||||
val compactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(bytes)
|
||||
//TODO: Figure out a better way to do this, we can theoretically have numbers larger than Int.MaxValue,
|
||||
//but scala collections don't allow you to use 'slice' with longs
|
||||
val len = Try(compactSizeUInt.num.toInt).getOrElse(Int.MaxValue)
|
||||
val scriptPubKeyBytes = bytes.slice(compactSizeUInt.size.toInt, len + compactSizeUInt.size.toInt)
|
||||
val scriptPubKeyBytes =
|
||||
bytes.slice(compactSizeUInt.size.toInt, len + compactSizeUInt.size.toInt)
|
||||
val script: List[ScriptToken] = ScriptParser.fromBytes(scriptPubKeyBytes)
|
||||
f(script.toVector)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package org.bitcoins.core.wallet.builder
|
|||
import scala.util.Failure
|
||||
|
||||
/**
|
||||
* Represents an error that can be returned by the [[org.bitcoins.core.wallet.builder.TxBuilder]]
|
||||
* Represents an error that can be returned by the [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]]
|
||||
* if it failed to sign a set of utxos
|
||||
*/
|
||||
sealed abstract class TxBuilderError
|
||||
|
@ -20,7 +20,7 @@ object TxBuilderError {
|
|||
"This tx fails the invariants function you passed in"))
|
||||
|
||||
/**
|
||||
* Means that we gave too many [[org.bitcoins.core.wallet.signer.Signer.Sign]] for the TxBuilder
|
||||
* Means that we gave too many [[org.bitcoins.core.crypto.Sign Sign]] for the TxBuilder
|
||||
* to use during the signing process for a utxo.
|
||||
* An example of this occurring is if we gave 2 private keys to sign a p2pkh spk.
|
||||
* A p2pkh only requires one private key to sign the utxo.
|
||||
|
@ -30,29 +30,30 @@ object TxBuilderError {
|
|||
"You passed in too many signers for this scriptPubKey type"))
|
||||
|
||||
/**
|
||||
* Means that you are using the wrong [[org.bitcoins.core.wallet.signer.Signer]] to
|
||||
* sign the given [[org.bitcoins.core.protocol.script.ScriptPubKey]]
|
||||
* Means that you are using the wrong [[org.bitcoins.core.wallet.signer.Signer Signer]] to
|
||||
* sign the given [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]]
|
||||
*/
|
||||
val WrongSigner = Failure(new IllegalArgumentException(
|
||||
"You did not pass in the write Signer to sign the given transaction, you probably gave the wrong identifier"))
|
||||
|
||||
/**
|
||||
* Means that the [[org.bitcoins.core.protocol.script.ScriptWitnessV0]] you passed as an argument does
|
||||
* not hash to the commitment inside of [[org.bitcoins.core.protocol.script.P2WSHWitnessSPKV0]]
|
||||
* Means that the [[org.bitcoins.core.protocol.script.ScriptWitnessV0 ScriptWitnessV0]] you passed as an argument does
|
||||
* not hash to the commitment inside of [[org.bitcoins.core.protocol.script.P2WSHWitnessSPKV0 P2WSHWitnessSPKV0]]
|
||||
*/
|
||||
val WrongWitness = Failure(new IllegalArgumentException(
|
||||
"You passed in the wrong ScriptWitness type to sign the given WitnessScriptPubKey"))
|
||||
|
||||
/**
|
||||
* Means that the redeem script you passed as an argument does not hash to the commitment
|
||||
* inside of the [[org.bitcoins.core.protocol.script.P2SHScriptPubKey]]
|
||||
* inside of the [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]]
|
||||
*/
|
||||
val WrongRedeemScript = Failure(new IllegalArgumentException(
|
||||
"Means that the redeem script you passed as an argument does not hash to the commitment"))
|
||||
|
||||
/**
|
||||
* Means that you passed the wrong public key for a [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey]] or a
|
||||
* [[org.bitcoins.core.protocol.script.P2WPKHWitnessSPKV0]] that you are trying to spend
|
||||
* Means that you passed the wrong public key for a
|
||||
* [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey P2PKHScriptPubKey]] or a
|
||||
* [[org.bitcoins.core.protocol.script.P2WPKHWitnessSPKV0 P2WPKHWitnessSPKV0]] that you are trying to spend
|
||||
*/
|
||||
//case object WrongPublicKey extends TxBuilderError
|
||||
val WrongPublicKey = Failure(
|
||||
|
@ -60,7 +61,8 @@ object TxBuilderError {
|
|||
"You passed in the wrong public key to sign a P2PKHScriptPubKey"))
|
||||
|
||||
/**
|
||||
* Can occurr when we are trying to sign a [[org.bitcoins.core.protocol.script.P2SHScriptPubKey]] but
|
||||
* Can occurr when we are trying to sign a
|
||||
* [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] but
|
||||
* we do not have a redeem script for that p2sh spk.
|
||||
*/
|
||||
//case object NoRedeemScript extends TxBuilderError
|
||||
|
@ -69,30 +71,38 @@ object TxBuilderError {
|
|||
"We are missing a redeem script to sign a transaction"))
|
||||
|
||||
/**
|
||||
* Can occurr when we are trying to sign a [[org.bitcoins.core.protocol.script.WitnessScriptPubKey]]
|
||||
* but we do not have a [[org.bitcoins.core.protocol.script.ScriptWitness]] for that witness spk
|
||||
* Can occurr when we are trying to sign a
|
||||
* [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]]
|
||||
* but we do not have a [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] for that witness spk
|
||||
*/
|
||||
//case object NoWitness extends TxBuilderError
|
||||
val NoWitness = Failure(
|
||||
new IllegalArgumentException("We are missing a witness redeem script"))
|
||||
|
||||
/** We expected a [[org.bitcoins.core.protocol.script.WitnessScriptPubKeyV0]], but got a non witness spk type */
|
||||
/** We expected a
|
||||
* [[org.bitcoins.core.protocol.script.WitnessScriptPubKeyV0 WitnessScriptPubKeyV0]],
|
||||
* but got a non witness spk type */
|
||||
val NonWitnessSPK = Failure(
|
||||
new IllegalArgumentException(
|
||||
"We expected a witness spk, but got a non witness spk"))
|
||||
|
||||
/** We cannot have a [[org.bitcoins.core.protocol.script.WitnessScriptPubKey]] nested inside of another [[org.bitcoins.core.protocol.script.ScriptPubKey]] */
|
||||
/** We cannot have a
|
||||
* [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] nested inside of another
|
||||
* [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] */
|
||||
//case object NestedWitnessSPK extends TxBuilderError
|
||||
val NestedWitnessSPK = Failure(
|
||||
new IllegalArgumentException("We cannot nested witness SPKs"))
|
||||
|
||||
/** We cannot have a [[org.bitcoins.core.protocol.script.P2SHScriptPubKey]] nested inside of another spk */
|
||||
/** We cannot have a [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]]
|
||||
* nested inside of another spk */
|
||||
val NestedP2SHSPK = Failure(
|
||||
new IllegalArgumentException("We cannot sign nested P2SHScriptPubKeys"))
|
||||
|
||||
/**
|
||||
* Means that there is no signer defined for the given [[org.bitcoins.core.protocol.script.ScriptPubKey]] type.
|
||||
* An example of a spk with no signer that is defined is [[org.bitcoins.core.protocol.script.WitnessCommitment]]
|
||||
* Means that there is no signer defined for the given
|
||||
* [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] type.
|
||||
* An example of a spk with no signer that is defined is
|
||||
* [[org.bitcoins.core.protocol.script.WitnessCommitment WitnessCommitment]]
|
||||
*/
|
||||
val NoSigner = Failure(
|
||||
new IllegalArgumentException(
|
||||
|
@ -106,7 +116,9 @@ object TxBuilderError {
|
|||
val FeeToLarge = Failure(new IllegalArgumentException("Fee too large"))
|
||||
|
||||
/**
|
||||
* Means that the [[TxBuilder.destinations]] outputs you specified when creating the [[TxBuilder]] are NOT
|
||||
* Means that the
|
||||
* [[org.bitcoins.core.wallet.builder.TxBuilder.destinations TxBuilder.destinations]]
|
||||
* outputs you specified when creating the [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]] are NOT
|
||||
* all included in the final signed tx
|
||||
*/
|
||||
val MissingDestinationOutput = Failure(
|
||||
|
@ -115,7 +127,7 @@ object TxBuilderError {
|
|||
|
||||
/**
|
||||
* Means that the script we are signing for requires a public key, but we did not pass one in
|
||||
* as a parameter inside of [[org.bitcoins.core.crypto.Sign]]
|
||||
* as a parameter inside of [[org.bitcoins.core.crypto.Sign Sign]]
|
||||
*/
|
||||
val MissingPublicKey = Failure(
|
||||
new IllegalArgumentException(
|
||||
|
@ -127,7 +139,9 @@ object TxBuilderError {
|
|||
|
||||
/**
|
||||
* Means that the signed version of this transaction has MORE outputs than what was specified
|
||||
* when building the [[TxBuilder]]. [[TxBuilder.destinations]] && [[TxBuilder.changeOutput]] should
|
||||
* when building the [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]].
|
||||
* [[org.bitcoins.core.wallet.builder.TxBuilder.destinations TxBuilder.destinations]] &&
|
||||
* [[org.bitcoins.core.wallet.builder.TxBuilder.changeSPK TxBuilder.changeSPK]] should
|
||||
* be the only outputs in the signedTx
|
||||
*/
|
||||
val ExtraOutputsAdded = Failure(new IllegalArgumentException(
|
||||
|
@ -135,7 +149,9 @@ object TxBuilderError {
|
|||
|
||||
/**
|
||||
* Means that the transaction spends outpoints that were not given when creating
|
||||
* the [[TxBuilder]], aka, we should only spend outpoints in [[TxBuilder.outPoints]]
|
||||
* the [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]], aka, we should
|
||||
* only spend outpoints in
|
||||
* [[org.bitcoins.core.wallet.builder.TxBuilder.outPoints TxBuilder.outPoints]]
|
||||
*/
|
||||
val ExtraOutPoints = Failure(new IllegalArgumentException(
|
||||
"Means that the transaction spends outpoints that were not given when creating the TxBuilder"))
|
||||
|
@ -144,17 +160,20 @@ object TxBuilderError {
|
|||
val MintsMoney = Failure(new IllegalArgumentException(
|
||||
"This transaction creates spends more money than it was funded by the given utxos"))
|
||||
|
||||
/** Means that the fee was too low for [[TxBuilder.feeRate]] */
|
||||
/** Means that the fee was too low for
|
||||
* [[org.bitcoins.core.wallet.builder.TxBuilder.feeRate TxBuilder.feeRate]] */
|
||||
val LowFee = Failure(
|
||||
new IllegalArgumentException("Means that the fee was too low"))
|
||||
|
||||
/** Means tha this transaction pays too high of a fee for [[TxBuilder.feeRate]] */
|
||||
/** Means tha this transaction pays too high of a fee for
|
||||
* [[org.bitcoins.core.wallet.builder.TxBuilder.feeRate TxBuilder.feeRate]] */
|
||||
|
||||
val HighFee = Failure(
|
||||
new IllegalArgumentException("Means that the fee was too high"))
|
||||
|
||||
/**
|
||||
* Indicates we are spending multiple [[org.bitcoins.core.protocol.script.CLTVScriptPubKey]],
|
||||
* Indicates we are spending multiple
|
||||
* [[org.bitcoins.core.protocol.script.CLTVScriptPubKey CLTVScriptPubKey]],
|
||||
* and that one of those spk's outputs are locked by block height, while the other is locked by
|
||||
* a time stamp. Since there is only one locktime field on a transaction, we cannot satisfy both of these
|
||||
* locktimes simultaneously.
|
||||
|
@ -162,7 +181,8 @@ object TxBuilderError {
|
|||
val IncompatibleLockTimes = Failure(new IllegalArgumentException(
|
||||
"Means you tried to spend an output that requires a lock by blockheight, and another output that requires a lock by timestamp"))
|
||||
|
||||
/** Means we have a output on this transaction below [[org.bitcoins.core.policy.Policy.dustThreshold]] */
|
||||
/** Means we have a output on this transaction below
|
||||
* [[org.bitcoins.core.policy.Policy.dustThreshold Policy.dustThreshold]] */
|
||||
val OutputBelowDustThreshold = Failure(new IllegalArgumentException(
|
||||
"The p2p network discourages outputs below the dustThreshold, this tx won't be relayed"))
|
||||
|
||||
|
|
|
@ -9,10 +9,11 @@ import org.bitcoins.core.wallet.utxo.{BitcoinUTXOSpendingInfo, UTXOSpendingInfo}
|
|||
|
||||
/**
|
||||
* This meant to represent the class used to 'fund' an
|
||||
* unsigned [[Transaction]].
|
||||
* This is useful for when we have multiple [[org.bitcoins.core.config.NetworkParameters]]
|
||||
* unsigned [[org.bitcoins.core.protocol.transaction.Transaction Transaction]].
|
||||
* This is useful for when we have multiple [[org.bitcoins.core.config.NetworkParameters NetworkParameters]]
|
||||
* that each have their own transaction type. I.e. we should only be able to have
|
||||
* BitcoinTransactions paired with [[BitcoinUTXOSpendingInfo]], the same would apply for litecoin etc.
|
||||
* BitcoinTransactions paired with [[org.bitcoins.core.wallet.utxo.BitcoinUTXOSpendingInfo BitcoinUTXOSpendingInfo]],
|
||||
* the same would apply for litecoin etc.
|
||||
*/
|
||||
sealed abstract class FundingInfo {
|
||||
|
||||
|
|
|
@ -399,8 +399,9 @@ sealed abstract class MultiSigSigner extends BitcoinSigner {
|
|||
Future.successful((m, lock))
|
||||
case _: P2PKScriptPubKey | _: P2PKHScriptPubKey |
|
||||
_: P2SHScriptPubKey | _: P2WPKHWitnessSPKV0 |
|
||||
_: P2WSHWitnessSPKV0 | _: WitnessCommitment| _: CSVScriptPubKey |
|
||||
_: CLTVScriptPubKey | _: NonStandardScriptPubKey |
|
||||
_: P2WSHWitnessSPKV0 | _: WitnessCommitment |
|
||||
_: CSVScriptPubKey | _: CLTVScriptPubKey |
|
||||
_: NonStandardScriptPubKey |
|
||||
_: UnassignedWitnessScriptPubKey |
|
||||
_: P2WPKHWitnessSPKV0 | EmptyScriptPubKey =>
|
||||
Future.fromTry(TxBuilderError.WrongSigner)
|
||||
|
@ -408,9 +409,9 @@ sealed abstract class MultiSigSigner extends BitcoinSigner {
|
|||
case m: MultiSignatureScriptPubKey => Future.successful((m, m))
|
||||
case _: P2PKScriptPubKey | _: P2PKHScriptPubKey |
|
||||
_: P2SHScriptPubKey | _: P2WPKHWitnessSPKV0 |
|
||||
_: P2WSHWitnessSPKV0 | _: WitnessCommitment| _: NonStandardScriptPubKey |
|
||||
_: P2WPKHWitnessSPKV0 | _: UnassignedWitnessScriptPubKey |
|
||||
EmptyScriptPubKey =>
|
||||
_: P2WSHWitnessSPKV0 | _: WitnessCommitment |
|
||||
_: NonStandardScriptPubKey | _: P2WPKHWitnessSPKV0 |
|
||||
_: UnassignedWitnessScriptPubKey | EmptyScriptPubKey =>
|
||||
Future.fromTry(TxBuilderError.WrongSigner)
|
||||
}
|
||||
}
|
||||
|
@ -485,8 +486,7 @@ sealed abstract class MultiSigSigner extends BitcoinSigner {
|
|||
_: P2WPKHWitnessSPKV0 | _: P2WSHWitnessSPKV0 |
|
||||
_: CLTVScriptPubKey | _: CSVScriptPubKey |
|
||||
_: UnassignedWitnessScriptPubKey | _: NonStandardScriptPubKey |
|
||||
_: WitnessCommitment |
|
||||
EmptyScriptPubKey =>
|
||||
_: WitnessCommitment | EmptyScriptPubKey =>
|
||||
Future.fromTry(TxBuilderError.WrongSigner)
|
||||
}
|
||||
multiSigSPK.flatMap { mSPK =>
|
||||
|
@ -528,7 +528,8 @@ sealed abstract class MultiSigSigner extends BitcoinSigner {
|
|||
}
|
||||
case _: P2PKScriptPubKey | _: P2PKHScriptPubKey | _: P2SHScriptPubKey |
|
||||
_: P2WPKHWitnessSPKV0 | _: NonStandardScriptPubKey |
|
||||
_: WitnessCommitment | _: UnassignedWitnessScriptPubKey | EmptyScriptPubKey =>
|
||||
_: WitnessCommitment | _: UnassignedWitnessScriptPubKey |
|
||||
EmptyScriptPubKey =>
|
||||
Future.fromTry(TxBuilderError.WrongSigner)
|
||||
}
|
||||
signed
|
||||
|
|
|
@ -123,7 +123,7 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
(privateKeys, requiredSigs) <- CryptoGenerators.privateKeySeqWithRequiredSigs
|
||||
pubKeys = privateKeys.map(_.publicKey)
|
||||
multiSignatureScriptPubKey = MultiSignatureScriptPubKey(requiredSigs,
|
||||
pubKeys)
|
||||
pubKeys)
|
||||
} yield (multiSignatureScriptPubKey, privateKeys)
|
||||
|
||||
def smallMultiSigScriptPubKey: Gen[
|
||||
|
@ -132,7 +132,7 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
(privateKeys, requiredSigs) <- CryptoGenerators.smallPrivateKeySeqWithRequiredSigs
|
||||
pubKeys = privateKeys.map(_.publicKey)
|
||||
multiSignatureScriptPubKey = MultiSignatureScriptPubKey(requiredSigs,
|
||||
pubKeys)
|
||||
pubKeys)
|
||||
} yield (multiSignatureScriptPubKey, privateKeys)
|
||||
|
||||
def p2shScriptPubKey: Gen[(P2SHScriptPubKey, Seq[ECPrivateKey])] =
|
||||
|
@ -172,11 +172,13 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
|
||||
/** Generates an arbitrary [[org.bitcoins.core.protocol.script.WitnessScriptPubKey]] */
|
||||
def witnessScriptPubKey: Gen[(WitnessScriptPubKey, Seq[ECPrivateKey])] =
|
||||
Gen.oneOf(assignedWitnessScriptPubKey,unassignedWitnessScriptPubKey)
|
||||
Gen.oneOf(assignedWitnessScriptPubKey, unassignedWitnessScriptPubKey)
|
||||
|
||||
def assignedWitnessScriptPubKey: Gen[(WitnessScriptPubKey, Seq[ECPrivateKey])] = {
|
||||
def assignedWitnessScriptPubKey: Gen[
|
||||
(WitnessScriptPubKey, Seq[ECPrivateKey])] = {
|
||||
Gen.oneOf(p2wpkhSPKV0, p2wshSPKV0)
|
||||
}
|
||||
|
||||
def witnessCommitment: Gen[(WitnessCommitment, Seq[ECPrivateKey])] =
|
||||
for {
|
||||
hash <- CryptoGenerators.doubleSha256Digest
|
||||
|
@ -203,16 +205,16 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
def randomNonLockTimeNonP2SHScriptPubKey: Gen[
|
||||
(ScriptPubKey, Seq[ECPrivateKey])] = {
|
||||
Gen.oneOf(p2pkScriptPubKey.map(privKeyToSeq(_)),
|
||||
p2pkhScriptPubKey.map(privKeyToSeq(_)),
|
||||
multiSigScriptPubKey)
|
||||
p2pkhScriptPubKey.map(privKeyToSeq(_)),
|
||||
multiSigScriptPubKey)
|
||||
}
|
||||
|
||||
def randomNonLockTimeScriptSig: Gen[ScriptSignature] = {
|
||||
Gen.oneOf(p2pkScriptSignature,
|
||||
p2pkhScriptSignature,
|
||||
multiSignatureScriptSignature,
|
||||
emptyScriptSignature,
|
||||
p2shScriptSignature)
|
||||
p2pkhScriptSignature,
|
||||
multiSignatureScriptSignature,
|
||||
emptyScriptSignature,
|
||||
p2shScriptSignature)
|
||||
}
|
||||
|
||||
def lockTimeScriptPubKey: Gen[(LockTimeScriptPubKey, Seq[ECPrivateKey])] =
|
||||
|
@ -257,7 +259,7 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
* Note: Does NOT generate a correct/valid signature
|
||||
*/
|
||||
private def pickCorrespondingScriptSignature(
|
||||
scriptPubKey: ScriptPubKey): Gen[ScriptSignature] = scriptPubKey match {
|
||||
scriptPubKey: ScriptPubKey): Gen[ScriptSignature] = scriptPubKey match {
|
||||
case _: P2PKScriptPubKey => p2pkScriptSignature
|
||||
case _: P2PKHScriptPubKey => p2pkhScriptSignature
|
||||
case _: MultiSignatureScriptPubKey => multiSignatureScriptSignature
|
||||
|
@ -267,7 +269,7 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
case _: WitnessScriptPubKeyV0 | _: UnassignedWitnessScriptPubKey =>
|
||||
emptyScriptSignature
|
||||
case x @ (_: P2SHScriptPubKey | _: NonStandardScriptPubKey |
|
||||
_: WitnessCommitment) =>
|
||||
_: WitnessCommitment) =>
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot pick for p2sh script pubkey, " +
|
||||
"non standard script pubkey or witness commitment got: " + x)
|
||||
|
@ -344,7 +346,7 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
* sequence of [[ECPrivateKey]] used to sign the scriptSig
|
||||
*/
|
||||
def signedMultiSignatureScriptSignature: Gen[(
|
||||
MultiSignatureScriptSignature,
|
||||
MultiSignatureScriptSignature,
|
||||
MultiSignatureScriptPubKey,
|
||||
Seq[ECPrivateKey])] =
|
||||
for {
|
||||
|
@ -352,7 +354,7 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
hashType <- CryptoGenerators.hashType
|
||||
publicKeys = privateKeys.map(_.publicKey)
|
||||
multiSigScriptPubKey = MultiSignatureScriptPubKey(requiredSigs,
|
||||
publicKeys)
|
||||
publicKeys)
|
||||
emptyDigitalSignatures = privateKeys.map(_ => EmptyDigitalSignature)
|
||||
scriptSig = MultiSignatureScriptSignature(emptyDigitalSignatures)
|
||||
(creditingTx, outputIndex) = TransactionGenerators
|
||||
|
@ -394,9 +396,9 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
* used to sign the scriptSig
|
||||
*/
|
||||
def signedCLTVScriptSignature(
|
||||
cltvLockTime: ScriptNumber,
|
||||
lockTime: UInt32,
|
||||
sequence: UInt32): Gen[
|
||||
cltvLockTime: ScriptNumber,
|
||||
lockTime: UInt32,
|
||||
sequence: UInt32): Gen[
|
||||
(CLTVScriptSignature, CLTVScriptPubKey, Seq[ECPrivateKey])] =
|
||||
for {
|
||||
(scriptPubKey, privKeys) <- randomNonLockTimeNonP2SHScriptPubKey
|
||||
|
@ -407,26 +409,26 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
case m: MultiSignatureScriptPubKey =>
|
||||
val requiredSigs = m.requiredSigs
|
||||
val cltvScriptSig = lockTimeHelper(Some(lockTime),
|
||||
sequence,
|
||||
cltv,
|
||||
privKeys,
|
||||
Some(requiredSigs),
|
||||
hashType)
|
||||
sequence,
|
||||
cltv,
|
||||
privKeys,
|
||||
Some(requiredSigs),
|
||||
hashType)
|
||||
(cltvScriptSig.asInstanceOf[CLTVScriptSignature], cltv, privKeys)
|
||||
case _: P2PKHScriptPubKey | _: P2PKScriptPubKey =>
|
||||
val cltvScriptSig = lockTimeHelper(Some(lockTime),
|
||||
sequence,
|
||||
cltv,
|
||||
privKeys,
|
||||
None,
|
||||
hashType)
|
||||
sequence,
|
||||
cltv,
|
||||
privKeys,
|
||||
None,
|
||||
hashType)
|
||||
(cltvScriptSig.asInstanceOf[CLTVScriptSignature], cltv, privKeys)
|
||||
case _: UnassignedWitnessScriptPubKey | _: WitnessScriptPubKeyV0 =>
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot created a witness scriptPubKey for a CSVScriptSig since we do not have a witness")
|
||||
case _: P2SHScriptPubKey | _: CLTVScriptPubKey | _: CSVScriptPubKey |
|
||||
_: NonStandardScriptPubKey | _: WitnessCommitment |
|
||||
EmptyScriptPubKey =>
|
||||
_: NonStandardScriptPubKey | _: WitnessCommitment |
|
||||
EmptyScriptPubKey =>
|
||||
throw new IllegalArgumentException(
|
||||
"We only " +
|
||||
"want to generate P2PK, P2PKH, and MultiSig ScriptSignatures when creating a CSVScriptSignature")
|
||||
|
@ -439,8 +441,8 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
* used to sign the scriptSig
|
||||
*/
|
||||
def signedCSVScriptSignature(
|
||||
csvScriptNum: ScriptNumber,
|
||||
sequence: UInt32): Gen[
|
||||
csvScriptNum: ScriptNumber,
|
||||
sequence: UInt32): Gen[
|
||||
(CSVScriptSignature, CSVScriptPubKey, Seq[ECPrivateKey])] =
|
||||
for {
|
||||
(scriptPubKey, privKeys) <- randomNonLockTimeNonP2SHScriptPubKey
|
||||
|
@ -451,11 +453,11 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
case m: MultiSignatureScriptPubKey =>
|
||||
val requiredSigs = m.requiredSigs
|
||||
val csvScriptSig = lockTimeHelper(None,
|
||||
sequence,
|
||||
csv,
|
||||
privKeys,
|
||||
Some(requiredSigs),
|
||||
hashType)
|
||||
sequence,
|
||||
csv,
|
||||
privKeys,
|
||||
Some(requiredSigs),
|
||||
hashType)
|
||||
(csvScriptSig.asInstanceOf[CSVScriptSignature], csv, privKeys)
|
||||
case _: P2PKHScriptPubKey | _: P2PKScriptPubKey =>
|
||||
val csvScriptSig =
|
||||
|
@ -465,8 +467,8 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
throw new IllegalArgumentException(
|
||||
"Cannot created a witness scriptPubKey for a CSVScriptSig since we do not have a witness")
|
||||
case _: P2SHScriptPubKey | _: CLTVScriptPubKey | _: CSVScriptPubKey |
|
||||
_: NonStandardScriptPubKey | _: WitnessCommitment |
|
||||
EmptyScriptPubKey =>
|
||||
_: NonStandardScriptPubKey | _: WitnessCommitment |
|
||||
EmptyScriptPubKey =>
|
||||
throw new IllegalArgumentException(
|
||||
"We only " +
|
||||
"want to generate P2PK, P2PKH, and MultiSig ScriptSignatures when creating a CLTVScriptSignature.")
|
||||
|
@ -487,8 +489,8 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
txLockTime <- NumberGenerator.uInt32s
|
||||
sequence <- NumberGenerator.uInt32s
|
||||
scriptSig <- signedCLTVScriptSignature(cltv.locktime,
|
||||
txLockTime,
|
||||
sequence)
|
||||
txLockTime,
|
||||
sequence)
|
||||
} yield scriptSig
|
||||
|
||||
/** Generates a [[LockTimeScriptSignature]] and [[LockTimeScriptPubKey]] pair that are valid when run through the interpreter */
|
||||
|
@ -499,12 +501,12 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
|
||||
/** Helper function to generate [[LockTimeScriptSignature]]s */
|
||||
private def lockTimeHelper(
|
||||
lockTime: Option[UInt32],
|
||||
sequence: UInt32,
|
||||
lock: LockTimeScriptPubKey,
|
||||
privateKeys: Seq[ECPrivateKey],
|
||||
requiredSigs: Option[Int],
|
||||
hashType: HashType): LockTimeScriptSignature = {
|
||||
lockTime: Option[UInt32],
|
||||
sequence: UInt32,
|
||||
lock: LockTimeScriptPubKey,
|
||||
privateKeys: Seq[ECPrivateKey],
|
||||
requiredSigs: Option[Int],
|
||||
hashType: HashType): LockTimeScriptSignature = {
|
||||
val tc = TransactionConstants
|
||||
val pubKeys = privateKeys.map(_.publicKey)
|
||||
val (creditingTx, outputIndex) =
|
||||
|
@ -528,8 +530,8 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
i <- 0 until requiredSigs.getOrElse(1)
|
||||
} yield
|
||||
TransactionSignatureCreator.createSig(txSignatureComponent,
|
||||
privateKeys(i),
|
||||
hashType)
|
||||
privateKeys(i),
|
||||
hashType)
|
||||
|
||||
lock match {
|
||||
case csv: CSVScriptPubKey =>
|
||||
|
@ -545,7 +547,7 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
|
||||
def signedP2SHP2WPKHScriptSignature: Gen[
|
||||
(
|
||||
P2SHScriptSignature,
|
||||
P2SHScriptSignature,
|
||||
P2SHScriptPubKey,
|
||||
Seq[ECPrivateKey],
|
||||
TransactionWitness,
|
||||
|
@ -557,14 +559,14 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
wtxSigComponent.scriptPubKey.asInstanceOf[WitnessScriptPubKey])
|
||||
} yield
|
||||
(p2shScriptSig,
|
||||
p2shScriptPubKey,
|
||||
privKeys,
|
||||
witness,
|
||||
wtxSigComponent.amount)
|
||||
p2shScriptPubKey,
|
||||
privKeys,
|
||||
witness,
|
||||
wtxSigComponent.amount)
|
||||
|
||||
def signedP2SHP2WSHScriptSignature: Gen[
|
||||
(
|
||||
P2SHScriptSignature,
|
||||
P2SHScriptSignature,
|
||||
P2SHScriptPubKey,
|
||||
Seq[ECPrivateKey],
|
||||
TransactionWitness,
|
||||
|
@ -575,10 +577,10 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
p2shScriptSig = P2SHScriptSignature(wtxSigComponent.scriptPubKey)
|
||||
} yield
|
||||
(p2shScriptSig,
|
||||
p2shScriptPubKey,
|
||||
privKeys,
|
||||
witness,
|
||||
wtxSigComponent.amount)
|
||||
p2shScriptPubKey,
|
||||
privKeys,
|
||||
witness,
|
||||
wtxSigComponent.amount)
|
||||
|
||||
/**
|
||||
* This function chooses a random signed [[ScriptSignature]] that is NOT a [[P2SHScriptSignature]], [[CSVScriptSignature]],
|
||||
|
@ -616,7 +618,7 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
|
||||
/** Simply converts one private key in the generator to a sequence of private keys */
|
||||
private def packageToSequenceOfPrivateKeys(
|
||||
gen: Gen[(ScriptSignature, ScriptPubKey, ECPrivateKey)]): Gen[
|
||||
gen: Gen[(ScriptSignature, ScriptPubKey, ECPrivateKey)]): Gen[
|
||||
(ScriptSignature, ScriptPubKey, Seq[ECPrivateKey])] =
|
||||
for {
|
||||
(scriptSig, scriptPubKey, privateKey) <- gen
|
||||
|
@ -624,16 +626,16 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
|
||||
/** Simply converts one private key in the generator to a sequence of private keys */
|
||||
private def privKeyToSeq(tuple: (ScriptPubKey, ECPrivateKey)): (
|
||||
ScriptPubKey,
|
||||
ScriptPubKey,
|
||||
Seq[ECPrivateKey]) = {
|
||||
val (s, key) = tuple
|
||||
(s, Seq(key))
|
||||
}
|
||||
|
||||
private def lockTimeHelperScriptSig(
|
||||
lock: LockTimeScriptPubKey,
|
||||
sigs: Seq[ECDigitalSignature],
|
||||
keys: Seq[ECPublicKey]): LockTimeScriptSignature = {
|
||||
lock: LockTimeScriptPubKey,
|
||||
sigs: Seq[ECDigitalSignature],
|
||||
keys: Seq[ECPublicKey]): LockTimeScriptSignature = {
|
||||
|
||||
val nestedScriptSig = lock.nestedScriptPubKey match {
|
||||
case _: P2PKScriptPubKey => P2PKScriptSignature(sigs.head)
|
||||
|
@ -647,7 +649,7 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
throw new IllegalArgumentException(
|
||||
"Cannot have a nested locktimeScriptPubKey inside a lockTimeScriptPubKey")
|
||||
case x @ (_: NonStandardScriptPubKey | _: P2SHScriptPubKey |
|
||||
_: WitnessCommitment) =>
|
||||
_: WitnessCommitment) =>
|
||||
throw new IllegalArgumentException(
|
||||
"A NonStandardScriptPubKey/P2SHScriptPubKey/WitnessCommitment cannot be" +
|
||||
"the underlying scriptSig in a CSVScriptSignature. Got: " + x)
|
||||
|
@ -660,4 +662,4 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
}
|
||||
}
|
||||
|
||||
object ScriptGenerators extends ScriptGenerators
|
||||
object ScriptGenerators extends ScriptGenerators
|
||||
|
|
|
@ -85,25 +85,25 @@ sealed abstract class WitnessGenerators extends BitcoinSLogger {
|
|||
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
|
||||
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
|
||||
u = createUnsignedRawWTxSigComponent(witScriptPubKey,
|
||||
amount,
|
||||
unsignedScriptWitness,
|
||||
None)
|
||||
amount,
|
||||
unsignedScriptWitness,
|
||||
None)
|
||||
createdSig = TransactionSignatureCreator.createSig(u, privKeys, hashType)
|
||||
signedScriptWitness = P2WSHWitnessV0(scriptPubKey,
|
||||
P2PKScriptSignature(createdSig))
|
||||
P2PKScriptSignature(createdSig))
|
||||
oldTx = u.transaction
|
||||
txWitness = TransactionWitness(
|
||||
oldTx.witness.witnesses
|
||||
.updated(u.inputIndex.toInt, signedScriptWitness))
|
||||
wtx = WitnessTransaction(oldTx.version,
|
||||
oldTx.inputs,
|
||||
oldTx.outputs,
|
||||
oldTx.lockTime,
|
||||
txWitness)
|
||||
oldTx.inputs,
|
||||
oldTx.outputs,
|
||||
oldTx.lockTime,
|
||||
txWitness)
|
||||
signedWtxSigComponent = WitnessTxSigComponentRaw(wtx,
|
||||
u.inputIndex,
|
||||
u.output,
|
||||
u.flags)
|
||||
u.inputIndex,
|
||||
u.output,
|
||||
u.flags)
|
||||
} yield (txWitness, signedWtxSigComponent, Seq(privKeys))
|
||||
|
||||
def signedP2WSHP2PKHTransactionWitness: Gen[
|
||||
|
@ -115,9 +115,9 @@ sealed abstract class WitnessGenerators extends BitcoinSLogger {
|
|||
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
|
||||
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
|
||||
u = createUnsignedRawWTxSigComponent(witScriptPubKey,
|
||||
amount,
|
||||
unsignedScriptWitness,
|
||||
None)
|
||||
amount,
|
||||
unsignedScriptWitness,
|
||||
None)
|
||||
createdSig = TransactionSignatureCreator.createSig(u, privKey, hashType)
|
||||
signedScriptWitness = P2WSHWitnessV0(
|
||||
scriptPubKey,
|
||||
|
@ -127,14 +127,14 @@ sealed abstract class WitnessGenerators extends BitcoinSLogger {
|
|||
oldTx.witness.witnesses
|
||||
.updated(u.inputIndex.toInt, signedScriptWitness))
|
||||
wtx = WitnessTransaction(oldTx.version,
|
||||
oldTx.inputs,
|
||||
oldTx.outputs,
|
||||
oldTx.lockTime,
|
||||
txWitness)
|
||||
oldTx.inputs,
|
||||
oldTx.outputs,
|
||||
oldTx.lockTime,
|
||||
txWitness)
|
||||
signedWtxSigComponent = WitnessTxSigComponentRaw(wtx,
|
||||
u.inputIndex,
|
||||
u.output,
|
||||
u.flags)
|
||||
u.inputIndex,
|
||||
u.output,
|
||||
u.flags)
|
||||
} yield (txWitness, signedWtxSigComponent, Seq(privKey))
|
||||
|
||||
def signedP2WSHMultiSigTransactionWitness: Gen[
|
||||
|
@ -146,27 +146,27 @@ sealed abstract class WitnessGenerators extends BitcoinSLogger {
|
|||
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
|
||||
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
|
||||
u = createUnsignedRawWTxSigComponent(witScriptPubKey,
|
||||
amount,
|
||||
unsignedScriptWitness,
|
||||
None)
|
||||
amount,
|
||||
unsignedScriptWitness,
|
||||
None)
|
||||
signedScriptSig = multiSigScriptSigGenHelper(privKeys,
|
||||
scriptPubKey,
|
||||
u,
|
||||
hashType)
|
||||
scriptPubKey,
|
||||
u,
|
||||
hashType)
|
||||
signedScriptWitness = P2WSHWitnessV0(scriptPubKey, signedScriptSig)
|
||||
oldTx = u.transaction
|
||||
txWitness = TransactionWitness(
|
||||
oldTx.witness.witnesses
|
||||
.updated(u.inputIndex.toInt, signedScriptWitness))
|
||||
wtx = WitnessTransaction(oldTx.version,
|
||||
oldTx.inputs,
|
||||
oldTx.outputs,
|
||||
oldTx.lockTime,
|
||||
txWitness)
|
||||
oldTx.inputs,
|
||||
oldTx.outputs,
|
||||
oldTx.lockTime,
|
||||
txWitness)
|
||||
signedWtxSigComponent = WitnessTxSigComponentRaw(wtx,
|
||||
u.inputIndex,
|
||||
u.output,
|
||||
u.flags)
|
||||
u.inputIndex,
|
||||
u.output,
|
||||
u.flags)
|
||||
} yield (txWitness, signedWtxSigComponent, privKeys)
|
||||
|
||||
/**
|
||||
|
@ -176,23 +176,23 @@ sealed abstract class WitnessGenerators extends BitcoinSLogger {
|
|||
def signedP2WSHTransactionWitness: Gen[
|
||||
(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = {
|
||||
Gen.oneOf(signedP2WSHP2PKTransactionWitness,
|
||||
signedP2WSHP2PKHTransactionWitness,
|
||||
signedP2WSHMultiSigTransactionWitness)
|
||||
signedP2WSHP2PKHTransactionWitness,
|
||||
signedP2WSHMultiSigTransactionWitness)
|
||||
}
|
||||
|
||||
/** Helps generate a signed [[MultiSignatureScriptSignature]] */
|
||||
private def multiSigScriptSigGenHelper(
|
||||
privateKeys: Seq[ECPrivateKey],
|
||||
scriptPubKey: MultiSignatureScriptPubKey,
|
||||
unsignedWtxSigComponent: WitnessTxSigComponent,
|
||||
hashType: HashType): MultiSignatureScriptSignature = {
|
||||
privateKeys: Seq[ECPrivateKey],
|
||||
scriptPubKey: MultiSignatureScriptPubKey,
|
||||
unsignedWtxSigComponent: WitnessTxSigComponent,
|
||||
hashType: HashType): MultiSignatureScriptSignature = {
|
||||
val requiredSigs = scriptPubKey.requiredSigs
|
||||
val txSignatures = for {
|
||||
i <- 0 until requiredSigs
|
||||
} yield
|
||||
TransactionSignatureCreator.createSig(unsignedWtxSigComponent,
|
||||
privateKeys(i),
|
||||
hashType)
|
||||
privateKeys(i),
|
||||
hashType)
|
||||
|
||||
//add the signature to the scriptSig instead of having an empty scriptSig
|
||||
val signedScriptSig = MultiSignatureScriptSignature(txSignatures)
|
||||
|
@ -215,28 +215,28 @@ sealed abstract class WitnessGenerators extends BitcoinSLogger {
|
|||
|
||||
/** Takes a signed [[ScriptWitness]] and an unsignedTx and adds the witness to the unsigned [[WitnessTransaction]] */
|
||||
def createSignedWTxComponent(
|
||||
witness: ScriptWitness,
|
||||
unsignedWTxComponent: WitnessTxSigComponent): (
|
||||
TransactionWitness,
|
||||
witness: ScriptWitness,
|
||||
unsignedWTxComponent: WitnessTxSigComponent): (
|
||||
TransactionWitness,
|
||||
WitnessTxSigComponent) = {
|
||||
val signedTxWitness = TransactionWitness.fromWitOpt(Vector(Some(witness)))
|
||||
val unsignedSpendingTx = unsignedWTxComponent.transaction
|
||||
val signedSpendingTx = WitnessTransaction(unsignedSpendingTx.version,
|
||||
unsignedSpendingTx.inputs,
|
||||
unsignedSpendingTx.outputs,
|
||||
unsignedSpendingTx.lockTime,
|
||||
signedTxWitness)
|
||||
unsignedSpendingTx.inputs,
|
||||
unsignedSpendingTx.outputs,
|
||||
unsignedSpendingTx.lockTime,
|
||||
signedTxWitness)
|
||||
val signedWtxSigComponent = unsignedWTxComponent match {
|
||||
case wtxP2SH: WitnessTxSigComponentP2SH =>
|
||||
WitnessTxSigComponent(signedSpendingTx,
|
||||
unsignedWTxComponent.inputIndex,
|
||||
wtxP2SH.output,
|
||||
unsignedWTxComponent.flags)
|
||||
unsignedWTxComponent.inputIndex,
|
||||
wtxP2SH.output,
|
||||
unsignedWTxComponent.flags)
|
||||
case wtxRaw: WitnessTxSigComponentRaw =>
|
||||
WitnessTxSigComponent(signedSpendingTx,
|
||||
unsignedWTxComponent.inputIndex,
|
||||
wtxRaw.output,
|
||||
unsignedWTxComponent.flags)
|
||||
unsignedWTxComponent.inputIndex,
|
||||
wtxRaw.output,
|
||||
unsignedWTxComponent.flags)
|
||||
}
|
||||
|
||||
(signedTxWitness, signedWtxSigComponent)
|
||||
|
@ -244,10 +244,10 @@ sealed abstract class WitnessGenerators extends BitcoinSLogger {
|
|||
|
||||
/** Creates a unsigned [[WitnessTxSigComponent]] from the given parameters */
|
||||
def createUnsignedRawWTxSigComponent(
|
||||
witScriptPubKey: WitnessScriptPubKey,
|
||||
amount: CurrencyUnit,
|
||||
unsignedScriptWitness: ScriptWitness,
|
||||
sequence: Option[UInt32]): WitnessTxSigComponentRaw = {
|
||||
witScriptPubKey: WitnessScriptPubKey,
|
||||
amount: CurrencyUnit,
|
||||
unsignedScriptWitness: ScriptWitness,
|
||||
sequence: Option[UInt32]): WitnessTxSigComponentRaw = {
|
||||
val tc = TransactionConstants
|
||||
val flags = Policy.standardScriptVerifyFlags
|
||||
val witness =
|
||||
|
@ -270,4 +270,4 @@ sealed abstract class WitnessGenerators extends BitcoinSLogger {
|
|||
}
|
||||
}
|
||||
|
||||
object WitnessGenerators extends WitnessGenerators
|
||||
object WitnessGenerators extends WitnessGenerators
|
||||
|
|
|
@ -3,7 +3,10 @@ package org.bitcoins.core.gen.ln
|
|||
import org.bitcoins.core.gen.{CryptoGenerators, NumberGenerator}
|
||||
import org.bitcoins.core.protocol.ln.ShortChannelId
|
||||
import org.bitcoins.core.protocol.ln.currency.MilliSatoshis
|
||||
import org.bitcoins.core.protocol.ln.fee.{FeeBaseMSat, FeeProportionalMillionths}
|
||||
import org.bitcoins.core.protocol.ln.fee.{
|
||||
FeeBaseMSat,
|
||||
FeeProportionalMillionths
|
||||
}
|
||||
import org.bitcoins.core.protocol.ln.routing.LnRoute
|
||||
import org.scalacheck.Gen
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue