Breaking 'ScriptWitness' into two ADTs 'P2WPKHWitnessV0,P2WSHWitnessV0' and breaking 'WitnessScriptPubKeyV0' into two ADTs 'P2WPKHWitnessSPKV0, P2WSHWitnessSPKV0'

Adding abilility to create TransactionWitness from a Seq[Option[ScriptWitness]], adding checks to determine if a ScriptWitness is a P2WPKHWitnessV0 or a P2WSHWitnessV0

Deprecating some Transaction constructors that are dangerous

removing usages of deprecated Transaction constructors in bitcoin-s-core codebase

fixing nits
This commit is contained in:
Chris Stewart 2018-02-15 11:58:23 -06:00
parent 7c7f4e5cc9
commit ca167cdeaf
19 changed files with 304 additions and 130 deletions

View File

@ -1,6 +1,6 @@
//test in assembly := {}
//testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-verbosity", "3")
testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-verbosity", "2")
coverageExcludedPackages := ".*gen"

View File

@ -289,6 +289,11 @@ object ECPublicKey extends Factory[ECPublicKey] {
* Mimics this function in bitcoin core
* [[https://github.com/bitcoin/bitcoin/blob/27765b6403cece54320374b37afb01a0cfe571c3/src/pubkey.cpp#L207-L212]]
*/
def isFullyValid(bytes: Seq[Byte]): Boolean = Try(NativeSecp256k1.isValidPubKey(bytes.toArray)).isSuccess
def isFullyValid(bytes: Seq[Byte]): Boolean = Try(NativeSecp256k1.isValidPubKey(bytes.toArray)).isSuccess && isValid(bytes)
/**
* Mimics the CPubKey::IsValid function in Bitcoin core, this is a consensus rule
* [[https://github.com/bitcoin/bitcoin/blob/27765b6403cece54320374b37afb01a0cfe571c3/src/pubkey.h#L158]]
*/
def isValid(bytes: Seq[Byte]): Boolean = bytes.nonEmpty
}

View File

@ -77,7 +77,7 @@ sealed abstract class TransactionSignatureSerializer {
else input
}
val txWithInputSigsRemoved = Transaction(spendingTransaction,UpdateTransactionInputs(updatedInputs))
val txWithInputSigsRemoved = BaseTransaction(spendingTransaction.version,updatedInputs, spendingTransaction.outputs, spendingTransaction.lockTime)
val sigHashBytes = hashType.num.bytes.reverse
//check the hash type
//TODO: could probably be optimized w/ HO function
@ -240,10 +240,9 @@ sealed abstract class TransactionSignatureSerializer {
//following this implementation from bitcoinj
//[[https://github.com/bitcoinj/bitcoinj/blob/09a2ca64d2134b0dcbb27b1a6eb17dda6087f448/core/src/main/java/org/bitcoinj/core/Transaction.java#L957]]
//means that no outputs are signed at all
val txWithNoOutputs = Transaction.emptyOutputs(spendingTransaction)
//set the sequence number of all inputs to 0 EXCEPT the input at inputIndex
val updatedInputs : Seq[TransactionInput] = setSequenceNumbersZero(spendingTransaction.inputs,inputIndex)
val sigHashNoneTx = Transaction(txWithNoOutputs,UpdateTransactionInputs(updatedInputs))
val sigHashNoneTx = BaseTransaction(spendingTransaction.version,updatedInputs,Nil,spendingTransaction.lockTime)
//append hash type byte onto the end of the tx bytes
sigHashNoneTx
}
@ -266,11 +265,10 @@ sealed abstract class TransactionSignatureSerializer {
}
val updatedOutputs : Seq[TransactionOutput] = updatedOutputsOpt.flatten
val spendingTxOutputsEmptied = Transaction(spendingTransaction,UpdateTransactionOutputs(updatedOutputs))
//create blank inputs with sequence numbers set to zero EXCEPT
//the input at the inputIndex
val updatedInputs : Seq[TransactionInput] = setSequenceNumbersZero(spendingTxOutputsEmptied.inputs,inputIndex)
val sigHashSingleTx = Transaction(spendingTxOutputsEmptied,UpdateTransactionInputs(updatedInputs))
val updatedInputs : Seq[TransactionInput] = setSequenceNumbersZero(spendingTransaction.inputs,inputIndex)
val sigHashSingleTx = BaseTransaction(spendingTransaction.version, updatedInputs, updatedOutputs, spendingTransaction.lockTime)
sigHashSingleTx
}
@ -281,9 +279,7 @@ sealed abstract class TransactionSignatureSerializer {
/** Executes the [[SIGHASH_ANYONECANPAY]] procedure on a spending transaction at inputIndex. */
private def sigHashAnyoneCanPay(spendingTransaction : Transaction, input : TransactionInput) : Transaction = {
val txWithEmptyInputs = Transaction.emptyInputs(spendingTransaction)
val txWithInputsRemoved = Transaction(txWithEmptyInputs,UpdateTransactionInputs(Seq(input)))
txWithInputsRemoved
BaseTransaction(spendingTransaction.version,Seq(input), spendingTransaction.outputs, spendingTransaction.lockTime)
}
/** Removes [[OP_CODESEPARATOR]] operations then returns the script. */

View File

@ -6,7 +6,7 @@ import org.bitcoins.core.currency.{CurrencyUnit, Satoshis}
import org.bitcoins.core.number.{Int64, UInt32, UInt64}
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.script.{ScriptPubKey, ScriptSignature}
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionConstants, TransactionInput, TransactionOutput}
import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.script.constant.{BytesToPushOntoStack, ScriptConstant, ScriptNumber}
import org.bitcoins.core.script.crypto.OP_CHECKSIG
import org.bitcoins.core.util.BitcoinSUtil
@ -77,7 +77,7 @@ sealed trait ChainParams {
BytesToPushOntoStack(1), ScriptNumber(4), BytesToPushOntoStack(69), ScriptConstant(timestampHex)))
val input = TransactionInput(scriptSignature)
val output = TransactionOutput(amount,scriptPubKey)
val tx = Transaction(TransactionConstants.version,Seq(input), Seq(output), TransactionConstants.lockTime)
val tx = BaseTransaction(TransactionConstants.version,Seq(input), Seq(output), TransactionConstants.lockTime)
val prevBlockHash = DoubleSha256Digest("0000000000000000000000000000000000000000000000000000000000000000")
val merkleRootHash = Merkle.computeMerkleRoot(Seq(tx))
val genesisBlockHeader = BlockHeader(version,prevBlockHash,merkleRootHash,time,nBits,nonce)

