properly generate both spendable and unspendable csv transactions, add factory to CSV/CLTVScriptSignatures

This commit is contained in:
Tom McCabe 2016-09-15 22:28:56 -05:00
parent 10d4041efb
commit bb806716cb
7 changed files with 119 additions and 131 deletions

View file

@ -376,9 +376,13 @@ object CLTVScriptPubKey extends Factory[CLTVScriptPubKey] {
CLTVScriptPubKey(asm) CLTVScriptPubKey(asm)
} }
def isCLTVScriptPubKey(asm : Seq[ScriptToken]) : Boolean = asm.slice(0,4) match { def isCLTVScriptPubKey(asm : Seq[ScriptToken]) : Boolean = {
case List(lockTimeBytesToPush : BytesToPushOntoStack, lockTime : ScriptConstant, OP_CHECKLOCKTIMEVERIFY, OP_DROP) => true val tailTokens = asm.slice(4, asm.length)
case _ => false 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) CSVScriptPubKey(asm)
} }
def isCSVScriptPubKey(asm : Seq[ScriptToken]) : Boolean = asm.slice(0,4) match { def isCSVScriptPubKey(asm : Seq[ScriptToken]) : Boolean = {
case List(lockTimeBytesToPush : BytesToPushOntoStack, lockTime : ScriptConstant, OP_CHECKSEQUENCEVERIFY, OP_DROP) => true val tailTokens = asm.slice(4, asm.length)
case _ => false 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 sealed trait NonStandardScriptPubKey extends ScriptPubKey

View file

@ -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. * of [[ECPublicKey]] needed to satisfy the scriptPubKey. If a [[P2SHScriptPubKey]] is provided, a redeemScript must also be provided.
* @return * @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 p2pkScriptPubKey : P2PKScriptPubKey => CLTVScriptSignature(P2PKScriptSignature(sigs.head))
case p2pkhScriptPubKey : P2PKHScriptPubKey => CLTVScriptSignature(P2PKHScriptSignature(sigs.head, pubKeys.head)) case p2pkhScriptPubKey : P2PKHScriptPubKey => CLTVScriptSignature(P2PKHScriptSignature(sigs.head, pubKeys.head))
case multiSigScriptPubKey : MultiSignatureScriptPubKey => CLTVScriptSignature(MultiSignatureScriptSignature(sigs)) case multiSigScriptPubKey : MultiSignatureScriptPubKey => CLTVScriptSignature(MultiSignatureScriptSignature(sigs))
case cltvScriptPubKey : CLTVScriptPubKey => apply(cltvScriptPubKey.scriptPubKeyAfterCLTV, sigs, pubKeys, redeemScript) case cltvScriptPubKey : CLTVScriptPubKey => apply(cltvScriptPubKey.scriptPubKeyAfterCLTV, sigs, pubKeys)
case csvScriptPubKey : CSVScriptPubKey => apply(csvScriptPubKey.scriptPubKeyAfterCSV, sigs, pubKeys, redeemScript) case csvScriptPubKey : CSVScriptPubKey => apply(csvScriptPubKey.scriptPubKeyAfterCSV, sigs, pubKeys)
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 EmptyScriptPubKey => CLTVScriptSignature(EmptyScriptSignature) case EmptyScriptPubKey => CLTVScriptSignature(EmptyScriptSignature)
case nonstandard : NonStandardScriptPubKey => throw new IllegalArgumentException("A NonStandardScriptSignature cannot be" + case _ : NonStandardScriptPubKey | _ : P2SHScriptPubKey => throw new IllegalArgumentException("A NonStandardScriptSignature or P2SHScriptSignature cannot be" +
"the underlying scriptSig in a CLTVScriptSignature.") "the underlying scriptSig in a CLTVScriptSignature. Got: " + this)
} }
} }
sealed trait CSVScriptSignature extends ScriptSignature { sealed trait CSVScriptSignature extends ScriptSignature {
def scriptSig : ScriptSignature def scriptSig : ScriptSignature = ScriptSignature(hex)
override def signatures : Seq[ECDigitalSignature] = scriptSig.signatures override def signatures : Seq[ECDigitalSignature] = scriptSig.signatures
override def hex = scriptSig.hex override def hex = scriptSig.hex
} }
object CSVScriptSignature { object CSVScriptSignature extends Factory[CSVScriptSignature] {
private case class CSVScriptSignatureImpl(scriptSig : ScriptSignature) extends 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 * 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. * of [[ECPublicKey]] needed to satisfy the scriptPubKey. If a [[P2SHScriptPubKey]] is provided, a redeemScript must also be provided.
* @return * @return
*/ */
def apply(scriptPubKey: ScriptPubKey, sigs : Seq[ECDigitalSignature], pubKeys : Seq[ECPublicKey], redeemScript : Option[ScriptPubKey]) : CSVScriptSignature = scriptPubKey match { def apply(scriptPubKey: ScriptPubKey, sigs : Seq[ECDigitalSignature], pubKeys : Seq[ECPublicKey]) : CSVScriptSignature = scriptPubKey match {
case p2pkScriptPubKey : P2PKScriptPubKey => CSVScriptSignatureImpl(P2PKScriptSignature(sigs.head)) case p2pkScriptPubKey : P2PKScriptPubKey => CSVScriptSignature(P2PKScriptSignature(sigs.head))
case p2pkhScriptPubKey : P2PKHScriptPubKey => CSVScriptSignatureImpl(P2PKHScriptSignature(sigs.head, pubKeys.head)) case p2pkhScriptPubKey : P2PKHScriptPubKey => CSVScriptSignature(P2PKHScriptSignature(sigs.head, pubKeys.head))
case multiSigScriptPubKey : MultiSignatureScriptPubKey => CSVScriptSignatureImpl(MultiSignatureScriptSignature(sigs)) case multiSigScriptPubKey : MultiSignatureScriptPubKey => CSVScriptSignature(MultiSignatureScriptSignature(sigs))
case cltvScriptPubKey : CLTVScriptPubKey => apply(cltvScriptPubKey.scriptPubKeyAfterCLTV, sigs, pubKeys, redeemScript) case cltvScriptPubKey : CLTVScriptPubKey => apply(cltvScriptPubKey.scriptPubKeyAfterCLTV, sigs, pubKeys)
case csvScriptPubKey : CSVScriptPubKey => apply(csvScriptPubKey.scriptPubKeyAfterCSV, sigs, pubKeys, redeemScript) case csvScriptPubKey : CSVScriptPubKey => apply(csvScriptPubKey.scriptPubKeyAfterCSV, sigs, pubKeys)
case p2shScriptPubKey : P2SHScriptPubKey => case EmptyScriptPubKey => CSVScriptSignature(EmptyScriptSignature)
require(redeemScript.isDefined, "If the underlying scriptSig is a P2SHScriptSignature, a redeemScript must be defined.") case _ : NonStandardScriptPubKey | _ : P2SHScriptPubKey => throw new IllegalArgumentException("A NonStandardScriptSignature or P2SHScriptSignature cannot be" +
val csvScriptSigBeforeRedeemScript = apply(redeemScript.get, sigs, pubKeys, None) "the underlying scriptSig in a CSVScriptSignature. Got: " + this)
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.")
} }
} }

