mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 09:52:09 +01:00
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:
parent
7c7f4e5cc9
commit
ca167cdeaf
@ -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"
|
||||
|
||||
|
@ -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
|
||||
}
|
@ -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. */
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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"))
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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") =
|
||||
|
@ -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"))
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user