View File

@ -1,9 +1,9 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.crypto.{DoubleSha256Digest, ECPublicKey, HashDigest, Sha256Hash160Digest}
import org.bitcoins.core.crypto._
import org.bitcoins.core.protocol._
import org.bitcoins.core.protocol.transaction.WitnessTransaction
import org.bitcoins.core.protocol.blockchain.Block
import org.bitcoins.core.protocol.transaction.WitnessTransaction
import org.bitcoins.core.script.ScriptSettings
import org.bitcoins.core.script.bitwise.{OP_EQUAL, OP_EQUALVERIFY}
import org.bitcoins.core.script.constant.{BytesToPushOntoStack, _}
@ -514,7 +514,8 @@ object WitnessScriptPubKey {
def apply(asm: Seq[ScriptToken]): Option[WitnessScriptPubKey] = fromAsm(asm)
def fromAsm(asm: Seq[ScriptToken]): Option[WitnessScriptPubKey] = asm match {
case _ if WitnessScriptPubKeyV0.isWitnessScriptPubKeyV0(asm) => Some(WitnessScriptPubKeyV0(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
}
@ -534,34 +535,11 @@ object WitnessScriptPubKey {
}
/** Represents a [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program]] */
sealed trait WitnessScriptPubKeyV0 extends WitnessScriptPubKey {
sealed abstract class WitnessScriptPubKeyV0 extends WitnessScriptPubKey {
override def witnessProgram: Seq[ScriptToken] = asm.tail.tail
}
object WitnessScriptPubKeyV0 extends ScriptFactory[WitnessScriptPubKeyV0] {
private case class WitnessScriptPubKeyV0Impl(bytes: Seq[Byte]) extends WitnessScriptPubKeyV0 {
override def toString = "WitnessScriptPubKeyV0Impl(" + hex + ")"
}
def fromAsm(asm: Seq[ScriptToken]): WitnessScriptPubKeyV0 = {
buildScript(asm,WitnessScriptPubKeyV0Impl(_),isWitnessScriptPubKeyV0(_), "Given asm was not a WitnessScriptPubKeyV0, got: " + asm )
}
def apply(asm: Seq[ScriptToken]): WitnessScriptPubKeyV0 = fromAsm(asm)
/** Creates a P2WPKH witness script pubkey */
def apply(pubKey: ECPublicKey): WitnessScriptPubKeyV0 = build(pubKey.bytes, CryptoUtil.sha256Hash160 _)
/** Creates a raw P2WSH script pubkey from the given [[ScriptPubKey]] */
def apply(scriptPubKey: ScriptPubKey): WitnessScriptPubKey = build(scriptPubKey.asmBytes, CryptoUtil.sha256 _)
/** Helper function to build [[WitnessScriptPubKey]], applies given hash function to the bytes,
* then places it inside of [[WitnessScriptPubKey]] */
private def build(bytes: Seq[Byte], hashFunc: Seq[Byte] => HashDigest): WitnessScriptPubKeyV0 = {
val hash = hashFunc(bytes)
val pushOp = BitcoinScriptUtil.calculatePushOp(hash.bytes)
WitnessScriptPubKeyV0(Seq(OP_0) ++ pushOp ++ Seq(ScriptConstant(hash.bytes)))
}
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
@ -569,11 +547,68 @@ object WitnessScriptPubKeyV0 extends ScriptFactory[WitnessScriptPubKeyV0] {
* 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 isWitnessScriptPubKeyV0(asm: Seq[ScriptToken]): Boolean = {
def isValid(asm: Seq[ScriptToken]): Boolean = {
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]]
* */
sealed abstract class P2WPKHWitnessSPKV0 extends WitnessScriptPubKeyV0 {
def pubKeyHash: Sha256Hash160Digest = Sha256Hash160Digest(asm(3).bytes)
override def toString = s"P2WPKHWitnessSPKV0($hex)"
}
object P2WPKHWitnessSPKV0 extends ScriptFactory[P2WPKHWitnessSPKV0] {
private case class P2WPKHWitnessSPKV0Impl(bytes: Seq[Byte]) extends P2WPKHWitnessSPKV0
override def fromAsm(asm: Seq[ScriptToken]): P2WPKHWitnessSPKV0 = {
buildScript(asm,P2WPKHWitnessSPKV0Impl(_), isValid(_), s"Given asm was not a P2WPKHWitnessSPKV0, got $asm")
}
def isValid(asm: Seq[ScriptToken]): Boolean = {
WitnessScriptPubKeyV0.isValid(asm) &&
asm.flatMap(_.bytes).size == 22
}
/** Creates a P2WPKH witness script pubkey */
def apply(pubKey: ECPublicKey): P2WPKHWitnessSPKV0 = {
val hash = CryptoUtil.sha256Hash160(pubKey.bytes)
val pushop = BitcoinScriptUtil.calculatePushOp(hash.bytes)
fromAsm(Seq(OP_0) ++ pushop ++ Seq(ScriptConstant(hash.bytes)))
}
}
/** Reprents the pay-to-witness-scripthash script pubkey type as defined in BIP141
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wsh]]
* */
sealed abstract class P2WSHWitnessSPKV0 extends WitnessScriptPubKeyV0 {
def scriptHash: Sha256Digest = Sha256Digest(asm(3).bytes)
override def toString = s"P2WSHWitnessSPKV0($hex)"
}
object P2WSHWitnessSPKV0 extends ScriptFactory[P2WSHWitnessSPKV0] {
private case class P2WSHWitnessSPKV0Impl(bytes: Seq[Byte]) extends P2WSHWitnessSPKV0
override def fromAsm(asm: Seq[ScriptToken]): P2WSHWitnessSPKV0 = {
buildScript(asm,P2WSHWitnessSPKV0Impl(_), isValid(_), s"Given asm was not a P2WSHWitnessSPKV0, got $asm")
}
def isValid(asm: Seq[ScriptToken]): Boolean = {
WitnessScriptPubKeyV0.isValid(asm) &&
asm.flatMap(_.bytes).size == 34
}
def apply(spk: ScriptPubKey): P2WSHWitnessSPKV0 = {
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 */
sealed trait UnassignedWitnessScriptPubKey extends WitnessScriptPubKey {
override def witnessProgram: Seq[ScriptToken] = asm.tail.tail

View File

@ -1,22 +1,20 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.crypto.{ECDigitalSignature, ECPublicKey}
import org.bitcoins.core.protocol.NetworkElement
import org.bitcoins.core.crypto.{ECDigitalSignature, ECPublicKey, EmptyDigitalSignature}
import org.bitcoins.core.protocol.{CompactSizeUInt, NetworkElement}
import org.bitcoins.core.serializers.script.RawScriptWitnessParser
import org.bitcoins.core.util.{BitcoinSUtil, Factory}
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil, BitcoinScriptUtil}
/**
* Created by chris on 11/10/16.
* The witness used to evaluate a [[ScriptPubKey]] inside of Bitcoin
* [[https://github.com/bitcoin/bitcoin/blob/57b34599b2deb179ff1bd97ffeab91ec9f904d85/src/script/script.h#L648-L660]]
*/
sealed trait ScriptWitness extends NetworkElement {
sealed abstract class ScriptWitness extends NetworkElement {
/** The byte vectors that are placed on to the stack when evaluating a witness program */
def stack : Seq[Seq[Byte]]
override def toString = "ScriptWitness(" + stack.map(BitcoinSUtil.encodeHex(_)).toString + ")"
override def bytes = RawScriptWitnessParser.write(this)
}
@ -26,16 +24,105 @@ case object EmptyScriptWitness extends ScriptWitness {
override def bytes = Seq(0.toByte)
}
object ScriptWitness extends Factory[ScriptWitness] {
private case class ScriptWitnessImpl(stack: Seq[Seq[Byte]]) extends ScriptWitness
sealed abstract class ScriptWitnessV0 extends ScriptWitness
def apply(stack: Seq[Seq[Byte]]): ScriptWitness = ScriptWitnessImpl(stack)
/** Represents a [[org.bitcoins.core.protocol.script.ScriptWitness]] that is needed to spend a
* [[P2WPKHWitnessV0]] scriptPubKey
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wpkh-nested-in-bip16-p2sh]]
* Format: <pubKey> <signature>
*/
sealed abstract class P2WPKHWitnessV0 extends ScriptWitness {
def pubKey: ECPublicKey = ECPublicKey(stack.head)
override def fromBytes(bytes: Seq[Byte]): ScriptWitness = RawScriptWitnessParser.read(bytes)
def signature: ECDigitalSignature = stack(1) match {
case Nil => EmptyDigitalSignature
case bytes: Seq[Byte] => ECDigitalSignature(bytes)
}
def apply(signature: ECDigitalSignature, publicKey: ECPublicKey): ScriptWitness = {
val sigConstant = signature.bytes
val pubKeyConstant = publicKey.bytes
ScriptWitness(Seq(sigConstant, pubKeyConstant))
override def toString = "P2WPKHWitnessV0(" + stack.map(BitcoinSUtil.encodeHex(_)).toString + ")"
}
object P2WPKHWitnessV0 {
private case class P2WPKHWitnessV0Impl(stack: Seq[Seq[Byte]]) extends P2WPKHWitnessV0
private def apply(stack: Seq[Seq[Byte]]): P2WPKHWitnessV0 = P2WPKHWitnessV0Impl(stack)
def apply(pubKey: ECPublicKey): P2WPKHWitnessV0 = {
P2WPKHWitnessV0(pubKey, EmptyDigitalSignature)
}
def apply(publicKey: ECPublicKey, signature: ECDigitalSignature): P2WPKHWitnessV0 = {
P2WPKHWitnessV0(Seq(publicKey.bytes, signature.bytes))
}
}
/**
* Reprsents a [[ScriptWitness]] that is needed to spend a
* [[P2WSHWitnessV0]] scriptPubKey
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wsh]]
* Format: <redeem script> <scriptSig data1> <scriptSig data2> ... <scriptSig dataN>
*/
sealed abstract class P2WSHWitnessV0 extends ScriptWitness {
def redeemScript: ScriptPubKey = {
val cmpct = CompactSizeUInt.calc(stack.head)
ScriptPubKey.fromBytes(cmpct.bytes ++ stack.head)
}
override def toString = "P2WSHWitnessV0(" + stack.map(BitcoinSUtil.encodeHex(_)).toString + ")"
}
object P2WSHWitnessV0 {
private case class P2WSHWitnessV0Impl(stack: Seq[Seq[Byte]]) extends P2WSHWitnessV0
def apply(spk: ScriptPubKey): P2WSHWitnessV0 = {
P2WSHWitnessV0(spk, EmptyScriptSignature)
}
def apply(spk: ScriptPubKey, scriptSig: ScriptSignature): P2WSHWitnessV0 = {
//need to remove the OP_0 or OP_1 and replace it with ScriptNumber.zero / ScriptNumber.one since witnesses are *not* run through the interpreter
//remove pushops from scriptSig
val minimalIf = BitcoinScriptUtil.minimalIfOp(scriptSig.asm)
val noPushOps = BitcoinScriptUtil.filterPushOps(minimalIf)
val minimalDummy = BitcoinScriptUtil.minimalDummy(noPushOps).reverse
val stack: Seq[Seq[Byte]] = spk.asmBytes +: minimalDummy.map(_.bytes)
P2WSHWitnessV0(stack)
}
private def apply(stack: Seq[Seq[Byte]]): P2WSHWitnessV0 = {
P2WSHWitnessV0Impl(stack)
}
def apply(spk: ScriptPubKey, stack: Seq[Seq[Byte]]): P2WSHWitnessV0 = {
val fullStack: Seq[Seq[Byte]] = spk.asmBytes +: stack
P2WSHWitnessV0(fullStack)
}
}
object ScriptWitness {
private val logger = BitcoinSLogger.logger
def apply(stack: Seq[Seq[Byte]]): ScriptWitness = {
//TODO: eventually only compressed public keys will be allowed in v0 scripts
//https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#restrictions-on-public-key-type
val isPubKey = stack.headOption.isDefined && ECPublicKey.isFullyValid(stack.head) && (stack.head.size == 33 || stack.head.size == 65)
if (stack.isEmpty) {
EmptyScriptWitness
} else if (isPubKey && stack.size == 2) {
val pubKey = ECPublicKey(stack.head)
val sig = ECDigitalSignature(stack(1))
P2WPKHWitnessV0(pubKey,sig)
} else if (isPubKey && stack.size == 1) {
val pubKey = ECPublicKey(stack.head)
P2WPKHWitnessV0(pubKey)
} else {
//wont match a Vector if I don't convert to list
val s = stack.toList
s match {
case Nil =>
EmptyScriptWitness
case h :: t =>
val cmpct = CompactSizeUInt.calc(h)
val spk = ScriptPubKey(cmpct.bytes ++ h)
P2WSHWitnessV0(spk,t)
}
}
}
}

View File

@ -78,30 +78,6 @@ sealed abstract class WitnessTransaction extends Transaction {
object Transaction extends Factory[Transaction] {
/** Updates a transaction outputs */
def factory(oldTx : Transaction, updatedOutputs : UpdateTransactionOutputs) : Transaction = {
Transaction(oldTx.version,oldTx.inputs,updatedOutputs.outputs,oldTx.lockTime)
}
/** Updates a transaction's input */
def factory(oldTx : Transaction,updatedInputs : UpdateTransactionInputs) : Transaction = {
Transaction(oldTx.version,updatedInputs.inputs,oldTx.outputs,oldTx.lockTime)
}
/** Factory function that modifies a transactions locktime */
def factory(oldTx : Transaction, lockTime : UInt32) : Transaction = {
Transaction(oldTx.version,oldTx.inputs,oldTx.outputs,lockTime)
}
/** Removes the inputs of the transactions */
def emptyInputs(oldTx : Transaction) : Transaction = Transaction(oldTx.version,Nil,oldTx.outputs,oldTx.lockTime)
/** Removes the outputs of the transactions */
def emptyOutputs(oldTx : Transaction) : Transaction = Transaction(oldTx.version,oldTx.inputs,Nil,oldTx.lockTime)
def factory(bytes : Array[Byte]) : Transaction = fromBytes(bytes.toSeq)
def fromBytes(bytes : Seq[Byte]) : Transaction = {
val wtxTry = Try(RawWitnessTransactionParser.read(bytes))
wtxTry match {
@ -112,12 +88,30 @@ object Transaction extends Factory[Transaction] {
btx
}
}
@deprecated("", "2018/02/16")
def apply(oldTx : Transaction, lockTime : UInt32): Transaction = oldTx match {
case btx: BaseTransaction =>
BaseTransaction(btx.version,btx.inputs,btx.outputs,lockTime)
case wtx: WitnessTransaction =>
WitnessTransaction(wtx.version,wtx.inputs,wtx.outputs,lockTime,wtx.witness)
}
def apply(bytes : Array[Byte]) : Transaction = factory(bytes)
def apply(oldTx : Transaction, lockTime : UInt32) : Transaction = factory(oldTx,lockTime)
def apply(oldTx : Transaction, updatedInputs : UpdateTransactionInputs) : Transaction = factory(oldTx, updatedInputs)
def apply(oldTx : Transaction, updatedOutputs : UpdateTransactionOutputs) : Transaction = factory(oldTx, updatedOutputs)
@deprecated("", "2018/02/16")
def apply(oldTx : Transaction, updatedInputs : UpdateTransactionInputs): Transaction = oldTx match {
case btx: BaseTransaction =>
BaseTransaction(btx.version,updatedInputs.inputs,btx.outputs,btx.lockTime)
case wtx: WitnessTransaction =>
WitnessTransaction(wtx.version,updatedInputs.inputs,wtx.outputs,wtx.lockTime,wtx.witness)
}
@deprecated("", "2018/02/16")
def apply(oldTx : Transaction, updatedOutputs : UpdateTransactionOutputs) : Transaction = oldTx match {
case btx: BaseTransaction =>
BaseTransaction(btx.version,btx.inputs,updatedOutputs.outputs,btx.lockTime)
case wtx: WitnessTransaction =>
WitnessTransaction(wtx.version,wtx.inputs,updatedOutputs.outputs,wtx.lockTime,wtx.witness)
}
@deprecated("Dangerous was you can lose TransactionWitness, use BaseTransaction", "2018/02/16")
def apply(version : UInt32, inputs : Seq[TransactionInput],
outputs : Seq[TransactionOutput], lockTime : UInt32) : Transaction = {
BaseTransaction(version,inputs,outputs,lockTime)

View File

@ -1,7 +1,7 @@
package org.bitcoins.core.protocol.transaction
import org.bitcoins.core.protocol.NetworkElement
import org.bitcoins.core.protocol.script.ScriptWitness
import org.bitcoins.core.protocol.script.{EmptyScriptWitness, ScriptWitness}
import org.bitcoins.core.serializers.transaction.RawTransactionWitnessParser
import org.bitcoins.core.util.BitcoinSUtil
@ -27,6 +27,19 @@ object TransactionWitness {
def apply(witnesses: Seq[ScriptWitness]): TransactionWitness = TransactionWitnessImpl(witnesses)
/** Creates a [[TransactionWitness]] from a Seq[Option[ScriptWitness]].
* This constructor is for convinience if a certain input does not spend a [[org.bitcoins.core.protocol.script.WitnessScriptPubKey]]
* It simply transforms the `None` types to [[EmptyScriptWitness]] and then calls the normal TransactionWitness constructor
* @param witnesses
* @return
*/
def fromWitOpt(witnesses: Seq[Option[ScriptWitness]]): TransactionWitness = {
val replaced: Seq[ScriptWitness] = witnesses.map {
case Some(wit) => wit
case None => EmptyScriptWitness
}
TransactionWitness(replaced)
}
def fromBytes(bytes: Seq[Byte], numInputs: Int): TransactionWitness = RawTransactionWitnessParser.read(bytes,numInputs)
def apply(bytes: Seq[Byte], numInputs: Int): TransactionWitness = fromBytes(bytes,numInputs)

View File

@ -11,15 +11,12 @@ import scala.annotation.tailrec
/**
* Created by chris on 12/14/16.
*/
trait RawScriptWitnessParser extends RawBitcoinSerializer[ScriptWitness] {
sealed abstract class RawScriptWitnessParser extends RawBitcoinSerializer[ScriptWitness] {
def read(bytes: List[Byte]): ScriptWitness = {
logger.debug("Bytes for witness: " + BitcoinSUtil.encodeHex(bytes))
//first byte is the number of stack items
val stackSize = CompactSizeUInt.parseCompactSizeUInt(bytes)
logger.debug("Stack size: " + stackSize)
val (_,stackBytes) = bytes.splitAt(stackSize.size.toInt)
logger.debug("Stack bytes: " + BitcoinSUtil.encodeHex(stackBytes))
@tailrec
def loop(remainingBytes: Seq[Byte], accum: Seq[Seq[Byte]], remainingStackItems: UInt64): Seq[Seq[Byte]] = {
if (remainingStackItems <= UInt64.zero) accum
@ -27,9 +24,7 @@ trait RawScriptWitnessParser extends RawBitcoinSerializer[ScriptWitness] {
val elementSize = CompactSizeUInt.parseCompactSizeUInt(remainingBytes)
val (_,stackElementBytes) = remainingBytes.splitAt(elementSize.size.toInt)
val stackElement = stackElementBytes.take(elementSize.num.toInt)
logger.debug("Parsed stack element: " + BitcoinSUtil.encodeHex(stackElement))
val (_,newRemainingBytes) = stackElementBytes.splitAt(stackElement.size)
logger.debug("New remaining bytes: " + BitcoinSUtil.encodeHex(newRemainingBytes))
loop(newRemainingBytes, stackElement +: accum, remainingStackItems - UInt64.one)
}
}

View File

@ -2,6 +2,7 @@ package org.bitcoins.core.serializers.transaction
import org.bitcoins.core.protocol.script.ScriptWitness
import org.bitcoins.core.protocol.transaction.TransactionWitness
import org.bitcoins.core.serializers.script.RawScriptWitnessParser
import scala.annotation.tailrec
@ -13,19 +14,20 @@ import scala.annotation.tailrec
*/
sealed abstract class RawTransactionWitnessParser {
/** We can only tell how many [[org.bitcoins.core.protocol.transaction.TransactionInputWitness]]
/** We can only tell how many [[ScriptWitness]]
* we have if we have the number of inputs the transaction creates
*/
def read(bytes: Seq[Byte], numInputs: Int): TransactionWitness = {
@tailrec
def loop(remainingBytes: Seq[Byte], remainingInputs: Int, accum: Seq[ScriptWitness]): Seq[ScriptWitness] = {
if (remainingInputs != 0) {
val w = ScriptWitness(remainingBytes)
val w = RawScriptWitnessParser.read(remainingBytes)
val (_,newRemainingBytes) = remainingBytes.splitAt(w.bytes.size)
loop(newRemainingBytes,remainingInputs - 1, w +: accum)
} else accum.reverse
}
val witnesses = loop(bytes,numInputs,Nil)
require(witnesses.size == numInputs)
TransactionWitness(witnesses)
}

View File

@ -371,17 +371,18 @@ trait BitcoinScriptUtil extends BitcoinSLogger {
/** Since witnesses are not run through the interpreter, replace OP_0/OP_1 with ScriptNumber.zero/ScriptNumber.one */
def minimalIfOp(asm: Seq[ScriptToken]): Seq[ScriptToken] = {
if (asm.last == OP_0) {
if (asm == Nil) asm
else if (asm.last == OP_0) {
asm.dropRight(1) ++ Seq(ScriptNumber.zero)
} else if (asm.last == OP_1) {
asm.dropRight(1) ++ Seq(ScriptNumber.one)
} else throw new IllegalArgumentException("EscrowTimeoutScriptSig must end with OP_0 or OP_1")
} else asm
}
/** Replaces the OP_0 dummy for OP_CHECKMULTISIG with ScriptNumber.zero */
def minimalDummy(asm: Seq[ScriptToken]): Seq[ScriptToken] = {
if (asm.head == OP_0) ScriptNumber.zero +: asm.tail
if (asm.headOption == Some(OP_0)) ScriptNumber.zero +: asm.tail
else asm
}

View File

@ -460,12 +460,12 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
BitcoinSUtil.encodeHex(serializedForSig) must be (expected)
}
it must "serialize a p2wsh with SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" in {
it must "serialize a p2wpkh with SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" in {
val rawTx = "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff05540b0000000000000151d0070000000000000151840300000000000001513c0f00000000000001512c010000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71000000000000"
val inputIndex = UInt32(1)
val wtx = WitnessTransaction(rawTx)
val scriptWitness = wtx.witness.witnesses(inputIndex.toInt)
val witScriptPubKey = WitnessScriptPubKeyV0("1600144c9c3dfac4207d5d8cb89df5722cb3d712385e3f")
val witScriptPubKey = P2WPKHWitnessSPKV0("1600144c9c3dfac4207d5d8cb89df5722cb3d712385e3f")
val (_,scriptPubKey) = witScriptPubKey.witnessVersion.rebuild(scriptWitness,witScriptPubKey.witnessProgram).left.get
val amount = Satoshis(Int64(2000))
val serializedForSig = TransactionSignatureSerializer.serializeForSignature(wtx,inputIndex,scriptPubKey.asm,

View File

@ -3,7 +3,7 @@ package org.bitcoins.core.protocol
import org.bitcoins.core.config.{MainNet, TestNet3}
import org.bitcoins.core.crypto.ECPublicKey
import org.bitcoins.core.number.UInt8
import org.bitcoins.core.protocol.script.{P2PKHScriptPubKey, P2PKScriptPubKey, WitnessScriptPubKey, WitnessScriptPubKeyV0}
import org.bitcoins.core.protocol.script._
import org.scalatest.{FlatSpec, MustMatchers}
import scala.util.{Success, Try}
@ -43,7 +43,7 @@ class Bech32Test extends FlatSpec with MustMatchers {
it must "follow the example in BIP173" in {
//https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#examples
val key = ECPublicKey("0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798".toLowerCase)
val p2wpkh = WitnessScriptPubKeyV0(key)
val p2wpkh = P2WPKHWitnessSPKV0(key)
val addr = Bech32Address(p2wpkh,TestNet3)
addr.map(_.value) must be (Success("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"))
@ -58,7 +58,7 @@ class Bech32Test extends FlatSpec with MustMatchers {
mp2wpkhDecoded must be (Success(p2wpkh))
val p2pk = P2PKScriptPubKey(key)
val p2wsh = WitnessScriptPubKeyV0(p2pk)
val p2wsh = P2WSHWitnessSPKV0(p2pk)
val addr1 = Bech32Address(p2wsh,TestNet3)
addr1.map(_.value) must be (Success("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7"))

View File

@ -0,0 +1,21 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.{ScriptGenerators, WitnessGenerators}
import org.bitcoins.core.util.BitcoinSLogger
import org.scalacheck.{Prop, Properties}
class ScriptWitnessSpec extends Properties("ScriptWitnessSpec") {
private val logger = BitcoinSLogger.logger
property("serialization symmetry") = {
Prop.forAll(WitnessGenerators.scriptWitness) { scriptWit =>
val x = ScriptWitness(scriptWit.stack)
scriptWit == x
}
}
property("pull redeem script out of p2wsh witness") = {
Prop.forAll(ScriptGenerators.scriptPubKey) { case (spk,_) =>
P2WSHWitnessV0(spk).redeemScript == spk
}
}
}

View File

@ -10,12 +10,22 @@ class WitnessScriptPubKeySpec extends Properties("WitnessScriptPubKeySpec") {
property("witnessScriptPubKeyV0 serialization symmetry") =
Prop.forAll(ScriptGenerators.witnessScriptPubKeyV0) { case (witScriptPubKeyV0, _) =>
WitnessScriptPubKeyV0(witScriptPubKeyV0.hex) == witScriptPubKeyV0
witScriptPubKeyV0 match {
case p2wpkh: P2WPKHWitnessSPKV0 =>
P2WPKHWitnessSPKV0(p2wpkh.hex) == witScriptPubKeyV0
case p2wsh: P2WSHWitnessSPKV0 =>
P2WSHWitnessSPKV0(p2wsh.hex) == witScriptPubKeyV0
}
}
property("witnessScriptPubKeyV0 fromAsm symmetry") =
Prop.forAll(ScriptGenerators.witnessScriptPubKeyV0) { case (witScriptPubKeyV0,_) =>
WitnessScriptPubKeyV0.fromAsm(witScriptPubKeyV0.asm) == witScriptPubKeyV0
witScriptPubKeyV0 match {
case p2wpkh: P2WPKHWitnessSPKV0 =>
P2WPKHWitnessSPKV0.fromAsm(p2wpkh.asm) == witScriptPubKeyV0
case p2wsh: P2WSHWitnessSPKV0 =>
P2WSHWitnessSPKV0.fromAsm(p2wsh.asm) == witScriptPubKeyV0
}
}
property("unassignedWitnessScriptPubKey serialization symmetry") =

View File

@ -83,11 +83,20 @@ class TransactionTest extends FlatSpec with MustMatchers {
//use this to represent a single test case from script_valid.json
/* val lines =
"""
|[[[["437a1002eb125dec0f93f635763e0ae45f28ff8e81d82945753d0107611cd390", 1, "DUP HASH160 0x14 0x383fb81cb0a3fc724b5e08cf8bbd404336d711f6 EQUALVERIFY CHECKSIG"],
| ["2d48d32ccad087bcda0ac5b31555bd58d1d2568184cbc8e752dd2be2684af03f", 1, "DUP HASH160 0x14 0x275ec2a233e5b23d43fa19e7bf9beb0cb3996117 EQUALVERIFY CHECKSIG"],
| ["c76168ef1a272a4f176e55e73157ecfce040cfad16a5272f6296eb7089dca846", 1, "DUP HASH160 0x14 0x34fea2c5a75414fd945273ae2d029ce1f28dafcf EQUALVERIFY CHECKSIG"]],
|"010000000390d31c6107013d754529d8818eff285fe40a3e7635f6930fec5d12eb02107a43010000006b483045022100f40815ae3c81a0dd851cc8d376d6fd226c88416671346a9033468cca2cdcc6c202204f764623903e6c4bed1b734b75d82c40f1725e4471a55ad4f51218f86130ac038321033d710ab45bb54ac99618ad23b3c1da661631aa25f23bfe9d22b41876f1d46e4effffffff3ff04a68e22bdd52e7c8cb848156d2d158bd5515b3c50adabc87d0ca2cd3482d010000006a4730440220598d263c107004008e9e26baa1e770be30fd31ee55ded1898f7c00da05a75977022045536bead322ca246779698b9c3df3003377090f41afeca7fb2ce9e328ec4af2832102b738b531def73020bd637f32935924cc88549c8206976226d968edd3a42fc2d7ffffffff46a8dc8970eb96622f27a516adcf40e0fcec5731e7556e174f2a271aef6861c7010000006b483045022100c5b90a777a9fdc90c208dbef7290d1fc1be651f47151ee4ccff646872a454cf90220640cfbc4550446968fbbe9d12528f3adf7d87b31541569c59e790db8a220482583210391332546e22bbe8fe3af54addfad6f8b83d05fa4f5e047593d4c07ae938795beffffffff028036be26000000001976a914ddfb29efad43a667465ac59ff14dc6442a1adfca88ac3d5cba01000000001976a914b64dde7a505a13ca986c40e86e984a8dc81368b688ac00000000", "P2SH"]]
""".stripMargin*/
|[[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1000],
|["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1001],
|["0000000000000000000000000000000000000000000000000000000000000100", 2, "DUP HASH160 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f EQUALVERIFY CHECKSIG", 1002],
|["0000000000000000000000000000000000000000000000000000000000000100", 3, "DUP HASH160 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f EQUALVERIFY CHECKSIG", 1003],
|["0000000000000000000000000000000000000000000000000000000000000100", 4, "DUP HASH160 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f EQUALVERIFY CHECKSIG", 1004],
|["0000000000000000000000000000000000000000000000000000000000000100", 5, "DUP HASH160 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f EQUALVERIFY CHECKSIG", 1005],
|["0000000000000000000000000000000000000000000000000000000000000100", 6, "DUP HASH160 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f EQUALVERIFY CHECKSIG", 1006],
|["0000000000000000000000000000000000000000000000000000000000000100", 7, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1007],
|["0000000000000000000000000000000000000000000000000000000000000100", 8, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1008],
|["0000000000000000000000000000000000000000000000000000000000000100", 9, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1009],
|["0000000000000000000000000000000000000000000000000000000000000100", 10, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1010],
|["0000000000000000000000000000000000000000000000000000000000000100", 11, "DUP HASH160 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f EQUALVERIFY CHECKSIG", 1011]],
|"0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"]]
|""".stripMargin*/
val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close()
val json = lines.parseJson
@ -140,7 +149,6 @@ class TransactionTest extends FlatSpec with MustMatchers {
}
}
it must "read all of the tx_invalid.json's contents and return a ScriptError" in {
val source = Source.fromURL(getClass.getResource("/tx_invalid.json"))

View File

@ -139,7 +139,8 @@ class CryptoInterpreterTest extends FlatSpec with MustMatchers {
val flags = Seq(ScriptVerifyNullDummy)
val scriptSig = ScriptSignature.fromAsm(Seq(OP_1))
val input = TransactionInput(EmptyTransactionOutPoint, scriptSig, TransactionConstants.sequence)
val tx = Transaction(TestUtil.transaction,UpdateTransactionInputs(Seq(input)))
val empty = EmptyTransaction
val tx = BaseTransaction(empty.version, Seq(input), empty.outputs, empty.lockTime)
val baseProgram = ScriptProgram.toExecutionInProgress(ScriptProgram(tx,TestUtil.scriptPubKey,
UInt32.zero,flags))

View File

@ -2,7 +2,7 @@ package org.bitcoins.core.script.locktime
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionConstants, TransactionInput, UpdateTransactionInputs}
import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.script.constant.{OP_0, ScriptNumber}
import org.bitcoins.core.script.result._
import org.bitcoins.core.script.{ExecutedScriptProgram, PreExecutionScriptProgram, ScriptProgram}
@ -34,8 +34,9 @@ class LockTimeInterpreterTest extends FlatSpec with MustMatchers {
val stack = Seq(ScriptNumber(-1))
val script = Seq(OP_CHECKLOCKTIMEVERIFY)
val txInputAdjustedSequenceNumber = TransactionInput(TestUtil.transaction.inputs(0),UInt32.zero)
val txAdjustedSequenceNumber = Transaction(TestUtil.transaction,UpdateTransactionInputs(Seq(txInputAdjustedSequenceNumber)))
val adjustedLockTimeTx = Transaction(txAdjustedSequenceNumber,UInt32.zero)
val emptyTx = EmptyTransaction
val txAdjustedSequenceNumber = BaseTransaction(emptyTx.version,Seq(txInputAdjustedSequenceNumber), emptyTx.outputs, emptyTx.lockTime)
val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version,txAdjustedSequenceNumber.inputs,txAdjustedSequenceNumber.outputs,UInt32.zero)
val baseProgram = ScriptProgram(adjustedLockTimeTx,TestUtil.testProgram.txSignatureComponent.scriptPubKey,
TestUtil.testProgram.txSignatureComponent.inputIndex,TestUtil.testProgram.flags)
val program = ScriptProgramTestUtil.toPreExecutionScriptProgram(ScriptProgram(baseProgram,stack,script))
@ -47,8 +48,9 @@ class LockTimeInterpreterTest extends FlatSpec with MustMatchers {
val stack = Seq(ScriptNumber(500000000))
val script = Seq(OP_CHECKLOCKTIMEVERIFY)
val txInputAdjustedSequenceNumber = TransactionInput(TestUtil.transaction.inputs(0),UInt32.zero)
val txAdjustedSequenceNumber = Transaction(TestUtil.transaction,UpdateTransactionInputs(Seq(txInputAdjustedSequenceNumber)))
val adjustedLockTimeTx = Transaction(txAdjustedSequenceNumber,UInt32.zero)
val emptyTx = EmptyTransaction
val txAdjustedSequenceNumber = BaseTransaction(emptyTx.version,Seq(txInputAdjustedSequenceNumber), emptyTx.outputs, emptyTx.lockTime)
val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version,txAdjustedSequenceNumber.inputs,txAdjustedSequenceNumber.outputs,UInt32.zero)
val baseProgram = ScriptProgram(adjustedLockTimeTx,TestUtil.testProgram.txSignatureComponent.scriptPubKey,
TestUtil.testProgram.txSignatureComponent.inputIndex,TestUtil.testProgram.flags)
val program = ScriptProgramTestUtil.toPreExecutionScriptProgram(ScriptProgram(baseProgram,stack,script))
@ -60,8 +62,9 @@ class LockTimeInterpreterTest extends FlatSpec with MustMatchers {
val stack = Seq(ScriptNumber(499999999))
val script = Seq(OP_CHECKLOCKTIMEVERIFY)
val txInputAdjustedSequenceNumber = TransactionInput(TestUtil.transaction.inputs(0),UInt32.zero)
val txAdjustedSequenceNumber = Transaction(TestUtil.transaction,UpdateTransactionInputs(Seq(txInputAdjustedSequenceNumber)))
val adjustedLockTimeTx = Transaction(txAdjustedSequenceNumber,UInt32(500000000))
val emptyTx = EmptyTransaction
val txAdjustedSequenceNumber = BaseTransaction(emptyTx.version,Seq(txInputAdjustedSequenceNumber), emptyTx.outputs, emptyTx.lockTime)
val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version,txAdjustedSequenceNumber.inputs,txAdjustedSequenceNumber.outputs,UInt32.zero)
val baseProgram = ScriptProgram(adjustedLockTimeTx,TestUtil.testProgram.txSignatureComponent.scriptPubKey,
TestUtil.testProgram.txSignatureComponent.inputIndex,TestUtil.testProgram.flags)
val program = ScriptProgramTestUtil.toPreExecutionScriptProgram(ScriptProgram(baseProgram,stack,script))
@ -74,9 +77,9 @@ class LockTimeInterpreterTest extends FlatSpec with MustMatchers {
val stack = Seq(ScriptNumber(499999999))
val script = Seq(OP_CHECKLOCKTIMEVERIFY)
val txInputAdjustedSequenceNumber = TransactionInput(TestUtil.transaction.inputs(0),UInt32.zero)
val txAdjustedSequenceNumber = Transaction(TestUtil.transaction,
UpdateTransactionInputs(Seq(txInputAdjustedSequenceNumber)))
val adjustedLockTimeTx = Transaction(txAdjustedSequenceNumber,UInt32.zero)
val emptyTx = EmptyTransaction
val txAdjustedSequenceNumber = BaseTransaction(emptyTx.version,Seq(txInputAdjustedSequenceNumber), emptyTx.outputs, emptyTx.lockTime)
val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version,txAdjustedSequenceNumber.inputs,txAdjustedSequenceNumber.outputs,UInt32.zero)
val baseProgram = ScriptProgram.toExecutionInProgress(ScriptProgram(adjustedLockTimeTx,
TestUtil.testProgram.txSignatureComponent.scriptPubKey,
TestUtil.testProgram.txSignatureComponent.inputIndex,TestUtil.testProgram.flags))
@ -92,9 +95,11 @@ class LockTimeInterpreterTest extends FlatSpec with MustMatchers {
val stack = Seq(ScriptNumber(0))
val script = Seq(OP_CHECKLOCKTIMEVERIFY)
val txInputAdjustedSequenceNumber = TransactionInput(TestUtil.transaction.inputs(0),UInt32.zero)
val txAdjustedSequenceNumber = Transaction(TestUtil.transaction,
UpdateTransactionInputs(Seq(txInputAdjustedSequenceNumber)))
val adjustedLockTimeTx = Transaction(txAdjustedSequenceNumber,UInt32.zero)
val emptyTx = EmptyTransaction
val txAdjustedSequenceNumber = BaseTransaction(emptyTx.version,Seq(txInputAdjustedSequenceNumber),
emptyTx.outputs, emptyTx.lockTime)
val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version,txAdjustedSequenceNumber.inputs,
txAdjustedSequenceNumber.outputs,UInt32.zero)
val baseProgram = ScriptProgram.toExecutionInProgress(ScriptProgram(adjustedLockTimeTx,
TestUtil.testProgram.txSignatureComponent.scriptPubKey,
TestUtil.testProgram.txSignatureComponent.inputIndex,TestUtil.testProgram.flags))
@ -109,8 +114,11 @@ class LockTimeInterpreterTest extends FlatSpec with MustMatchers {
val stack = Seq(ScriptNumber(500000000))
val script = Seq(OP_CHECKLOCKTIMEVERIFY)
val txInputAdjustedSequenceNumber = TransactionInput(TestUtil.transaction.inputs(0),UInt32.zero)
val txAdjustedSequenceNumber = Transaction(TestUtil.transaction,UpdateTransactionInputs(Seq(txInputAdjustedSequenceNumber)))
val adjustedLockTimeTx = Transaction(txAdjustedSequenceNumber,UInt32(500000000))
val emptyTx = EmptyTransaction
val txAdjustedSequenceNumber = BaseTransaction(emptyTx.version, Seq(txInputAdjustedSequenceNumber),
emptyTx.outputs, emptyTx.lockTime)
val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version, txAdjustedSequenceNumber.inputs,
txAdjustedSequenceNumber.outputs,UInt32(500000000))
val baseProgram : PreExecutionScriptProgram = ScriptProgram(adjustedLockTimeTx,
TestUtil.testProgram.txSignatureComponent.scriptPubKey,
TestUtil.testProgram.txSignatureComponent.inputIndex,TestUtil.testProgram.flags

View File

@ -45,7 +45,7 @@ trait TransactionTestUtil extends BitcoinSLogger {
val input = TransactionInput(outpoint,scriptSignature,TransactionConstants.sequence)
val output = TransactionOutput(amount.getOrElse(CurrencyUnits.zero),scriptPubKey)
val tx = Transaction(TransactionConstants.version,Seq(input),Seq(output),TransactionConstants.lockTime)
val tx = BaseTransaction(TransactionConstants.version,Seq(input),Seq(output),TransactionConstants.lockTime)
(tx,UInt32.zero)
}
@ -85,7 +85,7 @@ trait TransactionTestUtil extends BitcoinSLogger {
TransactionConstants.lockTime, txWitness)
case None =>
val output = TransactionOutput(CurrencyUnits.zero,EmptyScriptPubKey)
Transaction(TransactionConstants.version,Seq(input),Seq(output),TransactionConstants.lockTime)
BaseTransaction(TransactionConstants.version,Seq(input),Seq(output),TransactionConstants.lockTime)
}
@ -179,9 +179,7 @@ trait TransactionTestUtil extends BitcoinSLogger {
* the scriptSignature to be whatever we need it to be
* @return
*/
def testTransaction : Transaction = {
Transaction(EmptyTransaction,UpdateTransactionInputs(Seq(EmptyTransactionInput)))
}
def testTransaction : Transaction = BaseTransaction(EmptyTransaction.version,Seq(EmptyTransactionInput),Nil,EmptyTransaction.lockTime)
}
object TransactionTestUtil extends TransactionTestUtil