diff --git a/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala b/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala index 894c00748c..37aaefedb5 100644 --- a/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala +++ b/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala @@ -376,9 +376,13 @@ object CLTVScriptPubKey extends Factory[CLTVScriptPubKey] { CLTVScriptPubKey(asm) } - def isCLTVScriptPubKey(asm : Seq[ScriptToken]) : Boolean = asm.slice(0,4) match { - case List(lockTimeBytesToPush : BytesToPushOntoStack, lockTime : ScriptConstant, OP_CHECKLOCKTIMEVERIFY, OP_DROP) => true - case _ => false + def isCLTVScriptPubKey(asm : Seq[ScriptToken]) : Boolean = { + val tailTokens = asm.slice(4, asm.length) + if (P2SHScriptPubKey.isP2SHScriptPubKey(tailTokens) || tailTokens.contains(OP_CHECKLOCKTIMEVERIFY)) return false + asm.slice(0,4) match { + case List(lockTimeBytesToPush : BytesToPushOntoStack, lockTime : ScriptConstant, OP_CHECKLOCKTIMEVERIFY, OP_DROP) => true + case _ => false + } } } @@ -429,10 +433,15 @@ object CSVScriptPubKey extends Factory[CSVScriptPubKey] { CSVScriptPubKey(asm) } - def isCSVScriptPubKey(asm : Seq[ScriptToken]) : Boolean = asm.slice(0,4) match { - case List(lockTimeBytesToPush : BytesToPushOntoStack, lockTime : ScriptConstant, OP_CHECKSEQUENCEVERIFY, OP_DROP) => true - case _ => false + def isCSVScriptPubKey(asm : Seq[ScriptToken]) : Boolean = { + val tailTokens = asm.slice(4, asm.length) + if (P2SHScriptPubKey.isP2SHScriptPubKey(tailTokens) || tailTokens.contains(OP_CHECKSEQUENCEVERIFY)) return false + asm.slice(0,4) match { + case List(lockTimeBytesToPush : BytesToPushOntoStack, lockTime : ScriptConstant, OP_CHECKSEQUENCEVERIFY, OP_DROP) => true + case _ => false + } } + } sealed trait NonStandardScriptPubKey extends ScriptPubKey diff --git a/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala b/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala index f96296eb84..8ce5bc1804 100644 --- a/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala +++ b/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala @@ -416,52 +416,56 @@ object CLTVScriptSignature extends Factory[CLTVScriptSignature] { * of [[ECPublicKey]] needed to satisfy the scriptPubKey. If a [[P2SHScriptPubKey]] is provided, a redeemScript must also be provided. * @return */ - def apply(scriptPubKey: ScriptPubKey, sigs : Seq[ECDigitalSignature], pubKeys : Seq[ECPublicKey], redeemScript : Option[ScriptPubKey]) : CLTVScriptSignature = scriptPubKey match { + def apply(scriptPubKey: ScriptPubKey, sigs : Seq[ECDigitalSignature], pubKeys : Seq[ECPublicKey]) : CLTVScriptSignature = scriptPubKey match { case p2pkScriptPubKey : P2PKScriptPubKey => CLTVScriptSignature(P2PKScriptSignature(sigs.head)) case p2pkhScriptPubKey : P2PKHScriptPubKey => CLTVScriptSignature(P2PKHScriptSignature(sigs.head, pubKeys.head)) case multiSigScriptPubKey : MultiSignatureScriptPubKey => CLTVScriptSignature(MultiSignatureScriptSignature(sigs)) - case cltvScriptPubKey : CLTVScriptPubKey => apply(cltvScriptPubKey.scriptPubKeyAfterCLTV, sigs, pubKeys, redeemScript) - case csvScriptPubKey : CSVScriptPubKey => apply(csvScriptPubKey.scriptPubKeyAfterCSV, sigs, pubKeys, redeemScript) - case p2shScriptPubKey : P2SHScriptPubKey => - require(redeemScript.isDefined, "If the underlying scriptSig is a P2SHScriptSignature, a redeemScript must be defined.") - val cltvScriptSigBeforeRedeemScript = apply(redeemScript.get, sigs, pubKeys, None) - CLTVScriptSignature(P2SHScriptSignature(cltvScriptSigBeforeRedeemScript, redeemScript.get)) + case cltvScriptPubKey : CLTVScriptPubKey => apply(cltvScriptPubKey.scriptPubKeyAfterCLTV, sigs, pubKeys) + case csvScriptPubKey : CSVScriptPubKey => apply(csvScriptPubKey.scriptPubKeyAfterCSV, sigs, pubKeys) case EmptyScriptPubKey => CLTVScriptSignature(EmptyScriptSignature) - case nonstandard : NonStandardScriptPubKey => throw new IllegalArgumentException("A NonStandardScriptSignature cannot be" + - "the underlying scriptSig in a CLTVScriptSignature.") + case _ : NonStandardScriptPubKey | _ : P2SHScriptPubKey => throw new IllegalArgumentException("A NonStandardScriptSignature or P2SHScriptSignature cannot be" + + "the underlying scriptSig in a CLTVScriptSignature. Got: " + this) } } sealed trait CSVScriptSignature extends ScriptSignature { - def scriptSig : ScriptSignature + def scriptSig : ScriptSignature = ScriptSignature(hex) override def signatures : Seq[ECDigitalSignature] = scriptSig.signatures override def hex = scriptSig.hex } -object CSVScriptSignature { - private case class CSVScriptSignatureImpl(scriptSig : ScriptSignature) extends CSVScriptSignature +object CSVScriptSignature extends Factory[CSVScriptSignature] { + private case class CSVScriptSignatureImpl(override val hex : String) extends CSVScriptSignature + override def fromBytes(bytes : Seq[Byte]) : CSVScriptSignature = { + val hex = BitcoinSUtil.encodeHex(bytes) + fromHex(hex) + } + + override def fromHex(hex : String) : CSVScriptSignature = { + CSVScriptSignatureImpl(hex) + } + + def apply(scriptSig : ScriptSignature) : CSVScriptSignature = { + fromHex(scriptSig.hex) + } /** * Creates a CSVScriptSignature out the [[ScriptPubKey]] we are satisfying, a sequence of [[ECDigitalSignature]], and a sequence * of [[ECPublicKey]] needed to satisfy the scriptPubKey. If a [[P2SHScriptPubKey]] is provided, a redeemScript must also be provided. * @return */ - def apply(scriptPubKey: ScriptPubKey, sigs : Seq[ECDigitalSignature], pubKeys : Seq[ECPublicKey], redeemScript : Option[ScriptPubKey]) : CSVScriptSignature = scriptPubKey match { - case p2pkScriptPubKey : P2PKScriptPubKey => CSVScriptSignatureImpl(P2PKScriptSignature(sigs.head)) - case p2pkhScriptPubKey : P2PKHScriptPubKey => CSVScriptSignatureImpl(P2PKHScriptSignature(sigs.head, pubKeys.head)) - case multiSigScriptPubKey : MultiSignatureScriptPubKey => CSVScriptSignatureImpl(MultiSignatureScriptSignature(sigs)) - case cltvScriptPubKey : CLTVScriptPubKey => apply(cltvScriptPubKey.scriptPubKeyAfterCLTV, sigs, pubKeys, redeemScript) - case csvScriptPubKey : CSVScriptPubKey => apply(csvScriptPubKey.scriptPubKeyAfterCSV, sigs, pubKeys, redeemScript) - case p2shScriptPubKey : P2SHScriptPubKey => - require(redeemScript.isDefined, "If the underlying scriptSig is a P2SHScriptSignature, a redeemScript must be defined.") - val csvScriptSigBeforeRedeemScript = apply(redeemScript.get, sigs, pubKeys, None) - CSVScriptSignatureImpl(P2SHScriptSignature(csvScriptSigBeforeRedeemScript, redeemScript.get)) - case EmptyScriptPubKey => CSVScriptSignatureImpl(EmptyScriptSignature) - case nonstandard : NonStandardScriptPubKey => throw new IllegalArgumentException("A NonStandardScriptSignature cannot be" + - "the underlying scriptSig in a CSVScriptSignature.") + def apply(scriptPubKey: ScriptPubKey, sigs : Seq[ECDigitalSignature], pubKeys : Seq[ECPublicKey]) : CSVScriptSignature = scriptPubKey match { + case p2pkScriptPubKey : P2PKScriptPubKey => CSVScriptSignature(P2PKScriptSignature(sigs.head)) + case p2pkhScriptPubKey : P2PKHScriptPubKey => CSVScriptSignature(P2PKHScriptSignature(sigs.head, pubKeys.head)) + case multiSigScriptPubKey : MultiSignatureScriptPubKey => CSVScriptSignature(MultiSignatureScriptSignature(sigs)) + case cltvScriptPubKey : CLTVScriptPubKey => apply(cltvScriptPubKey.scriptPubKeyAfterCLTV, sigs, pubKeys) + case csvScriptPubKey : CSVScriptPubKey => apply(csvScriptPubKey.scriptPubKeyAfterCSV, sigs, pubKeys) + case EmptyScriptPubKey => CSVScriptSignature(EmptyScriptSignature) + case _ : NonStandardScriptPubKey | _ : P2SHScriptPubKey => throw new IllegalArgumentException("A NonStandardScriptSignature or P2SHScriptSignature cannot be" + + "the underlying scriptSig in a CSVScriptSignature. Got: " + this) } } diff --git a/src/main/scala/org/bitcoins/core/script/locktime/LockTimeInterpreter.scala b/src/main/scala/org/bitcoins/core/script/locktime/LockTimeInterpreter.scala index 94c1c628a9..db4aa6fa27 100644 --- a/src/main/scala/org/bitcoins/core/script/locktime/LockTimeInterpreter.scala +++ b/src/main/scala/org/bitcoins/core/script/locktime/LockTimeInterpreter.scala @@ -31,7 +31,6 @@ trait LockTimeInterpreter extends BitcoinSLogger { */ @tailrec final def opCheckLockTimeVerify(program : ScriptProgram) : ScriptProgram = { - logger.warn("+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!") require(program.script.headOption.isDefined && program.script.head == OP_CHECKLOCKTIMEVERIFY, "Script top must be OP_CHECKLOCKTIMEVERIFY") val input = program.txSignatureComponent.transaction.inputs(program.txSignatureComponent.inputIndex.toInt) @@ -176,7 +175,7 @@ trait LockTimeInterpreter extends BitcoinSLogger { (txToSequenceMasked >= Int64(TransactionConstants.sequenceLockTimeTypeFlag.underlying) && nSequenceMasked >= Int64(TransactionConstants.sequenceLockTimeTypeFlag.underlying)) )) { - logger.error("The nSequence mask is not the same as it was in the transaction") + logger.error("The txSequence and nSequence (OP_CSV value) are not of the same type (timestamp/block-height).") return false } @@ -216,7 +215,6 @@ trait LockTimeInterpreter extends BitcoinSLogger { // Now that we know we're comparing apples-to-apples, the // comparison is a simple numeric one. - println("cltvLocktime: " + locktime + " and txLocktime: " + transaction.lockTime) if (locktime > Int64(transaction.lockTime.underlying)) return false // Finally the nLockTime feature can be disabled and thus @@ -231,10 +229,7 @@ trait LockTimeInterpreter extends BitcoinSLogger { // required to prove correct CHECKLOCKTIMEVERIFY execution. if (input.sequence == TransactionConstants.sequence) { false - } else { - println("it passed") - true - } + } else true } /** diff --git a/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala b/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala index 055b6d8268..17a314692e 100644 --- a/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala +++ b/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala @@ -1,6 +1,7 @@ package org.bitcoins.core.crypto import org.bitcoins.core.gen.TransactionGenerators +import org.bitcoins.core.number.Int64 import org.bitcoins.core.protocol.script.{CLTVScriptPubKey, P2SHScriptPubKey} import org.bitcoins.core.script.interpreter.ScriptInterpreter import org.bitcoins.core.script.result.{ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize, ScriptOk} @@ -12,59 +13,58 @@ import org.scalacheck.{Prop, Properties} * Created by chris on 7/25/16. */ class TransactionSignatureCreatorSpec extends Properties("TransactionSignatureCreatorSpec") with BitcoinSLogger { -// property("Must generate a valid signature for a p2pk transaction") = -// Prop.forAll(TransactionGenerators.signedP2PKTransaction) { -// case (txSignatureComponent: TransactionSignatureComponent, _) => -// //run it through the interpreter -// val program: PreExecutionScriptProgram = ScriptProgram(txSignatureComponent) -// val result = ScriptInterpreter.run(program) -// result == ScriptOk -// } -// -// property("generate a valid signature for a p2pkh transaction") = -// Prop.forAll(TransactionGenerators.signedP2PKHTransaction) { -// case (txSignatureComponent: TransactionSignatureComponent, _) => -// //run it through the interpreter -// val program = ScriptProgram(txSignatureComponent) -// val result = ScriptInterpreter.run(program) -// result == ScriptOk -// } -// -// property("generate valid signatures for a multisignature transaction") = -// Prop.forAllNoShrink(TransactionGenerators.signedMultiSigTransaction) { -// case (txSignatureComponent: TransactionSignatureComponent, _) => -// //run it through the interpreter -// val program = ScriptProgram(txSignatureComponent) -// -// val result = ScriptInterpreter.run(program) -// -// result == ScriptOk -// } -// -// property("generate a valid signature for a p2sh transaction") = -// Prop.forAll(TransactionGenerators.signedP2SHTransaction) { -// case (txSignatureComponent: TransactionSignatureComponent, _) => -// //run it through the interpreter -// val program = ScriptProgram(txSignatureComponent) -// val result = ScriptInterpreter.run(program) -// //can be ScriptErrorPushSize if the redeemScript is larger than 520 bytes -// Seq(ScriptOk, ScriptErrorPushSize).contains(result) -// } -// -// property("generate a valid signature for a valid and spendable cltv transaction") = -// Prop.forAllNoShrink(TransactionGenerators.spendableCLTVTransaction :| "cltv_spendable") { -// case (txSignatureComponent: TransactionSignatureComponent, _, scriptNumber) => -// //run it through the interpreter -// require(txSignatureComponent.transaction.lockTime.underlying >= scriptNumber.underlying, "TxLocktime must be satisifed so it should be greater than or equal to " + -// "the cltv value. Got TxLockTime : " + txSignatureComponent.transaction.lockTime.underlying + " , and cltv Value: " + -// scriptNumber.underlying) -// val program = ScriptProgram(txSignatureComponent) -// val result = ScriptInterpreter.run(program) -// val cltv = CLTVScriptPubKey(txSignatureComponent.scriptPubKey.hex) -// if (cltv.scriptPubKeyAfterCLTV.isInstanceOf[P2SHScriptPubKey]) Seq(ScriptOk, ScriptErrorPushSize).contains(result) -// else Seq(ScriptOk).contains(result) -// } -// + property("Must generate a valid signature for a p2pk transaction") = + Prop.forAll(TransactionGenerators.signedP2PKTransaction) { + case (txSignatureComponent: TransactionSignatureComponent, _) => + //run it through the interpreter + val program: PreExecutionScriptProgram = ScriptProgram(txSignatureComponent) + val result = ScriptInterpreter.run(program) + result == ScriptOk + } + + property("generate a valid signature for a p2pkh transaction") = + Prop.forAll(TransactionGenerators.signedP2PKHTransaction) { + case (txSignatureComponent: TransactionSignatureComponent, _) => + //run it through the interpreter + val program = ScriptProgram(txSignatureComponent) + val result = ScriptInterpreter.run(program) + result == ScriptOk + } + + property("generate valid signatures for a multisignature transaction") = + Prop.forAllNoShrink(TransactionGenerators.signedMultiSigTransaction) { + case (txSignatureComponent: TransactionSignatureComponent, _) => + //run it through the interpreter + val program = ScriptProgram(txSignatureComponent) + + val result = ScriptInterpreter.run(program) + + result == ScriptOk + } + + property("generate a valid signature for a p2sh transaction") = + Prop.forAll(TransactionGenerators.signedP2SHTransaction) { + case (txSignatureComponent: TransactionSignatureComponent, _) => + //run it through the interpreter + val program = ScriptProgram(txSignatureComponent) + val result = ScriptInterpreter.run(program) + //can be ScriptErrorPushSize if the redeemScript is larger than 520 bytes + Seq(ScriptOk, ScriptErrorPushSize).contains(result) + } + + property("generate a valid signature for a valid and spendable cltv transaction") = + Prop.forAllNoShrink(TransactionGenerators.spendableCLTVTransaction :| "cltv_spendable") { + case (txSignatureComponent: TransactionSignatureComponent, _, scriptNumber) => + //run it through the interpreter + require(txSignatureComponent.transaction.lockTime.underlying >= scriptNumber.underlying, "TxLocktime must be satisifed so it should be greater than or equal to " + + "the cltv value. Got TxLockTime : " + txSignatureComponent.transaction.lockTime.underlying + " , and cltv Value: " + + scriptNumber.underlying) + val program = ScriptProgram(txSignatureComponent) + val result = ScriptInterpreter.run(program) + val cltv = CLTVScriptPubKey(txSignatureComponent.scriptPubKey.hex) + Seq(ScriptOk).contains(result) + } + property("generate a valid signature for a validly constructed, but NOT spendable cltv transaction") = Prop.forAllNoShrink(TransactionGenerators.unspendableCLTVTransaction :| "cltv_unspendable") { case (txSignatureComponent: TransactionSignatureComponent, _, scriptNumber) => @@ -75,16 +75,25 @@ class TransactionSignatureCreatorSpec extends Properties("TransactionSignatureCr val program = ScriptProgram(txSignatureComponent) val result = ScriptInterpreter.run(program) val cltv = CLTVScriptPubKey(txSignatureComponent.scriptPubKey.hex) - println("result: " + result) Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains(result) } -// -// property("generate a valid signature for a valid and spendable csv transaction") = -// Prop.forAllNoShrink(TransactionGenerators.spendableCSVTransaction :| "csv") { -// case (txSignatureComponent: TransactionSignatureComponent, keys, scriptNumber, sequence) => -// //run it through the interpreter -// val program = ScriptProgram(txSignatureComponent) -// val result = ScriptInterpreter.run(program) -// Seq(ScriptOk, ScriptErrorPushSize).contains(result) -// } + + property("generate a valid signature for a valid and spendable csv transaction") = + Prop.forAllNoShrink(TransactionGenerators.spendableCSVTransaction :| "spendable csv") { + case (txSignatureComponent: TransactionSignatureComponent, keys, scriptNumber, sequence) => + //run it through the interpreter + val program = ScriptProgram(txSignatureComponent) + val result = ScriptInterpreter.run(program) + Seq(ScriptOk, ScriptErrorPushSize).contains(result) + } + + property("generate a valid signature for a validly constructed but unspendable csv transaction") = + Prop.forAllNoShrink(TransactionGenerators.unspendableCSVTransaction :| "unspendable csv") { + case (txSignatureComponent: TransactionSignatureComponent, keys, scriptNumber, sequence) => + //run it through the interpreter + val program = ScriptProgram(txSignatureComponent) + val result = ScriptInterpreter.run(program) + Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains(result) + + } } diff --git a/src/test/scala/org/bitcoins/core/protocol/script/CLTVScriptPubKeySpec.scala b/src/test/scala/org/bitcoins/core/protocol/script/CLTVScriptPubKeySpec.scala index 0405e488e4..fd8f596530 100644 --- a/src/test/scala/org/bitcoins/core/protocol/script/CLTVScriptPubKeySpec.scala +++ b/src/test/scala/org/bitcoins/core/protocol/script/CLTVScriptPubKeySpec.scala @@ -15,17 +15,4 @@ class CLTVScriptPubKeySpec extends Properties("CLTVScriptPubKeySpec") with Bitco Prop.forAll(ScriptGenerators.cltvScriptPubKey) { case (cltvScriptPubKey, _) => CLTVScriptPubKey(cltvScriptPubKey.hex) == cltvScriptPubKey } - property("a valid unspendable CLTV Transaction's locktime must be less than the script's CLTV value ") = - Prop.forAll(TransactionGenerators.unspendableCLTVTransaction) { txSigComponent => - val locktime = txSigComponent._1.transaction.lockTime.underlying - val cltvScriptValue = txSigComponent._3.underlying - locktime < cltvScriptValue - } - - property("a valid spendable CLTV Transaction's locktime must be greater than the script's CLTV value ") = - Prop.forAll(TransactionGenerators.spendableCLTVTransaction) { txSigComponent => - val locktime = txSigComponent._1.transaction.lockTime.underlying - val cltvScriptValue = txSigComponent._3.underlying - locktime > cltvScriptValue - } } diff --git a/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureTest.scala b/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureTest.scala index 99fb43369a..760beab2f5 100644 --- a/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureTest.scala +++ b/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureTest.scala @@ -122,6 +122,6 @@ class ScriptSignatureTest extends FlatSpec with MustMatchers { val cltvScriptPubKey = CLTVScriptPubKey("04e71bbe57b17576a914da88dc82530f0a4d1327dcfe75cc60c44277532c88ac") val pubKey = ECPublicKey("039ba48e162b1f47246f4ce9dc40f197fab7bde11da1b2fe9ac21113959e9f381b") val sig = ECDigitalSignature("3045022100d71cfe32fa4545c5a0fd665b3701eb458a1bacbba868a05fa703fd1fa4b4f5c502204ee706334f976d0bee9b0f0ff919c1dfe9ba027993bf3e39fc03416ba4255b2401") - CLTVScriptSignature(cltvScriptPubKey, Seq(sig), Seq(pubKey), None).scriptSig.isInstanceOf[P2PKHScriptSignature] + CLTVScriptSignature(cltvScriptPubKey, Seq(sig), Seq(pubKey)).scriptSig.isInstanceOf[P2PKHScriptSignature] } } diff --git a/src/test/scala/org/bitcoins/core/script/interpreter/ScriptInterpreterTest.scala b/src/test/scala/org/bitcoins/core/script/interpreter/ScriptInterpreterTest.scala index 216b21ab69..d8960374e9 100644 --- a/src/test/scala/org/bitcoins/core/script/interpreter/ScriptInterpreterTest.scala +++ b/src/test/scala/org/bitcoins/core/script/interpreter/ScriptInterpreterTest.scala @@ -20,7 +20,6 @@ import scala.io.Source * Created by chris on 1/6/16. */ class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterpreter with BitcoinSLogger { -/* "ScriptInterpreter" must "evaluate all the scripts from the bitcoin core script_tests.json" in { @@ -61,19 +60,4 @@ class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterp } } } -*/ - - it must "fail CLTVScriptPubKey with nested P2SHScriptPubKey" in { - val privKey = ECPrivateKey("8fe79310a9a5400daf4f9690187db1607c668fca9f63a530d67cc7472c9de589") - val cltv = CLTVScriptPubKey("010ab175a914c280ffb6c00e2d8b333d84746dc38a807081590287") - val p2shScriptSig = P2SHScriptSignature("483045022100d817fbc5a5d71f0859b811c01e251a20ab897c2b07b96149340336183e80d1" + - "9e022065e20731db313b31c45b208919a8606f90d390620b65a71085d185618b6742bc0123210338a011f3d144d4af991b27d13bcac38ef312835e64a0971c7f5404e1252a332eac") - val cltvScriptSignature = CLTVScriptSignature(p2shScriptSig) - val redeemScript = p2shScriptSig.redeemScript - val (creditingTx, outputIndex) = TransactionGenerators.buildCreditingTransaction(cltv) - val (spendingTx, inputIndex) = TransactionGenerators.buildSpendingTransaction(UInt32.one, creditingTx, cltvScriptSignature, outputIndex, UInt32(5), UInt32.zero) - val txSigComp = TransactionSignatureComponent(spendingTx, inputIndex, redeemScript, Policy.standardScriptVerifyFlags) - ScriptInterpreter.run(ScriptProgram(txSigComp)) must be (ScriptErrorUnsatisfiedLocktime) - } - }