View file

@ -31,7 +31,6 @@ trait LockTimeInterpreter extends BitcoinSLogger {
*/ */
@tailrec @tailrec
final def opCheckLockTimeVerify(program : ScriptProgram) : ScriptProgram = { final def opCheckLockTimeVerify(program : ScriptProgram) : ScriptProgram = {
logger.warn("+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!+_+_+_+_!+_+_!!!!")
require(program.script.headOption.isDefined && program.script.head == OP_CHECKLOCKTIMEVERIFY, require(program.script.headOption.isDefined && program.script.head == OP_CHECKLOCKTIMEVERIFY,
"Script top must be OP_CHECKLOCKTIMEVERIFY") "Script top must be OP_CHECKLOCKTIMEVERIFY")
val input = program.txSignatureComponent.transaction.inputs(program.txSignatureComponent.inputIndex.toInt) val input = program.txSignatureComponent.transaction.inputs(program.txSignatureComponent.inputIndex.toInt)
@ -176,7 +175,7 @@ trait LockTimeInterpreter extends BitcoinSLogger {
(txToSequenceMasked >= Int64(TransactionConstants.sequenceLockTimeTypeFlag.underlying) && (txToSequenceMasked >= Int64(TransactionConstants.sequenceLockTimeTypeFlag.underlying) &&
nSequenceMasked >= 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 return false
} }
@ -216,7 +215,6 @@ trait LockTimeInterpreter extends BitcoinSLogger {
// Now that we know we're comparing apples-to-apples, the // Now that we know we're comparing apples-to-apples, the
// comparison is a simple numeric one. // comparison is a simple numeric one.
println("cltvLocktime: " + locktime + " and txLocktime: " + transaction.lockTime)
if (locktime > Int64(transaction.lockTime.underlying)) return false if (locktime > Int64(transaction.lockTime.underlying)) return false
// Finally the nLockTime feature can be disabled and thus // Finally the nLockTime feature can be disabled and thus
@ -231,10 +229,7 @@ trait LockTimeInterpreter extends BitcoinSLogger {
// required to prove correct CHECKLOCKTIMEVERIFY execution. // required to prove correct CHECKLOCKTIMEVERIFY execution.
if (input.sequence == TransactionConstants.sequence) { if (input.sequence == TransactionConstants.sequence) {
false false
} else { } else true
println("it passed")
true
}
} }
/** /**

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.crypto package org.bitcoins.core.crypto
import org.bitcoins.core.gen.TransactionGenerators import org.bitcoins.core.gen.TransactionGenerators
import org.bitcoins.core.number.Int64
import org.bitcoins.core.protocol.script.{CLTVScriptPubKey, P2SHScriptPubKey} import org.bitcoins.core.protocol.script.{CLTVScriptPubKey, P2SHScriptPubKey}
import org.bitcoins.core.script.interpreter.ScriptInterpreter import org.bitcoins.core.script.interpreter.ScriptInterpreter
import org.bitcoins.core.script.result.{ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize, ScriptOk} 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. * Created by chris on 7/25/16.
*/ */
class TransactionSignatureCreatorSpec extends Properties("TransactionSignatureCreatorSpec") with BitcoinSLogger { class TransactionSignatureCreatorSpec extends Properties("TransactionSignatureCreatorSpec") with BitcoinSLogger {
// property("Must generate a valid signature for a p2pk transaction") = property("Must generate a valid signature for a p2pk transaction") =
// Prop.forAll(TransactionGenerators.signedP2PKTransaction) { Prop.forAll(TransactionGenerators.signedP2PKTransaction) {
// case (txSignatureComponent: TransactionSignatureComponent, _) => case (txSignatureComponent: TransactionSignatureComponent, _) =>
// //run it through the interpreter //run it through the interpreter
// val program: PreExecutionScriptProgram = ScriptProgram(txSignatureComponent) val program: PreExecutionScriptProgram = ScriptProgram(txSignatureComponent)
// val result = ScriptInterpreter.run(program) val result = ScriptInterpreter.run(program)
// result == ScriptOk result == ScriptOk
// } }
//
// property("generate a valid signature for a p2pkh transaction") = property("generate a valid signature for a p2pkh transaction") =
// Prop.forAll(TransactionGenerators.signedP2PKHTransaction) { Prop.forAll(TransactionGenerators.signedP2PKHTransaction) {
// case (txSignatureComponent: TransactionSignatureComponent, _) => case (txSignatureComponent: TransactionSignatureComponent, _) =>
// //run it through the interpreter //run it through the interpreter
// val program = ScriptProgram(txSignatureComponent) val program = ScriptProgram(txSignatureComponent)
// val result = ScriptInterpreter.run(program) val result = ScriptInterpreter.run(program)
// result == ScriptOk result == ScriptOk
// } }
//
// property("generate valid signatures for a multisignature transaction") = property("generate valid signatures for a multisignature transaction") =
// Prop.forAllNoShrink(TransactionGenerators.signedMultiSigTransaction) { Prop.forAllNoShrink(TransactionGenerators.signedMultiSigTransaction) {
// case (txSignatureComponent: TransactionSignatureComponent, _) => case (txSignatureComponent: TransactionSignatureComponent, _) =>
// //run it through the interpreter //run it through the interpreter
// val program = ScriptProgram(txSignatureComponent) val program = ScriptProgram(txSignatureComponent)
//
// val result = ScriptInterpreter.run(program) val result = ScriptInterpreter.run(program)
//
// result == ScriptOk result == ScriptOk
// } }
//
// property("generate a valid signature for a p2sh transaction") = property("generate a valid signature for a p2sh transaction") =
// Prop.forAll(TransactionGenerators.signedP2SHTransaction) { Prop.forAll(TransactionGenerators.signedP2SHTransaction) {
// case (txSignatureComponent: TransactionSignatureComponent, _) => case (txSignatureComponent: TransactionSignatureComponent, _) =>
// //run it through the interpreter //run it through the interpreter
// val program = ScriptProgram(txSignatureComponent) val program = ScriptProgram(txSignatureComponent)
// val result = ScriptInterpreter.run(program) val result = ScriptInterpreter.run(program)
// //can be ScriptErrorPushSize if the redeemScript is larger than 520 bytes //can be ScriptErrorPushSize if the redeemScript is larger than 520 bytes
// Seq(ScriptOk, ScriptErrorPushSize).contains(result) Seq(ScriptOk, ScriptErrorPushSize).contains(result)
// } }
//
// property("generate a valid signature for a valid and spendable cltv transaction") = property("generate a valid signature for a valid and spendable cltv transaction") =
// Prop.forAllNoShrink(TransactionGenerators.spendableCLTVTransaction :| "cltv_spendable") { Prop.forAllNoShrink(TransactionGenerators.spendableCLTVTransaction :| "cltv_spendable") {
// case (txSignatureComponent: TransactionSignatureComponent, _, scriptNumber) => case (txSignatureComponent: TransactionSignatureComponent, _, scriptNumber) =>
// //run it through the interpreter //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 " + 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: " + "the cltv value. Got TxLockTime : " + txSignatureComponent.transaction.lockTime.underlying + " , and cltv Value: " +
// scriptNumber.underlying) scriptNumber.underlying)
// val program = ScriptProgram(txSignatureComponent) val program = ScriptProgram(txSignatureComponent)
// val result = ScriptInterpreter.run(program) val result = ScriptInterpreter.run(program)
// val cltv = CLTVScriptPubKey(txSignatureComponent.scriptPubKey.hex) val cltv = CLTVScriptPubKey(txSignatureComponent.scriptPubKey.hex)
// if (cltv.scriptPubKeyAfterCLTV.isInstanceOf[P2SHScriptPubKey]) Seq(ScriptOk, ScriptErrorPushSize).contains(result) Seq(ScriptOk).contains(result)
// else Seq(ScriptOk).contains(result) }
// }
//
property("generate a valid signature for a validly constructed, but NOT spendable cltv transaction") = property("generate a valid signature for a validly constructed, but NOT spendable cltv transaction") =
Prop.forAllNoShrink(TransactionGenerators.unspendableCLTVTransaction :| "cltv_unspendable") { Prop.forAllNoShrink(TransactionGenerators.unspendableCLTVTransaction :| "cltv_unspendable") {
case (txSignatureComponent: TransactionSignatureComponent, _, scriptNumber) => case (txSignatureComponent: TransactionSignatureComponent, _, scriptNumber) =>
@ -75,16 +75,25 @@ class TransactionSignatureCreatorSpec extends Properties("TransactionSignatureCr
val program = ScriptProgram(txSignatureComponent) val program = ScriptProgram(txSignatureComponent)
val result = ScriptInterpreter.run(program) val result = ScriptInterpreter.run(program)
val cltv = CLTVScriptPubKey(txSignatureComponent.scriptPubKey.hex) val cltv = CLTVScriptPubKey(txSignatureComponent.scriptPubKey.hex)
println("result: " + result)
Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains(result) Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains(result)
} }
//
// property("generate a valid signature for a valid and spendable csv transaction") = property("generate a valid signature for a valid and spendable csv transaction") =
// Prop.forAllNoShrink(TransactionGenerators.spendableCSVTransaction :| "csv") { Prop.forAllNoShrink(TransactionGenerators.spendableCSVTransaction :| "spendable csv") {
// case (txSignatureComponent: TransactionSignatureComponent, keys, scriptNumber, sequence) => case (txSignatureComponent: TransactionSignatureComponent, keys, scriptNumber, sequence) =>
// //run it through the interpreter //run it through the interpreter
// val program = ScriptProgram(txSignatureComponent) val program = ScriptProgram(txSignatureComponent)
// val result = ScriptInterpreter.run(program) val result = ScriptInterpreter.run(program)
// Seq(ScriptOk, ScriptErrorPushSize).contains(result) 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)
}
} }

View file

@ -15,17 +15,4 @@ class CLTVScriptPubKeySpec extends Properties("CLTVScriptPubKeySpec") with Bitco
Prop.forAll(ScriptGenerators.cltvScriptPubKey) { case (cltvScriptPubKey, _) => Prop.forAll(ScriptGenerators.cltvScriptPubKey) { case (cltvScriptPubKey, _) =>
CLTVScriptPubKey(cltvScriptPubKey.hex) == 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
}
} }

View file

@ -122,6 +122,6 @@ class ScriptSignatureTest extends FlatSpec with MustMatchers {
val cltvScriptPubKey = CLTVScriptPubKey("04e71bbe57b17576a914da88dc82530f0a4d1327dcfe75cc60c44277532c88ac") val cltvScriptPubKey = CLTVScriptPubKey("04e71bbe57b17576a914da88dc82530f0a4d1327dcfe75cc60c44277532c88ac")
val pubKey = ECPublicKey("039ba48e162b1f47246f4ce9dc40f197fab7bde11da1b2fe9ac21113959e9f381b") val pubKey = ECPublicKey("039ba48e162b1f47246f4ce9dc40f197fab7bde11da1b2fe9ac21113959e9f381b")
val sig = ECDigitalSignature("3045022100d71cfe32fa4545c5a0fd665b3701eb458a1bacbba868a05fa703fd1fa4b4f5c502204ee706334f976d0bee9b0f0ff919c1dfe9ba027993bf3e39fc03416ba4255b2401") val sig = ECDigitalSignature("3045022100d71cfe32fa4545c5a0fd665b3701eb458a1bacbba868a05fa703fd1fa4b4f5c502204ee706334f976d0bee9b0f0ff919c1dfe9ba027993bf3e39fc03416ba4255b2401")
CLTVScriptSignature(cltvScriptPubKey, Seq(sig), Seq(pubKey), None).scriptSig.isInstanceOf[P2PKHScriptSignature] CLTVScriptSignature(cltvScriptPubKey, Seq(sig), Seq(pubKey)).scriptSig.isInstanceOf[P2PKHScriptSignature]
} }
} }

View file

@ -20,7 +20,6 @@ import scala.io.Source
* Created by chris on 1/6/16. * Created by chris on 1/6/16.
*/ */
class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterpreter with BitcoinSLogger { class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterpreter with BitcoinSLogger {
/*
"ScriptInterpreter" must "evaluate all the scripts from the bitcoin core script_tests.json" in { "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)
}
} }