Fixes some Scaladocs (#286)

* Fixes some Scaladocs

* ran scalafmt

* ran test:scalafmt
This commit is contained in:
Torkel Rogstad 2019-01-07 16:23:29 +01:00 committed by Chris Stewart
parent a50c6c15b3
commit abcd7c5d6d
19 changed files with 790 additions and 482 deletions

View file

@ -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")
}

View file

@ -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))

View file

@ -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)
}

View file

@ -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],

View file

@ -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

View file

@ -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)
}
/**

View file

@ -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
}
}
}

View file

@ -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)
}
}

View file

@ -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")
}

View file

@ -96,8 +96,7 @@ sealed abstract class ScriptInterpreter {
case _: P2PKHScriptPubKey | _: P2PKScriptPubKey |
_: MultiSignatureScriptPubKey | _: CSVScriptPubKey |
_: CLTVScriptPubKey | _: NonStandardScriptPubKey |
_: WitnessCommitment |
EmptyScriptPubKey =>
_: WitnessCommitment | EmptyScriptPubKey =>
scriptPubKeyExecutedProgram
}
}

View file

@ -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

View file

@ -8,14 +8,13 @@ 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)
}
}

View file

@ -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)
}

View file

@ -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"))

View file

@ -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 {

View file

@ -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

View file

@ -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)

View file

@ -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 =

View file

@ -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