mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-26 01:29:20 +01:00
Merge branch 'master' into eclair_bench
This commit is contained in:
commit
3124a1afc5
67 changed files with 2080 additions and 947 deletions
|
@ -21,4 +21,12 @@ class NetworkParametersTest extends BitcoinSUnitTest {
|
|||
it must "create the correct magic network bytes for regtest" in {
|
||||
BitcoinSUtil.encodeHex(RegTest.magicBytes) must be("fabfb5da")
|
||||
}
|
||||
|
||||
it must "get the correct Network from string" in {
|
||||
assert(Networks.fromString("mainnet").contains(MainNet))
|
||||
assert(Networks.fromString("testnet").contains(TestNet3))
|
||||
assert(Networks.fromString("regtest").contains(RegTest))
|
||||
assert(Networks.fromString("").isEmpty)
|
||||
assert(Networks.fromString("craig wright is a fraud").isEmpty)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@ import org.bitcoins.core.script.PreExecutionScriptProgram
|
|||
import org.bitcoins.core.script.crypto.HashType
|
||||
import org.bitcoins.core.script.interpreter.ScriptInterpreter
|
||||
import org.bitcoins.core.script.result.ScriptOk
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, TransactionTestUtil}
|
||||
import org.bitcoins.core.util.BitcoinSLogger
|
||||
import org.bitcoins.testkit.util.TransactionTestUtil
|
||||
import org.scalatest.concurrent.ScalaFutures
|
||||
import org.scalatest.{FlatSpec, MustMatchers}
|
||||
import scodec.bits.ByteVector
|
||||
|
|
|
@ -72,7 +72,7 @@ class CurrencyUnitTest extends BitcoinSUnitTest {
|
|||
}
|
||||
}
|
||||
|
||||
it must "subtract satoshis " in {
|
||||
it must "subtract satoshis" in {
|
||||
forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) {
|
||||
(num1: Satoshis, num2: Satoshis) =>
|
||||
val result: Try[Int64] = Try(Int64(num1.toBigInt - num2.toBigInt))
|
||||
|
@ -150,6 +150,7 @@ class CurrencyUnitTest extends BitcoinSUnitTest {
|
|||
forAll(CurrencyUnitGenerator.satoshis) { satoshis =>
|
||||
val b = Bitcoins(satoshis)
|
||||
assert(b.satoshis == satoshis)
|
||||
assert(CurrencyUnits.toSatoshis(b) == satoshis)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,4 +165,16 @@ class CurrencyUnitTest extends BitcoinSUnitTest {
|
|||
else actual.isFailure && expected.isFailure
|
||||
}
|
||||
}
|
||||
|
||||
it must "correctly compare two currency units" in {
|
||||
forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) {
|
||||
(num1, num2) =>
|
||||
if (num1 > num2)
|
||||
assert(num1.compare(num2) == 1)
|
||||
else if (num1 < num2)
|
||||
assert(num1.compare(num2) == -1)
|
||||
else
|
||||
assert(num1.compare(num2) == 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,5 +15,6 @@ class FilterTypeTest extends BitcoinSUnitTest {
|
|||
assert(FilterType.getCode(FilterType.Basic) == 0)
|
||||
assert(FilterType.byCode(0) == FilterType.Basic)
|
||||
assertThrows[IllegalArgumentException](FilterType.byCode(1))
|
||||
assertThrows[IllegalArgumentException](FilterType.getCode(FilterType.fromHex("ffff")))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,4 +37,15 @@ class ServiceIdentifierTest extends BitcoinSUnitTest {
|
|||
it must "parse NODE_NETWORK_LIMITED" in {
|
||||
assert(ServiceIdentifier.NODE_NETWORK_LIMITED.nodeNetworkLimited)
|
||||
}
|
||||
|
||||
it must "correctly get a ServiceIdentifier from string" in {
|
||||
assert(ServiceIdentifier.fromString("NETWORK") == ServiceIdentifier.NODE_NETWORK)
|
||||
assert(ServiceIdentifier.fromString("NETWORK_LIMITED") == ServiceIdentifier.NODE_NETWORK_LIMITED)
|
||||
assert(ServiceIdentifier.fromString("WITNESS") == ServiceIdentifier.NODE_WITNESS)
|
||||
assert(ServiceIdentifier.fromString("BLOOM") == ServiceIdentifier.NODE_BLOOM)
|
||||
assert(ServiceIdentifier.fromString("GETUTXO") == ServiceIdentifier.NODE_GET_UTXO)
|
||||
assert(ServiceIdentifier.fromString("COMPACT_FILTERS") == ServiceIdentifier.NODE_COMPACT_FILTERS)
|
||||
assert(ServiceIdentifier.fromString("XTHIN") == ServiceIdentifier.NODE_XTHIN)
|
||||
assertThrows[IllegalArgumentException](ServiceIdentifier.fromString("this is invalid"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@ import org.bitcoins.testkit.util.BitcoinSUnitTest
|
|||
|
||||
class TypeIdentifierTest extends BitcoinSUnitTest {
|
||||
|
||||
it must "Create a MsgUnassigned" in {
|
||||
assert(TypeIdentifier(100000).isInstanceOf[MsgUnassigned])
|
||||
}
|
||||
|
||||
"MsgTx" must "serialize to 01000000" in {
|
||||
MsgTx.hex must be("01000000")
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.bitcoins.core.protocol
|
||||
|
||||
import org.bitcoins.core.util.{Base58, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.util.Base58
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 3/30/16.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package org.bitcoins.core.protocol
|
||||
|
||||
import org.bitcoins.core.config.{MainNet, RegTest, TestNet3}
|
||||
import org.bitcoins.core.crypto.Sha256Hash160Digest
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.bitcoins.core.crypto.{ECPublicKey, Sha256Hash160Digest}
|
||||
import org.bitcoins.core.protocol.script.{EmptyScriptPubKey, P2PKHScriptPubKey, P2SHScriptPubKey, P2WPKHWitnessSPKV0, ScriptPubKey, WitnessScriptPubKeyV0}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
@ -90,4 +90,36 @@ class BitcoinAddressTest extends BitcoinSUnitTest {
|
|||
val addr = P2SHAddress(scriptPubKey, MainNet)
|
||||
addr must be(BitcoinAddress("3P14159f73E4gFr7JterCCQh9QjiTjiZrG").get)
|
||||
}
|
||||
|
||||
it must "create a bech32 address from a WitnessScriptPubKey" in {
|
||||
val scriptPubKey = P2WPKHWitnessSPKV0(ECPublicKey.freshPublicKey)
|
||||
assert(Bech32Address.fromScriptPubKey(scriptPubKey, RegTest).isSuccess)
|
||||
}
|
||||
|
||||
it must "fail to create a bech32 address from an invalid ScriptPubKey" in {
|
||||
assert(Bech32Address.fromScriptPubKey(EmptyScriptPubKey, RegTest).isFailure)
|
||||
}
|
||||
|
||||
it must "create an address from a P2PKHScriptPubKey" in {
|
||||
val scriptPubKey = P2PKHScriptPubKey(ECPublicKey.freshPublicKey)
|
||||
assert(P2PKHAddress.fromScriptPubKey(scriptPubKey, RegTest).isSuccess)
|
||||
}
|
||||
|
||||
it must "fail to create a P2PKHAddress address from an invalid ScriptPubKey" in {
|
||||
assert(P2PKHAddress.fromScriptPubKey(EmptyScriptPubKey, RegTest).isFailure)
|
||||
}
|
||||
|
||||
it must "create an address from a P2SHScriptPubKey" in {
|
||||
val scriptPubKey = P2SHScriptPubKey(EmptyScriptPubKey)
|
||||
assert(P2SHAddress.fromScriptPubKey(scriptPubKey, RegTest).isSuccess)
|
||||
}
|
||||
|
||||
it must "fail to create a P2SHScriptPubKey address from an invalid ScriptPubKey" in {
|
||||
assert(P2SHAddress.fromScriptPubKey(EmptyScriptPubKey, RegTest).isFailure)
|
||||
}
|
||||
|
||||
it must "create an address from a ScriptPubKey" in {
|
||||
val scriptPubKey = P2SHScriptPubKey(EmptyScriptPubKey)
|
||||
assert(Address.fromScriptPubKey(scriptPubKey, RegTest).isSuccess)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ package org.bitcoins.core.protocol
|
|||
|
||||
import org.bitcoins.core.number.UInt64
|
||||
import org.bitcoins.core.protocol.script.ScriptSignature
|
||||
import org.bitcoins.core.util.{BitcoinSUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.util.BitcoinSUtil
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,17 +2,11 @@ package org.bitcoins.core.protocol.script
|
|||
|
||||
import org.bitcoins.core.crypto.ECPrivateKey
|
||||
import org.bitcoins.core.script.bitwise.OP_EQUALVERIFY
|
||||
import org.bitcoins.core.script.constant.{
|
||||
BytesToPushOntoStack,
|
||||
ScriptConstant,
|
||||
ScriptNumber,
|
||||
ScriptToken
|
||||
}
|
||||
import org.bitcoins.core.script.constant.{BytesToPushOntoStack, ScriptConstant, ScriptNumber, ScriptToken}
|
||||
import org.bitcoins.core.script.crypto.{OP_CHECKSIG, OP_HASH160}
|
||||
import org.bitcoins.core.script.locktime.OP_CHECKLOCKTIMEVERIFY
|
||||
import org.bitcoins.core.script.stack.{OP_DROP, OP_DUP}
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by tom on 9/21/16.
|
||||
|
|
|
@ -2,17 +2,11 @@ package org.bitcoins.core.protocol.script
|
|||
|
||||
import org.bitcoins.core.crypto.ECPrivateKey
|
||||
import org.bitcoins.core.script.bitwise.OP_EQUALVERIFY
|
||||
import org.bitcoins.core.script.constant.{
|
||||
BytesToPushOntoStack,
|
||||
ScriptConstant,
|
||||
ScriptNumber,
|
||||
ScriptToken
|
||||
}
|
||||
import org.bitcoins.core.script.constant.{BytesToPushOntoStack, ScriptConstant, ScriptNumber, ScriptToken}
|
||||
import org.bitcoins.core.script.crypto.{OP_CHECKSIG, OP_HASH160}
|
||||
import org.bitcoins.core.script.locktime.OP_CHECKSEQUENCEVERIFY
|
||||
import org.bitcoins.core.script.stack.{OP_DROP, OP_DUP}
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by tom on 9/21/16.
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.core.crypto.ECPublicKey
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 3/8/16.
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.core.util.TransactionTestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TransactionTestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 3/8/16.
|
||||
|
|
|
@ -2,8 +2,7 @@ package org.bitcoins.core.protocol.script
|
|||
|
||||
import org.bitcoins.core.crypto.ECDigitalSignature
|
||||
import org.bitcoins.core.script.crypto.HashType
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.core.crypto.ECPublicKey
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 4/1/16.
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.core.crypto.ECDigitalSignature
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 3/16/16.
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.core.crypto.ECPublicKey
|
||||
import org.bitcoins.core.script.constant.{
|
||||
BytesToPushOntoStack,
|
||||
OP_0,
|
||||
ScriptConstant
|
||||
}
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, TestUtil}
|
||||
import org.bitcoins.core.script.constant.{BytesToPushOntoStack, OP_0, ScriptConstant}
|
||||
import org.bitcoins.core.util.BitcoinSLogger
|
||||
import org.bitcoins.testkit.util.TestUtil
|
||||
import org.scalatest.{FlatSpec, MustMatchers}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.core.util.{BitcoinSUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.util.BitcoinSUtil
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 3/2/16.
|
||||
|
|
|
@ -6,8 +6,8 @@ import org.bitcoins.core.script.bitwise.OP_EQUALVERIFY
|
|||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.crypto.{OP_CHECKSIG, OP_HASH160}
|
||||
import org.bitcoins.core.script.stack.OP_DUP
|
||||
import org.bitcoins.core.util.{CryptoUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.util.CryptoUtil
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 1/14/16.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.core.crypto._
|
||||
import org.bitcoins.core.util.{BitcoinSUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.util.BitcoinSUtil
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,15 +5,11 @@ import org.bitcoins.core.currency.CurrencyUnits
|
|||
import org.bitcoins.core.number.Int32
|
||||
import org.bitcoins.core.policy.Policy
|
||||
import org.bitcoins.core.protocol.script.testprotocol.SignatureHashTestCase
|
||||
import org.bitcoins.core.protocol.transaction.{
|
||||
BaseTransaction,
|
||||
Transaction,
|
||||
TransactionOutput,
|
||||
WitnessTransaction
|
||||
}
|
||||
import org.bitcoins.core.protocol.transaction.{BaseTransaction, Transaction, TransactionOutput, WitnessTransaction}
|
||||
import org.bitcoins.core.script.crypto.{HashType, SIGHASH_ALL}
|
||||
import org.bitcoins.core.serializers.script.RawScriptSignatureParser
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil, TestUtil}
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil}
|
||||
import org.bitcoins.testkit.util.TestUtil
|
||||
import org.scalatest.{FlatSpec, MustMatchers}
|
||||
import scodec.bits.ByteVector
|
||||
import spray.json._
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
package org.bitcoins.core.protocol.transaction
|
||||
|
||||
import org.bitcoins.core.protocol.script.{
|
||||
EmptyScriptSignature,
|
||||
P2PKScriptSignature
|
||||
}
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.protocol.script.{EmptyScriptSignature, P2PKScriptSignature}
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 3/30/16.
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package org.bitcoins.core.protocol.transaction
|
||||
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 3/30/16.
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package org.bitcoins.core.protocol.transaction
|
||||
|
||||
import org.bitcoins.core.crypto.{
|
||||
BaseTxSigComponent,
|
||||
WitnessTxSigComponentP2SH,
|
||||
WitnessTxSigComponentRaw
|
||||
}
|
||||
import org.bitcoins.core.crypto.{BaseTxSigComponent, WitnessTxSigComponentP2SH, WitnessTxSigComponentRaw}
|
||||
import org.bitcoins.core.currency.CurrencyUnits
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.protocol.script._
|
||||
|
@ -14,14 +10,13 @@ import org.bitcoins.core.script.PreExecutionScriptProgram
|
|||
import org.bitcoins.core.script.interpreter.ScriptInterpreter
|
||||
import org.bitcoins.core.script.result.ScriptOk
|
||||
import org.bitcoins.core.serializers.transaction.RawBaseTransactionParser
|
||||
import org.bitcoins.core.util.{CryptoUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.slf4j.LoggerFactory
|
||||
import spray.json._
|
||||
import org.bitcoins.core.util.CryptoUtil
|
||||
import org.bitcoins.testkit.core.gen.TransactionGenerators
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
import scodec.bits._
|
||||
import spray.json._
|
||||
|
||||
import scala.io.Source
|
||||
import org.bitcoins.testkit.core.gen.TransactionGenerators
|
||||
|
||||
class TransactionTest extends BitcoinSUnitTest {
|
||||
behavior of "Transaction"
|
||||
|
@ -71,10 +66,11 @@ class TransactionTest extends BitcoinSUnitTest {
|
|||
"0000000000000000000000000000000000000000000000000000000000000000")
|
||||
}
|
||||
|
||||
it must "calculate the size of a tranaction correctly" in {
|
||||
it must "calculate the size of a transaction correctly" in {
|
||||
val rawTx = TestUtil.rawTransaction
|
||||
val tx = Transaction(rawTx)
|
||||
//size is in bytes so divide by 2
|
||||
assert(tx.size == tx.totalSize)
|
||||
tx.size must be(rawTx.size / 2)
|
||||
}
|
||||
|
||||
|
@ -135,7 +131,7 @@ class TransactionTest extends BitcoinSUnitTest {
|
|||
tx2.size must be(216)
|
||||
tx2.weight must be(534)
|
||||
tx2.vsize must be(134)
|
||||
|
||||
tx2.baseSize must be(106)
|
||||
}
|
||||
|
||||
it must "parse a transaction with an OP_PUSHDATA4 op code but not enough data to push" in {
|
||||
|
|
|
@ -6,8 +6,7 @@ import org.bitcoins.core.number.UInt32
|
|||
import org.bitcoins.core.protocol.transaction.TransactionOutput
|
||||
import org.bitcoins.core.script.constant.{OP_0, OP_1}
|
||||
import org.bitcoins.core.script.flag.ScriptFlagFactory
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 3/31/16.
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package org.bitcoins.core.script
|
||||
|
||||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 2/6/16.
|
||||
|
|
|
@ -3,12 +3,9 @@ package org.bitcoins.core.script.arithmetic
|
|||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.flag.ScriptFlag
|
||||
import org.bitcoins.core.script.result._
|
||||
import org.bitcoins.core.script.{
|
||||
ExecutedScriptProgram,
|
||||
ExecutionInProgressScriptProgram
|
||||
}
|
||||
import org.bitcoins.core.util.{ScriptProgramTestUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.script.{ExecutedScriptProgram, ExecutionInProgressScriptProgram}
|
||||
import org.bitcoins.core.util.ScriptProgramTestUtil
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@ package org.bitcoins.core.script.bitwise
|
|||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.result.ScriptErrorInvalidStackOperation
|
||||
import org.bitcoins.core.script.ExecutedScriptProgram
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 1/6/16.
|
||||
|
|
|
@ -3,12 +3,9 @@ package org.bitcoins.core.script.constant
|
|||
import org.bitcoins.core.script.bitwise.OP_EQUAL
|
||||
import org.bitcoins.core.script.crypto.OP_CHECKMULTISIGVERIFY
|
||||
import org.bitcoins.core.script.flag.{ScriptFlag, ScriptVerifyMinimalData}
|
||||
import org.bitcoins.core.script.result.{
|
||||
ScriptErrorBadOpCode,
|
||||
ScriptErrorMinimalData
|
||||
}
|
||||
import org.bitcoins.core.util.{ScriptProgramTestUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.script.result.{ScriptErrorBadOpCode, ScriptErrorMinimalData}
|
||||
import org.bitcoins.core.util.ScriptProgramTestUtil
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,20 +1,14 @@
|
|||
package org.bitcoins.core.script.control
|
||||
|
||||
import org.bitcoins.core.script.{
|
||||
ExecutedScriptProgram,
|
||||
ExecutionInProgressScriptProgram,
|
||||
StartedScriptProgram
|
||||
}
|
||||
import org.bitcoins.core.script.{ExecutedScriptProgram, ExecutionInProgressScriptProgram, StartedScriptProgram}
|
||||
import org.bitcoins.core.script.arithmetic.OP_ADD
|
||||
import org.bitcoins.core.script.bitwise.OP_EQUAL
|
||||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.reserved.{OP_RESERVED, OP_VER}
|
||||
import org.bitcoins.core.script.result.{
|
||||
ScriptErrorInvalidStackOperation,
|
||||
ScriptErrorOpReturn
|
||||
}
|
||||
import org.bitcoins.core.script.result.{ScriptErrorInvalidStackOperation, ScriptErrorOpReturn}
|
||||
import org.bitcoins.core.serializers.script.ScriptParser
|
||||
import org.bitcoins.core.util._
|
||||
import org.bitcoins.testkit.util.TestUtil
|
||||
import org.scalatest.{FlatSpec, MustMatchers}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,13 +7,10 @@ import org.bitcoins.core.protocol.script.ScriptSignature
|
|||
import org.bitcoins.core.protocol.transaction._
|
||||
import org.bitcoins.core.script._
|
||||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.flag.{
|
||||
ScriptFlagFactory,
|
||||
ScriptVerifyDerSig,
|
||||
ScriptVerifyNullDummy
|
||||
}
|
||||
import org.bitcoins.core.script.flag.{ScriptFlagFactory, ScriptVerifyDerSig, ScriptVerifyNullDummy}
|
||||
import org.bitcoins.core.script.result._
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, ScriptProgramTestUtil, TestUtil}
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, ScriptProgramTestUtil}
|
||||
import org.bitcoins.testkit.util.TestUtil
|
||||
import org.scalatest.{FlatSpec, MustMatchers}
|
||||
|
||||
import scala.util.Try
|
||||
|
|
|
@ -1,24 +1,14 @@
|
|||
package org.bitcoins.core.script.interpreter
|
||||
|
||||
import org.bitcoins.core.crypto.{
|
||||
BaseTxSigComponent,
|
||||
WitnessTxSigComponentP2SH,
|
||||
WitnessTxSigComponentRaw
|
||||
}
|
||||
import org.bitcoins.core.crypto.{BaseTxSigComponent, WitnessTxSigComponentP2SH, WitnessTxSigComponentRaw}
|
||||
import org.bitcoins.core.currency.CurrencyUnits
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.transaction.{
|
||||
TransactionOutput,
|
||||
WitnessTransaction
|
||||
}
|
||||
import org.bitcoins.core.protocol.transaction.{TransactionOutput, WitnessTransaction}
|
||||
import org.bitcoins.core.script.PreExecutionScriptProgram
|
||||
import org.bitcoins.core.script.flag.ScriptFlagFactory
|
||||
import org.bitcoins.core.script.interpreter.testprotocol.CoreTestCase
|
||||
import org.bitcoins.core.script.interpreter.testprotocol.CoreTestCaseProtocol._
|
||||
import org.bitcoins.core.util._
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TransactionTestUtil}
|
||||
import spray.json._
|
||||
|
||||
import scala.io.Source
|
||||
|
|
|
@ -6,12 +6,9 @@ import org.bitcoins.core.number.UInt32
|
|||
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
|
||||
}
|
||||
import org.bitcoins.core.util.{ScriptProgramTestUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.script.{ExecutedScriptProgram, PreExecutionScriptProgram}
|
||||
import org.bitcoins.core.util.ScriptProgramTestUtil
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 3/30/16.
|
||||
|
|
|
@ -3,8 +3,7 @@ package org.bitcoins.core.script.splice
|
|||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.result.ScriptErrorInvalidStackOperation
|
||||
import org.bitcoins.core.script.ExecutedScriptProgram
|
||||
import org.bitcoins.core.util.TestUtil
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 2/4/16.
|
||||
|
|
|
@ -3,8 +3,8 @@ package org.bitcoins.core.script.stack
|
|||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.result._
|
||||
import org.bitcoins.core.script.ExecutedScriptProgram
|
||||
import org.bitcoins.core.util.{BitcoinSUtil, ScriptProgramTestUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.util.{BitcoinSUtil, ScriptProgramTestUtil}
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 1/6/16.
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package org.bitcoins.core.serializers.script
|
||||
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.bitcoins.core.protocol.script.{EmptyScriptPubKey, ScriptPubKey}
|
||||
import org.bitcoins.core.script.bitwise.OP_EQUALVERIFY
|
||||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.crypto.{OP_CHECKSIG, OP_HASH160}
|
||||
import org.bitcoins.core.script.stack.OP_DUP
|
||||
import org.bitcoins.core.util.{BitcoinSUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.util.BitcoinSUtil
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/**
|
||||
|
@ -21,6 +21,10 @@ class RawScriptPubKeyParserTest extends BitcoinSUnitTest {
|
|||
TestUtil.rawScriptPubKey)
|
||||
}
|
||||
|
||||
it must "read an EmptyScriptPubKey" in {
|
||||
assert(RawScriptPubKeyParser.read(ByteVector.empty) == EmptyScriptPubKey)
|
||||
}
|
||||
|
||||
it must "read a raw scriptPubKey and give us the expected asm" in {
|
||||
val scriptPubKey = RawScriptPubKeyParser.read(TestUtil.rawP2PKHScriptPubKey)
|
||||
val expectedAsm: Seq[ScriptToken] =
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package org.bitcoins.core.serializers.script
|
||||
|
||||
import org.bitcoins.core.protocol.script.ScriptSignature
|
||||
import org.bitcoins.core.protocol.script.{EmptyScriptSignature, ScriptSignature}
|
||||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.util.{BitcoinSUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.util.BitcoinSUtil
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/**
|
||||
|
@ -21,6 +21,10 @@ class RawScriptSignatureParserTest extends BitcoinSUnitTest {
|
|||
encode(RawScriptSignatureParser.write(scriptSig)) must be(rawScriptSig)
|
||||
}
|
||||
|
||||
it must "read an EmptyScriptSignature" in {
|
||||
assert(RawScriptSignatureParser.read(ByteVector.empty) == EmptyScriptSignature)
|
||||
}
|
||||
|
||||
it must "read then write a raw script sig" in {
|
||||
//from this tx
|
||||
//https://tbtc.blockr.io/api/v1/tx/raw/bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74
|
||||
|
|
|
@ -4,17 +4,13 @@ import org.bitcoins.core.script.arithmetic.OP_1ADD
|
|||
import org.bitcoins.core.script.bitwise.{OP_EQUAL, OP_EQUALVERIFY}
|
||||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.control.{OP_ELSE, OP_ENDIF, OP_IF, OP_NOTIF}
|
||||
import org.bitcoins.core.script.crypto.{
|
||||
OP_CHECKMULTISIG,
|
||||
OP_CHECKSIG,
|
||||
OP_HASH160
|
||||
}
|
||||
import org.bitcoins.core.script.crypto.{OP_CHECKMULTISIG, OP_CHECKSIG, OP_HASH160}
|
||||
import org.bitcoins.core.script.locktime.OP_CHECKLOCKTIMEVERIFY
|
||||
import org.bitcoins.core.script.reserved.OP_NOP
|
||||
import org.bitcoins.core.script.splice.OP_SIZE
|
||||
import org.bitcoins.core.script.stack.{OP_DROP, OP_DUP, OP_PICK, OP_SWAP}
|
||||
import org.bitcoins.core.util.{BitcoinSUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.util.BitcoinSUtil
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
package org.bitcoins.core.serializers.transaction
|
||||
|
||||
import org.bitcoins.core.number.{Int32, UInt32}
|
||||
import org.bitcoins.core.protocol.transaction.{
|
||||
Transaction,
|
||||
TransactionConstants
|
||||
}
|
||||
import org.bitcoins.core.util.{BitcoinSUtil, TestUtil}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionConstants}
|
||||
import org.bitcoins.core.util.BitcoinSUtil
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package org.bitcoins.core.serializers.transaction
|
||||
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.protocol.transaction.{
|
||||
TransactionConstants,
|
||||
TransactionInput
|
||||
}
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil, TestUtil}
|
||||
import org.bitcoins.core.protocol.transaction.{TransactionConstants, TransactionInput}
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil}
|
||||
import org.bitcoins.testkit.util.TestUtil
|
||||
import org.scalatest.{FlatSpec, MustMatchers}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.bitcoins.core.script.locktime.OP_CHECKLOCKTIMEVERIFY
|
|||
import org.bitcoins.core.script.reserved.{OP_NOP, OP_RESERVED}
|
||||
import org.bitcoins.core.script.result.ScriptErrorWitnessPubKeyType
|
||||
import org.bitcoins.testkit.core.gen.ScriptGenerators
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,9 +21,9 @@ import org.bitcoins.core.protocol.transaction._
|
|||
import org.bitcoins.core.script.crypto.HashType
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.core.wallet.utxo.{
|
||||
BitcoinUTXOSpendingInfo,
|
||||
BitcoinUTXOSpendingInfoFull,
|
||||
ConditionalPath,
|
||||
LockTimeSpendingInfo,
|
||||
LockTimeSpendingInfoFull,
|
||||
UTXOSpendingInfo
|
||||
}
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerByte
|
||||
|
@ -35,6 +35,7 @@ import org.bitcoins.core.script.interpreter.ScriptInterpreter
|
|||
import org.bitcoins.core.wallet.builder.BitcoinTxBuilder.UTXOMap
|
||||
import org.bitcoins.testkit.Implicits._
|
||||
import org.bitcoins.testkit.util.BitcoinSAsyncTest
|
||||
import org.scalacheck.Gen
|
||||
|
||||
class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
||||
val tc = TransactionConstants
|
||||
|
@ -56,10 +57,10 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
outputs = Seq(creditingOutput),
|
||||
lockTime = tc.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
val utxo = BitcoinUTXOSpendingInfo(
|
||||
val utxo = BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = creditingOutput,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = None,
|
||||
hashType = HashType.sigHashAll,
|
||||
|
@ -67,14 +68,14 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
)
|
||||
|
||||
val listF =
|
||||
BitcoinTxBuilder(destinations = Seq.empty,
|
||||
BitcoinTxBuilder(destinations = Vector.empty,
|
||||
utxos = List(utxo),
|
||||
feeRate = SatoshisPerByte(1.sat),
|
||||
changeSPK = EmptyScriptPubKey,
|
||||
network = RegTest)
|
||||
|
||||
val vecF =
|
||||
BitcoinTxBuilder(destinations = Seq.empty,
|
||||
BitcoinTxBuilder(destinations = Vector.empty,
|
||||
utxos = List(utxo),
|
||||
feeRate = SatoshisPerByte(1.sat),
|
||||
changeSPK = EmptyScriptPubKey,
|
||||
|
@ -91,16 +92,16 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
|
||||
val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk)
|
||||
val destinations =
|
||||
Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey))
|
||||
Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey))
|
||||
val creditingTx = BaseTransaction(version = tc.validLockVersion,
|
||||
inputs = Nil,
|
||||
outputs = Seq(creditingOutput),
|
||||
outputs = Vector(creditingOutput),
|
||||
lockTime = tc.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
val utxo = BitcoinUTXOSpendingInfo(
|
||||
val utxo = BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = creditingOutput,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = None,
|
||||
hashType = HashType.sigHashAll,
|
||||
|
@ -122,16 +123,16 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
it must "fail to build a transaction when we pass in a negative fee rate" in {
|
||||
val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk)
|
||||
val destinations =
|
||||
Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey))
|
||||
Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey))
|
||||
val creditingTx = BaseTransaction(version = tc.validLockVersion,
|
||||
inputs = Nil,
|
||||
outputs = Seq(creditingOutput),
|
||||
outputs = Vector(creditingOutput),
|
||||
lockTime = tc.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
val utxo = BitcoinUTXOSpendingInfo(
|
||||
val utxo = BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = creditingOutput,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = None,
|
||||
hashType = HashType.sigHashAll,
|
||||
|
@ -152,20 +153,20 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
it must "fail a transaction when the user invariants fail" in {
|
||||
val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk)
|
||||
val destinations =
|
||||
Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey))
|
||||
Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey))
|
||||
val creditingTx = BaseTransaction(tc.validLockVersion,
|
||||
Nil,
|
||||
Seq(creditingOutput),
|
||||
Vector(creditingOutput),
|
||||
tc.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
val utxo = BitcoinUTXOSpendingInfo(outPoint,
|
||||
creditingOutput,
|
||||
Seq(privKey),
|
||||
None,
|
||||
None,
|
||||
HashType.sigHashAll,
|
||||
conditionalPath =
|
||||
ConditionalPath.NoConditionsLeft)
|
||||
val utxo = BitcoinUTXOSpendingInfoFull(outPoint,
|
||||
creditingOutput,
|
||||
Vector(privKey),
|
||||
None,
|
||||
None,
|
||||
HashType.sigHashAll,
|
||||
conditionalPath =
|
||||
ConditionalPath.NoConditionsLeft)
|
||||
val utxoMap: UTXOMap = Map(outPoint -> utxo)
|
||||
val feeUnit = SatoshisPerVirtualByte(currencyUnit = Satoshis(1))
|
||||
val txBuilder = BitcoinTxBuilder(destinations = destinations,
|
||||
|
@ -174,7 +175,7 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
changeSPK = EmptyScriptPubKey,
|
||||
network = TestNet3)
|
||||
//trivially false
|
||||
val f = (_: Seq[BitcoinUTXOSpendingInfo], _: Transaction) => false
|
||||
val f = (_: Seq[BitcoinUTXOSpendingInfoFull], _: Transaction) => false
|
||||
val resultFuture = txBuilder.flatMap(_.sign(f))
|
||||
recoverToSucceededIf[IllegalArgumentException] {
|
||||
resultFuture
|
||||
|
@ -185,29 +186,29 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
val creditingOutput =
|
||||
TransactionOutput(value = CurrencyUnits.zero, scriptPubKey = spk)
|
||||
val destinations = {
|
||||
Seq(
|
||||
Vector(
|
||||
TransactionOutput(value = Satoshis.one,
|
||||
scriptPubKey = EmptyScriptPubKey))
|
||||
}
|
||||
val creditingTx = BaseTransaction(version = tc.validLockVersion,
|
||||
inputs = Nil,
|
||||
outputs = Seq(creditingOutput),
|
||||
outputs = Vector(creditingOutput),
|
||||
lockTime = tc.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
val utxo = BitcoinUTXOSpendingInfo(
|
||||
val utxo = BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = creditingOutput,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = None,
|
||||
hashType = HashType.sigHashAll,
|
||||
conditionalPath = ConditionalPath.NoConditionsLeft
|
||||
)
|
||||
val utxoMap: UTXOMap = Map(outPoint -> utxo)
|
||||
val utxoSpendingInfo = BitcoinUTXOSpendingInfo(
|
||||
val utxoSpendingInfo = BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = creditingOutput,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = None,
|
||||
hashType = HashType.sigHashAll,
|
||||
|
@ -221,7 +222,7 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
changeSPK = EmptyScriptPubKey,
|
||||
network = TestNet3)
|
||||
val txBuilderTuple = BitcoinTxBuilder(destinations = destinations,
|
||||
utxos = Seq(utxoSpendingInfo),
|
||||
utxos = Vector(utxoSpendingInfo),
|
||||
feeRate = feeUnit,
|
||||
changeSPK = EmptyScriptPubKey,
|
||||
network = TestNet3)
|
||||
|
@ -238,14 +239,14 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2sh)
|
||||
val creditingTx = BaseTransaction(version = tc.validLockVersion,
|
||||
inputs = Nil,
|
||||
outputs = Seq(creditingOutput),
|
||||
outputs = Vector(creditingOutput),
|
||||
lockTime = tc.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
assertThrows[IllegalArgumentException] {
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = creditingOutput,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
redeemScriptOpt = Some(EmptyScriptPubKey),
|
||||
scriptWitnessOpt = None,
|
||||
hashType = HashType.sigHashAll,
|
||||
|
@ -259,14 +260,14 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2wsh)
|
||||
val creditingTx = BaseTransaction(tc.validLockVersion,
|
||||
Nil,
|
||||
Seq(creditingOutput),
|
||||
Vector(creditingOutput),
|
||||
tc.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
assertThrows[IllegalArgumentException] {
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint,
|
||||
creditingOutput,
|
||||
Seq(privKey),
|
||||
Vector(privKey),
|
||||
None,
|
||||
Some(P2WSHWitnessV0(EmptyScriptPubKey)),
|
||||
HashType.sigHashAll,
|
||||
|
@ -279,16 +280,16 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
val p2pkh = P2PKHScriptPubKey(privKey.publicKey)
|
||||
val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2pkh)
|
||||
val destinations =
|
||||
Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey))
|
||||
Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey))
|
||||
val creditingTx = BaseTransaction(tc.validLockVersion,
|
||||
Nil,
|
||||
Seq(creditingOutput),
|
||||
Vector(creditingOutput),
|
||||
tc.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
val utxo = BitcoinUTXOSpendingInfo(
|
||||
val utxo = BitcoinUTXOSpendingInfoFull(
|
||||
outPoint,
|
||||
creditingOutput,
|
||||
Seq(privKey),
|
||||
Vector(privKey),
|
||||
None,
|
||||
Some(P2WSHWitnessV0(EmptyScriptPubKey)),
|
||||
HashType.sigHashAll,
|
||||
|
@ -313,17 +314,17 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
val pubKey2 = ECPrivateKey().publicKey
|
||||
val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2pkh)
|
||||
val destinations =
|
||||
Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey))
|
||||
Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey))
|
||||
val creditingTx = BaseTransaction(version = tc.validLockVersion,
|
||||
inputs = Nil,
|
||||
outputs = Seq(creditingOutput),
|
||||
outputs = Vector(creditingOutput),
|
||||
lockTime = tc.lockTime)
|
||||
val outPoint =
|
||||
TransactionOutPoint(txId = creditingTx.txId, vout = UInt32.zero)
|
||||
val utxo = BitcoinUTXOSpendingInfo(
|
||||
val utxo = BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = creditingOutput,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = Some(P2WSHWitnessV0(EmptyScriptPubKey)),
|
||||
hashType = HashType.sigHashAll,
|
||||
|
@ -349,15 +350,15 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
TransactionOutput(value = CurrencyUnits.zero, scriptPubKey = p2wpkh)
|
||||
val creditingTx = BaseTransaction(version = tc.validLockVersion,
|
||||
inputs = Nil,
|
||||
outputs = Seq(creditingOutput),
|
||||
outputs = Vector(creditingOutput),
|
||||
lockTime = tc.lockTime)
|
||||
val outPoint =
|
||||
TransactionOutPoint(txId = creditingTx.txId, vout = UInt32.zero)
|
||||
assertThrows[IllegalArgumentException] {
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = creditingOutput,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = Some(P2WSHWitnessV0(EmptyScriptPubKey)),
|
||||
hashType = HashType.sigHashAll,
|
||||
|
@ -371,14 +372,14 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2wpkh)
|
||||
val creditingTx = BaseTransaction(tc.validLockVersion,
|
||||
Nil,
|
||||
Seq(creditingOutput),
|
||||
Vector(creditingOutput),
|
||||
tc.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
assertThrows[IllegalArgumentException] {
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint,
|
||||
creditingOutput,
|
||||
Seq(privKey),
|
||||
Vector(privKey),
|
||||
None,
|
||||
Some(P2WSHWitnessV0(EmptyScriptPubKey)),
|
||||
HashType.sigHashAll,
|
||||
|
@ -396,7 +397,7 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
CLTVScriptPubKey(ScriptNumber(lockTime),
|
||||
P2PKScriptPubKey(fundingPrivKey.publicKey))
|
||||
|
||||
val cltvSpendingInfo = LockTimeSpendingInfo(
|
||||
val cltvSpendingInfo = LockTimeSpendingInfoFull(
|
||||
TransactionOutPoint(DoubleSha256DigestBE.empty, UInt32.zero),
|
||||
Bitcoins.one,
|
||||
cltvSPK,
|
||||
|
@ -430,7 +431,7 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
CLTVScriptPubKey(ScriptNumber(lockTime),
|
||||
P2PKScriptPubKey(fundingPrivKey.publicKey))
|
||||
|
||||
val cltvSpendingInfo = LockTimeSpendingInfo(
|
||||
val cltvSpendingInfo = LockTimeSpendingInfoFull(
|
||||
TransactionOutPoint(DoubleSha256DigestBE.empty, UInt32.zero),
|
||||
Bitcoins.one,
|
||||
cltvSPK,
|
||||
|
@ -469,7 +470,7 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
CLTVScriptPubKey(ScriptNumber(lockTime2),
|
||||
P2PKScriptPubKey(fundingPrivKey2.publicKey))
|
||||
|
||||
val cltvSpendingInfo1 = LockTimeSpendingInfo(
|
||||
val cltvSpendingInfo1 = LockTimeSpendingInfoFull(
|
||||
TransactionOutPoint(DoubleSha256DigestBE.empty, UInt32.zero),
|
||||
Bitcoins.one,
|
||||
cltvSPK1,
|
||||
|
@ -478,7 +479,7 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
ConditionalPath.NoConditionsLeft
|
||||
)
|
||||
|
||||
val cltvSpendingInfo2 = LockTimeSpendingInfo(
|
||||
val cltvSpendingInfo2 = LockTimeSpendingInfoFull(
|
||||
TransactionOutPoint(DoubleSha256DigestBE.empty, UInt32.one),
|
||||
Bitcoins.one,
|
||||
cltvSPK2,
|
||||
|
@ -503,74 +504,79 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
)
|
||||
}
|
||||
|
||||
def verifyScript(tx: Transaction, utxos: Seq[UTXOSpendingInfo]): Boolean = {
|
||||
val programs: Seq[PreExecutionScriptProgram] = tx.inputs.zipWithIndex.map {
|
||||
case (input: TransactionInput, idx: Int) =>
|
||||
val outpoint = input.previousOutput
|
||||
def verifyScript(tx: Transaction,
|
||||
utxos: Vector[UTXOSpendingInfo]): Boolean = {
|
||||
val programs: Vector[PreExecutionScriptProgram] =
|
||||
tx.inputs.zipWithIndex.toVector.map {
|
||||
case (input: TransactionInput, idx: Int) =>
|
||||
val outpoint = input.previousOutput
|
||||
|
||||
val creditingTx = utxos.find(u => u.outPoint.txId == outpoint.txId).get
|
||||
val creditingTx =
|
||||
utxos.find(u => u.outPoint.txId == outpoint.txId).get
|
||||
|
||||
val output = creditingTx.output
|
||||
val output = creditingTx.output
|
||||
|
||||
val spk = output.scriptPubKey
|
||||
val spk = output.scriptPubKey
|
||||
|
||||
val amount = output.value
|
||||
val amount = output.value
|
||||
|
||||
val txSigComponent = spk match {
|
||||
case witSPK: WitnessScriptPubKeyV0 =>
|
||||
val o = TransactionOutput(amount, witSPK)
|
||||
WitnessTxSigComponentRaw(tx.asInstanceOf[WitnessTransaction],
|
||||
val txSigComponent = spk match {
|
||||
case witSPK: WitnessScriptPubKeyV0 =>
|
||||
val o = TransactionOutput(amount, witSPK)
|
||||
WitnessTxSigComponentRaw(tx.asInstanceOf[WitnessTransaction],
|
||||
UInt32(idx),
|
||||
o,
|
||||
Policy.standardFlags)
|
||||
case _: UnassignedWitnessScriptPubKey => ???
|
||||
case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey |
|
||||
_: P2PKWithTimeoutScriptPubKey | _: MultiSignatureScriptPubKey |
|
||||
_: WitnessCommitment | _: CSVScriptPubKey |
|
||||
_: CLTVScriptPubKey | _: ConditionalScriptPubKey |
|
||||
_: NonStandardScriptPubKey | EmptyScriptPubKey) =>
|
||||
val o = TransactionOutput(CurrencyUnits.zero, x)
|
||||
BaseTxSigComponent(tx, UInt32(idx), o, Policy.standardFlags)
|
||||
|
||||
case p2sh: P2SHScriptPubKey =>
|
||||
val p2shScriptSig =
|
||||
tx.inputs(idx).scriptSignature.asInstanceOf[P2SHScriptSignature]
|
||||
p2shScriptSig.redeemScript match {
|
||||
|
||||
case _: WitnessScriptPubKey =>
|
||||
WitnessTxSigComponentP2SH(
|
||||
transaction = tx.asInstanceOf[WitnessTransaction],
|
||||
inputIndex = UInt32(idx),
|
||||
output = output,
|
||||
flags = Policy.standardFlags)
|
||||
|
||||
case _ =>
|
||||
BaseTxSigComponent(tx,
|
||||
UInt32(idx),
|
||||
o,
|
||||
output,
|
||||
Policy.standardFlags)
|
||||
case _: UnassignedWitnessScriptPubKey => ???
|
||||
case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey |
|
||||
_: P2PKWithTimeoutScriptPubKey | _: MultiSignatureScriptPubKey |
|
||||
_: WitnessCommitment | _: CSVScriptPubKey | _: CLTVScriptPubKey |
|
||||
_: ConditionalScriptPubKey | _: NonStandardScriptPubKey |
|
||||
EmptyScriptPubKey) =>
|
||||
val o = TransactionOutput(CurrencyUnits.zero, x)
|
||||
BaseTxSigComponent(tx, UInt32(idx), o, Policy.standardFlags)
|
||||
}
|
||||
}
|
||||
|
||||
case p2sh: P2SHScriptPubKey =>
|
||||
val p2shScriptSig =
|
||||
tx.inputs(idx).scriptSignature.asInstanceOf[P2SHScriptSignature]
|
||||
p2shScriptSig.redeemScript match {
|
||||
|
||||
case _: WitnessScriptPubKey =>
|
||||
WitnessTxSigComponentP2SH(transaction =
|
||||
tx.asInstanceOf[WitnessTransaction],
|
||||
inputIndex = UInt32(idx),
|
||||
output = output,
|
||||
flags = Policy.standardFlags)
|
||||
|
||||
case _ =>
|
||||
BaseTxSigComponent(tx,
|
||||
UInt32(idx),
|
||||
output,
|
||||
Policy.standardFlags)
|
||||
}
|
||||
}
|
||||
|
||||
PreExecutionScriptProgram(txSigComponent)
|
||||
}
|
||||
PreExecutionScriptProgram(txSigComponent)
|
||||
}
|
||||
ScriptInterpreter.runAllVerify(programs)
|
||||
}
|
||||
|
||||
private val outputGen = CreditingTxGen.outputs
|
||||
.flatMap { creditingTxsInfo =>
|
||||
val creditingOutputs = creditingTxsInfo.map(c => c.output)
|
||||
val creditingOutputsAmt = creditingOutputs.map(_.value)
|
||||
val totalAmount = creditingOutputsAmt.fold(CurrencyUnits.zero)(_ + _)
|
||||
private def outputGen(outputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]]) = {
|
||||
outputs
|
||||
.flatMap { creditingTxsInfo =>
|
||||
val creditingOutputs = creditingTxsInfo.map(c => c.output)
|
||||
val creditingOutputsAmt = creditingOutputs.map(_.value)
|
||||
val totalAmount = creditingOutputsAmt.fold(CurrencyUnits.zero)(_ + _)
|
||||
|
||||
TransactionGenerators.smallOutputs(totalAmount).map { destinations =>
|
||||
(creditingTxsInfo, destinations)
|
||||
TransactionGenerators.smallOutputs(totalAmount).map { destinations =>
|
||||
(creditingTxsInfo, destinations)
|
||||
}
|
||||
}
|
||||
}
|
||||
.suchThat(_._1.nonEmpty)
|
||||
.suchThat(_._1.nonEmpty)
|
||||
}
|
||||
|
||||
it must "sign a mix of spks in a tx and then have it verified" in {
|
||||
forAllAsync(outputGen,
|
||||
forAllAsync(outputGen(CreditingTxGen.outputs),
|
||||
ScriptGenerators.scriptPubKey,
|
||||
ChainParamsGenerator.bitcoinNetworkParams) {
|
||||
case ((creditingTxsInfo, destinations), changeSPK, network) =>
|
||||
|
@ -583,13 +589,13 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
val txF = builder.flatMap(_.sign)
|
||||
|
||||
txF.map { tx =>
|
||||
assert(verifyScript(tx, creditingTxsInfo))
|
||||
assert(verifyScript(tx, creditingTxsInfo.toVector))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it must "sign a mix of p2sh/p2wsh in a tx and then have it verified" in {
|
||||
forAllAsync(outputGen,
|
||||
forAllAsync(outputGen(CreditingTxGen.nestedOutputs),
|
||||
ScriptGenerators.scriptPubKey,
|
||||
ChainParamsGenerator.bitcoinNetworkParams) {
|
||||
case ((creditingTxsInfo, destinations), changeSPK, network) =>
|
||||
|
@ -602,7 +608,7 @@ class BitcoinTxBuilderTest extends BitcoinSAsyncTest {
|
|||
val txF = builder.flatMap(_.sign)
|
||||
|
||||
txF.map { tx =>
|
||||
assert(verifyScript(tx, creditingTxsInfo))
|
||||
assert(verifyScript(tx, creditingTxsInfo.toVector))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,40 @@
|
|||
package org.bitcoins.core.wallet.signer
|
||||
|
||||
import org.bitcoins.core.protocol.script.WitnessScriptPubKey
|
||||
import org.bitcoins.core.crypto.ECDigitalSignature
|
||||
import org.bitcoins.core.currency.{CurrencyUnits, Satoshis}
|
||||
import org.bitcoins.core.protocol.script.{
|
||||
EmptyScriptWitness,
|
||||
P2WPKHWitnessV0,
|
||||
P2WSHWitnessV0,
|
||||
WitnessScriptPubKey
|
||||
}
|
||||
import org.bitcoins.core.protocol.transaction.WitnessTransaction
|
||||
import org.bitcoins.core.wallet.builder.BitcoinTxBuilder
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.core.wallet.utxo.{
|
||||
P2WPKHV0SpendingInfo,
|
||||
P2WSHV0SpendingInfo,
|
||||
P2WSHV0SpendingInfoFull,
|
||||
UTXOSpendingInfoSingle,
|
||||
UnassignedSegwitNativeUTXOSpendingInfo
|
||||
}
|
||||
import org.bitcoins.testkit.core.gen.{
|
||||
ChainParamsGenerator,
|
||||
CreditingTxGen,
|
||||
GenUtil,
|
||||
ScriptGenerators,
|
||||
TransactionGenerators
|
||||
}
|
||||
import org.bitcoins.testkit.util.BitcoinSAsyncTest
|
||||
|
||||
import scala.concurrent.ExecutionContext
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
class SignerTest extends BitcoinSAsyncTest {
|
||||
|
||||
implicit val ec: ExecutionContext = ExecutionContext.global
|
||||
|
||||
implicit override val generatorDrivenConfig: PropertyCheckConfiguration =
|
||||
generatorDrivenConfigNewCode
|
||||
|
||||
behavior of "Signer"
|
||||
|
||||
it should "fail to sign a UnassignedSegwit UTXO" in {
|
||||
|
@ -59,10 +75,87 @@ class SignerTest extends BitcoinSAsyncTest {
|
|||
val dumbSpendingInfo = GenUtil.sample(CreditingTxGen.output)
|
||||
val p2wsh = GenUtil
|
||||
.sample(CreditingTxGen.p2wshOutput)
|
||||
.asInstanceOf[P2WSHV0SpendingInfo]
|
||||
.asInstanceOf[P2WSHV0SpendingInfoFull]
|
||||
val tx = GenUtil.sample(TransactionGenerators.baseTransaction)
|
||||
recoverToSucceededIf[IllegalArgumentException] {
|
||||
P2WSHSigner.sign(dumbSpendingInfo, tx, isDummySignature = false, p2wsh)
|
||||
}
|
||||
}
|
||||
|
||||
private val outputGen = CreditingTxGen.outputs
|
||||
.flatMap { creditingTxsInfo =>
|
||||
val creditingOutputs = creditingTxsInfo.map(c => c.output)
|
||||
val creditingOutputsAmt = creditingOutputs.map(_.value)
|
||||
val totalAmount = creditingOutputsAmt.fold(CurrencyUnits.zero)(_ + _)
|
||||
|
||||
TransactionGenerators.smallOutputs(totalAmount).map { destinations =>
|
||||
(creditingTxsInfo, destinations)
|
||||
}
|
||||
}
|
||||
.suchThat(_._1.nonEmpty)
|
||||
|
||||
it must "sign a mix of spks in a tx and then verify that single signing agrees" in {
|
||||
forAllAsync(outputGen,
|
||||
ScriptGenerators.scriptPubKey,
|
||||
ChainParamsGenerator.bitcoinNetworkParams) {
|
||||
case ((creditingTxsInfos, destinations), changeSPK, network) =>
|
||||
val fee = SatoshisPerVirtualByte(Satoshis(1000))
|
||||
|
||||
for {
|
||||
builder <- BitcoinTxBuilder(destinations,
|
||||
creditingTxsInfos,
|
||||
fee,
|
||||
changeSPK._1,
|
||||
network)
|
||||
unsignedTx <- builder.unsignedTx
|
||||
signedTx <- builder.sign
|
||||
|
||||
singleSigs: Vector[Vector[ECDigitalSignature]] <- {
|
||||
val singleInfosVec: Vector[Vector[UTXOSpendingInfoSingle]] =
|
||||
creditingTxsInfos.toVector.map(_.toSingles)
|
||||
val sigVecFs = singleInfosVec.map { singleInfos =>
|
||||
val sigFs = singleInfos.map { singleInfo =>
|
||||
val keyAndSigF =
|
||||
BitcoinSignerSingle.signSingle(singleInfo,
|
||||
unsignedTx,
|
||||
isDummySignature = false)
|
||||
|
||||
keyAndSigF.map(_._2)
|
||||
}
|
||||
|
||||
Future.sequence(sigFs)
|
||||
}
|
||||
|
||||
Future.sequence(sigVecFs)
|
||||
}
|
||||
} yield {
|
||||
signedTx.inputs.zipWithIndex.foreach {
|
||||
case (input, inputIndex) =>
|
||||
val infoAndIndexOpt = creditingTxsInfos.zipWithIndex
|
||||
.find(_._1.outPoint == input.previousOutput)
|
||||
assert(infoAndIndexOpt.isDefined)
|
||||
val (info, index) = infoAndIndexOpt.get
|
||||
val sigs = singleSigs(index)
|
||||
|
||||
val expectedSigs = if (info.scriptWitnessOpt.isEmpty) {
|
||||
input.scriptSignature.signatures
|
||||
} else {
|
||||
signedTx
|
||||
.asInstanceOf[WitnessTransaction]
|
||||
.witness
|
||||
.witnesses(inputIndex) match {
|
||||
case p2wpkh: P2WPKHWitnessV0 => Vector(p2wpkh.signature)
|
||||
case p2wsh: P2WSHWitnessV0 => p2wsh.signatures
|
||||
case EmptyScriptWitness => Vector.empty
|
||||
}
|
||||
}
|
||||
|
||||
assert(sigs.length == expectedSigs.length)
|
||||
assert(sigs.forall(expectedSigs.contains))
|
||||
}
|
||||
|
||||
succeed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,11 +42,11 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[IllegalArgumentException] {
|
||||
P2SHNoNestSpendingInfo(
|
||||
P2SHNoNestSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
amount = CurrencyUnits.zero,
|
||||
scriptPubKey = p2sh,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScript = randomRawSPK,
|
||||
conditionalPath = ConditionalPath.NoConditionsLeft
|
||||
|
@ -63,11 +63,11 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[IllegalArgumentException] {
|
||||
P2SHNestedSegwitV0UTXOSpendingInfo(
|
||||
P2SHNestedSegwitV0UTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
amount = CurrencyUnits.zero,
|
||||
scriptPubKey = p2sh,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScript = randomWitnessSPK,
|
||||
scriptWitness = P2WPKHWitnessV0(pubKey),
|
||||
|
@ -85,16 +85,16 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val creditingTx = BaseTransaction(version =
|
||||
TransactionConstants.validLockVersion,
|
||||
inputs = Nil,
|
||||
outputs = Seq(creditingOutput),
|
||||
outputs = Vector(creditingOutput),
|
||||
lockTime = TransactionConstants.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[IllegalArgumentException] {
|
||||
P2SHNestedSegwitV0UTXOSpendingInfo(
|
||||
P2SHNestedSegwitV0UTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
amount = CurrencyUnits.zero,
|
||||
scriptPubKey = p2sh,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScript = P2WPKHWitnessSPKV0(pubKey),
|
||||
scriptWitness = P2WPKHWitnessV0(ECPrivateKey.freshPrivateKey.publicKey),
|
||||
|
@ -112,11 +112,11 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[IllegalArgumentException] {
|
||||
P2SHNestedSegwitV0UTXOSpendingInfo(
|
||||
P2SHNestedSegwitV0UTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
amount = CurrencyUnits.zero,
|
||||
scriptPubKey = p2sh,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScript = randomWitnessSPK,
|
||||
scriptWitness = P2WSHWitnessV0(P2PKScriptPubKey(pubKey)),
|
||||
|
@ -134,11 +134,11 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[IllegalArgumentException] {
|
||||
P2SHNestedSegwitV0UTXOSpendingInfo(
|
||||
P2SHNestedSegwitV0UTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
amount = CurrencyUnits.zero,
|
||||
scriptPubKey = p2sh,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScript = P2WSHWitnessSPKV0(P2PKScriptPubKey(pubKey)),
|
||||
scriptWitness = P2WSHWitnessV0(randomRawSPK),
|
||||
|
@ -157,11 +157,11 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[IllegalArgumentException] {
|
||||
SegwitV0NativeUTXOSpendingInfo(
|
||||
SegwitV0NativeUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
amount = CurrencyUnits.zero,
|
||||
scriptPubKey = p2wpkh,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
scriptWitness = P2WPKHWitnessV0(ECPrivateKey.freshPrivateKey.publicKey),
|
||||
conditionalPath = ConditionalPath.NoConditionsLeft
|
||||
|
@ -179,11 +179,11 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[IllegalArgumentException] {
|
||||
SegwitV0NativeUTXOSpendingInfo(
|
||||
SegwitV0NativeUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
amount = CurrencyUnits.zero,
|
||||
scriptPubKey = p2wsh,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
scriptWitness = P2WSHWitnessV0(randomRawSPK),
|
||||
conditionalPath = ConditionalPath.NoConditionsLeft
|
||||
|
@ -209,10 +209,10 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[IllegalArgumentException] {
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = TransactionOutput(CurrencyUnits.zero, p2sh),
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = None,
|
||||
|
@ -230,15 +230,15 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val creditingTx = BaseTransaction(version =
|
||||
TransactionConstants.validLockVersion,
|
||||
inputs = Nil,
|
||||
outputs = Seq(creditingOutput),
|
||||
outputs = Vector(creditingOutput),
|
||||
lockTime = TransactionConstants.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[IllegalArgumentException] {
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = TransactionOutput(CurrencyUnits.zero, p2sh),
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScriptOpt = Some(P2WPKHWitnessSPKV0(pubKey)),
|
||||
scriptWitnessOpt = None,
|
||||
|
@ -256,15 +256,15 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val creditingTx = BaseTransaction(version =
|
||||
TransactionConstants.validLockVersion,
|
||||
inputs = Nil,
|
||||
outputs = Seq(creditingOutput),
|
||||
outputs = Vector(creditingOutput),
|
||||
lockTime = TransactionConstants.lockTime)
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[UnsupportedOperationException] {
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = TransactionOutput(CurrencyUnits.zero, p2sh),
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScriptOpt = Some(P2WPKHWitnessSPKV0(pubKey)),
|
||||
scriptWitnessOpt = Some(EmptyScriptWitness),
|
||||
|
@ -284,10 +284,10 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[UnsupportedOperationException] {
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = TransactionOutput(CurrencyUnits.zero, p2sh),
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScriptOpt = Some(unassingedWitnessSPK),
|
||||
scriptWitnessOpt = None,
|
||||
|
@ -306,10 +306,10 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[UnsupportedOperationException] {
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = TransactionOutput(CurrencyUnits.zero, p2wpkh),
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = Some(EmptyScriptWitness),
|
||||
|
@ -328,10 +328,10 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[IllegalArgumentException] {
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = TransactionOutput(CurrencyUnits.zero, p2wpkh),
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = None,
|
||||
|
@ -340,7 +340,7 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
}
|
||||
}
|
||||
|
||||
it should "successfully return UnassingedSegwitNativeUTXOSpendingInfo" in {
|
||||
it should "successfully return UnassingedSegwitNativeUTXOSpendingInfoFull" in {
|
||||
val unassingedWitnessSPK = UnassignedWitnessScriptPubKey.fromAsm(
|
||||
P2WPKHWitnessSPKV0(ECPublicKey.freshPublicKey).asm)
|
||||
|
||||
|
@ -353,10 +353,10 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
val spendingInfo =
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = TransactionOutput(CurrencyUnits.zero, unassingedWitnessSPK),
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = None,
|
||||
|
@ -368,7 +368,7 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
outPoint = outPoint,
|
||||
amount = CurrencyUnits.zero,
|
||||
scriptPubKey = unassingedWitnessSPK,
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
hashType = HashType.sigHashAll,
|
||||
scriptWitness = EmptyScriptWitness,
|
||||
conditionalPath = ConditionalPath.NoConditionsLeft
|
||||
|
@ -386,10 +386,10 @@ class UTXOSpendingInfoTest extends BitcoinSAsyncTest {
|
|||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
|
||||
assertThrows[UnsupportedOperationException] {
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = outPoint,
|
||||
output = TransactionOutput(CurrencyUnits.zero, spk),
|
||||
signers = Seq(privKey),
|
||||
signers = Vector(privKey),
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = None,
|
||||
hashType = HashType.sigHashAll,
|
||||
|
|
|
@ -190,7 +190,7 @@ object Bech32Address extends AddressFactory[Bech32Address] {
|
|||
np: NetworkParameters): Try[Bech32Address] =
|
||||
spk match {
|
||||
case witSPK: WitnessScriptPubKey =>
|
||||
Bech32Address.fromScriptPubKey(witSPK, np)
|
||||
Success(Bech32Address(witSPK, np))
|
||||
case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey |
|
||||
_: P2PKWithTimeoutScriptPubKey | _: MultiSignatureScriptPubKey |
|
||||
_: P2SHScriptPubKey | _: LockTimeScriptPubKey |
|
||||
|
|
|
@ -91,6 +91,17 @@ sealed abstract class P2WSHWitnessV0 extends ScriptWitnessV0 {
|
|||
val cmpct = CompactSizeUInt.calc(stack.head)
|
||||
RawScriptPubKey.fromBytes(cmpct.bytes ++ stack.head)
|
||||
}
|
||||
|
||||
lazy val signatures: Vector[ECDigitalSignature] = {
|
||||
// ECDigital signatures are between 71 and 73 bytes long
|
||||
// with a exponential decay on the probability of smaller sigs
|
||||
// [[https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm]]
|
||||
val relevantStack = stack.toVector.tail.filter(bytes =>
|
||||
bytes.length >= 67 && bytes.length <= 73)
|
||||
|
||||
relevantStack.map(ECDigitalSignature.fromBytes)
|
||||
}
|
||||
|
||||
override def toString =
|
||||
s"P2WSHWitnessV0(${stack.map(BitcoinSUtil.encodeHex(_)).toString})"
|
||||
}
|
||||
|
|
|
@ -1078,6 +1078,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
|
|||
val inputOutputsNotZero =
|
||||
!(transaction.inputs.isEmpty || transaction.outputs.isEmpty)
|
||||
val txNotLargerThanBlock = transaction.bytes.size < Consensus.maxBlockSize
|
||||
val txNotHeavierThanBlock = transaction.weight < Consensus.maxBlockWeight
|
||||
val outputsSpendValidAmountsOfMoney = !transaction.outputs.exists(o =>
|
||||
o.value < CurrencyUnits.zero || o.value > Consensus.maxMoney)
|
||||
|
||||
|
@ -1094,7 +1095,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
|
|||
} else {
|
||||
!transaction.inputs.exists(_.previousOutput == EmptyTransactionOutPoint)
|
||||
}
|
||||
inputOutputsNotZero && txNotLargerThanBlock && outputsSpendValidAmountsOfMoney &&
|
||||
inputOutputsNotZero && txNotLargerThanBlock && txNotHeavierThanBlock && outputsSpendValidAmountsOfMoney &&
|
||||
allOutputsValidMoneyRange && noDuplicateInputs && isValidScriptSigForCoinbaseTx
|
||||
}
|
||||
|
||||
|
|
|
@ -20,18 +20,18 @@ import org.bitcoins.core.util.BitcoinSLogger
|
|||
import org.bitcoins.core.wallet.fee.FeeUnit
|
||||
import org.bitcoins.core.wallet.signer._
|
||||
import org.bitcoins.core.wallet.utxo.{
|
||||
BitcoinUTXOSpendingInfo,
|
||||
ConditionalSpendingInfo,
|
||||
BitcoinUTXOSpendingInfoFull,
|
||||
ConditionalSpendingInfoFull,
|
||||
EmptySpendingInfo,
|
||||
LockTimeSpendingInfo,
|
||||
MultiSignatureSpendingInfo,
|
||||
LockTimeSpendingInfoFull,
|
||||
MultiSignatureSpendingInfoFull,
|
||||
P2PKHSpendingInfo,
|
||||
P2PKSpendingInfo,
|
||||
P2PKWithTimeoutSpendingInfo,
|
||||
P2SHSpendingInfo,
|
||||
P2SHSpendingInfoFull,
|
||||
P2WPKHV0SpendingInfo,
|
||||
P2WSHV0SpendingInfo,
|
||||
UTXOSpendingInfo,
|
||||
P2WSHV0SpendingInfoFull,
|
||||
UTXOSpendingInfoFull,
|
||||
UnassignedSegwitNativeUTXOSpendingInfo
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ sealed abstract class TxBuilder {
|
|||
*/
|
||||
def utxoMap: TxBuilder.UTXOMap
|
||||
|
||||
def utxos: Seq[UTXOSpendingInfo] = utxoMap.values.toSeq
|
||||
def utxos: Seq[UTXOSpendingInfoFull] = utxoMap.values.toSeq
|
||||
|
||||
/** This represents the rate, in [[org.bitcoins.core.wallet.fee.FeeUnit FeeUnit]], we
|
||||
* should pay for this transaction */
|
||||
|
@ -140,8 +140,9 @@ sealed abstract class BitcoinTxBuilder extends TxBuilder {
|
|||
override def utxoMap: BitcoinTxBuilder.UTXOMap
|
||||
|
||||
override def sign(implicit ec: ExecutionContext): Future[Transaction] = {
|
||||
val f: (Seq[BitcoinUTXOSpendingInfo], Transaction) => Boolean = { (_, _) =>
|
||||
true
|
||||
val f: (Seq[BitcoinUTXOSpendingInfoFull], Transaction) => Boolean = {
|
||||
(_, _) =>
|
||||
true
|
||||
}
|
||||
sign(f)
|
||||
}
|
||||
|
@ -212,7 +213,8 @@ sealed abstract class BitcoinTxBuilder extends TxBuilder {
|
|||
* @param invariants - invariants that should hold true when we are done signing the transaction
|
||||
* @return the signed transaction, or a [[TxBuilderError]] indicating what went wrong when signing the tx
|
||||
*/
|
||||
def sign(invariants: (Seq[BitcoinUTXOSpendingInfo], Transaction) => Boolean)(
|
||||
def sign(
|
||||
invariants: (Seq[BitcoinUTXOSpendingInfoFull], Transaction) => Boolean)(
|
||||
implicit ec: ExecutionContext): Future[Transaction] = {
|
||||
val utxos = utxoMap.values.toList
|
||||
val signedTxWithFee = unsignedTx.flatMap { utx: Transaction =>
|
||||
|
@ -237,7 +239,7 @@ sealed abstract class BitcoinTxBuilder extends TxBuilder {
|
|||
}
|
||||
|
||||
private def loop(
|
||||
remaining: List[BitcoinUTXOSpendingInfo],
|
||||
remaining: List[BitcoinUTXOSpendingInfoFull],
|
||||
txInProgress: Transaction,
|
||||
dummySignatures: Boolean)(
|
||||
implicit ec: ExecutionContext): Future[Transaction] = remaining match {
|
||||
|
@ -254,7 +256,7 @@ sealed abstract class BitcoinTxBuilder extends TxBuilder {
|
|||
* @return either the transaction with the signed input added, or a [[TxBuilderError]]
|
||||
*/
|
||||
private def signAndAddInput(
|
||||
utxo: BitcoinUTXOSpendingInfo,
|
||||
utxo: BitcoinUTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
dummySignatures: Boolean)(
|
||||
implicit ec: ExecutionContext): Future[Transaction] = {
|
||||
|
@ -266,7 +268,7 @@ sealed abstract class BitcoinTxBuilder extends TxBuilder {
|
|||
utxo match {
|
||||
case _: UnassignedSegwitNativeUTXOSpendingInfo =>
|
||||
Future.fromTry(TxBuilderError.NoSigner)
|
||||
case _: BitcoinUTXOSpendingInfo =>
|
||||
case _: BitcoinUTXOSpendingInfoFull =>
|
||||
BitcoinSigner
|
||||
.sign(utxo, unsignedTx, dummySignatures)
|
||||
.map(_.transaction)
|
||||
|
@ -303,7 +305,8 @@ sealed abstract class BitcoinTxBuilder extends TxBuilder {
|
|||
* locktime set to the same value (or higher) than the output it is spending.
|
||||
* See BIP65 for more info
|
||||
*/
|
||||
private def calcLockTime(utxos: Seq[BitcoinUTXOSpendingInfo]): Try[UInt32] = {
|
||||
private def calcLockTime(
|
||||
utxos: Seq[BitcoinUTXOSpendingInfoFull]): Try[UInt32] = {
|
||||
def computeNextLockTime(
|
||||
currentLockTimeOpt: Option[UInt32],
|
||||
locktime: Long): Try[UInt32] = {
|
||||
|
@ -335,14 +338,14 @@ sealed abstract class BitcoinTxBuilder extends TxBuilder {
|
|||
|
||||
@tailrec
|
||||
def loop(
|
||||
remaining: Seq[BitcoinUTXOSpendingInfo],
|
||||
remaining: Seq[BitcoinUTXOSpendingInfoFull],
|
||||
currentLockTimeOpt: Option[UInt32]): Try[UInt32] =
|
||||
remaining match {
|
||||
case Nil =>
|
||||
Success(currentLockTimeOpt.getOrElse(TransactionConstants.lockTime))
|
||||
case spendingInfo +: newRemaining =>
|
||||
spendingInfo match {
|
||||
case lockTime: LockTimeSpendingInfo =>
|
||||
case lockTime: LockTimeSpendingInfoFull =>
|
||||
lockTime.scriptPubKey match {
|
||||
case _: CSVScriptPubKey =>
|
||||
loop(newRemaining, currentLockTimeOpt)
|
||||
|
@ -370,17 +373,17 @@ sealed abstract class BitcoinTxBuilder extends TxBuilder {
|
|||
case _: Failure[UInt32] => result
|
||||
}
|
||||
}
|
||||
case p2sh: P2SHSpendingInfo =>
|
||||
case p2sh: P2SHSpendingInfoFull =>
|
||||
loop(p2sh.nestedSpendingInfo +: newRemaining, currentLockTimeOpt)
|
||||
case p2wsh: P2WSHV0SpendingInfo =>
|
||||
case p2wsh: P2WSHV0SpendingInfoFull =>
|
||||
loop(p2wsh.nestedSpendingInfo +: newRemaining, currentLockTimeOpt)
|
||||
case conditional: ConditionalSpendingInfo =>
|
||||
case conditional: ConditionalSpendingInfoFull =>
|
||||
loop(conditional.nestedSpendingInfo +: newRemaining,
|
||||
currentLockTimeOpt)
|
||||
case _: P2WPKHV0SpendingInfo |
|
||||
_: UnassignedSegwitNativeUTXOSpendingInfo |
|
||||
_: P2PKSpendingInfo | _: P2PKHSpendingInfo |
|
||||
_: MultiSignatureSpendingInfo | _: EmptySpendingInfo =>
|
||||
_: MultiSignatureSpendingInfoFull | _: EmptySpendingInfo =>
|
||||
// none of these scripts affect the locktime of a tx
|
||||
loop(newRemaining, currentLockTimeOpt)
|
||||
}
|
||||
|
@ -396,17 +399,17 @@ sealed abstract class BitcoinTxBuilder extends TxBuilder {
|
|||
* See BIP68/112 and BIP65 for more info
|
||||
*/
|
||||
private def calcSequenceForInputs(
|
||||
utxos: Seq[UTXOSpendingInfo],
|
||||
utxos: Seq[UTXOSpendingInfoFull],
|
||||
isRBFEnabled: Boolean): Seq[TransactionInput] = {
|
||||
@tailrec
|
||||
def loop(
|
||||
remaining: Seq[UTXOSpendingInfo],
|
||||
remaining: Seq[UTXOSpendingInfoFull],
|
||||
accum: Seq[TransactionInput]): Seq[TransactionInput] =
|
||||
remaining match {
|
||||
case Nil => accum.reverse
|
||||
case spendingInfo +: newRemaining =>
|
||||
spendingInfo match {
|
||||
case lockTime: LockTimeSpendingInfo =>
|
||||
case lockTime: LockTimeSpendingInfoFull =>
|
||||
val sequence = lockTime.scriptPubKey match {
|
||||
case csv: CSVScriptPubKey => solveSequenceForCSV(csv.locktime)
|
||||
case _: CLTVScriptPubKey => UInt32.zero
|
||||
|
@ -431,16 +434,16 @@ sealed abstract class BitcoinTxBuilder extends TxBuilder {
|
|||
UInt32.zero)
|
||||
loop(newRemaining, input +: accum)
|
||||
}
|
||||
case p2sh: P2SHSpendingInfo =>
|
||||
case p2sh: P2SHSpendingInfoFull =>
|
||||
loop(p2sh.nestedSpendingInfo +: newRemaining, accum)
|
||||
case p2wsh: P2WSHV0SpendingInfo =>
|
||||
case p2wsh: P2WSHV0SpendingInfoFull =>
|
||||
loop(p2wsh.nestedSpendingInfo +: newRemaining, accum)
|
||||
case conditional: ConditionalSpendingInfo =>
|
||||
case conditional: ConditionalSpendingInfoFull =>
|
||||
loop(conditional.nestedSpendingInfo +: newRemaining, accum)
|
||||
case _: P2WPKHV0SpendingInfo |
|
||||
_: UnassignedSegwitNativeUTXOSpendingInfo |
|
||||
_: P2PKSpendingInfo | _: P2PKHSpendingInfo |
|
||||
_: MultiSignatureSpendingInfo | _: EmptySpendingInfo =>
|
||||
_: MultiSignatureSpendingInfoFull | _: EmptySpendingInfo =>
|
||||
//none of these script types affect the sequence number of a tx
|
||||
//the sequence only needs to be adjustd if we have replace by fee (RBF) enabled
|
||||
//see BIP125 for more information
|
||||
|
@ -462,7 +465,7 @@ sealed abstract class BitcoinTxBuilder extends TxBuilder {
|
|||
inputIndex: UInt32,
|
||||
p2wpkh: P2WPKHWitnessSPKV0,
|
||||
output: TransactionOutput,
|
||||
utxo: UTXOSpendingInfo,
|
||||
utxo: UTXOSpendingInfoFull,
|
||||
hashType: HashType,
|
||||
dummySignatures: Boolean): Future[Transaction] = {
|
||||
//special rule for p2sh(p2wpkh)
|
||||
|
@ -520,7 +523,7 @@ object TxBuilder {
|
|||
|
||||
/** This contains all the information needed to create a valid
|
||||
* [[org.bitcoins.core.protocol.transaction.TransactionInput TransactionInput]] that spends this utxo */
|
||||
type UTXOMap = Map[TransactionOutPoint, UTXOSpendingInfo]
|
||||
type UTXOMap = Map[TransactionOutPoint, UTXOSpendingInfoFull]
|
||||
private val logger = BitcoinSLogger.logger
|
||||
|
||||
/** Runs various sanity checks on the final version of the signed transaction from TxBuilder */
|
||||
|
@ -639,7 +642,7 @@ object TxBuilder {
|
|||
}
|
||||
|
||||
object BitcoinTxBuilder {
|
||||
type UTXOMap = Map[TransactionOutPoint, BitcoinUTXOSpendingInfo]
|
||||
type UTXOMap = Map[TransactionOutPoint, BitcoinUTXOSpendingInfoFull]
|
||||
|
||||
private case class BitcoinTxBuilderImpl(
|
||||
destinations: Seq[TransactionOutput],
|
||||
|
@ -675,16 +678,16 @@ object BitcoinTxBuilder {
|
|||
|
||||
def apply(
|
||||
destinations: Seq[TransactionOutput],
|
||||
utxos: Seq[BitcoinUTXOSpendingInfo],
|
||||
utxos: Seq[BitcoinUTXOSpendingInfoFull],
|
||||
feeRate: FeeUnit,
|
||||
changeSPK: ScriptPubKey,
|
||||
network: BitcoinNetwork): Future[BitcoinTxBuilder] = {
|
||||
@tailrec
|
||||
def loop(utxos: Seq[UTXOSpendingInfo], accum: UTXOMap): UTXOMap =
|
||||
def loop(utxos: Seq[UTXOSpendingInfoFull], accum: UTXOMap): UTXOMap =
|
||||
utxos match {
|
||||
case Nil => accum
|
||||
case h +: t =>
|
||||
val u = BitcoinUTXOSpendingInfo(
|
||||
val u = BitcoinUTXOSpendingInfoFull(
|
||||
outPoint = h.outPoint,
|
||||
output = h.output,
|
||||
signers = h.signers,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package org.bitcoins.core.wallet.fee
|
||||
|
||||
import org.bitcoins.core.currency.{CurrencyUnit, Satoshis}
|
||||
import org.bitcoins.core.currency.{CurrencyUnit, CurrencyUnits, Satoshis}
|
||||
import org.bitcoins.core.protocol.transaction.Transaction
|
||||
|
||||
/**
|
||||
|
@ -53,3 +53,8 @@ case class SatoshisPerKiloByte(currencyUnit: CurrencyUnit)
|
|||
*/
|
||||
case class SatoshisPerVirtualByte(currencyUnit: CurrencyUnit)
|
||||
extends BitcoinFeeUnit
|
||||
|
||||
object SatoshisPerVirtualByte {
|
||||
val zero: SatoshisPerVirtualByte = SatoshisPerVirtualByte(CurrencyUnits.zero)
|
||||
val one: SatoshisPerVirtualByte = SatoshisPerVirtualByte(Satoshis.one)
|
||||
}
|
||||
|
|
|
@ -13,43 +13,7 @@ import scodec.bits.ByteVector
|
|||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
/** The class used to represent a signing process for a specific [[org.bitcoins.core.protocol.script.ScriptPubKey]] type */
|
||||
sealed abstract class Signer[-SpendingInfo <: UTXOSpendingInfo] {
|
||||
|
||||
/**
|
||||
* The method used to sign a bitcoin unspent transaction output
|
||||
* @param spendingInfo - The information required for signing
|
||||
* @param unsignedTx the external Transaction that needs an input signed
|
||||
* @param isDummySignature - do not sign the tx for real, just use a dummy signature this is useful for fee estimation
|
||||
* @return
|
||||
*/
|
||||
def sign(
|
||||
spendingInfo: SpendingInfo,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
sign(
|
||||
spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingInfoToSatisfy = spendingInfo
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The method used to sign a bitcoin unspent transaction output that is potentially nested
|
||||
* @param spendingInfo - The information required for signing
|
||||
* @param unsignedTx the external Transaction that needs an input signed
|
||||
* @param isDummySignature - do not sign the tx for real, just use a dummy signature this is useful for fee estimation
|
||||
* @param spendingInfoToSatisfy - specifies the UTXOSpendingInfo whose ScriptPubKey needs a ScriptSignature to be generated
|
||||
* @return
|
||||
*/
|
||||
def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: SpendingInfo)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent]
|
||||
sealed abstract class SignerUtils {
|
||||
|
||||
def doSign(
|
||||
sigComponent: TxSigComponent,
|
||||
|
@ -113,11 +77,107 @@ sealed abstract class Signer[-SpendingInfo <: UTXOSpendingInfo] {
|
|||
|
||||
WitnessTxSigComponent(wtx, index, spendingInfo.output, flags)
|
||||
case _: P2SHScriptPubKey =>
|
||||
P2SHTxSigComponent(unsignedTx, index, spendingInfo.output, flags)
|
||||
val emptyInput = unsignedTx.inputs(index.toInt)
|
||||
val newInput = TransactionInput(
|
||||
emptyInput.previousOutput,
|
||||
P2SHScriptSignature(EmptyScriptSignature,
|
||||
spendingInfo.redeemScriptOpt.get),
|
||||
emptyInput.sequence)
|
||||
val updatedTx = unsignedTx.updateInput(index.toInt, newInput)
|
||||
spendingInfo.redeemScriptOpt.get match {
|
||||
case _: WitnessScriptPubKey =>
|
||||
val wtx = WitnessTransaction.toWitnessTx(updatedTx)
|
||||
val updatedWtx =
|
||||
wtx.updateWitness(index.toInt, spendingInfo.scriptWitnessOpt.get)
|
||||
|
||||
WitnessTxSigComponentP2SH(updatedWtx,
|
||||
index,
|
||||
spendingInfo.output,
|
||||
flags)
|
||||
case _: ScriptPubKey =>
|
||||
P2SHTxSigComponent(updatedTx, index, spendingInfo.output, flags)
|
||||
}
|
||||
case _: ScriptPubKey =>
|
||||
BaseTxSigComponent(unsignedTx, index, spendingInfo.output, flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The class used to represent a single key's signing process for a
|
||||
* specific [[org.bitcoins.core.protocol.script.ScriptPubKey]] type */
|
||||
sealed trait SingleSigner[-SpendingInfo <: UTXOSpendingInfoSingle]
|
||||
extends SignerUtils {
|
||||
|
||||
/**
|
||||
* The method used to sign a bitcoin unspent transaction output with a single key
|
||||
* @param spendingInfo The information required for creating the signature
|
||||
* @param unsignedTx the external Transaction that needs an input signed
|
||||
* @param isDummySignature generates a dummy signature if true, useful for fee estimation
|
||||
*/
|
||||
def signSingle(
|
||||
spendingInfo: SpendingInfo,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean)(implicit ec: ExecutionContext): Future[
|
||||
(ECPublicKey, ECDigitalSignature)] = {
|
||||
signSingle(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingInfoToSatisfy = spendingInfo)
|
||||
}
|
||||
|
||||
/**
|
||||
* The method used to sign, with a single key, a bitcoin unspent transaction output that is potentially nested
|
||||
* @param spendingInfo The information required for creating the signature
|
||||
* @param unsignedTx the external Transaction that needs an input signed
|
||||
* @param isDummySignature generates a dummy signature if true, useful for fee estimation
|
||||
* @param spendingInfoToSatisfy - specifies the UTXOSpendingInfoSingle whose ScriptPubKey needs an ECDigitalSignature to be generated
|
||||
*/
|
||||
def signSingle(
|
||||
spendingInfo: UTXOSpendingInfoSingle,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: SpendingInfo)(
|
||||
implicit ec: ExecutionContext): Future[(ECPublicKey, ECDigitalSignature)]
|
||||
}
|
||||
|
||||
/** The class used to represent a signing process for a specific [[org.bitcoins.core.protocol.script.ScriptPubKey]] type */
|
||||
sealed abstract class FullSigner[-SpendingInfo <: UTXOSpendingInfoFull]
|
||||
extends SignerUtils {
|
||||
|
||||
/**
|
||||
* The method used to sign a bitcoin unspent transaction output
|
||||
* @param spendingInfo - The information required for signing
|
||||
* @param unsignedTx the external Transaction that needs an input signed
|
||||
* @param isDummySignature - do not sign the tx for real, just use a dummy signature this is useful for fee estimation
|
||||
* @return
|
||||
*/
|
||||
def sign(
|
||||
spendingInfo: SpendingInfo,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
sign(
|
||||
spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingInfoToSatisfy = spendingInfo
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The method used to sign a bitcoin unspent transaction output that is potentially nested
|
||||
* @param spendingInfo - The information required for signing
|
||||
* @param unsignedTx the external Transaction that needs an input signed
|
||||
* @param isDummySignature - do not sign the tx for real, just use a dummy signature this is useful for fee estimation
|
||||
* @param spendingInfoToSatisfy - specifies the UTXOSpendingInfo whose ScriptPubKey needs a ScriptSignature to be generated
|
||||
* @return
|
||||
*/
|
||||
def sign(
|
||||
spendingInfo: UTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: SpendingInfo)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent]
|
||||
|
||||
/** Creates a BaseTxSigComponent by replacing the unsignedTx input at inputIndex
|
||||
* with a signed one using the given ScriptSignature
|
||||
|
@ -151,14 +211,109 @@ sealed abstract class Signer[-SpendingInfo <: UTXOSpendingInfo] {
|
|||
}
|
||||
}
|
||||
|
||||
sealed trait SingleAndFullSigner[
|
||||
-SpendingInfo <: UTXOSpendingInfoFull with UTXOSpendingInfoSingle]
|
||||
|
||||
/** Represents all signers (for single keys) for the bitcoin protocol,
|
||||
* we could add another network later like litecoin
|
||||
*/
|
||||
sealed trait BitcoinSignerSingle[-SpendingInfo <: BitcoinUTXOSpendingInfoSingle]
|
||||
extends SingleSigner[SpendingInfo] {
|
||||
override def signSingle(
|
||||
spendingInfo: UTXOSpendingInfoSingle,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: SpendingInfo)(
|
||||
implicit ec: ExecutionContext): Future[
|
||||
(ECPublicKey, ECDigitalSignature)] = {
|
||||
val signatureF = doSign(
|
||||
sigComponent = sigComponent(spendingInfo, unsignedTx),
|
||||
sign = spendingInfoToSatisfy.signer.signFunction,
|
||||
hashType = spendingInfoToSatisfy.hashType,
|
||||
isDummySignature = isDummySignature
|
||||
)
|
||||
|
||||
signatureF.map { sig =>
|
||||
(spendingInfoToSatisfy.signer.publicKey, sig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object BitcoinSignerSingle {
|
||||
|
||||
def signSingle(
|
||||
spendingInfo: UTXOSpendingInfoSingle,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean)(implicit ec: ExecutionContext): Future[
|
||||
(ECPublicKey, ECDigitalSignature)] = {
|
||||
signSingle(spendingInfo, unsignedTx, isDummySignature, spendingInfo)
|
||||
}
|
||||
|
||||
def signSingle(
|
||||
spendingInfo: UTXOSpendingInfoSingle,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: UTXOSpendingInfoSingle)(
|
||||
implicit ec: ExecutionContext): Future[
|
||||
(ECPublicKey, ECDigitalSignature)] = {
|
||||
spendingInfoToSatisfy match {
|
||||
case p2pk: P2PKSpendingInfo =>
|
||||
P2PKSigner.signSingle(spendingInfo, unsignedTx, isDummySignature, p2pk)
|
||||
case p2pkh: P2PKHSpendingInfo =>
|
||||
P2PKHSigner.signSingle(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
p2pkh)
|
||||
case p2pkWithTimeout: P2PKWithTimeoutSpendingInfo =>
|
||||
P2PKWithTimeoutSigner.signSingle(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
p2pkWithTimeout)
|
||||
case multiSig: MultiSignatureSpendingInfoSingle =>
|
||||
MultiSigSignerSingle.signSingle(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
multiSig)
|
||||
case p2sh: P2SHSpendingInfoSingle =>
|
||||
P2SHSignerSingle.signSingle(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
p2sh)
|
||||
case lockTime: LockTimeSpendingInfoSingle =>
|
||||
LockTimeSignerSingle.signSingle(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
lockTime)
|
||||
case conditional: ConditionalSpendingInfoSingle =>
|
||||
ConditionalSignerSingle.signSingle(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
conditional)
|
||||
case p2wpkh: P2WPKHV0SpendingInfo =>
|
||||
P2WPKHSigner.signSingle(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
p2wpkh)
|
||||
case p2wsh: P2WSHV0SpendingInfoSingle =>
|
||||
P2WSHSignerSingle.signSingle(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
p2wsh)
|
||||
case _: UnassignedSegwitNativeUTXOSpendingInfo =>
|
||||
throw new UnsupportedOperationException("Unsupported Segwit version")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents all signers for the bitcoin protocol, we could add another network later like litecoin */
|
||||
sealed abstract class BitcoinSigner[-SpendingInfo <: BitcoinUTXOSpendingInfo]
|
||||
extends Signer[SpendingInfo]
|
||||
sealed abstract class BitcoinSignerFull[
|
||||
-SpendingInfo <: BitcoinUTXOSpendingInfoFull]
|
||||
extends FullSigner[SpendingInfo]
|
||||
|
||||
object BitcoinSigner {
|
||||
|
||||
def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
spendingInfo: UTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
|
@ -166,10 +321,10 @@ object BitcoinSigner {
|
|||
}
|
||||
|
||||
def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
spendingInfo: UTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: UTXOSpendingInfo)(
|
||||
spendingInfoToSatisfy: UTXOSpendingInfoFull)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
spendingInfoToSatisfy match {
|
||||
case empty: EmptySpendingInfo =>
|
||||
|
@ -183,26 +338,26 @@ object BitcoinSigner {
|
|||
unsignedTx,
|
||||
isDummySignature,
|
||||
p2pKWithTimeout)
|
||||
case p2sh: P2SHSpendingInfo =>
|
||||
case p2sh: P2SHSpendingInfoFull =>
|
||||
P2SHSigner.sign(spendingInfo, unsignedTx, isDummySignature, p2sh)
|
||||
case multiSig: MultiSignatureSpendingInfo =>
|
||||
case multiSig: MultiSignatureSpendingInfoFull =>
|
||||
MultiSigSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
multiSig)
|
||||
case lockTime: LockTimeSpendingInfo =>
|
||||
case lockTime: LockTimeSpendingInfoFull =>
|
||||
LockTimeSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
lockTime)
|
||||
case conditional: ConditionalSpendingInfo =>
|
||||
case conditional: ConditionalSpendingInfoFull =>
|
||||
ConditionalSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
conditional)
|
||||
case p2wpkh: P2WPKHV0SpendingInfo =>
|
||||
P2WPKHSigner.sign(spendingInfo, unsignedTx, isDummySignature, p2wpkh)
|
||||
case pw2sh: P2WSHV0SpendingInfo =>
|
||||
case pw2sh: P2WSHV0SpendingInfoFull =>
|
||||
P2WSHSigner.sign(spendingInfo, unsignedTx, isDummySignature, pw2sh)
|
||||
case _: UnassignedSegwitNativeUTXOSpendingInfo =>
|
||||
throw new UnsupportedOperationException("Unsupported Segwit version")
|
||||
|
@ -210,11 +365,53 @@ object BitcoinSigner {
|
|||
}
|
||||
}
|
||||
|
||||
/** For signing EmptyScriptPubKeys in tests, should probably not be used in real life. */
|
||||
sealed abstract class EmptySigner extends BitcoinSigner[EmptySpendingInfo] {
|
||||
/** Represents a BitcoinSigner for which only a single signature is required */
|
||||
sealed abstract class SingleKeyBitcoinSigner[
|
||||
-SpendingInfo <: BitcoinUTXOSpendingInfoFull with BitcoinUTXOSpendingInfoSingle]
|
||||
extends BitcoinSignerFull[SpendingInfo]
|
||||
with BitcoinSignerSingle[SpendingInfo]
|
||||
|
||||
/** Represents a SingleKeyBitcoinSigner which signs a RawScriptPubKey */
|
||||
sealed abstract class RawSingleKeyBitcoinSigner[
|
||||
-SpendingInfo <: RawScriptUTXOSpendingInfoFull with RawScriptUTXOSpendingInfoSingle]
|
||||
extends SingleKeyBitcoinSigner[SpendingInfo] {
|
||||
|
||||
def keyAndSigToScriptSig(
|
||||
key: ECPublicKey,
|
||||
sig: ECDigitalSignature,
|
||||
spendingInfo: SpendingInfo): ScriptSignature
|
||||
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
spendingInfo: UTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: SpendingInfo)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
val (_, output, inputIndex, _) =
|
||||
relevantInfo(spendingInfo, unsignedTx)
|
||||
|
||||
val keyAndSigF = signSingle(spendingInfo.toSingle(0),
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingInfoToSatisfy)
|
||||
|
||||
val scriptSigF = keyAndSigF.map {
|
||||
case (key, sig) =>
|
||||
keyAndSigToScriptSig(key, sig, spendingInfoToSatisfy)
|
||||
}
|
||||
|
||||
updateScriptSigInSigComponent(unsignedTx,
|
||||
inputIndex.toInt,
|
||||
output,
|
||||
scriptSigF)
|
||||
}
|
||||
}
|
||||
|
||||
/** For signing EmptyScriptPubKeys in tests, should probably not be used in real life. */
|
||||
sealed abstract class EmptySigner extends BitcoinSignerFull[EmptySpendingInfo] {
|
||||
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: EmptySpendingInfo)(
|
||||
|
@ -235,125 +432,73 @@ sealed abstract class EmptySigner extends BitcoinSigner[EmptySpendingInfo] {
|
|||
object EmptySigner extends EmptySigner
|
||||
|
||||
/** Used to sign a [[org.bitcoins.core.protocol.script.P2PKScriptPubKey]] */
|
||||
sealed abstract class P2PKSigner extends BitcoinSigner[P2PKSpendingInfo] {
|
||||
sealed abstract class P2PKSigner
|
||||
extends RawSingleKeyBitcoinSigner[P2PKSpendingInfo] {
|
||||
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: P2PKSpendingInfo)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
val (_, output, inputIndex, hashType) =
|
||||
relevantInfo(spendingInfo, unsignedTx)
|
||||
|
||||
val signatureF = doSign(sigComponent(spendingInfo, unsignedTx),
|
||||
spendingInfoToSatisfy.signer.signFunction,
|
||||
hashType,
|
||||
isDummySignature)
|
||||
|
||||
val scriptSigF = signatureF.map { signature =>
|
||||
P2PKScriptSignature(signature)
|
||||
}
|
||||
|
||||
updateScriptSigInSigComponent(unsignedTx,
|
||||
inputIndex.toInt,
|
||||
output,
|
||||
scriptSigF)
|
||||
override def keyAndSigToScriptSig(
|
||||
key: ECPublicKey,
|
||||
sig: ECDigitalSignature,
|
||||
spendingInfo: P2PKSpendingInfo): ScriptSignature = {
|
||||
P2PKScriptSignature(sig)
|
||||
}
|
||||
}
|
||||
|
||||
object P2PKSigner extends P2PKSigner
|
||||
|
||||
/** Used to sign a [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey]] */
|
||||
sealed abstract class P2PKHSigner extends BitcoinSigner[P2PKHSpendingInfo] {
|
||||
sealed abstract class P2PKHSigner
|
||||
extends RawSingleKeyBitcoinSigner[P2PKHSpendingInfo] {
|
||||
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: P2PKHSpendingInfo)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
val (signers, output, inputIndex, hashType) =
|
||||
relevantInfo(spendingInfo, unsignedTx)
|
||||
|
||||
val sign = signers.head.signFunction
|
||||
val pubKey = signers.head.publicKey
|
||||
|
||||
val signatureF =
|
||||
doSign(sigComponent(spendingInfo, unsignedTx),
|
||||
sign,
|
||||
hashType,
|
||||
isDummySignature)
|
||||
|
||||
val scriptSigF = signatureF.map { signature =>
|
||||
P2PKHScriptSignature(signature, pubKey)
|
||||
}
|
||||
|
||||
updateScriptSigInSigComponent(unsignedTx,
|
||||
inputIndex.toInt,
|
||||
output,
|
||||
scriptSigF)
|
||||
override def keyAndSigToScriptSig(
|
||||
key: ECPublicKey,
|
||||
sig: ECDigitalSignature,
|
||||
spendingInfo: P2PKHSpendingInfo): ScriptSignature = {
|
||||
P2PKHScriptSignature(sig, key)
|
||||
}
|
||||
}
|
||||
|
||||
object P2PKHSigner extends P2PKHSigner
|
||||
|
||||
sealed abstract class P2PKWithTimeoutSigner
|
||||
extends BitcoinSigner[P2PKWithTimeoutSpendingInfo] {
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: P2PKWithTimeoutSpendingInfo)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
val (signers, output, inputIndex, hashType) =
|
||||
relevantInfo(spendingInfo, unsignedTx)
|
||||
extends RawSingleKeyBitcoinSigner[P2PKWithTimeoutSpendingInfo] {
|
||||
|
||||
val sign = signers.head.signFunction
|
||||
|
||||
val signatureF = doSign(sigComponent(spendingInfo, unsignedTx),
|
||||
sign,
|
||||
hashType,
|
||||
isDummySignature)
|
||||
|
||||
val scriptSigF = signatureF.map { signature =>
|
||||
P2PKWithTimeoutScriptSignature(spendingInfoToSatisfy.isBeforeTimeout,
|
||||
signature)
|
||||
}
|
||||
|
||||
updateScriptSigInSigComponent(unsignedTx,
|
||||
inputIndex.toInt,
|
||||
output,
|
||||
scriptSigF)
|
||||
override def keyAndSigToScriptSig(
|
||||
key: ECPublicKey,
|
||||
sig: ECDigitalSignature,
|
||||
spendingInfo: P2PKWithTimeoutSpendingInfo): ScriptSignature = {
|
||||
P2PKWithTimeoutScriptSignature(spendingInfo.isBeforeTimeout, sig)
|
||||
}
|
||||
}
|
||||
|
||||
object P2PKWithTimeoutSigner extends P2PKWithTimeoutSigner
|
||||
|
||||
sealed abstract class MultiSigSignerSingle
|
||||
extends BitcoinSignerSingle[MultiSignatureSpendingInfoSingle]
|
||||
|
||||
object MultiSigSignerSingle extends MultiSigSignerSingle
|
||||
|
||||
sealed abstract class MultiSigSigner
|
||||
extends BitcoinSigner[MultiSignatureSpendingInfo] {
|
||||
extends BitcoinSignerFull[MultiSignatureSpendingInfoFull] {
|
||||
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
spendingInfo: UTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: MultiSignatureSpendingInfo)(
|
||||
spendingInfoToSatisfy: MultiSignatureSpendingInfoFull)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
val (signersWithPubKeys, output, inputIndex, hashType) =
|
||||
val (_, output, inputIndex, _) =
|
||||
relevantInfo(spendingInfo, unsignedTx)
|
||||
val signers = signersWithPubKeys.map(_.signFunction)
|
||||
|
||||
val requiredSigs = spendingInfoToSatisfy.scriptPubKey.requiredSigs
|
||||
val signatureFs = 0
|
||||
.until(requiredSigs)
|
||||
.map(
|
||||
i =>
|
||||
doSign(sigComponent(spendingInfo, unsignedTx),
|
||||
signers(i),
|
||||
hashType,
|
||||
isDummySignature))
|
||||
val keysAndSigsF = spendingInfoToSatisfy.toSingles.zipWithIndex.map {
|
||||
case (infoSingle, index) =>
|
||||
MultiSigSignerSingle
|
||||
.signSingle(spendingInfo.toSingle(index),
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
infoSingle)
|
||||
}
|
||||
|
||||
val signaturesF = Future.sequence(signatureFs)
|
||||
val signaturesF = Future.sequence(keysAndSigsF).map(_.map(_._2))
|
||||
|
||||
val scriptSigF = signaturesF.map { sigs =>
|
||||
MultiSignatureScriptSignature(sigs)
|
||||
|
@ -368,13 +513,49 @@ sealed abstract class MultiSigSigner
|
|||
|
||||
object MultiSigSigner extends MultiSigSigner
|
||||
|
||||
/** Used to sign a [[org.bitcoins.core.protocol.script.P2SHScriptPubKey]] */
|
||||
sealed abstract class P2SHSigner extends BitcoinSigner[P2SHSpendingInfo] {
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
sealed abstract class P2SHSignerSingle
|
||||
extends BitcoinSignerSingle[P2SHSpendingInfoSingle] {
|
||||
|
||||
override def signSingle(
|
||||
spendingInfo: UTXOSpendingInfoSingle,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: P2SHSpendingInfo)(
|
||||
spendingInfoToSatisfy: P2SHSpendingInfoSingle)(
|
||||
implicit ec: ExecutionContext): Future[
|
||||
(ECPublicKey, ECDigitalSignature)] = {
|
||||
if (spendingInfoToSatisfy != spendingInfo) {
|
||||
Future.fromTry(TxBuilderError.WrongSigner)
|
||||
} else {
|
||||
val inputIndex = super.inputIndex(spendingInfo, unsignedTx)
|
||||
|
||||
val oldInput = unsignedTx.inputs(inputIndex.toInt)
|
||||
val input =
|
||||
TransactionInput(spendingInfo.outPoint,
|
||||
EmptyScriptSignature,
|
||||
oldInput.sequence)
|
||||
|
||||
val updatedTx =
|
||||
unsignedTx.updateInput(inputIndex.toInt, input)
|
||||
|
||||
BitcoinSignerSingle
|
||||
.signSingle(spendingInfo,
|
||||
updatedTx,
|
||||
isDummySignature,
|
||||
spendingInfoToSatisfy.nestedSpendingInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object P2SHSignerSingle extends P2SHSignerSingle
|
||||
|
||||
/** Used to sign a [[org.bitcoins.core.protocol.script.P2SHScriptPubKey]] */
|
||||
sealed abstract class P2SHSigner
|
||||
extends BitcoinSignerFull[P2SHSpendingInfoFull] {
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: P2SHSpendingInfoFull)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
if (spendingInfoToSatisfy != spendingInfo) {
|
||||
Future.fromTry(TxBuilderError.WrongSigner)
|
||||
|
@ -434,10 +615,41 @@ sealed abstract class P2SHSigner extends BitcoinSigner[P2SHSpendingInfo] {
|
|||
|
||||
object P2SHSigner extends P2SHSigner
|
||||
|
||||
sealed abstract class P2WPKHSigner extends BitcoinSigner[P2WPKHV0SpendingInfo] {
|
||||
sealed abstract class P2WPKHSigner
|
||||
extends SingleKeyBitcoinSigner[P2WPKHV0SpendingInfo] {
|
||||
|
||||
override def signSingle(
|
||||
spendingInfo: UTXOSpendingInfoSingle,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: P2WPKHV0SpendingInfo)(
|
||||
implicit ec: ExecutionContext): Future[
|
||||
(ECPublicKey, ECDigitalSignature)] = {
|
||||
for {
|
||||
sigComponent <- sign(spendingInfoToSatisfy,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingInfoToSatisfy)
|
||||
} yield {
|
||||
val sig = sigComponent match {
|
||||
case witnessSigComp: WitnessTxSigComponent =>
|
||||
witnessSigComp.witness match {
|
||||
case p2wpkhWit: P2WPKHWitnessV0 => p2wpkhWit.signature
|
||||
case _: ScriptWitness =>
|
||||
throw new RuntimeException(
|
||||
"P2WPKHSigner.sign must generate a P2WPKHWitness")
|
||||
}
|
||||
case _: TxSigComponent =>
|
||||
throw new RuntimeException(
|
||||
"P2WPKHSigner.sign must return a WitnessTxSigComponent")
|
||||
}
|
||||
|
||||
(spendingInfoToSatisfy.signer.publicKey, sig)
|
||||
}
|
||||
}
|
||||
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
spendingInfo: UTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: P2WPKHV0SpendingInfo)(
|
||||
|
@ -504,13 +716,34 @@ sealed abstract class P2WPKHSigner extends BitcoinSigner[P2WPKHV0SpendingInfo] {
|
|||
}
|
||||
object P2WPKHSigner extends P2WPKHSigner
|
||||
|
||||
sealed abstract class P2WSHSigner extends BitcoinSigner[P2WSHV0SpendingInfo] {
|
||||
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
sealed abstract class P2WSHSignerSingle
|
||||
extends BitcoinSignerSingle[P2WSHV0SpendingInfoSingle] {
|
||||
override def signSingle(
|
||||
spendingInfo: UTXOSpendingInfoSingle,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: P2WSHV0SpendingInfo)(
|
||||
spendingInfoToSatisfy: P2WSHV0SpendingInfoSingle)(
|
||||
implicit ec: ExecutionContext): Future[
|
||||
(ECPublicKey, ECDigitalSignature)] = {
|
||||
val wtx = WitnessTransaction.toWitnessTx(unsignedTx)
|
||||
|
||||
BitcoinSignerSingle.signSingle(spendingInfo,
|
||||
wtx,
|
||||
isDummySignature,
|
||||
spendingInfoToSatisfy.nestedSpendingInfo)
|
||||
}
|
||||
}
|
||||
|
||||
object P2WSHSignerSingle extends P2WSHSignerSingle
|
||||
|
||||
sealed abstract class P2WSHSigner
|
||||
extends BitcoinSignerFull[P2WSHV0SpendingInfoFull] {
|
||||
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: P2WSHV0SpendingInfoFull)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
if (spendingInfoToSatisfy != spendingInfo) {
|
||||
Future.fromTry(TxBuilderError.WrongSigner)
|
||||
|
@ -545,14 +778,33 @@ sealed abstract class P2WSHSigner extends BitcoinSigner[P2WSHV0SpendingInfo] {
|
|||
}
|
||||
object P2WSHSigner extends P2WSHSigner
|
||||
|
||||
sealed abstract class LockTimeSigner
|
||||
extends BitcoinSigner[LockTimeSpendingInfo] {
|
||||
sealed abstract class LockTimeSignerSingle
|
||||
extends BitcoinSignerSingle[LockTimeSpendingInfoSingle] {
|
||||
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
override def signSingle(
|
||||
spendingInfo: UTXOSpendingInfoSingle,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: LockTimeSpendingInfo)(
|
||||
spendingInfoToSatisfy: LockTimeSpendingInfoSingle)(
|
||||
implicit ec: ExecutionContext): Future[
|
||||
(ECPublicKey, ECDigitalSignature)] = {
|
||||
BitcoinSignerSingle.signSingle(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingInfoToSatisfy.nestedSpendingInfo)
|
||||
}
|
||||
}
|
||||
|
||||
object LockTimeSignerSingle extends LockTimeSignerSingle
|
||||
|
||||
sealed abstract class LockTimeSigner
|
||||
extends BitcoinSignerFull[LockTimeSpendingInfoFull] {
|
||||
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: LockTimeSpendingInfoFull)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
BitcoinSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
|
@ -562,17 +814,36 @@ sealed abstract class LockTimeSigner
|
|||
}
|
||||
object LockTimeSigner extends LockTimeSigner
|
||||
|
||||
sealed abstract class ConditionalSignerSingle
|
||||
extends BitcoinSignerSingle[ConditionalSpendingInfoSingle] {
|
||||
|
||||
override def signSingle(
|
||||
spendingInfo: UTXOSpendingInfoSingle,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ConditionalSpendingInfoSingle)(
|
||||
implicit ec: ExecutionContext): Future[
|
||||
(ECPublicKey, ECDigitalSignature)] = {
|
||||
BitcoinSignerSingle.signSingle(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingInfoToSatisfy.nestedSpendingInfo)
|
||||
}
|
||||
}
|
||||
|
||||
object ConditionalSignerSingle extends ConditionalSignerSingle
|
||||
|
||||
/** Delegates to get a ScriptSignature for the case being
|
||||
* spent and then adds an OP_TRUE or OP_FALSE
|
||||
*/
|
||||
sealed abstract class ConditionalSigner
|
||||
extends BitcoinSigner[ConditionalSpendingInfo] {
|
||||
extends BitcoinSignerFull[ConditionalSpendingInfoFull] {
|
||||
|
||||
override def sign(
|
||||
spendingInfo: UTXOSpendingInfo,
|
||||
spendingInfo: UTXOSpendingInfoFull,
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ConditionalSpendingInfo)(
|
||||
spendingInfoToSatisfy: ConditionalSpendingInfoFull)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
val (_, output, inputIndex, _) = relevantInfo(spendingInfo, unsignedTx)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -55,15 +55,15 @@ val destinations = {
|
|||
val destination1 = TransactionOutput(value = destinationAmount,
|
||||
scriptPubKey = destinationSPK)
|
||||
|
||||
List(destination1)
|
||||
Vector(destination1)
|
||||
}
|
||||
|
||||
// we have to fabricate a transaction that contains the
|
||||
// UTXO we are trying to spend. If this were a real blockchain
|
||||
// we would need to reference the UTXO set
|
||||
val creditingTx = BaseTransaction(version = Int32.one,
|
||||
inputs = List.empty,
|
||||
outputs = List(utxo),
|
||||
inputs = Vector.empty,
|
||||
outputs = Vector(utxo),
|
||||
lockTime = UInt32.zero)
|
||||
|
||||
// this is the information we need from the crediting TX
|
||||
|
@ -72,19 +72,19 @@ val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
|||
|
||||
// this contains all the information we need to
|
||||
// validly sign the UTXO above
|
||||
val utxoSpendingInfo = BitcoinUTXOSpendingInfo(outPoint = outPoint,
|
||||
output = utxo,
|
||||
signers = List(privKey),
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = None,
|
||||
hashType =
|
||||
HashType.sigHashAll,
|
||||
conditionalPath =
|
||||
ConditionalPath.NoConditionsLeft)
|
||||
val utxoSpendingInfo = BitcoinUTXOSpendingInfoFull(outPoint = outPoint,
|
||||
output = utxo,
|
||||
signers = Vector(privKey),
|
||||
redeemScriptOpt = None,
|
||||
scriptWitnessOpt = None,
|
||||
hashType =
|
||||
HashType.sigHashAll,
|
||||
conditionalPath =
|
||||
ConditionalPath.NoConditionsLeft)
|
||||
|
||||
// all of the UTXO spending information, since we are only
|
||||
//spending one UTXO, this is just one element
|
||||
val utxos: List[BitcoinUTXOSpendingInfo] = List(utxoSpendingInfo)
|
||||
val utxos: Vector[BitcoinUTXOSpendingInfoFull] = Vector(utxoSpendingInfo)
|
||||
|
||||
// this is how much we are going to pay as a fee to the network
|
||||
// for this example, we are going to pay 1 satoshi per byte
|
||||
|
|
|
@ -47,7 +47,7 @@ object Deps {
|
|||
// obviously has to be changed before this is
|
||||
// merged.
|
||||
|
||||
val sourcecodeV = "0.1.9"
|
||||
val sourcecodeV = "0.2.0"
|
||||
|
||||
// CLI deps
|
||||
val scoptV = "4.0.0-RC2"
|
||||
|
|
|
@ -1 +1 @@
|
|||
sbt.version=1.3.6
|
||||
sbt.version=1.3.7
|
||||
|
|
|
@ -7,9 +7,9 @@ import org.bitcoins.core.protocol.transaction._
|
|||
import org.bitcoins.core.script.crypto.HashType
|
||||
import org.bitcoins.core.script.interpreter.ScriptInterpreter
|
||||
import org.bitcoins.core.wallet.utxo.{
|
||||
BitcoinUTXOSpendingInfo,
|
||||
BitcoinUTXOSpendingInfoFull,
|
||||
ConditionalPath,
|
||||
P2SHNestedSegwitV0UTXOSpendingInfo
|
||||
P2SHNestedSegwitV0UTXOSpendingInfoFull
|
||||
}
|
||||
import org.scalacheck.Gen
|
||||
|
||||
|
@ -28,7 +28,7 @@ sealed abstract class CreditingTxGen {
|
|||
}
|
||||
|
||||
/** Generator for non-script hash based output */
|
||||
def nonSHOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||
def nonSHOutput: Gen[BitcoinUTXOSpendingInfoFull] = {
|
||||
Gen.oneOf(
|
||||
p2pkOutput,
|
||||
p2pkhOutput,
|
||||
|
@ -40,14 +40,14 @@ sealed abstract class CreditingTxGen {
|
|||
)
|
||||
}
|
||||
|
||||
def nonSHOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
||||
def nonSHOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] =
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, nonSHOutput))
|
||||
|
||||
def basicOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||
def basicOutput: Gen[BitcoinUTXOSpendingInfoFull] = {
|
||||
Gen.oneOf(p2pkOutput, p2pkhOutput, multiSigOutput)
|
||||
}
|
||||
|
||||
def nonP2WSHOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||
def nonP2WSHOutput: Gen[BitcoinUTXOSpendingInfoFull] = {
|
||||
//note, cannot put a p2wpkh here
|
||||
Gen.oneOf(p2pkOutput,
|
||||
p2pkhOutput,
|
||||
|
@ -58,7 +58,7 @@ sealed abstract class CreditingTxGen {
|
|||
}
|
||||
|
||||
/** Only for use in constructing P2SH outputs */
|
||||
private def nonP2SHOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||
private def nonP2SHOutput: Gen[BitcoinUTXOSpendingInfoFull] = {
|
||||
Gen
|
||||
.oneOf(
|
||||
p2pkOutput,
|
||||
|
@ -73,14 +73,14 @@ sealed abstract class CreditingTxGen {
|
|||
.suchThat(output =>
|
||||
!ScriptGenerators.redeemScriptTooBig(output.scriptPubKey))
|
||||
.suchThat {
|
||||
case P2SHNestedSegwitV0UTXOSpendingInfo(_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
witness: P2WSHWitnessV0,
|
||||
_) =>
|
||||
case P2SHNestedSegwitV0UTXOSpendingInfoFull(_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
witness: P2WSHWitnessV0,
|
||||
_) =>
|
||||
witness.stack.exists(_.length > ScriptInterpreter.MAX_PUSH_SIZE)
|
||||
case _ => true
|
||||
}
|
||||
|
@ -100,11 +100,11 @@ sealed abstract class CreditingTxGen {
|
|||
|
||||
private val cltvOutputGens = Vector(p2pkWithTimeoutOutput, cltvOutput)
|
||||
|
||||
def output: Gen[BitcoinUTXOSpendingInfo] =
|
||||
def output: Gen[BitcoinUTXOSpendingInfoFull] =
|
||||
Gen.oneOf(nonCltvOutputGens).flatMap(identity)
|
||||
|
||||
/** Either a list of non-CLTV outputs or a single CLTV output, with proportional probability */
|
||||
def outputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = {
|
||||
def outputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] = {
|
||||
val cltvGen = Gen
|
||||
.oneOf(cltvOutput, p2pkWithTimeoutOutput)
|
||||
.map { output =>
|
||||
|
@ -119,23 +119,23 @@ sealed abstract class CreditingTxGen {
|
|||
}
|
||||
|
||||
/** Generates a crediting tx with a p2pk spk at the returned index */
|
||||
def p2pkOutput: Gen[BitcoinUTXOSpendingInfo] =
|
||||
def p2pkOutput: Gen[BitcoinUTXOSpendingInfoFull] =
|
||||
ScriptGenerators.p2pkScriptPubKey.flatMap { p2pk =>
|
||||
build(p2pk._1, Seq(p2pk._2), None, None)
|
||||
}
|
||||
|
||||
/** Generates multiple crediting txs with p2pk spks at the returned index */
|
||||
def p2pkOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = {
|
||||
def p2pkOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] = {
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2pkOutput))
|
||||
}
|
||||
|
||||
def p2pkWithTimeoutOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||
def p2pkWithTimeoutOutput: Gen[BitcoinUTXOSpendingInfoFull] = {
|
||||
ScriptGenerators.p2pkWithTimeoutScriptPubKey.flatMap { p2pkWithTimeout =>
|
||||
build(p2pkWithTimeout._1, Seq(p2pkWithTimeout._2.head), None, None)
|
||||
}
|
||||
}
|
||||
|
||||
def p2pkWithTimeoutOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = {
|
||||
def p2pkWithTimeoutOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] = {
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2pkWithTimeoutOutput))
|
||||
}
|
||||
|
||||
|
@ -143,39 +143,39 @@ sealed abstract class CreditingTxGen {
|
|||
* Generates a transaction that has a p2pkh output at the returned index. This
|
||||
* output can be spent by the returned ECPrivateKey
|
||||
*/
|
||||
def p2pkhOutput: Gen[BitcoinUTXOSpendingInfo] =
|
||||
def p2pkhOutput: Gen[BitcoinUTXOSpendingInfoFull] =
|
||||
ScriptGenerators.p2pkhScriptPubKey.flatMap { p2pkh =>
|
||||
build(p2pkh._1, Seq(p2pkh._2), None, None)
|
||||
}
|
||||
|
||||
/** Generates a sequence of p2pkh outputs at the returned index */
|
||||
def p2pkhOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = {
|
||||
def p2pkhOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] = {
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2pkhOutput))
|
||||
}
|
||||
|
||||
def multiSigOutput: Gen[BitcoinUTXOSpendingInfo] =
|
||||
def multiSigOutput: Gen[BitcoinUTXOSpendingInfoFull] =
|
||||
ScriptGenerators.multiSigScriptPubKey.flatMap { multisig =>
|
||||
build(multisig._1, multisig._2, None, None)
|
||||
}
|
||||
|
||||
def multiSigOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = {
|
||||
def multiSigOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] = {
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, multiSigOutput))
|
||||
}
|
||||
|
||||
def multiSignatureWithTimeoutOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||
def multiSignatureWithTimeoutOutput: Gen[BitcoinUTXOSpendingInfoFull] = {
|
||||
ScriptGenerators.multiSignatureWithTimeoutScriptPubKey.flatMap {
|
||||
case (conditional, keys) =>
|
||||
build(conditional, keys, None, None)
|
||||
}
|
||||
}
|
||||
|
||||
def multiSignatureWithTimeoutOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = {
|
||||
def multiSignatureWithTimeoutOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] = {
|
||||
Gen
|
||||
.choose(min, max)
|
||||
.flatMap(n => Gen.listOfN(n, multiSignatureWithTimeoutOutput))
|
||||
}
|
||||
|
||||
def conditionalOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||
def conditionalOutput: Gen[BitcoinUTXOSpendingInfoFull] = {
|
||||
ScriptGenerators
|
||||
.nonLocktimeConditionalScriptPubKey(ScriptGenerators.defaultMaxDepth)
|
||||
.flatMap {
|
||||
|
@ -184,33 +184,34 @@ sealed abstract class CreditingTxGen {
|
|||
}
|
||||
}
|
||||
|
||||
def conditionalOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = {
|
||||
def conditionalOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] = {
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, conditionalOutput))
|
||||
}
|
||||
|
||||
def p2shOutput: Gen[BitcoinUTXOSpendingInfo] = nonP2SHOutput.flatMap { o =>
|
||||
CryptoGenerators.hashType.map { hashType =>
|
||||
val oldOutput = o.output
|
||||
val redeemScript = o.output.scriptPubKey
|
||||
val p2sh = P2SHScriptPubKey(redeemScript)
|
||||
val updatedOutput = TransactionOutput(oldOutput.value, p2sh)
|
||||
BitcoinUTXOSpendingInfo(
|
||||
TransactionOutPoint(o.outPoint.txId, o.outPoint.vout),
|
||||
updatedOutput,
|
||||
o.signers,
|
||||
Some(redeemScript),
|
||||
o.scriptWitnessOpt,
|
||||
hashType,
|
||||
computeAllTrueConditionalPath(redeemScript, None, o.scriptWitnessOpt)
|
||||
)
|
||||
}
|
||||
def p2shOutput: Gen[BitcoinUTXOSpendingInfoFull] = nonP2SHOutput.flatMap {
|
||||
o =>
|
||||
CryptoGenerators.hashType.map { hashType =>
|
||||
val oldOutput = o.output
|
||||
val redeemScript = o.output.scriptPubKey
|
||||
val p2sh = P2SHScriptPubKey(redeemScript)
|
||||
val updatedOutput = TransactionOutput(oldOutput.value, p2sh)
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
TransactionOutPoint(o.outPoint.txId, o.outPoint.vout),
|
||||
updatedOutput,
|
||||
o.signers,
|
||||
Some(redeemScript),
|
||||
o.scriptWitnessOpt,
|
||||
hashType,
|
||||
computeAllTrueConditionalPath(redeemScript, None, o.scriptWitnessOpt)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def p2shOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = {
|
||||
def p2shOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] = {
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2shOutput))
|
||||
}
|
||||
|
||||
def cltvOutput: Gen[BitcoinUTXOSpendingInfo] =
|
||||
def cltvOutput: Gen[BitcoinUTXOSpendingInfoFull] =
|
||||
TransactionGenerators.spendableCLTVValues.flatMap {
|
||||
case (scriptNum, _) =>
|
||||
basicOutput.flatMap { o =>
|
||||
|
@ -218,7 +219,7 @@ sealed abstract class CreditingTxGen {
|
|||
val oldOutput = o.output
|
||||
val csvSPK = CLTVScriptPubKey(scriptNum, oldOutput.scriptPubKey)
|
||||
val updatedOutput = TransactionOutput(oldOutput.value, csvSPK)
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
TransactionOutPoint(o.outPoint.txId, o.outPoint.vout),
|
||||
updatedOutput,
|
||||
o.signers,
|
||||
|
@ -231,10 +232,10 @@ sealed abstract class CreditingTxGen {
|
|||
}
|
||||
}
|
||||
|
||||
def cltvOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
||||
def cltvOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] =
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, cltvOutput))
|
||||
|
||||
def csvOutput: Gen[BitcoinUTXOSpendingInfo] =
|
||||
def csvOutput: Gen[BitcoinUTXOSpendingInfoFull] =
|
||||
TransactionGenerators.spendableCSVValues.flatMap {
|
||||
case (scriptNum, _) =>
|
||||
basicOutput.flatMap { o =>
|
||||
|
@ -242,7 +243,7 @@ sealed abstract class CreditingTxGen {
|
|||
val oldOutput = o.output
|
||||
val csvSPK = CSVScriptPubKey(scriptNum, oldOutput.scriptPubKey)
|
||||
val updatedOutput = TransactionOutput(oldOutput.value, csvSPK)
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
TransactionOutPoint(o.outPoint.txId, o.outPoint.vout),
|
||||
updatedOutput,
|
||||
o.signers,
|
||||
|
@ -255,24 +256,24 @@ sealed abstract class CreditingTxGen {
|
|||
}
|
||||
}
|
||||
|
||||
def csvOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
||||
def csvOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] =
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, csvOutput))
|
||||
|
||||
def p2wpkhOutput: Gen[BitcoinUTXOSpendingInfo] =
|
||||
def p2wpkhOutput: Gen[BitcoinUTXOSpendingInfoFull] =
|
||||
ScriptGenerators.p2wpkhSPKV0.flatMap { witSPK =>
|
||||
val scriptWit = P2WPKHWitnessV0(witSPK._2.head.publicKey)
|
||||
build(witSPK._1, witSPK._2, None, Some(scriptWit))
|
||||
}
|
||||
|
||||
def p2wpkhOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
||||
def p2wpkhOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] =
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2wpkhOutput))
|
||||
|
||||
def p2wshOutput: Gen[BitcoinUTXOSpendingInfo] =
|
||||
def p2wshOutput: Gen[BitcoinUTXOSpendingInfoFull] =
|
||||
nonP2WSHOutput
|
||||
.suchThat(output =>
|
||||
!ScriptGenerators.redeemScriptTooBig(output.scriptPubKey))
|
||||
.flatMap {
|
||||
case BitcoinUTXOSpendingInfo(_, txOutput, signer, _, _, _, _) =>
|
||||
case BitcoinUTXOSpendingInfoFull(_, txOutput, signer, _, _, _, _) =>
|
||||
val spk = txOutput.scriptPubKey
|
||||
spk match {
|
||||
case rspk: RawScriptPubKey =>
|
||||
|
@ -285,18 +286,18 @@ sealed abstract class CreditingTxGen {
|
|||
}
|
||||
}
|
||||
|
||||
def p2wshOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
||||
def p2wshOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] =
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2wshOutput))
|
||||
|
||||
/** A nested output is a p2sh/p2wsh wrapped output */
|
||||
def nestedOutput: Gen[BitcoinUTXOSpendingInfo] = {
|
||||
def nestedOutput: Gen[BitcoinUTXOSpendingInfoFull] = {
|
||||
Gen.oneOf(p2wshOutput, p2shOutput)
|
||||
}
|
||||
|
||||
def nestedOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
||||
def nestedOutputs: Gen[Seq[BitcoinUTXOSpendingInfoFull]] =
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, nestedOutput))
|
||||
|
||||
def random: Gen[BitcoinUTXOSpendingInfo] = nonEmptyOutputs.flatMap {
|
||||
def random: Gen[BitcoinUTXOSpendingInfoFull] = nonEmptyOutputs.flatMap {
|
||||
outputs =>
|
||||
Gen.choose(0, outputs.size - 1).flatMap { outputIndex: Int =>
|
||||
ScriptGenerators.scriptPubKey.flatMap {
|
||||
|
@ -304,12 +305,12 @@ sealed abstract class CreditingTxGen {
|
|||
WitnessGenerators.scriptWitness.flatMap { wit: ScriptWitness =>
|
||||
CryptoGenerators.hashType.map { hashType: HashType =>
|
||||
val tc = TransactionConstants
|
||||
val signers: Seq[Sign] = keys
|
||||
val signers: Vector[Sign] = keys.toVector
|
||||
val creditingTx = BaseTransaction(tc.validLockVersion,
|
||||
Nil,
|
||||
outputs,
|
||||
tc.lockTime)
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
TransactionOutPoint(creditingTx.txId,
|
||||
UInt32.apply(outputIndex)),
|
||||
TransactionOutput(
|
||||
|
@ -327,7 +328,7 @@ sealed abstract class CreditingTxGen {
|
|||
}
|
||||
}
|
||||
|
||||
def randoms: Gen[Seq[BitcoinUTXOSpendingInfo]] =
|
||||
def randoms: Gen[Seq[BitcoinUTXOSpendingInfoFull]] =
|
||||
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, random))
|
||||
|
||||
private def computeAllTrueConditionalPath(
|
||||
|
@ -371,7 +372,7 @@ sealed abstract class CreditingTxGen {
|
|||
spk: ScriptPubKey,
|
||||
signers: Seq[Sign],
|
||||
redeemScript: Option[ScriptPubKey],
|
||||
scriptWitness: Option[ScriptWitness]): Gen[BitcoinUTXOSpendingInfo] =
|
||||
scriptWitness: Option[ScriptWitness]): Gen[BitcoinUTXOSpendingInfoFull] =
|
||||
nonEmptyOutputs.flatMap { outputs =>
|
||||
CryptoGenerators.hashType.flatMap { hashType =>
|
||||
Gen.choose(0, outputs.size - 1).map { idx =>
|
||||
|
@ -379,10 +380,10 @@ sealed abstract class CreditingTxGen {
|
|||
val updated = outputs.updated(idx, TransactionOutput(old.value, spk))
|
||||
val tc = TransactionConstants
|
||||
val btx = BaseTransaction(tc.version, Nil, updated, tc.lockTime)
|
||||
BitcoinUTXOSpendingInfo(
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
TransactionOutPoint(btx.txId, UInt32.apply(idx)),
|
||||
TransactionOutput(old.value, spk),
|
||||
signers,
|
||||
signers.toVector,
|
||||
redeemScript,
|
||||
scriptWitness,
|
||||
hashType,
|
||||
|
|
|
@ -20,7 +20,7 @@ import org.bitcoins.core.wallet.signer.{
|
|||
P2PKWithTimeoutSigner
|
||||
}
|
||||
import org.bitcoins.core.wallet.utxo.{
|
||||
MultiSignatureSpendingInfo,
|
||||
MultiSignatureSpendingInfoFull,
|
||||
P2PKHSpendingInfo,
|
||||
P2PKSpendingInfo,
|
||||
P2PKWithTimeoutSpendingInfo
|
||||
|
@ -660,7 +660,7 @@ sealed abstract class ScriptGenerators extends BitcoinSLogger {
|
|||
creditingTx,
|
||||
scriptSig,
|
||||
outputIndex)
|
||||
spendingInfo = MultiSignatureSpendingInfo(
|
||||
spendingInfo = MultiSignatureSpendingInfoFull(
|
||||
TransactionOutPoint(creditingTx.txIdBE, inputIndex),
|
||||
creditingTx.outputs(outputIndex.toInt).value,
|
||||
multiSigScriptPubKey,
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
package org.bitcoins.core.util
|
||||
package org.bitcoins.testkit.util
|
||||
|
||||
import org.bitcoins.core.crypto.BaseTxSigComponent
|
||||
import org.bitcoins.core.currency.CurrencyUnits
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.policy.Policy
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.script.{
|
||||
EmptyScriptPubKey,
|
||||
P2SHScriptSignature,
|
||||
ScriptPubKey,
|
||||
ScriptSignature
|
||||
}
|
||||
import org.bitcoins.core.protocol.transaction.{
|
||||
Transaction,
|
||||
TransactionInput,
|
||||
TransactionOutput
|
||||
}
|
||||
import org.bitcoins.core.script.PreExecutionScriptProgram
|
||||
import org.bitcoins.core.script.bitwise.{OP_EQUAL, OP_EQUALVERIFY}
|
||||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.crypto.{
|
||||
|
@ -19,7 +25,6 @@ import org.bitcoins.core.script.crypto.{
|
|||
OP_HASH160
|
||||
}
|
||||
import org.bitcoins.core.script.stack.OP_DUP
|
||||
import org.bitcoins.core.script.PreExecutionScriptProgram
|
||||
import org.bitcoins.core.serializers.script.RawScriptPubKeyParser
|
||||
import org.bitcoins.core.serializers.transaction.RawTransactionInputParser
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
package org.bitcoins.core.util
|
||||
package org.bitcoins.testkit.util
|
||||
|
||||
import org.bitcoins.core.crypto.{ECPrivateKey, ECPublicKey}
|
||||
import org.bitcoins.core.currency.{CurrencyUnit, CurrencyUnits}
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.number.{Int32, UInt32}
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.transaction._
|
||||
import org.bitcoins.core.util.BitcoinSLogger
|
||||
|
||||
/**
|
||||
* Created by chris on 2/12/16.
|
||||
|
@ -239,6 +240,14 @@ trait TransactionTestUtil extends BitcoinSLogger {
|
|||
Seq(EmptyTransactionInput),
|
||||
Nil,
|
||||
EmptyTransaction.lockTime)
|
||||
|
||||
/** Builds a dummy transaction that sends money to the given output */
|
||||
def buildTransactionTo(output: TransactionOutput): Transaction = {
|
||||
BaseTransaction(version = Int32.one,
|
||||
inputs = Vector(EmptyTransactionInput),
|
||||
outputs = Vector(output),
|
||||
lockTime = TransactionConstants.lockTime)
|
||||
}
|
||||
}
|
||||
|
||||
object TransactionTestUtil extends TransactionTestUtil
|
|
@ -8,6 +8,7 @@ import org.bitcoins.core.crypto.{DoubleSha256Digest, DoubleSha256DigestBE}
|
|||
import org.bitcoins.core.currency._
|
||||
import org.bitcoins.core.gcs.BlockFilter
|
||||
import org.bitcoins.core.protocol.BlockStamp
|
||||
import org.bitcoins.core.protocol.transaction.TransactionOutput
|
||||
import org.bitcoins.core.util.FutureUtil
|
||||
import org.bitcoins.db.AppConfig
|
||||
import org.bitcoins.keymanager.KeyManagerTestUtil
|
||||
|
@ -17,11 +18,11 @@ import org.bitcoins.server.BitcoinSAppConfig
|
|||
import org.bitcoins.server.BitcoinSAppConfig._
|
||||
import org.bitcoins.testkit.BitcoinSTestAppConfig
|
||||
import org.bitcoins.testkit.fixtures.BitcoinSFixture
|
||||
import org.bitcoins.testkit.util.FileUtil
|
||||
import org.bitcoins.wallet.api.UnlockedWalletApi
|
||||
import org.bitcoins.testkit.util.{FileUtil, TransactionTestUtil}
|
||||
import org.bitcoins.wallet.api.{LockedWalletApi, UnlockedWalletApi}
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
import org.bitcoins.wallet.db.WalletDbManagement
|
||||
import org.bitcoins.wallet.{Wallet, WalletLogger}
|
||||
import org.bitcoins.wallet.{LockedWallet, Wallet, WalletLogger}
|
||||
import org.scalatest._
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
@ -127,6 +128,18 @@ trait BitcoinSWalletTest extends BitcoinSFixture with WalletLogger {
|
|||
)
|
||||
}
|
||||
|
||||
/** Creates a wallet that is funded with some bitcoin, this wallet is NOT
|
||||
* peered with a bitcoind so the funds in the wallet are not tied to an
|
||||
* underlying blockchain */
|
||||
def withFundedWallet(test: OneArgAsyncTest): FutureOutcome = {
|
||||
makeDependentFixture(
|
||||
build = () => createFundedWallet(nodeApi, chainQueryApi),
|
||||
destroy = { funded: FundedWallet =>
|
||||
destroyWallet(funded.wallet)
|
||||
}
|
||||
)(test)
|
||||
}
|
||||
|
||||
/** Fixture for an initialized wallet which produce legacy addresses */
|
||||
def withLegacyWallet(test: OneArgAsyncTest): FutureOutcome = {
|
||||
val confOverride =
|
||||
|
@ -293,6 +306,22 @@ object BitcoinSWalletTest extends WalletLogger {
|
|||
chainQueryApi = chainQueryApi)(config, ec)() // get the standard config
|
||||
}
|
||||
|
||||
/** This wallet should have a total of 6 bitcoin in it
|
||||
* spread across 3 utxos that have values 1, 2, 3 bitcoins */
|
||||
case class FundedWallet(wallet: LockedWallet)
|
||||
|
||||
/** This creates a wallet that is funded that is not paired to a bitcoind instance. */
|
||||
def createFundedWallet(nodeApi: NodeApi, chainQueryApi: ChainQueryApi)(
|
||||
implicit config: BitcoinSAppConfig,
|
||||
system: ActorSystem): Future[FundedWallet] = {
|
||||
|
||||
import system.dispatcher
|
||||
for {
|
||||
wallet <- createDefaultWallet(nodeApi, chainQueryApi)
|
||||
funded <- fundWallet(wallet)
|
||||
} yield funded
|
||||
}
|
||||
|
||||
/** Pairs the given wallet with a bitcoind instance that has money in the bitcoind wallet */
|
||||
def createWalletWithBitcoind(
|
||||
wallet: UnlockedWalletApi
|
||||
|
@ -347,6 +376,48 @@ object BitcoinSWalletTest extends WalletLogger {
|
|||
} yield funded
|
||||
}
|
||||
|
||||
/** Funds a bitcoin-s wallet with 3 utxos with 1, 2 and 3 bitcoin in the utxos */
|
||||
def fundWallet(wallet: UnlockedWalletApi)(
|
||||
implicit ec: ExecutionContext): Future[FundedWallet] = {
|
||||
//get three addresses
|
||||
val addressesF = Future.sequence(Vector.fill(3) {
|
||||
//this Thread.sleep is needed because of
|
||||
//https://github.com/bitcoin-s/bitcoin-s/issues/1009
|
||||
//once that is resolved we should be able to remove this
|
||||
Thread.sleep(500)
|
||||
wallet.getNewAddress()
|
||||
})
|
||||
|
||||
//construct three txs that send money to these addresses
|
||||
//these are "fictional" transactions in the sense that the
|
||||
//outpoints do not exist on a blockchain anywhere
|
||||
val amounts = Vector(1.bitcoin, 2.bitcoin, 3.bitcoin)
|
||||
val expectedAmt = amounts.fold(CurrencyUnits.zero)(_ + _)
|
||||
val txsF = for {
|
||||
addresses <- addressesF
|
||||
} yield {
|
||||
addresses.zip(amounts).map {
|
||||
case (addr, amt) =>
|
||||
val output =
|
||||
TransactionOutput(value = amt, scriptPubKey = addr.scriptPubKey)
|
||||
TransactionTestUtil.buildTransactionTo(output)
|
||||
}
|
||||
}
|
||||
|
||||
val fundedWalletF =
|
||||
txsF.flatMap(txs =>
|
||||
wallet.processTransactions(transactions = txs, blockHash = None))
|
||||
|
||||
//sanity check to make sure we have money
|
||||
for {
|
||||
fundedWallet <- fundedWalletF
|
||||
balance <- fundedWallet.getBalance()
|
||||
_ = require(
|
||||
balance == 6.bitcoin,
|
||||
s"Funding wallet fixture failed ot fund the wallet, got balance=${balance} expected=${expectedAmt}")
|
||||
} yield FundedWallet(fundedWallet.asInstanceOf[LockedWallet])
|
||||
}
|
||||
|
||||
/** Funds the given wallet with money from the given bitcoind */
|
||||
def fundWalletWithBitcoind(pair: WalletWithBitcoind)(
|
||||
implicit ec: ExecutionContext): Future[WalletWithBitcoind] = {
|
||||
|
@ -378,10 +449,14 @@ object BitcoinSWalletTest extends WalletLogger {
|
|||
|
||||
def destroyWallet(wallet: UnlockedWalletApi)(
|
||||
implicit ec: ExecutionContext): Future[Unit] = {
|
||||
destroyWallet(wallet.lock())
|
||||
}
|
||||
|
||||
def destroyWallet(wallet: LockedWalletApi)(
|
||||
implicit ec: ExecutionContext): Future[Unit] = {
|
||||
val destroyWalletF = WalletDbManagement
|
||||
.dropAll()(config = wallet.walletConfig, ec = ec)
|
||||
.map(_ => ())
|
||||
|
||||
destroyWalletF
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
package org.bitcoins.wallet
|
||||
|
||||
import org.bitcoins.core.currency.Bitcoins
|
||||
import org.bitcoins.core.protocol.transaction.TransactionOutput
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.testkit.util.TestUtil
|
||||
import org.bitcoins.testkit.wallet.BitcoinSWalletTest
|
||||
import org.bitcoins.testkit.wallet.BitcoinSWalletTest.FundedWallet
|
||||
import org.scalatest.FutureOutcome
|
||||
|
||||
class FundTransactionHandlingTest extends BitcoinSWalletTest {
|
||||
|
||||
override type FixtureParam = FundedWallet
|
||||
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
|
||||
withFundedWallet(test)
|
||||
}
|
||||
|
||||
val destination = TransactionOutput(Bitcoins(0.5),TestUtil.p2pkhScriptPubKey)
|
||||
val feeRate = SatoshisPerVirtualByte.one
|
||||
|
||||
it must "fund a simple raw transaction that requires one utxo" in { fundedWallet : FundedWallet =>
|
||||
|
||||
val wallet = fundedWallet.wallet
|
||||
val fundedTxF = wallet.fundRawTransaction(
|
||||
destinations = Vector(destination),
|
||||
feeRate = feeRate)
|
||||
for {
|
||||
fundedTx <- fundedTxF
|
||||
} yield {
|
||||
assert(fundedTx.inputs.length == 1, s"We should only need one input to fund this tx")
|
||||
assert(fundedTx.outputs.contains(destination))
|
||||
assert(fundedTx.outputs.length == 2, s"We must have a single destination output and a change output")
|
||||
}
|
||||
}
|
||||
|
||||
it must "fund a transaction that requires all utxos in our wallet" in { fundedWallet: FundedWallet =>
|
||||
val amt = Bitcoins(5.5)
|
||||
val newDestination = destination.copy(value = amt)
|
||||
val wallet = fundedWallet.wallet
|
||||
val fundedTxF = wallet.fundRawTransaction(
|
||||
destinations = Vector(newDestination),
|
||||
feeRate = feeRate)
|
||||
for {
|
||||
fundedTx <- fundedTxF
|
||||
} yield {
|
||||
assert(fundedTx.inputs.length == 3, s"We should need 3 inputs to fund this tx")
|
||||
assert(fundedTx.outputs.contains(newDestination))
|
||||
assert(fundedTx.outputs.length == 2, s"We must have a 2 destination output and a change output")
|
||||
}
|
||||
}
|
||||
|
||||
it must "not care about the number of destinations" in { fundedWallet: FundedWallet =>
|
||||
val destinations = Vector.fill(5)(destination)
|
||||
|
||||
val wallet = fundedWallet.wallet
|
||||
val fundedTxF = wallet.fundRawTransaction(
|
||||
destinations = destinations,
|
||||
feeRate = feeRate)
|
||||
for {
|
||||
fundedTx <- fundedTxF
|
||||
} yield {
|
||||
assert(fundedTx.inputs.length == 1, s"We should only need one input to fund this tx")
|
||||
|
||||
destinations.foreach(d =>
|
||||
assert(fundedTx.outputs.contains(d))
|
||||
)
|
||||
assert(fundedTx.outputs.length == 6, s"We must have a 6 destination output and a change output")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
it must "fail to fund a raw transaction if we don't have enough money in our wallet" in { fundedWallet: FundedWallet =>
|
||||
//our wallet should only have 6 bitcoin in it
|
||||
val tooMuchMoney = Bitcoins(10)
|
||||
val tooBigOutput = destination.copy(value = tooMuchMoney)
|
||||
val wallet = fundedWallet.wallet
|
||||
val fundedTxF = wallet.fundRawTransaction(
|
||||
destinations = Vector(tooBigOutput),
|
||||
feeRate = feeRate)
|
||||
|
||||
recoverToSucceededIf[RuntimeException] {
|
||||
fundedTxF
|
||||
}
|
||||
}
|
||||
|
||||
it must "fail to fund a raw transaction if we have the _exact_ amount of money in the wallet because of the fee" in {fundedWallet: FundedWallet =>
|
||||
//our wallet should only have 6 bitcoin in it
|
||||
val tooMuchMoney = Bitcoins(6)
|
||||
val tooBigOutput = destination.copy(value = tooMuchMoney)
|
||||
val wallet = fundedWallet.wallet
|
||||
|
||||
//6 bitcoin destination + 1 sat/vbyte fee means we should
|
||||
//not have enough money for this
|
||||
val fundedTxF = wallet.fundRawTransaction(
|
||||
destinations = Vector(tooBigOutput),
|
||||
feeRate = feeRate)
|
||||
|
||||
recoverToSucceededIf[RuntimeException] {
|
||||
fundedTxF
|
||||
}
|
||||
}
|
||||
|
||||
it must "fund from a specific account" ignore { _: FundedWallet =>
|
||||
assert(false)
|
||||
|
||||
}
|
||||
}
|
|
@ -173,5 +173,4 @@ class WalletUnitTest extends BitcoinSWalletTest {
|
|||
blockHeight = 1)) == matched)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ abstract class LockedWallet
|
|||
with UtxoHandling
|
||||
with AddressHandling
|
||||
with AccountHandling
|
||||
with FundTransactionHandling
|
||||
with TransactionProcessing
|
||||
with RescanHandling {
|
||||
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
package org.bitcoins.wallet
|
||||
|
||||
import org.bitcoins.core.api.{ChainQueryApi, NodeApi}
|
||||
import org.bitcoins.core.config.BitcoinNetwork
|
||||
import org.bitcoins.core.crypto._
|
||||
import org.bitcoins.core.currency._
|
||||
import org.bitcoins.core.hd._
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.transaction._
|
||||
import org.bitcoins.core.wallet.builder.BitcoinTxBuilder
|
||||
import org.bitcoins.core.wallet.fee.FeeUnit
|
||||
import org.bitcoins.core.wallet.utxo.BitcoinUTXOSpendingInfo
|
||||
import org.bitcoins.keymanager.KeyManagerParams
|
||||
import org.bitcoins.keymanager.bip39.BIP39KeyManager
|
||||
import org.bitcoins.keymanager.util.HDUtil
|
||||
|
@ -39,50 +36,15 @@ sealed abstract class Wallet extends LockedWallet with UnlockedWalletApi {
|
|||
feeRate: FeeUnit,
|
||||
fromAccount: AccountDb): Future[Transaction] = {
|
||||
logger.info(s"Sending $amount to $address at feerate $feeRate")
|
||||
val destination = TransactionOutput(amount, address.scriptPubKey)
|
||||
for {
|
||||
change <- getNewChangeAddress(fromAccount)
|
||||
walletUtxos <- listUtxos()
|
||||
txBuilder <- {
|
||||
val destinations = Vector(
|
||||
TransactionOutput(amount, address.scriptPubKey))
|
||||
|
||||
// currencly just grabs the biggest utxos until it finds enough
|
||||
val utxos: Vector[BitcoinUTXOSpendingInfo] =
|
||||
CoinSelector
|
||||
.accumulateLargest(walletUtxos, destinations, feeRate)
|
||||
.map(
|
||||
_.toUTXOSpendingInfo(account = fromAccount,
|
||||
keyManager = keyManager,
|
||||
network = networkParameters))
|
||||
|
||||
logger.info({
|
||||
val utxosStr = utxos
|
||||
.map { utxo =>
|
||||
import utxo.outPoint
|
||||
s"${outPoint.txId.hex}:${outPoint.vout.toInt}"
|
||||
}
|
||||
.mkString(", ")
|
||||
s"Spending UTXOs: $utxosStr"
|
||||
})
|
||||
|
||||
utxos.zipWithIndex.foreach {
|
||||
case (utxo, index) =>
|
||||
logger.info(s"UTXO $index details: ${utxo.output}")
|
||||
}
|
||||
|
||||
networkParameters match {
|
||||
case b: BitcoinNetwork =>
|
||||
BitcoinTxBuilder(destinations = destinations,
|
||||
utxos = utxos,
|
||||
feeRate = feeRate,
|
||||
changeSPK = change.scriptPubKey,
|
||||
network = b)
|
||||
}
|
||||
|
||||
}
|
||||
txBuilder <- fundRawTransactionInternal(
|
||||
destinations = Vector(destination),
|
||||
feeRate = feeRate,
|
||||
fromAccount = fromAccount,
|
||||
keyManagerOpt = Some(keyManager))
|
||||
signed <- txBuilder.sign
|
||||
ourOuts <- findOurOuts(signed)
|
||||
// TODO internal
|
||||
_ <- processOurTransaction(signed, blockHashOpt = None)
|
||||
} yield {
|
||||
logger.debug(
|
||||
|
|
|
@ -10,8 +10,9 @@ import org.bitcoins.core.gcs.{GolombFilter, SimpleFilterMatcher}
|
|||
import org.bitcoins.core.hd.{AddressType, HDPurpose}
|
||||
import org.bitcoins.core.protocol.blockchain.{Block, ChainParams}
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.bitcoins.core.protocol.transaction.Transaction
|
||||
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutput}
|
||||
import org.bitcoins.core.protocol.{BitcoinAddress, BlockStamp}
|
||||
import org.bitcoins.core.util.FutureUtil
|
||||
import org.bitcoins.core.wallet.fee.FeeUnit
|
||||
import org.bitcoins.keymanager._
|
||||
import org.bitcoins.keymanager.bip39.{BIP39KeyManager, BIP39LockedKeyManager}
|
||||
|
@ -22,6 +23,7 @@ import org.bitcoins.wallet.models.{AccountDb, AddressDb, SpendingInfoDb}
|
|||
|
||||
import scala.annotation.tailrec
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
/**
|
||||
* API for the wallet project.
|
||||
|
@ -63,6 +65,15 @@ trait LockedWalletApi extends WalletApi {
|
|||
transaction: Transaction,
|
||||
blockHash: Option[DoubleSha256DigestBE]): Future[LockedWalletApi]
|
||||
|
||||
def processTransactions(
|
||||
transactions: Vector[Transaction],
|
||||
blockHash: Option[DoubleSha256DigestBE]): Future[LockedWalletApi] = {
|
||||
transactions.foldLeft(Future.successful(this)) {
|
||||
case (wallet, tx) =>
|
||||
wallet.flatMap(_.processTransaction(tx, blockHash))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the give block, updating our DB state if it's relevant to us.
|
||||
* @param block The block we're processing
|
||||
|
@ -155,6 +166,19 @@ trait LockedWalletApi extends WalletApi {
|
|||
*/
|
||||
def getAddressInfo(address: BitcoinAddress): Future[Option[AddressInfo]]
|
||||
|
||||
def getAddressInfo(
|
||||
spendingInfoDb: SpendingInfoDb): Future[Option[AddressInfo]] = {
|
||||
val addressT = BitcoinAddress.fromScriptPubKey(
|
||||
spk = spendingInfoDb.output.scriptPubKey,
|
||||
np = networkParameters)
|
||||
addressT match {
|
||||
case Success(addr) =>
|
||||
getAddressInfo(addr)
|
||||
case Failure(_) =>
|
||||
FutureUtil.none
|
||||
}
|
||||
}
|
||||
|
||||
/** Generates a new change address */
|
||||
protected[wallet] def getNewChangeAddress(
|
||||
account: AccountDb): Future[BitcoinAddress]
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
package org.bitcoins.wallet.internal
|
||||
|
||||
import org.bitcoins.core.config.BitcoinNetwork
|
||||
import org.bitcoins.core.crypto.Sign
|
||||
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutput}
|
||||
import org.bitcoins.core.wallet.builder.BitcoinTxBuilder
|
||||
import org.bitcoins.core.wallet.fee.FeeUnit
|
||||
import org.bitcoins.keymanager.bip39.BIP39KeyManager
|
||||
import org.bitcoins.wallet.WalletLogger
|
||||
import org.bitcoins.wallet.api.{AddressInfo, CoinSelector, LockedWalletApi}
|
||||
import org.bitcoins.wallet.models.{AccountDb, SpendingInfoDb}
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
trait FundTransactionHandling extends WalletLogger { self: LockedWalletApi =>
|
||||
|
||||
def fundRawTransaction(
|
||||
destinations: Vector[TransactionOutput],
|
||||
feeRate: FeeUnit): Future[Transaction] = {
|
||||
for {
|
||||
account <- getDefaultAccount()
|
||||
funded <- fundRawTransaction(destinations = destinations,
|
||||
feeRate = feeRate,
|
||||
fromAccount = account)
|
||||
} yield funded
|
||||
}
|
||||
|
||||
def fundRawTransaction(
|
||||
destinations: Vector[TransactionOutput],
|
||||
feeRate: FeeUnit,
|
||||
fromAccount: AccountDb): Future[Transaction] = {
|
||||
val txBuilderF =
|
||||
fundRawTransactionInternal(destinations = destinations,
|
||||
feeRate = feeRate,
|
||||
fromAccount = fromAccount,
|
||||
keyManagerOpt = None)
|
||||
txBuilderF.flatMap(_.unsignedTx)
|
||||
}
|
||||
|
||||
/** This returns a [[BitcoinTxBuilder]] that can be used to generate a unsigned transaction with [[BitcoinTxBuilder.unsignedTx unsignedTx]]
|
||||
* which can be used with signing, or you can just directly call [[BitcoinTxBuilder.sign sign]] to sign the transaction with this instance
|
||||
* of [[BitcoinTxBuilder]]
|
||||
*
|
||||
* If you pass in a [[org.bitcoins.keymanager.KeyManager]], the [[org.bitcoins.core.wallet.utxo.UTXOSpendingInfo.signers signers]]
|
||||
* will be populated with valid signers that can be used to produce valid [[org.bitcoins.core.crypto.ECDigitalSignature signatures]]
|
||||
*
|
||||
* If you do not pass in a key manager, the transaction built by [[BitcoinTxBuilder txbuilder]] will contain [[org.bitcoins.core.protocol.script.EmptyScriptSignature EmptyScriptSignature]]
|
||||
*
|
||||
* Currently utxos are funded with [[CoinSelector.accumulateLargest() accumulateLargest]] coin seleciton algorithm
|
||||
* */
|
||||
private[wallet] def fundRawTransactionInternal(
|
||||
destinations: Vector[TransactionOutput],
|
||||
feeRate: FeeUnit,
|
||||
fromAccount: AccountDb,
|
||||
keyManagerOpt: Option[BIP39KeyManager]): Future[BitcoinTxBuilder] = {
|
||||
val utxosF = listUtxos()
|
||||
val changeAddrF = getNewChangeAddress(fromAccount)
|
||||
val selectedUtxosF = for {
|
||||
walletUtxos <- utxosF
|
||||
change <- changeAddrF
|
||||
//currently just grab the biggest utxos
|
||||
selectedUtxos = CoinSelector
|
||||
.accumulateLargest(walletUtxos, destinations, feeRate)
|
||||
} yield selectedUtxos
|
||||
|
||||
val addrInfosWithUtxoF: Future[Vector[(SpendingInfoDb, AddressInfo)]] =
|
||||
for {
|
||||
selectedUtxos <- selectedUtxosF
|
||||
addrInfoOptF = selectedUtxos.map { utxo =>
|
||||
val addrInfoOptF = getAddressInfo(utxo)
|
||||
//.get should be safe here because of foreign key at the database level
|
||||
addrInfoOptF.map(addrInfoOpt => (utxo, addrInfoOpt.get))
|
||||
}
|
||||
vec <- Future.sequence(addrInfoOptF)
|
||||
} yield vec
|
||||
|
||||
val txBuilderF = for {
|
||||
addrInfosWithUtxo <- addrInfosWithUtxoF
|
||||
change <- changeAddrF
|
||||
utxoSpendingInfos = {
|
||||
addrInfosWithUtxo.map {
|
||||
case (utxo, addrInfo) =>
|
||||
keyManagerOpt match {
|
||||
case Some(km) =>
|
||||
utxo.toUTXOSpendingInfo(account = fromAccount,
|
||||
keyManager = km,
|
||||
networkParameters = networkParameters)
|
||||
case None =>
|
||||
utxo.toUTXOSpendingInfo(account = fromAccount,
|
||||
sign = Sign.dummySign(addrInfo.pubkey),
|
||||
networkParameters = networkParameters)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
txBuilder <- {
|
||||
|
||||
logger.info({
|
||||
val utxosStr = utxoSpendingInfos
|
||||
.map { utxo =>
|
||||
import utxo.outPoint
|
||||
s"${outPoint.txId.hex}:${outPoint.vout.toInt}"
|
||||
}
|
||||
.mkString(", ")
|
||||
s"Spending UTXOs: $utxosStr"
|
||||
})
|
||||
|
||||
utxoSpendingInfos.zipWithIndex.foreach {
|
||||
case (utxo, index) =>
|
||||
logger.info(s"UTXO $index details: ${utxo.output}")
|
||||
}
|
||||
|
||||
networkParameters match {
|
||||
case b: BitcoinNetwork =>
|
||||
BitcoinTxBuilder(destinations = destinations,
|
||||
utxos = utxoSpendingInfos,
|
||||
feeRate = feeRate,
|
||||
changeSPK = change.scriptPubKey,
|
||||
network = b)
|
||||
}
|
||||
|
||||
}
|
||||
} yield {
|
||||
txBuilder
|
||||
}
|
||||
|
||||
txBuilderF
|
||||
}
|
||||
}
|
|
@ -135,10 +135,10 @@ class AddressTable(tag: Tag) extends Table[AddressDb](tag, "addresses") {
|
|||
|
||||
def purpose: Rep[HDPurpose] = column("hd_purpose")
|
||||
|
||||
def accountIndex: Rep[Int] = column("account_index")
|
||||
|
||||
def accountCoin: Rep[HDCoinType] = column("hd_coin")
|
||||
|
||||
def accountIndex: Rep[Int] = column("account_index")
|
||||
|
||||
def accountChainType: Rep[HDChainType] = column("hd_chain_type")
|
||||
|
||||
def addressIndex: Rep[Int] = column("address_index")
|
||||
|
|
|
@ -11,7 +11,7 @@ import org.bitcoins.core.protocol.transaction.{
|
|||
}
|
||||
import org.bitcoins.core.script.crypto.HashType
|
||||
import org.bitcoins.core.wallet.utxo.{
|
||||
BitcoinUTXOSpendingInfo,
|
||||
BitcoinUTXOSpendingInfoFull,
|
||||
ConditionalPath,
|
||||
TxoState
|
||||
}
|
||||
|
@ -133,14 +133,24 @@ sealed trait SpendingInfoDb extends DbRowAutoInc[SpendingInfoDb] {
|
|||
def toUTXOSpendingInfo(
|
||||
account: AccountDb,
|
||||
keyManager: BIP39KeyManager,
|
||||
network: NetworkParameters): BitcoinUTXOSpendingInfo = {
|
||||
networkParameters: NetworkParameters): BitcoinUTXOSpendingInfoFull = {
|
||||
|
||||
val sign: Sign = keyManager.toSign(privKeyPath = privKeyPath)
|
||||
|
||||
BitcoinUTXOSpendingInfo(
|
||||
toUTXOSpendingInfo(account = account,
|
||||
sign = sign,
|
||||
networkParameters = networkParameters)
|
||||
}
|
||||
|
||||
def toUTXOSpendingInfo(
|
||||
account: AccountDb,
|
||||
sign: Sign,
|
||||
networkParameters: NetworkParameters
|
||||
): BitcoinUTXOSpendingInfoFull = {
|
||||
BitcoinUTXOSpendingInfoFull(
|
||||
outPoint,
|
||||
output,
|
||||
List(sign),
|
||||
Vector(sign),
|
||||
redeemScriptOpt,
|
||||
scriptWitnessOpt,
|
||||
hashType,
|
||||
|
|
Loading…
Add table
Reference in a new issue