mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-22 22:36:34 +01:00
Conditional Signing Tests (#865)
* Added ConditionalScriptPubKeys to CreditingTxGen so that we are actually testing Conditional signing now * Responded to code review * Renamed scriptPubKeyTooBig => redeemScriptTooBig
This commit is contained in:
parent
fad72c66d5
commit
ab00fffffc
5 changed files with 170 additions and 33 deletions
|
@ -39,7 +39,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
|
||||||
private lazy val MAX_SCRIPT_OPS = 201
|
private lazy val MAX_SCRIPT_OPS = 201
|
||||||
|
|
||||||
/** We cannot push an element larger than 520 bytes onto the stack */
|
/** We cannot push an element larger than 520 bytes onto the stack */
|
||||||
private lazy val MAX_PUSH_SIZE = 520
|
val MAX_PUSH_SIZE: Int = 520
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs an entire script though our script programming language and
|
* Runs an entire script though our script programming language and
|
||||||
|
|
|
@ -537,13 +537,11 @@ trait BitcoinScriptUtil extends BitcoinSLogger {
|
||||||
/** Since witnesses are not run through the interpreter, replace
|
/** Since witnesses are not run through the interpreter, replace
|
||||||
* `OP_0`/`OP_1` with `ScriptNumber.zero`/`ScriptNumber.one` */
|
* `OP_0`/`OP_1` with `ScriptNumber.zero`/`ScriptNumber.one` */
|
||||||
def minimalIfOp(asm: Seq[ScriptToken]): Seq[ScriptToken] = {
|
def minimalIfOp(asm: Seq[ScriptToken]): Seq[ScriptToken] = {
|
||||||
if (asm == Nil) asm
|
asm.map {
|
||||||
else if (asm.last == OP_0) {
|
case OP_0 => ScriptNumber.zero
|
||||||
asm.dropRight(1) ++ Seq(ScriptNumber.zero)
|
case OP_1 => ScriptNumber.one
|
||||||
} else if (asm.last == OP_1) {
|
case token: ScriptToken => token
|
||||||
asm.dropRight(1) ++ Seq(ScriptNumber.one)
|
}
|
||||||
} else asm
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Replaces the [[org.bitcoins.core.script.constant.OP_0 OP_0]] dummy for
|
/** Replaces the [[org.bitcoins.core.script.constant.OP_0 OP_0]] dummy for
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.bitcoins.core.wallet.builder.TxBuilderError
|
||||||
import org.bitcoins.core.wallet.utxo.{
|
import org.bitcoins.core.wallet.utxo.{
|
||||||
BitcoinUTXOSpendingInfo,
|
BitcoinUTXOSpendingInfo,
|
||||||
ConditionalSpendingInfo,
|
ConditionalSpendingInfo,
|
||||||
|
EmptySpendingInfo,
|
||||||
LockTimeSpendingInfo,
|
LockTimeSpendingInfo,
|
||||||
MultiSignatureSpendingInfo,
|
MultiSignatureSpendingInfo,
|
||||||
P2PKHSpendingInfo,
|
P2PKHSpendingInfo,
|
||||||
|
@ -185,6 +186,8 @@ object BitcoinSigner {
|
||||||
spendingInfoToSatisfy: UTXOSpendingInfo)(
|
spendingInfoToSatisfy: UTXOSpendingInfo)(
|
||||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||||
spendingInfoToSatisfy match {
|
spendingInfoToSatisfy match {
|
||||||
|
case empty: EmptySpendingInfo =>
|
||||||
|
EmptySigner.sign(spendingInfo, unsignedTx, isDummySignature, empty)
|
||||||
case p2pk: P2PKSpendingInfo =>
|
case p2pk: P2PKSpendingInfo =>
|
||||||
P2PKSigner.sign(spendingInfo, unsignedTx, isDummySignature, p2pk)
|
P2PKSigner.sign(spendingInfo, unsignedTx, isDummySignature, p2pk)
|
||||||
case p2pkh: P2PKHSpendingInfo =>
|
case p2pkh: P2PKHSpendingInfo =>
|
||||||
|
@ -217,6 +220,30 @@ object BitcoinSigner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** For signing EmptyScriptPubKeys in tests, should probably not be used in real life. */
|
||||||
|
sealed abstract class EmptySigner extends BitcoinSigner[EmptySpendingInfo] {
|
||||||
|
|
||||||
|
override def sign(
|
||||||
|
spendingInfo: UTXOSpendingInfo,
|
||||||
|
unsignedTx: Transaction,
|
||||||
|
isDummySignature: Boolean,
|
||||||
|
spendingInfoToSatisfy: EmptySpendingInfo)(
|
||||||
|
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||||
|
val (_, output, inputIndex, _) = relevantInfo(spendingInfo, unsignedTx)
|
||||||
|
|
||||||
|
// This script pushes an OP_TRUE onto the stack, causing a successful spend
|
||||||
|
val satisfyEmptyScriptSig =
|
||||||
|
Future.successful(NonStandardScriptSignature("0151"))
|
||||||
|
|
||||||
|
updateScriptSigInSigComponent(unsignedTx,
|
||||||
|
inputIndex.toInt,
|
||||||
|
output,
|
||||||
|
satisfyEmptyScriptSig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object EmptySigner extends EmptySigner
|
||||||
|
|
||||||
/** Used to sign a [[org.bitcoins.core.protocol.script.P2PKScriptPubKey]] */
|
/** Used to sign a [[org.bitcoins.core.protocol.script.P2PKScriptPubKey]] */
|
||||||
sealed abstract class P2PKSigner extends BitcoinSigner[P2PKSpendingInfo] {
|
sealed abstract class P2PKSigner extends BitcoinSigner[P2PKSpendingInfo] {
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,16 @@ import org.bitcoins.core.number.UInt32
|
||||||
import org.bitcoins.core.protocol.script._
|
import org.bitcoins.core.protocol.script._
|
||||||
import org.bitcoins.core.protocol.transaction._
|
import org.bitcoins.core.protocol.transaction._
|
||||||
import org.bitcoins.core.script.crypto.HashType
|
import org.bitcoins.core.script.crypto.HashType
|
||||||
import org.bitcoins.core.wallet.utxo.{BitcoinUTXOSpendingInfo, ConditionalPath}
|
import org.bitcoins.core.script.interpreter.ScriptInterpreter
|
||||||
|
import org.bitcoins.core.wallet.utxo.{
|
||||||
|
BitcoinUTXOSpendingInfo,
|
||||||
|
ConditionalPath,
|
||||||
|
P2SHNestedSegwitV0UTXOSpendingInfo
|
||||||
|
}
|
||||||
import org.scalacheck.Gen
|
import org.scalacheck.Gen
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
|
||||||
sealed abstract class CreditingTxGen {
|
sealed abstract class CreditingTxGen {
|
||||||
|
|
||||||
/** Minimum amount of outputs to generate */
|
/** Minimum amount of outputs to generate */
|
||||||
|
@ -22,15 +29,17 @@ sealed abstract class CreditingTxGen {
|
||||||
Gen.listOfN(n, TransactionGenerators.realisticOutput)
|
Gen.listOfN(n, TransactionGenerators.realisticOutput)
|
||||||
}
|
}
|
||||||
|
|
||||||
def rawOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
/** Generator for non-script hash based output */
|
||||||
|
def nonSHOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||||
Gen.oneOf(p2pkOutput,
|
Gen.oneOf(p2pkOutput,
|
||||||
p2pkhOutput,
|
p2pkhOutput,
|
||||||
multiSigOutput, /*cltvOutput,*/ csvOutput,
|
multiSigOutput, /*cltvOutput,*/ csvOutput,
|
||||||
|
conditionalOutput,
|
||||||
p2wpkhOutput)
|
p2wpkhOutput)
|
||||||
}
|
}
|
||||||
|
|
||||||
def rawOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
def nonSHOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
||||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, rawOutput))
|
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, nonSHOutput))
|
||||||
|
|
||||||
def basicOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
def basicOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||||
Gen.oneOf(p2pkOutput, p2pkhOutput, multiSigOutput)
|
Gen.oneOf(p2pkOutput, p2pkhOutput, multiSigOutput)
|
||||||
|
@ -40,15 +49,33 @@ sealed abstract class CreditingTxGen {
|
||||||
//note, cannot put a p2wpkh here
|
//note, cannot put a p2wpkh here
|
||||||
Gen.oneOf(p2pkOutput,
|
Gen.oneOf(p2pkOutput,
|
||||||
p2pkhOutput,
|
p2pkhOutput,
|
||||||
multiSigOutput, /*cltvOutput,*/ csvOutput)
|
multiSigOutput, /*cltvOutput,*/ csvOutput,
|
||||||
|
conditionalOutput)
|
||||||
}
|
}
|
||||||
|
|
||||||
def nonP2SHOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
/** Only for use in constructing P2SH outputs */
|
||||||
Gen.oneOf(p2pkOutput,
|
private def nonP2SHOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||||
p2pkhOutput,
|
Gen
|
||||||
multiSigOutput, /*cltvOutput,*/ csvOutput,
|
.oneOf(p2pkOutput,
|
||||||
p2wpkhOutput,
|
p2pkhOutput,
|
||||||
p2wshOutput)
|
multiSigOutput, /*cltvOutput,*/ csvOutput,
|
||||||
|
conditionalOutput,
|
||||||
|
p2wpkhOutput,
|
||||||
|
p2wshOutput)
|
||||||
|
.suchThat(output =>
|
||||||
|
!ScriptGenerators.redeemScriptTooBig(output.scriptPubKey))
|
||||||
|
.suchThat {
|
||||||
|
case P2SHNestedSegwitV0UTXOSpendingInfo(_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
witness: P2WSHWitnessV0,
|
||||||
|
_) =>
|
||||||
|
witness.stack.exists(_.length > ScriptInterpreter.MAX_PUSH_SIZE)
|
||||||
|
case _ => true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def output: Gen[BitcoinUTXOSpendingInfo] =
|
def output: Gen[BitcoinUTXOSpendingInfo] =
|
||||||
|
@ -57,6 +84,7 @@ sealed abstract class CreditingTxGen {
|
||||||
multiSigOutput,
|
multiSigOutput,
|
||||||
p2shOutput,
|
p2shOutput,
|
||||||
csvOutput, /*cltvOutput,*/
|
csvOutput, /*cltvOutput,*/
|
||||||
|
conditionalOutput,
|
||||||
p2wpkhOutput,
|
p2wpkhOutput,
|
||||||
p2wshOutput)
|
p2wshOutput)
|
||||||
|
|
||||||
|
@ -98,6 +126,31 @@ sealed abstract class CreditingTxGen {
|
||||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, multiSigOutput))
|
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, multiSigOutput))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@tailrec
|
||||||
|
private def noRelevantCLTV(spk: RawScriptPubKey): Boolean = {
|
||||||
|
spk match {
|
||||||
|
case _: CLTVScriptPubKey => false
|
||||||
|
case csv: CSVScriptPubKey => noRelevantCLTV(csv.nestedScriptPubKey)
|
||||||
|
case conditional: ConditionalScriptPubKey =>
|
||||||
|
noRelevantCLTV(conditional.trueSPK)
|
||||||
|
case _: RawScriptPubKey => true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def conditionalOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||||
|
ScriptGenerators
|
||||||
|
.nonLocktimeConditionalScriptPubKey(ScriptGenerators.defaultMaxDepth)
|
||||||
|
//.suchThat { case (spk, _) => noRelevantCLTV(spk) }
|
||||||
|
.flatMap {
|
||||||
|
case (conditional, keys) =>
|
||||||
|
build(conditional, keys, None, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def conditionalOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = {
|
||||||
|
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, conditionalOutput))
|
||||||
|
}
|
||||||
|
|
||||||
def p2shOutput: Gen[BitcoinUTXOSpendingInfo] = nonP2SHOutput.flatMap { o =>
|
def p2shOutput: Gen[BitcoinUTXOSpendingInfo] = nonP2SHOutput.flatMap { o =>
|
||||||
CryptoGenerators.hashType.map { hashType =>
|
CryptoGenerators.hashType.map { hashType =>
|
||||||
val oldOutput = o.output
|
val oldOutput = o.output
|
||||||
|
@ -111,7 +164,7 @@ sealed abstract class CreditingTxGen {
|
||||||
Some(redeemScript),
|
Some(redeemScript),
|
||||||
o.scriptWitnessOpt,
|
o.scriptWitnessOpt,
|
||||||
hashType,
|
hashType,
|
||||||
ConditionalPath.NoConditionsLeft
|
computeAllTrueConditionalPath(redeemScript, None, o.scriptWitnessOpt)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,13 +230,17 @@ sealed abstract class CreditingTxGen {
|
||||||
def p2wpkhOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
def p2wpkhOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
||||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2wpkhOutput))
|
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2wpkhOutput))
|
||||||
|
|
||||||
def p2wshOutput: Gen[BitcoinUTXOSpendingInfo] = nonP2WSHOutput.flatMap {
|
def p2wshOutput: Gen[BitcoinUTXOSpendingInfo] =
|
||||||
case BitcoinUTXOSpendingInfo(_, txOutput, signer, _, _, _, _) =>
|
nonP2WSHOutput
|
||||||
val spk = txOutput.scriptPubKey
|
.suchThat(output =>
|
||||||
val scriptWit = P2WSHWitnessV0(spk)
|
!ScriptGenerators.redeemScriptTooBig(output.scriptPubKey))
|
||||||
val witSPK = P2WSHWitnessSPKV0(spk)
|
.flatMap {
|
||||||
build(witSPK, signer, None, Some(scriptWit))
|
case BitcoinUTXOSpendingInfo(_, txOutput, signer, _, _, _, _) =>
|
||||||
}
|
val spk = txOutput.scriptPubKey
|
||||||
|
val scriptWit = P2WSHWitnessV0(spk)
|
||||||
|
val witSPK = P2WSHWitnessSPKV0(spk)
|
||||||
|
build(witSPK, signer, None, Some(scriptWit))
|
||||||
|
}
|
||||||
|
|
||||||
def p2wshOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
def p2wshOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
||||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2wshOutput))
|
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2wshOutput))
|
||||||
|
@ -230,6 +287,42 @@ sealed abstract class CreditingTxGen {
|
||||||
def randoms: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
def randoms: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
||||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, random))
|
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, random))
|
||||||
|
|
||||||
|
private def computeAllTrueConditionalPath(
|
||||||
|
spk: ScriptPubKey,
|
||||||
|
redeemScript: Option[ScriptPubKey],
|
||||||
|
scriptWitness: Option[ScriptWitness]): ConditionalPath = {
|
||||||
|
spk match {
|
||||||
|
case conditional: ConditionalScriptPubKey =>
|
||||||
|
ConditionalPath.ConditionTrue(
|
||||||
|
computeAllTrueConditionalPath(conditional.trueSPK, None, None))
|
||||||
|
case lockTimeScriptPubKey: LockTimeScriptPubKey =>
|
||||||
|
computeAllTrueConditionalPath(lockTimeScriptPubKey.nestedScriptPubKey,
|
||||||
|
None,
|
||||||
|
None)
|
||||||
|
case _: RawScriptPubKey | _: P2WPKHWitnessSPKV0 =>
|
||||||
|
ConditionalPath.NoConditionsLeft
|
||||||
|
case _: P2SHScriptPubKey =>
|
||||||
|
redeemScript match {
|
||||||
|
case None =>
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Expected redeem script for P2SH")
|
||||||
|
case Some(script) =>
|
||||||
|
computeAllTrueConditionalPath(script, None, scriptWitness)
|
||||||
|
}
|
||||||
|
case _: P2WSHWitnessSPKV0 =>
|
||||||
|
scriptWitness match {
|
||||||
|
case Some(witness: P2WSHWitnessV0) =>
|
||||||
|
computeAllTrueConditionalPath(witness.redeemScript, None, None)
|
||||||
|
case _ =>
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Expected P2WSHWitness for P2WSH")
|
||||||
|
}
|
||||||
|
case _: UnassignedWitnessScriptPubKey =>
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
s"Unexpected unassigned witness SPK: $spk")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private def build(
|
private def build(
|
||||||
spk: ScriptPubKey,
|
spk: ScriptPubKey,
|
||||||
signers: Seq[Sign],
|
signers: Seq[Sign],
|
||||||
|
@ -249,7 +342,7 @@ sealed abstract class CreditingTxGen {
|
||||||
redeemScript,
|
redeemScript,
|
||||||
scriptWitness,
|
scriptWitness,
|
||||||
hashType,
|
hashType,
|
||||||
ConditionalPath.NoConditionsLeft
|
computeAllTrueConditionalPath(spk, redeemScript, scriptWitness)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,14 @@ package org.bitcoins.testkit.core.gen
|
||||||
import org.bitcoins.core.consensus.Consensus
|
import org.bitcoins.core.consensus.Consensus
|
||||||
import org.bitcoins.core.crypto.{TransactionSignatureCreator, _}
|
import org.bitcoins.core.crypto.{TransactionSignatureCreator, _}
|
||||||
import org.bitcoins.core.currency.{CurrencyUnit, CurrencyUnits}
|
import org.bitcoins.core.currency.{CurrencyUnit, CurrencyUnits}
|
||||||
import org.bitcoins.core.number.UInt32
|
import org.bitcoins.core.number.{UInt32, UInt64}
|
||||||
import org.bitcoins.core.policy.Policy
|
import org.bitcoins.core.policy.Policy
|
||||||
|
import org.bitcoins.core.protocol.CompactSizeUInt
|
||||||
import org.bitcoins.core.protocol.script.{P2SHScriptPubKey, _}
|
import org.bitcoins.core.protocol.script.{P2SHScriptPubKey, _}
|
||||||
import org.bitcoins.core.protocol.transaction._
|
import org.bitcoins.core.protocol.transaction._
|
||||||
import org.bitcoins.core.script.constant.ScriptNumber
|
import org.bitcoins.core.script.constant.ScriptNumber
|
||||||
import org.bitcoins.core.script.crypto.HashType
|
import org.bitcoins.core.script.crypto.HashType
|
||||||
|
import org.bitcoins.core.script.interpreter.ScriptInterpreter
|
||||||
import org.bitcoins.core.util.BitcoinSLogger
|
import org.bitcoins.core.util.BitcoinSLogger
|
||||||
import org.bitcoins.core.wallet.signer.{MultiSigSigner, P2PKHSigner, P2PKSigner}
|
import org.bitcoins.core.wallet.signer.{MultiSigSigner, P2PKHSigner, P2PKSigner}
|
||||||
import org.bitcoins.core.wallet.utxo.{
|
import org.bitcoins.core.wallet.utxo.{
|
||||||
|
@ -26,7 +28,15 @@ import scala.concurrent.duration.DurationInt
|
||||||
//TODO: Need to provide generators for [[NonStandardScriptSignature]] and [[NonStandardScriptPubKey]]
|
//TODO: Need to provide generators for [[NonStandardScriptSignature]] and [[NonStandardScriptPubKey]]
|
||||||
sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
||||||
val timeout = 5.seconds
|
val timeout = 5.seconds
|
||||||
private val defaultMaxDepth = 2
|
val defaultMaxDepth: Int = 2
|
||||||
|
|
||||||
|
/** Since redeem scripts are pushed onto the stack, this function
|
||||||
|
* checks that the redeem script is not too large for a push operation.
|
||||||
|
*/
|
||||||
|
private[gen] def redeemScriptTooBig(redeemScript: ScriptPubKey): Boolean = {
|
||||||
|
redeemScript.compactSizeUInt.toInt + CompactSizeUInt(UInt64(
|
||||||
|
ScriptInterpreter.MAX_PUSH_SIZE)).bytes.length >= ScriptInterpreter.MAX_PUSH_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
def p2pkScriptSignature: Gen[P2PKScriptSignature] =
|
def p2pkScriptSignature: Gen[P2PKScriptSignature] =
|
||||||
for {
|
for {
|
||||||
|
@ -220,6 +230,10 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
||||||
def p2shScriptPubKey: Gen[(P2SHScriptPubKey, Seq[ECPrivateKey])] =
|
def p2shScriptPubKey: Gen[(P2SHScriptPubKey, Seq[ECPrivateKey])] =
|
||||||
for {
|
for {
|
||||||
(randomScriptPubKey, privKeys) <- randomNonP2SHScriptPubKey
|
(randomScriptPubKey, privKeys) <- randomNonP2SHScriptPubKey
|
||||||
|
.suchThat {
|
||||||
|
case (spk, _) =>
|
||||||
|
!redeemScriptTooBig(spk)
|
||||||
|
}
|
||||||
p2sh = P2SHScriptPubKey(randomScriptPubKey)
|
p2sh = P2SHScriptPubKey(randomScriptPubKey)
|
||||||
} yield (p2sh, privKeys)
|
} yield (p2sh, privKeys)
|
||||||
|
|
||||||
|
@ -268,9 +282,14 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
||||||
} yield (P2WPKHWitnessSPKV0(privKey.publicKey), Seq(privKey))
|
} yield (P2WPKHWitnessSPKV0(privKey.publicKey), Seq(privKey))
|
||||||
|
|
||||||
def p2wshSPKV0: Gen[(P2WSHWitnessSPKV0, Seq[ECPrivateKey])] =
|
def p2wshSPKV0: Gen[(P2WSHWitnessSPKV0, Seq[ECPrivateKey])] =
|
||||||
randomNonP2SHScriptPubKey.map { spk =>
|
randomNonP2SHScriptPubKey
|
||||||
(P2WSHWitnessSPKV0(spk._1), spk._2)
|
.suchThat {
|
||||||
}
|
case (spk, _) =>
|
||||||
|
!redeemScriptTooBig(spk)
|
||||||
|
}
|
||||||
|
.map { spk =>
|
||||||
|
(P2WSHWitnessSPKV0(spk._1), spk._2)
|
||||||
|
}
|
||||||
|
|
||||||
def witnessScriptPubKeyV0: Gen[(WitnessScriptPubKeyV0, Seq[ECPrivateKey])] =
|
def witnessScriptPubKeyV0: Gen[(WitnessScriptPubKeyV0, Seq[ECPrivateKey])] =
|
||||||
Gen.oneOf(p2wpkhSPKV0, p2wshSPKV0)
|
Gen.oneOf(p2wpkhSPKV0, p2wshSPKV0)
|
||||||
|
|
Loading…
Add table
Reference in a new issue