Added scalafmt and ran it (#264)

This commit is contained in:
Nadav Kohen 2018-12-09 13:43:31 -06:00 committed by Chris Stewart
parent 4a407ccdf1
commit b8dbd302cb
379 changed files with 20498 additions and 12663 deletions

12
.scalafmt.conf Normal file
View file

@ -0,0 +1,12 @@
# See Documentation at https://scalameta.org/scalafmt/#Configuration
maxColumn=80
docstrings=ScalaDoc
continuationIndent.callSite=2
continuationIndent.defnSite=4
align=some
align.openParenDefnSite=false
newlines.alwaysBeforeTopLevelStatements=true
newlines.sometimesBeforeColonInMethodReturnType=false
newlines.alwaysBeforeCurlyBraceLambdaParams=false
#newlines.alwaysBeforeMultilineDef=false
# Consider Rewrite Rules

View file

@ -14,15 +14,18 @@ object BlockBench extends App {
logger.info("Elapsed time: " + (time) + "ms")
time
}
def bench1(): Unit = {
val fileName = "/00000000000000000008513c860373da0484f065983aeb063ebf81c172e81d48.txt"
val fileName =
"/00000000000000000008513c860373da0484f065983aeb063ebf81c172e81d48.txt"
val lines = Source.fromURL(getClass.getResource(fileName)).mkString
val time = timeBlockParsing(Block.fromHex(lines))
require(time <= 15000)
}
def bench2(): Unit = {
val fileName = "/000000000000000000050f70113ab1932c195442cb49bcc4ee4d7f426c8a3295.txt"
val fileName =
"/000000000000000000050f70113ab1932c195442cb49bcc4ee4d7f426c8a3295.txt"
val lines = Source.fromURL(getClass.getResource(fileName)).mkString
val time = timeBlockParsing(Block.fromHex(lines))
require(time <= 15000)
@ -31,4 +34,4 @@ object BlockBench extends App {
0.until(10).foreach(_ => bench1())
//bench2()
}
}

View file

@ -29,23 +29,24 @@ lazy val testCompilerOpts = commonCompilerOpts
lazy val commonSettings = List(
scalacOptions in Compile := compilerOpts,
scalacOptions in Test := testCompilerOpts,
assemblyOption in assembly := (assemblyOption in assembly).value.copy(includeScala = false)
assemblyOption in assembly := (assemblyOption in assembly).value
.copy(includeScala = false)
)
lazy val root = project
.in(file("."))
.aggregate(
secp256k1jni,
core,
coreGen,
coreTest,
zmq,
rpc,
bench,
eclairRpc,
testkit
)
.settings(commonSettings: _*)
.in(file("."))
.aggregate(
secp256k1jni,
core,
coreGen,
coreTest,
zmq,
rpc,
bench,
eclairRpc,
testkit
)
.settings(commonSettings: _*)
lazy val secp256k1jni = project
.in(file("secp256k1jni"))
@ -92,14 +93,16 @@ lazy val rpc = project
.dependsOn(
core,
coreGen % "test->test"
).settings(
)
.settings(
testOptions in Test += Tests.Argument("-oF")
)
lazy val bench = project
.in(file("bench"))
.enablePlugins()
.settings(assemblyOption in assembly := (assemblyOption in assembly).value.copy(includeScala = true))
.settings(assemblyOption in assembly := (assemblyOption in assembly).value
.copy(includeScala = true))
.settings(libraryDependencies ++= Deps.bench)
.dependsOn(core)

View file

@ -1,4 +1,3 @@
name := "bitcoin-s-core-gen"
libraryDependencies ++= Deps.coreGen

View file

@ -4,31 +4,36 @@ import org.bitcoins.core.protocol._
import org.scalacheck.Gen
/**
* Created by chris on 6/12/17.
*/
* Created by chris on 6/12/17.
*/
sealed trait AddressGenerator {
def p2pkhAddress: Gen[P2PKHAddress] = for {
hash <- CryptoGenerators.sha256Hash160Digest
network <- ChainParamsGenerator.networkParams
addr = P2PKHAddress(hash, network)
} yield addr
def p2pkhAddress: Gen[P2PKHAddress] =
for {
hash <- CryptoGenerators.sha256Hash160Digest
network <- ChainParamsGenerator.networkParams
addr = P2PKHAddress(hash, network)
} yield addr
def p2shAddress: Gen[P2SHAddress] = for {
hash <- CryptoGenerators.sha256Hash160Digest
network <- ChainParamsGenerator.networkParams
addr = P2SHAddress(hash, network)
} yield addr
def p2shAddress: Gen[P2SHAddress] =
for {
hash <- CryptoGenerators.sha256Hash160Digest
network <- ChainParamsGenerator.networkParams
addr = P2SHAddress(hash, network)
} yield addr
def bech32Address: Gen[Bech32Address] = for {
(witSPK, _) <- ScriptGenerators.witnessScriptPubKeyV0
network <- ChainParamsGenerator.networkParams
addr = Bech32Address(witSPK, network)
} yield addr
def bech32Address: Gen[Bech32Address] =
for {
(witSPK, _) <- ScriptGenerators.witnessScriptPubKeyV0
network <- ChainParamsGenerator.networkParams
addr = Bech32Address(witSPK, network)
} yield addr
def bitcoinAddress: Gen[BitcoinAddress] = Gen.oneOf(p2pkhAddress, p2shAddress, bech32Address)
def bitcoinAddress: Gen[BitcoinAddress] =
Gen.oneOf(p2pkhAddress, p2shAddress, bech32Address)
def address: Gen[Address] = Gen.oneOf(p2pkhAddress, p2shAddress, bech32Address)
def address: Gen[Address] =
Gen.oneOf(p2pkhAddress, p2shAddress, bech32Address)
}
object AddressGenerator extends AddressGenerator
object AddressGenerator extends AddressGenerator

View file

@ -2,82 +2,106 @@ package org.bitcoins.core.gen
import org.bitcoins.core.consensus.Merkle
import org.bitcoins.core.crypto.DoubleSha256Digest
import org.bitcoins.core.number.{ Int32, UInt32 }
import org.bitcoins.core.protocol.blockchain.{ Block, BlockHeader }
import org.bitcoins.core.protocol.transaction.{ EmptyTransaction, Transaction }
import org.bitcoins.core.number.{Int32, UInt32}
import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader}
import org.bitcoins.core.protocol.transaction.{EmptyTransaction, Transaction}
import org.scalacheck.Gen
import scala.annotation.tailrec
/**
* Created by tom on 7/6/16.
*/
* Created by tom on 7/6/16.
*/
sealed abstract class BlockchainElementsGenerator {
/** Generates a block that contains the given txs, plus some more randomly generated ones */
def block(txs: Seq[Transaction]): Gen[Block] = for {
randomNum <- Gen.choose(1, 10)
neededTxs = if ((randomNum - txs.size) >= 0) randomNum else 0
genTxs <- Gen.listOfN(neededTxs, TransactionGenerators.transaction)
allTxs = genTxs ++ txs
header <- blockHeader(allTxs)
} yield Block(header, allTxs)
def block(txs: Seq[Transaction]): Gen[Block] =
for {
randomNum <- Gen.choose(1, 10)
neededTxs = if ((randomNum - txs.size) >= 0) randomNum else 0
genTxs <- Gen.listOfN(neededTxs, TransactionGenerators.transaction)
allTxs = genTxs ++ txs
header <- blockHeader(allTxs)
} yield Block(header, allTxs)
/**
* Generates a random [[Block]], note that we limit this
* to 10 transactions currently
*/
def block: Gen[Block] = for {
header <- blockHeader
txs <- TransactionGenerators.smallTransactions
} yield Block(header, txs)
* Generates a random [[Block]], note that we limit this
* to 10 transactions currently
*/
def block: Gen[Block] =
for {
header <- blockHeader
txs <- TransactionGenerators.smallTransactions
} yield Block(header, txs)
/** Generates a random [[BlockHeader]] */
def blockHeader: Gen[BlockHeader] = for {
previousBlockHash <- CryptoGenerators.doubleSha256Digest
b <- blockHeader(previousBlockHash)
} yield b
def blockHeader: Gen[BlockHeader] =
for {
previousBlockHash <- CryptoGenerators.doubleSha256Digest
b <- blockHeader(previousBlockHash)
} yield b
/** Generates a random [[BlockHeader]] with the specified previousBlockHash */
def blockHeader(previousBlockHash: DoubleSha256Digest): Gen[BlockHeader] = for {
nBits <- NumberGenerator.uInt32s
b <- blockHeader(previousBlockHash, nBits)
} yield b
def blockHeader(previousBlockHash: DoubleSha256Digest): Gen[BlockHeader] =
for {
nBits <- NumberGenerator.uInt32s
b <- blockHeader(previousBlockHash, nBits)
} yield b
/** Generates a random [[BlockHeader]] where you can specify the previousBlockHash and nBits */
def blockHeader(previousBlockHash: DoubleSha256Digest, nBits: UInt32): Gen[BlockHeader] = for {
numTxs <- Gen.choose(1, 5)
txs <- Gen.listOfN(numTxs, TransactionGenerators.transaction)
header <- blockHeader(previousBlockHash, nBits, txs)
} yield header
def blockHeader(
previousBlockHash: DoubleSha256Digest,
nBits: UInt32): Gen[BlockHeader] =
for {
numTxs <- Gen.choose(1, 5)
txs <- Gen.listOfN(numTxs, TransactionGenerators.transaction)
header <- blockHeader(previousBlockHash, nBits, txs)
} yield header
/** Generates a [[BlockHeader]]] that has the fields set to the given values */
def blockHeader(previousBlockHash: DoubleSha256Digest, nBits: UInt32, txs: Seq[Transaction]): Gen[BlockHeader] = for {
version <- NumberGenerator.int32s
merkleRootHash = Merkle.computeMerkleRoot(txs)
time <- NumberGenerator.uInt32s
nonce <- NumberGenerator.uInt32s
} yield BlockHeader(version, previousBlockHash, merkleRootHash, time, nBits, nonce)
def blockHeader(
previousBlockHash: DoubleSha256Digest,
nBits: UInt32,
txs: Seq[Transaction]): Gen[BlockHeader] =
for {
version <- NumberGenerator.int32s
merkleRootHash = Merkle.computeMerkleRoot(txs)
time <- NumberGenerator.uInt32s
nonce <- NumberGenerator.uInt32s
} yield
BlockHeader(version,
previousBlockHash,
merkleRootHash,
time,
nBits,
nonce)
/** Generates a [[BlockHeader]] that has a merkle root hash corresponding to the given txs */
def blockHeader(txs: Seq[Transaction]): Gen[BlockHeader] = for {
previousBlockHash <- CryptoGenerators.doubleSha256Digest
nBits <- NumberGenerator.uInt32s
header <- blockHeader(previousBlockHash, nBits, txs)
} yield header
def blockHeader(txs: Seq[Transaction]): Gen[BlockHeader] =
for {
previousBlockHash <- CryptoGenerators.doubleSha256Digest
nBits <- NumberGenerator.uInt32s
header <- blockHeader(previousBlockHash, nBits, txs)
} yield header
/**
* Generates a chain of valid headers of the size specified by num,
* 'valid' means their nBits are the same and each header properly
* references the previous block header's hash
*/
* Generates a chain of valid headers of the size specified by num,
* 'valid' means their nBits are the same and each header properly
* references the previous block header's hash
*/
def validHeaderChain(num: Long): Gen[Seq[BlockHeader]] = {
blockHeader.flatMap { startHeader =>
validHeaderChain(num, startHeader)
}
}
def validHeaderChain(num: Long, startHeader: BlockHeader): Gen[Seq[BlockHeader]] = {
def validHeaderChain(
num: Long,
startHeader: BlockHeader): Gen[Seq[BlockHeader]] = {
@tailrec
def loop(remainingHeaders: Long, accum: Seq[BlockHeader]): Seq[BlockHeader] = {
def loop(
remainingHeaders: Long,
accum: Seq[BlockHeader]): Seq[BlockHeader] = {
if (remainingHeaders == 0) accum.reverse
else {
val nextHeader = buildBlockHeader(accum.head.hash, accum.head.nBits)
@ -87,10 +111,17 @@ sealed abstract class BlockchainElementsGenerator {
loop(num - 1, Seq(startHeader))
}
private def buildBlockHeader(prevBlockHash: DoubleSha256Digest, nBits: UInt32): BlockHeader = {
private def buildBlockHeader(
prevBlockHash: DoubleSha256Digest,
nBits: UInt32): BlockHeader = {
//nonce for the unique hash
val nonce = NumberGenerator.uInt32s.sample.get
BlockHeader(Int32.one, prevBlockHash, EmptyTransaction.txId, UInt32.one, nBits, nonce)
BlockHeader(Int32.one,
prevBlockHash,
EmptyTransaction.txId,
UInt32.one,
nBits,
nonce)
}
}

View file

@ -5,33 +5,37 @@ import org.scalacheck.Gen
import scodec.bits.ByteVector
/**
* Created by chris on 8/7/16.
*/
* Created by chris on 8/7/16.
*/
abstract class BloomFilterGenerator {
/** Builds a generic bloom filter loaded with no hashes and returns it */
def bloomFilter: Gen[BloomFilter] = for {
size <- Gen.choose(1, 100)
falsePositiveRate <- Gen.choose(0.00001, 0.99999)
tweak <- NumberGenerator.uInt32s
flags <- bloomFlag
} yield BloomFilter(size, falsePositiveRate, tweak, flags)
def bloomFilter: Gen[BloomFilter] =
for {
size <- Gen.choose(1, 100)
falsePositiveRate <- Gen.choose(0.00001, 0.99999)
tweak <- NumberGenerator.uInt32s
flags <- bloomFlag
} yield BloomFilter(size, falsePositiveRate, tweak, flags)
/** Loads a generic bloom filter with the given byte vectors and returns it */
def bloomFilter(byteVectors: Seq[ByteVector]): Gen[BloomFilter] = for {
filter <- bloomFilter
} yield filter.insertByteVectors(byteVectors)
def bloomFilter(byteVectors: Seq[ByteVector]): Gen[BloomFilter] =
for {
filter <- bloomFilter
} yield filter.insertByteVectors(byteVectors)
/** Returns a bloom filter loaded with randomly generated byte vectors */
def loadedBloomFilter: Gen[(BloomFilter, Seq[ByteVector])] = for {
filter <- bloomFilter
randomNum <- Gen.choose(0, filter.filterSize.num.toInt)
hashes <- CryptoGenerators.doubleSha256DigestSeq(randomNum)
loaded = filter.insertHashes(hashes)
} yield (loaded, hashes.map(_.bytes))
def loadedBloomFilter: Gen[(BloomFilter, Seq[ByteVector])] =
for {
filter <- bloomFilter
randomNum <- Gen.choose(0, filter.filterSize.num.toInt)
hashes <- CryptoGenerators.doubleSha256DigestSeq(randomNum)
loaded = filter.insertHashes(hashes)
} yield (loaded, hashes.map(_.bytes))
/** Generates a random bloom flag */
def bloomFlag: Gen[BloomFlag] = Gen.oneOf(BloomUpdateNone, BloomUpdateAll, BloomUpdateP2PKOnly)
def bloomFlag: Gen[BloomFlag] =
Gen.oneOf(BloomUpdateNone, BloomUpdateAll, BloomUpdateP2PKOnly)
}

View file

@ -5,19 +5,19 @@ import org.bitcoins.core.protocol.ln.LnParams
import org.scalacheck.Gen
/**
* Created by chris on 6/6/17.
*/
* Created by chris on 6/6/17.
*/
sealed abstract class ChainParamsGenerator {
def networkParams: Gen[NetworkParameters] = bitcoinNetworkParams
def bitcoinNetworkParams: Gen[BitcoinNetwork] = Gen.oneOf(MainNet, TestNet3, RegTest)
def bitcoinNetworkParams: Gen[BitcoinNetwork] =
Gen.oneOf(MainNet, TestNet3, RegTest)
def lnNetworkParams: Gen[LnParams] = {
Gen.oneOf(
LnParams.LnBitcoinMainNet,
LnParams.LnBitcoinTestNet,
LnParams.LnBitcoinRegTest)
Gen.oneOf(LnParams.LnBitcoinMainNet,
LnParams.LnBitcoinTestNet,
LnParams.LnBitcoinRegTest)
}
}

View file

@ -11,84 +11,117 @@ import org.scalacheck.Gen
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.DurationInt
import scala.concurrent.{ Await, Future }
import scala.concurrent.{Await, Future}
/**
* Created by chris on 4/18/17.
*/
* Created by chris on 4/18/17.
*/
sealed trait ChannelGenerators extends BitcoinSLogger {
val timeout = 5.seconds
/** Creates an [[Transaction]], [[EscrowTimeoutScriptPubKey]] and the [[ECPrivateKey]] need to spend from the SPK */
def anchorTx: Gen[(Transaction, EscrowTimeoutScriptPubKey, Seq[ECPrivateKey])] = for {
(redeemScript, privKeys) <- ScriptGenerators.escrowTimeoutScriptPubKey2Of2
amount <- CurrencyUnitGenerator.satoshis.suchThat(_ >= Policy.minChannelAmount)
p2wsh = P2WSHWitnessSPKV0(redeemScript)
} yield {
val (aTx, _) = TransactionGenerators.buildCreditingTransaction(TransactionConstants.validLockVersion, p2wsh, amount)
(aTx, redeemScript, privKeys)
}
def channelAwaitingAnchorTxNotConfirmed: Gen[(ChannelAwaitingAnchorTx, Seq[ECPrivateKey])] = for {
(aTx, redeemScript, privKeys) <- anchorTx
} yield (ChannelAwaitingAnchorTx(aTx, redeemScript, 0).get, privKeys)
/** Creates an [[Transaction]], [[EscrowTimeoutScriptPubKey]] and the [[ECPrivateKey]] need to spend from the SPK */
def anchorTx: Gen[
(Transaction, EscrowTimeoutScriptPubKey, Seq[ECPrivateKey])] =
for {
(redeemScript, privKeys) <- ScriptGenerators.escrowTimeoutScriptPubKey2Of2
amount <- CurrencyUnitGenerator.satoshis.suchThat(
_ >= Policy.minChannelAmount)
p2wsh = P2WSHWitnessSPKV0(redeemScript)
} yield {
val (aTx, _) = TransactionGenerators.buildCreditingTransaction(
TransactionConstants.validLockVersion,
p2wsh,
amount)
(aTx, redeemScript, privKeys)
}
def channelAwaitingAnchorTxNotConfirmed: Gen[
(ChannelAwaitingAnchorTx, Seq[ECPrivateKey])] =
for {
(aTx, redeemScript, privKeys) <- anchorTx
} yield (ChannelAwaitingAnchorTx(aTx, redeemScript, 0).get, privKeys)
/**
* Creates a [[ChannelAwaitingAnchorTx]] and
* the private keys needed to spend from the locked output.
* This generator assumes that the anchor tx has sufficient confirmations
*/
def channelAwaitingAnchorTx: Gen[(ChannelAwaitingAnchorTx, Seq[ECPrivateKey])] = for {
(aTx, redeemScript, privKeys) <- anchorTx
} yield (ChannelAwaitingAnchorTx(aTx, redeemScript, Policy.confirmations).get, privKeys)
* Creates a [[ChannelAwaitingAnchorTx]] and
* the private keys needed to spend from the locked output.
* This generator assumes that the anchor tx has sufficient confirmations
*/
def channelAwaitingAnchorTx: Gen[
(ChannelAwaitingAnchorTx, Seq[ECPrivateKey])] =
for {
(aTx, redeemScript, privKeys) <- anchorTx
} yield
(ChannelAwaitingAnchorTx(aTx, redeemScript, Policy.confirmations).get,
privKeys)
/** A [[ChannelInProgress]] that has paid the server exactly one time */
def freshChannelInProgress: Gen[(ChannelInProgress, Seq[ECPrivateKey])] = for {
(awaiting, privKeys) <- channelAwaitingAnchorTx
(s1, _) <- ScriptGenerators.scriptPubKey
amount = Policy.minChannelAmount
clientSigned = Await.result(awaiting.clientSign(s1, amount, privKeys.head), timeout)
fullySigned = Await.result(clientSigned.serverSign(privKeys(1)), timeout)
} yield (fullySigned, privKeys)
def freshChannelInProgress: Gen[(ChannelInProgress, Seq[ECPrivateKey])] =
for {
(awaiting, privKeys) <- channelAwaitingAnchorTx
(s1, _) <- ScriptGenerators.scriptPubKey
amount = Policy.minChannelAmount
clientSigned = Await.result(
awaiting.clientSign(s1, amount, privKeys.head),
timeout)
fullySigned = Await.result(clientSigned.serverSign(privKeys(1)), timeout)
} yield (fullySigned, privKeys)
/** A [[ChannelInProgress]] that has paid the server between 1 and 10 times */
def channelInProgress: Gen[(ChannelInProgress, Seq[ECPrivateKey])] = for {
(old, privKeys) <- freshChannelInProgress
runs <- Gen.choose(1, 10)
amount = Policy.dustThreshold
inProgress = Await.result(simulate(runs, old, amount, privKeys.head, privKeys(1)), timeout)
} yield (inProgress, privKeys)
def channelInProgress: Gen[(ChannelInProgress, Seq[ECPrivateKey])] =
for {
(old, privKeys) <- freshChannelInProgress
runs <- Gen.choose(1, 10)
amount = Policy.dustThreshold
inProgress = Await.result(
simulate(runs, old, amount, privKeys.head, privKeys(1)),
timeout)
} yield (inProgress, privKeys)
/** Creates a Channel that has been signed by the client */
def channelInProgressClientSigned: Gen[(ChannelInProgressClientSigned, Seq[ECPrivateKey])] = for {
(old, privKeys) <- freshChannelInProgress
clientSigned = Await.result(old.clientSign(Policy.dustThreshold, privKeys.head), timeout)
} yield (clientSigned, privKeys)
def channelInProgressClientSigned: Gen[
(ChannelInProgressClientSigned, Seq[ECPrivateKey])] =
for {
(old, privKeys) <- freshChannelInProgress
clientSigned = Await.result(
old.clientSign(Policy.dustThreshold, privKeys.head),
timeout)
} yield (clientSigned, privKeys)
def baseInProgress: Gen[(BaseInProgress, Seq[ECPrivateKey])] = Gen.oneOf(channelInProgress, channelInProgressClientSigned)
def baseInProgress: Gen[(BaseInProgress, Seq[ECPrivateKey])] =
Gen.oneOf(channelInProgress, channelInProgressClientSigned)
/** Generator for a payment channel that opened, simulated, then closed */
def channelClosed: Gen[(ChannelClosed, Seq[ECPrivateKey])] = for {
(inProgress, privKeys) <- channelInProgress
(serverScriptPubKey, _) <- ScriptGenerators.scriptPubKey
(clientKey, serverKey) = (privKeys.head, privKeys(1))
amount = Policy.dustThreshold
fee = amount
clientSigned = inProgress.clientSign(amount, clientKey)
closed = Await.result(clientSigned.flatMap(_.close(serverScriptPubKey, serverKey, fee)), 5.seconds)
} yield (closed, privKeys)
def channelClosed: Gen[(ChannelClosed, Seq[ECPrivateKey])] =
for {
(inProgress, privKeys) <- channelInProgress
(serverScriptPubKey, _) <- ScriptGenerators.scriptPubKey
(clientKey, serverKey) = (privKeys.head, privKeys(1))
amount = Policy.dustThreshold
fee = amount
clientSigned = inProgress.clientSign(amount, clientKey)
closed = Await.result(
clientSigned.flatMap(_.close(serverScriptPubKey, serverKey, fee)),
5.seconds)
} yield (closed, privKeys)
/**
* Simulates the execution of a [[Channel]]
* @param runs the number of times the client pays the server
* @param inProgress the [[ChannelInProgress]] to simulate
* @param amount the amount we pay to the server every time
* @param clientKey key the client uses to sign the payment channel output
* @param serverKey key the server uses to sign the payment channel output
* @return
*/
def simulate(runs: Int, inProgress: ChannelInProgress, amount: CurrencyUnit,
clientKey: ECPrivateKey, serverKey: ECPrivateKey): Future[ChannelInProgress] = {
def loop(oldFuture: Future[ChannelInProgress], remaining: Int): Future[ChannelInProgress] = oldFuture.flatMap { old =>
* Simulates the execution of a [[Channel]]
* @param runs the number of times the client pays the server
* @param inProgress the [[ChannelInProgress]] to simulate
* @param amount the amount we pay to the server every time
* @param clientKey key the client uses to sign the payment channel output
* @param serverKey key the server uses to sign the payment channel output
* @return
*/
def simulate(
runs: Int,
inProgress: ChannelInProgress,
amount: CurrencyUnit,
clientKey: ECPrivateKey,
serverKey: ECPrivateKey): Future[ChannelInProgress] = {
def loop(
oldFuture: Future[ChannelInProgress],
remaining: Int): Future[ChannelInProgress] = oldFuture.flatMap { old =>
if (remaining == 0) Future.successful(old)
else {
val clientSigned = old.clientSign(amount, clientKey)

View file

@ -9,21 +9,28 @@ import org.bitcoins.core.wallet.utxo.BitcoinUTXOSpendingInfo
import org.scalacheck.Gen
sealed abstract class CreditingTxGen {
/** Minimum amount of outputs to generate */
private val min = 1
/** Maximum amount of outputs to generate */
private val max = 3
/** Note this generator does NOT generate outputs with negative values */
private def nonEmptyOutputs: Gen[Seq[TransactionOutput]] = Gen.choose(1, 5).flatMap { n =>
Gen.listOfN(n, TransactionGenerators.realisticOutput)
}
private def nonEmptyOutputs: Gen[Seq[TransactionOutput]] =
Gen.choose(1, 5).flatMap { n =>
Gen.listOfN(n, TransactionGenerators.realisticOutput)
}
def rawOutput: Gen[BitcoinUTXOSpendingInfo] = {
Gen.oneOf(p2pkOutput, p2pkhOutput, multiSigOutput, /*cltvOutput,*/ csvOutput, p2wpkhOutput)
Gen.oneOf(p2pkOutput,
p2pkhOutput,
multiSigOutput, /*cltvOutput,*/ csvOutput,
p2wpkhOutput)
}
def rawOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = Gen.choose(min, max).flatMap(n => Gen.listOfN(n, rawOutput))
def rawOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, rawOutput))
def basicOutput: Gen[BitcoinUTXOSpendingInfo] = {
Gen.oneOf(p2pkOutput, p2pkhOutput, multiSigOutput)
@ -31,27 +38,37 @@ sealed abstract class CreditingTxGen {
def nonP2WSHOutput: Gen[BitcoinUTXOSpendingInfo] = {
//note, cannot put a p2wpkh here
Gen.oneOf(p2pkOutput, p2pkhOutput, multiSigOutput, /*cltvOutput,*/ csvOutput)
Gen.oneOf(p2pkOutput,
p2pkhOutput,
multiSigOutput, /*cltvOutput,*/ csvOutput)
}
def nonP2SHOutput: Gen[BitcoinUTXOSpendingInfo] = {
Gen.oneOf(p2pkOutput, p2pkhOutput, multiSigOutput, /*cltvOutput,*/ csvOutput, p2wpkhOutput, p2wshOutput)
Gen.oneOf(p2pkOutput,
p2pkhOutput,
multiSigOutput, /*cltvOutput,*/ csvOutput,
p2wpkhOutput,
p2wshOutput)
}
def output: Gen[BitcoinUTXOSpendingInfo] = Gen.oneOf(
p2pkOutput,
p2pkhOutput, multiSigOutput, p2shOutput,
csvOutput, /*cltvOutput,*/
p2wpkhOutput, p2wshOutput)
def output: Gen[BitcoinUTXOSpendingInfo] =
Gen.oneOf(p2pkOutput,
p2pkhOutput,
multiSigOutput,
p2shOutput,
csvOutput, /*cltvOutput,*/
p2wpkhOutput,
p2wshOutput)
def outputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = {
Gen.choose(min, 5).flatMap(n => Gen.listOfN(n, output))
}
/** Generates a crediting tx with a p2pk spk at the returned index */
def p2pkOutput: Gen[BitcoinUTXOSpendingInfo] = ScriptGenerators.p2pkScriptPubKey.flatMap { p2pk =>
build(p2pk._1, Seq(p2pk._2), None, None)
}
def p2pkOutput: Gen[BitcoinUTXOSpendingInfo] =
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]] = {
@ -59,21 +76,23 @@ 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] = ScriptGenerators.p2pkhScriptPubKey.flatMap { p2pkh =>
build(p2pkh._1, Seq(p2pkh._2), None, None)
}
* 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] =
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]] = {
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2pkhOutput))
}
def multiSigOutput: Gen[BitcoinUTXOSpendingInfo] = ScriptGenerators.multiSigScriptPubKey.flatMap { multisig =>
build(multisig._1, multisig._2, None, None)
}
def multiSigOutput: Gen[BitcoinUTXOSpendingInfo] =
ScriptGenerators.multiSigScriptPubKey.flatMap { multisig =>
build(multisig._1, multisig._2, None, None)
}
def multiSigOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = {
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, multiSigOutput))
@ -85,7 +104,13 @@ sealed abstract class CreditingTxGen {
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)
BitcoinUTXOSpendingInfo(TransactionOutPoint(o.outPoint.txId,
o.outPoint.vout),
updatedOutput,
o.signers,
Some(redeemScript),
o.scriptWitnessOpt,
hashType)
}
}
@ -93,40 +118,58 @@ sealed abstract class CreditingTxGen {
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2shOutput))
}
def cltvOutput: Gen[BitcoinUTXOSpendingInfo] = TransactionGenerators.spendableCLTVValues.flatMap {
case (scriptNum, _) =>
basicOutput.flatMap { o =>
CryptoGenerators.hashType.map { hashType =>
val oldOutput = o.output
val csvSPK = CLTVScriptPubKey(scriptNum, oldOutput.scriptPubKey)
val updatedOutput = TransactionOutput(oldOutput.value, csvSPK)
BitcoinUTXOSpendingInfo(TransactionOutPoint(o.outPoint.txId, o.outPoint.vout), updatedOutput, o.signers, o.redeemScriptOpt, o.scriptWitnessOpt, hashType)
def cltvOutput: Gen[BitcoinUTXOSpendingInfo] =
TransactionGenerators.spendableCLTVValues.flatMap {
case (scriptNum, _) =>
basicOutput.flatMap { o =>
CryptoGenerators.hashType.map { hashType =>
val oldOutput = o.output
val csvSPK = CLTVScriptPubKey(scriptNum, oldOutput.scriptPubKey)
val updatedOutput = TransactionOutput(oldOutput.value, csvSPK)
BitcoinUTXOSpendingInfo(TransactionOutPoint(o.outPoint.txId,
o.outPoint.vout),
updatedOutput,
o.signers,
o.redeemScriptOpt,
o.scriptWitnessOpt,
hashType)
}
}
}
}
}
def cltvOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = Gen.choose(min, max).flatMap(n => Gen.listOfN(n, cltvOutput))
def cltvOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, cltvOutput))
def csvOutput: Gen[BitcoinUTXOSpendingInfo] = TransactionGenerators.spendableCSVValues.flatMap {
case (scriptNum, _) =>
basicOutput.flatMap { o =>
CryptoGenerators.hashType.map { hashType =>
val oldOutput = o.output
val csvSPK = CSVScriptPubKey(scriptNum, oldOutput.scriptPubKey)
val updatedOutput = TransactionOutput(oldOutput.value, csvSPK)
BitcoinUTXOSpendingInfo(TransactionOutPoint(o.outPoint.txId, o.outPoint.vout), updatedOutput, o.signers, o.redeemScriptOpt, o.scriptWitnessOpt, hashType)
def csvOutput: Gen[BitcoinUTXOSpendingInfo] =
TransactionGenerators.spendableCSVValues.flatMap {
case (scriptNum, _) =>
basicOutput.flatMap { o =>
CryptoGenerators.hashType.map { hashType =>
val oldOutput = o.output
val csvSPK = CSVScriptPubKey(scriptNum, oldOutput.scriptPubKey)
val updatedOutput = TransactionOutput(oldOutput.value, csvSPK)
BitcoinUTXOSpendingInfo(TransactionOutPoint(o.outPoint.txId,
o.outPoint.vout),
updatedOutput,
o.signers,
o.redeemScriptOpt,
o.scriptWitnessOpt,
hashType)
}
}
}
}
}
def csvOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = Gen.choose(min, max).flatMap(n => Gen.listOfN(n, csvOutput))
def csvOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, csvOutput))
def p2wpkhOutput: Gen[BitcoinUTXOSpendingInfo] = ScriptGenerators.p2wpkhSPKV0.flatMap { witSPK =>
val scriptWit = P2WPKHWitnessV0(witSPK._2.head.publicKey)
build(witSPK._1, witSPK._2, None, Some(scriptWit))
}
def p2wpkhOutput: Gen[BitcoinUTXOSpendingInfo] =
ScriptGenerators.p2wpkhSPKV0.flatMap { witSPK =>
val scriptWit = P2WPKHWitnessV0(witSPK._2.head.publicKey)
build(witSPK._1, witSPK._2, None, Some(scriptWit))
}
def p2wpkhOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2wpkhOutput))
def p2wpkhOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2wpkhOutput))
def p2wshOutput: Gen[BitcoinUTXOSpendingInfo] = nonP2WSHOutput.flatMap {
case BitcoinUTXOSpendingInfo(_, txOutput, signer, _, _, _) =>
@ -136,47 +179,72 @@ sealed abstract class CreditingTxGen {
build(witSPK, signer, None, Some(scriptWit))
}
def p2wshOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2wshOutput))
def p2wshOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2wshOutput))
/** A nested output is a p2sh/p2wsh wrapped output */
def nestedOutput: Gen[BitcoinUTXOSpendingInfo] = {
Gen.oneOf(p2wshOutput, p2shOutput)
}
def nestedOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] = Gen.choose(min, max).flatMap(n => Gen.listOfN(n, nestedOutput))
def nestedOutputs: Gen[Seq[BitcoinUTXOSpendingInfo]] =
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, nestedOutput))
def random: Gen[BitcoinUTXOSpendingInfo] = nonEmptyOutputs.flatMap { outputs =>
Gen.choose(0, outputs.size - 1).flatMap { outputIndex: Int =>
ScriptGenerators.scriptPubKey.flatMap {
case (spk, keys) =>
WitnessGenerators.scriptWitness.flatMap { wit: ScriptWitness =>
CryptoGenerators.hashType.map { hashType: HashType =>
val tc = TransactionConstants
val signers: Seq[Sign] = keys
val creditingTx = BaseTransaction(tc.validLockVersion, Nil, outputs, tc.lockTime)
BitcoinUTXOSpendingInfo(TransactionOutPoint(creditingTx.txId, UInt32.apply(outputIndex)), TransactionOutput(creditingTx.outputs(outputIndex).value, creditingTx.outputs(outputIndex).scriptPubKey), signers, Some(spk), Some(wit), hashType)
def random: Gen[BitcoinUTXOSpendingInfo] = nonEmptyOutputs.flatMap {
outputs =>
Gen.choose(0, outputs.size - 1).flatMap { outputIndex: Int =>
ScriptGenerators.scriptPubKey.flatMap {
case (spk, keys) =>
WitnessGenerators.scriptWitness.flatMap { wit: ScriptWitness =>
CryptoGenerators.hashType.map { hashType: HashType =>
val tc = TransactionConstants
val signers: Seq[Sign] = keys
val creditingTx = BaseTransaction(tc.validLockVersion,
Nil,
outputs,
tc.lockTime)
BitcoinUTXOSpendingInfo(
TransactionOutPoint(creditingTx.txId,
UInt32.apply(outputIndex)),
TransactionOutput(
creditingTx.outputs(outputIndex).value,
creditingTx.outputs(outputIndex).scriptPubKey),
signers,
Some(spk),
Some(wit),
hashType
)
}
}
}
}
}
}
}
def randoms: Gen[Seq[BitcoinUTXOSpendingInfo]] = Gen.choose(min, max).flatMap(n => Gen.listOfN(n, random))
def randoms: Gen[Seq[BitcoinUTXOSpendingInfo]] =
Gen.choose(min, max).flatMap(n => Gen.listOfN(n, random))
private def build(spk: ScriptPubKey, signers: Seq[Sign],
redeemScript: Option[ScriptPubKey],
scriptWitness: Option[ScriptWitness]): Gen[BitcoinUTXOSpendingInfo] = nonEmptyOutputs.flatMap { outputs =>
CryptoGenerators.hashType.flatMap { hashType =>
Gen.choose(0, outputs.size - 1).map { idx =>
val old = outputs(idx)
val updated = outputs.updated(idx, TransactionOutput(old.value, spk))
val tc = TransactionConstants
val btx = BaseTransaction(tc.version, Nil, updated, tc.lockTime)
BitcoinUTXOSpendingInfo(TransactionOutPoint(btx.txId, UInt32.apply(idx)), TransactionOutput(old.value, spk), signers, redeemScript, scriptWitness, hashType)
private def build(
spk: ScriptPubKey,
signers: Seq[Sign],
redeemScript: Option[ScriptPubKey],
scriptWitness: Option[ScriptWitness]): Gen[BitcoinUTXOSpendingInfo] =
nonEmptyOutputs.flatMap { outputs =>
CryptoGenerators.hashType.flatMap { hashType =>
Gen.choose(0, outputs.size - 1).map { idx =>
val old = outputs(idx)
val updated = outputs.updated(idx, TransactionOutput(old.value, spk))
val tc = TransactionConstants
val btx = BaseTransaction(tc.version, Nil, updated, tc.lockTime)
BitcoinUTXOSpendingInfo(TransactionOutPoint(btx.txId,
UInt32.apply(idx)),
TransactionOutput(old.value, spk),
signers,
redeemScript,
scriptWitness,
hashType)
}
}
}
}
}
object CreditingTxGen extends CreditingTxGen {
}
object CreditingTxGen extends CreditingTxGen {}

View file

@ -6,25 +6,26 @@ import org.bitcoins.core.util.CryptoUtil
import org.scalacheck.Gen
/**
* Created by chris on 6/22/16.
*/
* Created by chris on 6/22/16.
*/
sealed abstract class CryptoGenerators {
def privateKey: Gen[ECPrivateKey] = Gen.delay(ECPrivateKey())
/**
* Generate a sequence of private keys
* @param num maximum number of keys to generate
* @return
*/
def privateKeySeq(num: Int): Gen[Seq[ECPrivateKey]] = Gen.listOfN(num, privateKey)
* Generate a sequence of private keys
* @param num maximum number of keys to generate
* @return
*/
def privateKeySeq(num: Int): Gen[Seq[ECPrivateKey]] =
Gen.listOfN(num, privateKey)
/**
* Generates a sequence of private keys, and determines an amount of 'required' private keys
* that a transaction needs to be signed with
* @param num the maximum number of keys to generate
* @return
*/
* Generates a sequence of private keys, and determines an amount of 'required' private keys
* that a transaction needs to be signed with
* @param num the maximum number of keys to generate
* @return
*/
def privateKeySeqWithRequiredSigs(num: Int): Gen[(Seq[ECPrivateKey], Int)] = {
if (num <= 0) {
Gen.const(Nil, 0)
@ -38,67 +39,84 @@ sealed abstract class CryptoGenerators {
}
/**
* Generates a random number of private keys less than the max public keys setting in [[ScriptSettings]]
* also generates a random 'requiredSigs' number that a transaction needs to be signed with
*/
def privateKeySeqWithRequiredSigs: Gen[(Seq[ECPrivateKey], Int)] = for {
num <- Gen.choose(0, 15)
keysAndRequiredSigs <- privateKeySeqWithRequiredSigs(num)
} yield keysAndRequiredSigs
* Generates a random number of private keys less than the max public keys setting in [[ScriptSettings]]
* also generates a random 'requiredSigs' number that a transaction needs to be signed with
*/
def privateKeySeqWithRequiredSigs: Gen[(Seq[ECPrivateKey], Int)] =
for {
num <- Gen.choose(0, 15)
keysAndRequiredSigs <- privateKeySeqWithRequiredSigs(num)
} yield keysAndRequiredSigs
/** A generator with 7 or less private keys -- useful for creating smaller scripts */
def smallPrivateKeySeqWithRequiredSigs: Gen[(Seq[ECPrivateKey], Int)] = for {
num <- Gen.choose(0, 7)
keysAndRequiredSigs <- privateKeySeqWithRequiredSigs(num)
} yield keysAndRequiredSigs
def smallPrivateKeySeqWithRequiredSigs: Gen[(Seq[ECPrivateKey], Int)] =
for {
num <- Gen.choose(0, 7)
keysAndRequiredSigs <- privateKeySeqWithRequiredSigs(num)
} yield keysAndRequiredSigs
/** Generates a random public key */
def publicKey: Gen[ECPublicKey] = for {
privKey <- privateKey
} yield privKey.publicKey
def publicKey: Gen[ECPublicKey] =
for {
privKey <- privateKey
} yield privKey.publicKey
/** Generates a random digital signature */
def digitalSignature: Gen[ECDigitalSignature] = for {
privKey <- privateKey
hash <- CryptoGenerators.doubleSha256Digest
} yield privKey.sign(hash)
def digitalSignature: Gen[ECDigitalSignature] =
for {
privKey <- privateKey
hash <- CryptoGenerators.doubleSha256Digest
} yield privKey.sign(hash)
def sha256Digest: Gen[Sha256Digest] = for {
hex <- StringGenerators.hexString
digest = CryptoUtil.sha256(hex)
} yield digest
def sha256Digest: Gen[Sha256Digest] =
for {
hex <- StringGenerators.hexString
digest = CryptoUtil.sha256(hex)
} yield digest
/** Generates a random [[DoubleSha256Digest]] */
def doubleSha256Digest: Gen[DoubleSha256Digest] = for {
hex <- StringGenerators.hexString
digest = CryptoUtil.doubleSHA256(hex)
} yield digest
def doubleSha256Digest: Gen[DoubleSha256Digest] =
for {
hex <- StringGenerators.hexString
digest = CryptoUtil.doubleSHA256(hex)
} yield digest
/**
* Generates a sequence of [[DoubleSha256Digest]]
* @param num the number of digets to generate
* @return
*/
def doubleSha256DigestSeq(num: Int): Gen[Seq[DoubleSha256Digest]] = Gen.listOfN(num, doubleSha256Digest)
* Generates a sequence of [[DoubleSha256Digest]]
* @param num the number of digets to generate
* @return
*/
def doubleSha256DigestSeq(num: Int): Gen[Seq[DoubleSha256Digest]] =
Gen.listOfN(num, doubleSha256Digest)
/** Generates a random [[org.bitcoins.core.crypto.Sha256Hash160Digest]] */
def sha256Hash160Digest: Gen[Sha256Hash160Digest] = for {
pubKey <- publicKey
hash = CryptoUtil.sha256Hash160(pubKey.bytes)
} yield hash
def sha256Hash160Digest: Gen[Sha256Hash160Digest] =
for {
pubKey <- publicKey
hash = CryptoUtil.sha256Hash160(pubKey.bytes)
} yield hash
/** Generates a random [[HashType]] */
def hashType: Gen[HashType] = Gen.oneOf(HashType.sigHashAll, HashType.sigHashNone, HashType.sigHashSingle,
HashType.sigHashAnyoneCanPay, HashType.sigHashSingleAnyoneCanPay, HashType.sigHashNoneAnyoneCanPay,
HashType.sigHashAllAnyoneCanPay)
def hashType: Gen[HashType] =
Gen.oneOf(
HashType.sigHashAll,
HashType.sigHashNone,
HashType.sigHashSingle,
HashType.sigHashAnyoneCanPay,
HashType.sigHashSingleAnyoneCanPay,
HashType.sigHashNoneAnyoneCanPay,
HashType.sigHashAllAnyoneCanPay
)
def extVersion: Gen[ExtKeyVersion] = Gen.oneOf(MainNetPriv, MainNetPub, TestNet3Priv, TestNet3Pub)
def extVersion: Gen[ExtKeyVersion] =
Gen.oneOf(MainNetPriv, MainNetPub, TestNet3Priv, TestNet3Pub)
/** Generates an [[org.bitcoins.core.crypto.ExtPrivateKey]] */
def extPrivateKey: Gen[ExtPrivateKey] = for {
version <- Gen.oneOf(MainNetPriv, TestNet3Priv)
ext = ExtPrivateKey(version)
} yield ext
def extPrivateKey: Gen[ExtPrivateKey] =
for {
version <- Gen.oneOf(MainNetPriv, TestNet3Priv)
ext = ExtPrivateKey(version)
} yield ext
def extPublicKey: Gen[ExtPublicKey] = extPrivateKey.map(_.extPublicKey)
@ -106,4 +124,4 @@ sealed abstract class CryptoGenerators {
}
object CryptoGenerators extends CryptoGenerators
object CryptoGenerators extends CryptoGenerators

View file

@ -1,34 +1,42 @@
package org.bitcoins.core.gen
import org.bitcoins.core.currency.{ Bitcoins, CurrencyUnit, CurrencyUnits, Satoshis }
import org.bitcoins.core.currency.{
Bitcoins,
CurrencyUnit,
CurrencyUnits,
Satoshis
}
import org.bitcoins.core.number.Int64
import org.scalacheck.Gen
/**
* Created by chris on 6/23/16.
*/
* Created by chris on 6/23/16.
*/
trait CurrencyUnitGenerator {
def satoshis: Gen[Satoshis] = for {
int64 <- NumberGenerator.int64s
} yield Satoshis(int64)
def satoshis: Gen[Satoshis] =
for {
int64 <- NumberGenerator.int64s
} yield Satoshis(int64)
def bitcoins: Gen[Bitcoins] = for {
sat <- satoshis
} yield Bitcoins(sat)
def bitcoins: Gen[Bitcoins] =
for {
sat <- satoshis
} yield Bitcoins(sat)
def currencyUnit: Gen[CurrencyUnit] = Gen.oneOf(satoshis, bitcoins)
def positiveSatoshis: Gen[Satoshis] = satoshis.suchThat(_ >= CurrencyUnits.zero)
def positiveSatoshis: Gen[Satoshis] =
satoshis.suchThat(_ >= CurrencyUnits.zero)
/**
* Generates a postiive satoshi value that is 'realistic'. This current 'realistic' range
* is from 0 to 1,000,000 bitcoin
*/
def positiveRealistic: Gen[Satoshis] = Gen.choose(0, Bitcoins(1000000).satoshis.toLong).map { n =>
Satoshis(Int64(n))
}
* Generates a postiive satoshi value that is 'realistic'. This current 'realistic' range
* is from 0 to 1,000,000 bitcoin
*/
def positiveRealistic: Gen[Satoshis] =
Gen.choose(0, Bitcoins(1000000).satoshis.toLong).map { n =>
Satoshis(Int64(n))
}
}
object CurrencyUnitGenerator extends CurrencyUnitGenerator

View file

@ -2,66 +2,81 @@ package org.bitcoins.core.gen
import org.bitcoins.core.bloom.BloomFilter
import org.bitcoins.core.crypto.DoubleSha256Digest
import org.bitcoins.core.protocol.blockchain.{ Block, MerkleBlock, PartialMerkleTree }
import org.bitcoins.core.protocol.blockchain.{
Block,
MerkleBlock,
PartialMerkleTree
}
import org.bitcoins.core.protocol.transaction.Transaction
import org.scalacheck.Gen
/**
* Created by chris on 8/12/16.
*/
* Created by chris on 8/12/16.
*/
abstract class MerkleGenerator {
/** Generates a merkle block with the given txs matched inside the [[PartialMerkleTree]] */
def merkleBlockWithInsertedTxIds(txs: Seq[Transaction]): Gen[(MerkleBlock, Block, Seq[DoubleSha256Digest])] = for {
block <- BlockchainElementsGenerator.block(txs)
txIds = txs.map(_.txId)
merkleBlock = MerkleBlock(block, txIds)
} yield (merkleBlock, block, txIds)
def merkleBlockWithInsertedTxIds(txs: Seq[Transaction]): Gen[
(MerkleBlock, Block, Seq[DoubleSha256Digest])] =
for {
block <- BlockchainElementsGenerator.block(txs)
txIds = txs.map(_.txId)
merkleBlock = MerkleBlock(block, txIds)
} yield (merkleBlock, block, txIds)
/** Returns a [[MerkleBlock]] including the sequence of hashes inserted in to the bloom filter */
def merkleBlockWithInsertedTxIds: Gen[(MerkleBlock, Block, Seq[DoubleSha256Digest])] = for {
//TODO: Revisit this later, I've limited this to increase test speed. If I increase this from 5 tests take a lot longer
rand <- Gen.choose(1, 5)
txs <- Gen.listOfN(rand, TransactionGenerators.transaction)
result <- merkleBlockWithInsertedTxIds(txs)
} yield result
def merkleBlockWithInsertedTxIds: Gen[
(MerkleBlock, Block, Seq[DoubleSha256Digest])] =
for {
//TODO: Revisit this later, I've limited this to increase test speed. If I increase this from 5 tests take a lot longer
rand <- Gen.choose(1, 5)
txs <- Gen.listOfN(rand, TransactionGenerators.transaction)
result <- merkleBlockWithInsertedTxIds(txs)
} yield result
/**
* Returns a [[MerkleBlock]] created with a [[org.bitcoins.core.bloom.BloomFilter]], with the block it was created from
* and the transactions that were matched inside of that block
* NOTE: Since bloom filters can produce false positives, it is possible that there will be
* matches in the parital merkle tree that SHOULD NOT be matched. Bloom filters do not guaratnee no
* false negatives.
* @return
*/
def merkleBlockCreatedWithBloomFilter: Gen[(MerkleBlock, Block, Seq[DoubleSha256Digest], BloomFilter)] = for {
block <- BlockchainElementsGenerator.block
//choose some random txs in the block to put in the bloom filter
txIds <- Gen.someOf(block.transactions.map(_.txId))
initialFilter <- BloomFilterGenerator.bloomFilter(txIds.map(_.bytes))
} yield {
val (merkleBlock, loadedFilter) = MerkleBlock(block, initialFilter)
(merkleBlock, block, txIds, loadedFilter)
}
* Returns a [[MerkleBlock]] created with a [[org.bitcoins.core.bloom.BloomFilter]], with the block it was created from
* and the transactions that were matched inside of that block
* NOTE: Since bloom filters can produce false positives, it is possible that there will be
* matches in the parital merkle tree that SHOULD NOT be matched. Bloom filters do not guaratnee no
* false negatives.
* @return
*/
def merkleBlockCreatedWithBloomFilter: Gen[
(MerkleBlock, Block, Seq[DoubleSha256Digest], BloomFilter)] =
for {
block <- BlockchainElementsGenerator.block
//choose some random txs in the block to put in the bloom filter
txIds <- Gen.someOf(block.transactions.map(_.txId))
initialFilter <- BloomFilterGenerator.bloomFilter(txIds.map(_.bytes))
} yield {
val (merkleBlock, loadedFilter) = MerkleBlock(block, initialFilter)
(merkleBlock, block, txIds, loadedFilter)
}
/** Generates a partial merkle tree with a sequence of txids and a flag indicating if the txid was matched */
def partialMerkleTree: Gen[(PartialMerkleTree, Seq[(Boolean, DoubleSha256Digest)])] = for {
randomNum <- Gen.choose(1, 25)
txMatches <- txIdsWithMatchIndication(randomNum)
} yield (PartialMerkleTree(txMatches), txMatches)
def partialMerkleTree: Gen[
(PartialMerkleTree, Seq[(Boolean, DoubleSha256Digest)])] =
for {
randomNum <- Gen.choose(1, 25)
txMatches <- txIdsWithMatchIndication(randomNum)
} yield (PartialMerkleTree(txMatches), txMatches)
/**
* Generates a transaction ids with a boolean indicator if they match the bloom filter or not
* this is useful for testing partial merkle trees as this is how they are built.
* @return
*/
private def txIdWithMatchIndication: Gen[(Boolean, DoubleSha256Digest)] = for {
hash <- CryptoGenerators.doubleSha256Digest
bool <- Gen.choose(0, 1)
} yield (bool == 1, hash)
* Generates a transaction ids with a boolean indicator if they match the bloom filter or not
* this is useful for testing partial merkle trees as this is how they are built.
* @return
*/
private def txIdWithMatchIndication: Gen[(Boolean, DoubleSha256Digest)] =
for {
hash <- CryptoGenerators.doubleSha256Digest
bool <- Gen.choose(0, 1)
} yield (bool == 1, hash)
/** Generates a list of txids with a boolean indicator signifying if it matched the bloom filter or not */
def txIdsWithMatchIndication(num: Int): Gen[Seq[(Boolean, DoubleSha256Digest)]] = Gen.listOfN(num, txIdWithMatchIndication)
def txIdsWithMatchIndication(
num: Int): Gen[Seq[(Boolean, DoubleSha256Digest)]] =
Gen.listOfN(num, txIdWithMatchIndication)
}
object MerkleGenerator extends MerkleGenerator
object MerkleGenerator extends MerkleGenerator

View file

@ -9,8 +9,8 @@ import org.scalacheck.Gen
import scodec.bits.BitVector
/**
* Created by chris on 6/16/16.
*/
* Created by chris on 6/16/16.
*/
trait NumberGenerator {
def positiveShort: Gen[Short] = {
@ -33,37 +33,47 @@ trait NumberGenerator {
def uInt8: Gen[UInt8] = Gen.choose(0, 255).map(n => UInt8(n.toShort))
def uInt8s: Gen[Seq[UInt8]] = Gen.listOf(uInt8)
/**
* Generates a number in the range 0 <= x <= 2 ^^32 - 1
* then wraps it in a UInt32
*/
def uInt32s: Gen[UInt32] = Gen.choose(0L, (NumberUtil.pow2(32) - 1).toLong).map(UInt32(_))
* Generates a number in the range 0 <= x <= 2 ^^32 - 1
* then wraps it in a UInt32
*/
def uInt32s: Gen[UInt32] =
Gen.choose(0L, (NumberUtil.pow2(32) - 1).toLong).map(UInt32(_))
/** Chooses a BigInt in the ranges of 0 <= bigInt < 2^^64 */
def bigInts: Gen[BigInt] = Gen.chooseNum(Long.MinValue, Long.MaxValue)
.map(x => BigInt(x) + BigInt(2).pow(63))
def bigInts: Gen[BigInt] =
Gen
.chooseNum(Long.MinValue, Long.MaxValue)
.map(x => BigInt(x) + BigInt(2).pow(63))
def positiveBigInts: Gen[BigInt] = bigInts.filter(_ >= 0)
def bigIntsUInt64Range: Gen[BigInt] = positiveBigInts.filter(_ < (BigInt(1) << 64))
def bigIntsUInt64Range: Gen[BigInt] =
positiveBigInts.filter(_ < (BigInt(1) << 64))
/**
* Generates a number in the range 0 <= x < 2^^64
* then wraps it in a UInt64
*/
* Generates a number in the range 0 <= x < 2^^64
* then wraps it in a UInt64
*/
def uInt64s: Gen[UInt64] = uInt64
def uInt64: Gen[UInt64] = for {
bigInt <- bigIntsUInt64Range
} yield UInt64(bigInt)
def uInt64: Gen[UInt64] =
for {
bigInt <- bigIntsUInt64Range
} yield UInt64(bigInt)
def int32s: Gen[Int32] = Gen.choose(Int32.min.toLong, Int32.max.toLong).map(Int32(_))
def int32s: Gen[Int32] =
Gen.choose(Int32.min.toLong, Int32.max.toLong).map(Int32(_))
def int64s: Gen[Int64] = Gen.choose(Int64.min.toLong, Int64.max.toLong).map(Int64(_))
def int64s: Gen[Int64] =
Gen.choose(Int64.min.toLong, Int64.max.toLong).map(Int64(_))
def scriptNumbers: Gen[ScriptNumber] = Gen.choose(Int64.min.toLong, Int64.max.toLong).map(ScriptNumber(_))
def scriptNumbers: Gen[ScriptNumber] =
Gen.choose(Int64.min.toLong, Int64.max.toLong).map(ScriptNumber(_))
def positiveScriptNumbers: Gen[ScriptNumber] = Gen.choose(0L, Int64.max.toLong).map(ScriptNumber(_))
def positiveScriptNumbers: Gen[ScriptNumber] =
Gen.choose(0L, Int64.max.toLong).map(ScriptNumber(_))
def compactSizeUInts: Gen[CompactSizeUInt] = uInt64s.map(CompactSizeUInt(_))
@ -71,28 +81,31 @@ trait NumberGenerator {
def byte: Gen[Byte] = arbitrary[Byte]
/** Generates a 100 byte sequence */
def bytes: Gen[List[Byte]] = for {
num <- Gen.choose(0, 100)
b <- bytes(num)
} yield b
def bytes: Gen[List[Byte]] =
for {
num <- Gen.choose(0, 100)
b <- bytes(num)
} yield b
/**
* Generates the number of bytes specified by num
* @param num
* @return
*/
* Generates the number of bytes specified by num
* @param num
* @return
*/
def bytes(num: Int): Gen[List[Byte]] = Gen.listOfN(num, byte)
/** Generates a random boolean */
def bool: Gen[Boolean] = for {
num <- Gen.choose(0, 1)
} yield num == 1
def bool: Gen[Boolean] =
for {
num <- Gen.choose(0, 1)
} yield num == 1
/** Generates a bit vector */
def bitVector: Gen[BitVector] = for {
n <- Gen.choose(0, 100)
vector <- Gen.listOfN(n, bool)
} yield BitVector.bits(vector)
def bitVector: Gen[BitVector] =
for {
n <- Gen.choose(0, 100)
vector <- Gen.listOfN(n, bool)
} yield BitVector.bits(vector)
}

View file

@ -3,24 +3,25 @@ package org.bitcoins.core.gen
import org.scalacheck.Gen
/**
* Created by chris on 6/20/16.
*/
* Created by chris on 6/20/16.
*/
trait StringGenerators {
lazy val validHexChars = "0123456789abcdef".toCharArray
/**
* Generates a hex char
*
* @return
*/
def hexChar: Gen[Char] = Gen.choose(0, validHexChars.length - 1).map(validHexChars(_))
* Generates a hex char
*
* @return
*/
def hexChar: Gen[Char] =
Gen.choose(0, validHexChars.length - 1).map(validHexChars(_))
/**
* Generates a random hex string
*
* @return
*/
* Generates a random hex string
*
* @return
*/
def hexString: Gen[String] = {
val int = Gen.choose(0, 100)
val hexStringGen: Gen[List[Char]] = int.flatMap { i =>
@ -48,10 +49,11 @@ trait StringGenerators {
l.map(_.mkString)
}
def genString: Gen[String] = for {
randomNum <- Gen.choose(0, 100)
randomString <- genString(randomNum)
} yield randomString
def genString: Gen[String] =
for {
randomNum <- Gen.choose(0, 100)
randomString <- genString(randomNum)
} yield randomString
}

View file

@ -12,8 +12,8 @@ import org.bitcoins.core.wallet.EscrowTimeoutHelper
import org.scalacheck.Gen
/**
* Created by chris on 11/28/16.
*/
* Created by chris on 11/28/16.
*/
sealed abstract class WitnessGenerators extends BitcoinSLogger {
/** Generates a random [[org.bitcoins.core.protocol.script.ScriptWitness]] */
@ -40,211 +40,346 @@ sealed abstract class WitnessGenerators extends BitcoinSLogger {
}
/** Generates a [[TransactionWitness]] with the specified number of witnesses */
def transactionWitness(numWitnesses: Int): Gen[TransactionWitness] = for {
inputWitnesses <- Gen.listOfN(numWitnesses, Gen.option(scriptWitness))
} yield TransactionWitness.fromWitOpt(inputWitnesses.toVector)
def transactionWitness(numWitnesses: Int): Gen[TransactionWitness] =
for {
inputWitnesses <- Gen.listOfN(numWitnesses, Gen.option(scriptWitness))
} yield TransactionWitness.fromWitOpt(inputWitnesses.toVector)
def transactionWitness: Gen[TransactionWitness] = for {
num <- Gen.choose(1, 10)
wit <- transactionWitness(num)
} yield wit
def transactionWitness: Gen[TransactionWitness] =
for {
num <- Gen.choose(1, 10)
wit <- transactionWitness(num)
} yield wit
/** Generates a validly signed [[TransactionWitness]] */
def signedP2WPKHTransactionWitness: Gen[(TransactionWitness, WitnessTxSigComponent, Seq[ECPrivateKey])] = for {
privKey <- CryptoGenerators.privateKey
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WPKHWitnessSPKV0(privKey.publicKey)
unsignedScriptWitness = P2WPKHWitnessV0(privKey.publicKey)
unsignedWTxSigComponent = createUnsignedRawWTxSigComponent(witScriptPubKey, amount,
unsignedScriptWitness, None)
createdSig = TransactionSignatureCreator.createSig(unsignedWTxSigComponent, privKey, hashType)
scriptWitness = P2WPKHWitnessV0(privKey.publicKey, createdSig)
def signedP2WPKHTransactionWitness: Gen[
(TransactionWitness, WitnessTxSigComponent, Seq[ECPrivateKey])] =
for {
privKey <- CryptoGenerators.privateKey
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WPKHWitnessSPKV0(privKey.publicKey)
unsignedScriptWitness = P2WPKHWitnessV0(privKey.publicKey)
unsignedWTxSigComponent = createUnsignedRawWTxSigComponent(
witScriptPubKey,
amount,
unsignedScriptWitness,
None)
createdSig = TransactionSignatureCreator.createSig(
unsignedWTxSigComponent,
privKey,
hashType)
scriptWitness = P2WPKHWitnessV0(privKey.publicKey, createdSig)
} yield {
val (witness, signedWtxSigComponent) = createSignedWTxComponent(scriptWitness, unsignedWTxSigComponent)
(witness, signedWtxSigComponent, Seq(privKey))
}
} yield {
val (witness, signedWtxSigComponent) =
createSignedWTxComponent(scriptWitness, unsignedWTxSigComponent)
(witness, signedWtxSigComponent, Seq(privKey))
}
def signedP2WSHP2PKTransactionWitness: Gen[(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = for {
(scriptPubKey, privKeys) <- ScriptGenerators.p2pkScriptPubKey
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
u = createUnsignedRawWTxSigComponent(witScriptPubKey, amount,
unsignedScriptWitness, None)
createdSig = TransactionSignatureCreator.createSig(u, privKeys, hashType)
signedScriptWitness = P2WSHWitnessV0(scriptPubKey, P2PKScriptSignature(createdSig))
oldTx = u.transaction
txWitness = TransactionWitness(oldTx.witness.witnesses.updated(u.inputIndex.toInt, signedScriptWitness))
wtx = WitnessTransaction(oldTx.version, oldTx.inputs, oldTx.outputs, oldTx.lockTime, txWitness)
signedWtxSigComponent = WitnessTxSigComponentRaw(wtx, u.inputIndex, u.output, u.flags)
} yield (txWitness, signedWtxSigComponent, Seq(privKeys))
def signedP2WSHP2PKTransactionWitness: Gen[
(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] =
for {
(scriptPubKey, privKeys) <- ScriptGenerators.p2pkScriptPubKey
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
u = createUnsignedRawWTxSigComponent(witScriptPubKey,
amount,
unsignedScriptWitness,
None)
createdSig = TransactionSignatureCreator.createSig(u, privKeys, hashType)
signedScriptWitness = P2WSHWitnessV0(scriptPubKey,
P2PKScriptSignature(createdSig))
oldTx = u.transaction
txWitness = TransactionWitness(
oldTx.witness.witnesses
.updated(u.inputIndex.toInt, signedScriptWitness))
wtx = WitnessTransaction(oldTx.version,
oldTx.inputs,
oldTx.outputs,
oldTx.lockTime,
txWitness)
signedWtxSigComponent = WitnessTxSigComponentRaw(wtx,
u.inputIndex,
u.output,
u.flags)
} yield (txWitness, signedWtxSigComponent, Seq(privKeys))
def signedP2WSHP2PKHTransactionWitness: Gen[(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = for {
(scriptPubKey, privKey) <- ScriptGenerators.p2pkhScriptPubKey
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
u = createUnsignedRawWTxSigComponent(witScriptPubKey, amount, unsignedScriptWitness, None)
createdSig = TransactionSignatureCreator.createSig(u, privKey, hashType)
signedScriptWitness = P2WSHWitnessV0(scriptPubKey, P2PKHScriptSignature(createdSig, privKey.publicKey))
oldTx = u.transaction
txWitness = TransactionWitness(oldTx.witness.witnesses.updated(u.inputIndex.toInt, signedScriptWitness))
wtx = WitnessTransaction(oldTx.version, oldTx.inputs, oldTx.outputs, oldTx.lockTime, txWitness)
signedWtxSigComponent = WitnessTxSigComponentRaw(wtx, u.inputIndex, u.output, u.flags)
} yield (txWitness, signedWtxSigComponent, Seq(privKey))
def signedP2WSHP2PKHTransactionWitness: Gen[
(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] =
for {
(scriptPubKey, privKey) <- ScriptGenerators.p2pkhScriptPubKey
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
u = createUnsignedRawWTxSigComponent(witScriptPubKey,
amount,
unsignedScriptWitness,
None)
createdSig = TransactionSignatureCreator.createSig(u, privKey, hashType)
signedScriptWitness = P2WSHWitnessV0(
scriptPubKey,
P2PKHScriptSignature(createdSig, privKey.publicKey))
oldTx = u.transaction
txWitness = TransactionWitness(
oldTx.witness.witnesses
.updated(u.inputIndex.toInt, signedScriptWitness))
wtx = WitnessTransaction(oldTx.version,
oldTx.inputs,
oldTx.outputs,
oldTx.lockTime,
txWitness)
signedWtxSigComponent = WitnessTxSigComponentRaw(wtx,
u.inputIndex,
u.output,
u.flags)
} yield (txWitness, signedWtxSigComponent, Seq(privKey))
def signedP2WSHMultiSigTransactionWitness: Gen[(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = for {
(scriptPubKey, privKeys) <- ScriptGenerators.multiSigScriptPubKey
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
u = createUnsignedRawWTxSigComponent(witScriptPubKey, amount,
unsignedScriptWitness, None)
signedScriptSig = multiSigScriptSigGenHelper(privKeys, scriptPubKey, u, hashType)
signedScriptWitness = P2WSHWitnessV0(scriptPubKey, signedScriptSig)
oldTx = u.transaction
txWitness = TransactionWitness(oldTx.witness.witnesses.updated(u.inputIndex.toInt, signedScriptWitness))
wtx = WitnessTransaction(oldTx.version, oldTx.inputs, oldTx.outputs, oldTx.lockTime, txWitness)
signedWtxSigComponent = WitnessTxSigComponentRaw(wtx, u.inputIndex, u.output, u.flags)
} yield (txWitness, signedWtxSigComponent, privKeys)
def signedP2WSHMultiSigTransactionWitness: Gen[
(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] =
for {
(scriptPubKey, privKeys) <- ScriptGenerators.multiSigScriptPubKey
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
u = createUnsignedRawWTxSigComponent(witScriptPubKey,
amount,
unsignedScriptWitness,
None)
signedScriptSig = multiSigScriptSigGenHelper(privKeys,
scriptPubKey,
u,
hashType)
signedScriptWitness = P2WSHWitnessV0(scriptPubKey, signedScriptSig)
oldTx = u.transaction
txWitness = TransactionWitness(
oldTx.witness.witnesses
.updated(u.inputIndex.toInt, signedScriptWitness))
wtx = WitnessTransaction(oldTx.version,
oldTx.inputs,
oldTx.outputs,
oldTx.lockTime,
txWitness)
signedWtxSigComponent = WitnessTxSigComponentRaw(wtx,
u.inputIndex,
u.output,
u.flags)
} yield (txWitness, signedWtxSigComponent, privKeys)
/**
* Generates a random signed [[TransactionWitness]] with the corresponding [[WitnessTxSigComponent]]
* and [[ECPrivateKey]]s
*/
def signedP2WSHTransactionWitness: Gen[(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = {
Gen.oneOf(signedP2WSHP2PKTransactionWitness, signedP2WSHP2PKHTransactionWitness,
signedP2WSHMultiSigTransactionWitness, signedP2WSHEscrowTimeoutWitness)
* Generates a random signed [[TransactionWitness]] with the corresponding [[WitnessTxSigComponent]]
* and [[ECPrivateKey]]s
*/
def signedP2WSHTransactionWitness: Gen[
(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = {
Gen.oneOf(signedP2WSHP2PKTransactionWitness,
signedP2WSHP2PKHTransactionWitness,
signedP2WSHMultiSigTransactionWitness,
signedP2WSHEscrowTimeoutWitness)
}
def signedP2WSHMultiSigEscrowTimeoutWitness: Gen[(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = for {
(scriptPubKey, privKeys) <- ScriptGenerators.escrowTimeoutScriptPubKey
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
u = createUnsignedRawWTxSigComponent(witScriptPubKey, amount,
unsignedScriptWitness, None)
signedScriptSig = csvEscrowTimeoutGenHelper(privKeys, scriptPubKey, u, hashType)
witness = EscrowTimeoutHelper.buildEscrowTimeoutScriptWitness(signedScriptSig, scriptPubKey, u)
oldTx = u.transaction
wTx = WitnessTransaction(oldTx.version, oldTx.inputs, oldTx.outputs, oldTx.lockTime, witness)
signedWTxSigComponent = WitnessTxSigComponentRaw(wTx, u.inputIndex, u.output, u.flags)
} yield (witness, signedWTxSigComponent, privKeys)
def signedP2WSHMultiSigEscrowTimeoutWitness: Gen[
(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] =
for {
(scriptPubKey, privKeys) <- ScriptGenerators.escrowTimeoutScriptPubKey
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
u = createUnsignedRawWTxSigComponent(witScriptPubKey,
amount,
unsignedScriptWitness,
None)
signedScriptSig = csvEscrowTimeoutGenHelper(privKeys,
scriptPubKey,
u,
hashType)
witness = EscrowTimeoutHelper.buildEscrowTimeoutScriptWitness(
signedScriptSig,
scriptPubKey,
u)
oldTx = u.transaction
wTx = WitnessTransaction(oldTx.version,
oldTx.inputs,
oldTx.outputs,
oldTx.lockTime,
witness)
signedWTxSigComponent = WitnessTxSigComponentRaw(wTx,
u.inputIndex,
u.output,
u.flags)
} yield (witness, signedWTxSigComponent, privKeys)
def spendableP2WSHTimeoutEscrowTimeoutWitness: Gen[(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = for {
(p2pkh, privKey) <- ScriptGenerators.p2pkhScriptPubKey
(scriptNum, sequence) <- TransactionGenerators.spendableCSVValues
csv = CSVScriptPubKey(scriptNum, p2pkh)
(m, _) <- ScriptGenerators.smallMultiSigScriptPubKey
scriptPubKey = EscrowTimeoutScriptPubKey(m, csv)
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
u = createUnsignedRawWTxSigComponent(
witScriptPubKey,
amount, unsignedScriptWitness, Some(sequence))
createdSig = TransactionSignatureCreator.createSig(u, privKey, hashType)
scriptSig = CSVScriptSignature(P2PKHScriptSignature(createdSig, privKey.publicKey))
signedScriptWitness = P2WSHWitnessV0(scriptPubKey, EscrowTimeoutScriptSignature.fromLockTime(scriptSig))
//ScriptWitness(scriptPubKey.asm.flatMap(_.bytes) +: Seq(ScriptNumber.zero.bytes, privKey.publicKey.bytes,
//createdSig.bytes))
oldTx = u.transaction
txWitness = TransactionWitness(oldTx.witness.witnesses.updated(u.inputIndex.toInt, signedScriptWitness))
wtx = WitnessTransaction(oldTx.version, oldTx.inputs, oldTx.outputs, oldTx.lockTime, txWitness)
signedWtxSigComponent = WitnessTxSigComponentRaw(wtx, u.inputIndex, u.output, u.flags)
} yield (txWitness, signedWtxSigComponent, Seq(privKey))
def spendableP2WSHTimeoutEscrowTimeoutWitness: Gen[
(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] =
for {
(p2pkh, privKey) <- ScriptGenerators.p2pkhScriptPubKey
(scriptNum, sequence) <- TransactionGenerators.spendableCSVValues
csv = CSVScriptPubKey(scriptNum, p2pkh)
(m, _) <- ScriptGenerators.smallMultiSigScriptPubKey
scriptPubKey = EscrowTimeoutScriptPubKey(m, csv)
amount <- CurrencyUnitGenerator.satoshis
hashType <- CryptoGenerators.hashType
witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey)
unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey)
u = createUnsignedRawWTxSigComponent(witScriptPubKey,
amount,
unsignedScriptWitness,
Some(sequence))
createdSig = TransactionSignatureCreator.createSig(u, privKey, hashType)
scriptSig = CSVScriptSignature(
P2PKHScriptSignature(createdSig, privKey.publicKey))
signedScriptWitness = P2WSHWitnessV0(
scriptPubKey,
EscrowTimeoutScriptSignature.fromLockTime(scriptSig))
//ScriptWitness(scriptPubKey.asm.flatMap(_.bytes) +: Seq(ScriptNumber.zero.bytes, privKey.publicKey.bytes,
//createdSig.bytes))
oldTx = u.transaction
txWitness = TransactionWitness(
oldTx.witness.witnesses
.updated(u.inputIndex.toInt, signedScriptWitness))
wtx = WitnessTransaction(oldTx.version,
oldTx.inputs,
oldTx.outputs,
oldTx.lockTime,
txWitness)
signedWtxSigComponent = WitnessTxSigComponentRaw(wtx,
u.inputIndex,
u.output,
u.flags)
} yield (txWitness, signedWtxSigComponent, Seq(privKey))
def signedP2WSHEscrowTimeoutWitness: Gen[(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = {
Gen.oneOf(signedP2WSHMultiSigEscrowTimeoutWitness, spendableP2WSHTimeoutEscrowTimeoutWitness)
def signedP2WSHEscrowTimeoutWitness: Gen[
(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = {
Gen.oneOf(signedP2WSHMultiSigEscrowTimeoutWitness,
spendableP2WSHTimeoutEscrowTimeoutWitness)
}
/** Helps generate a signed [[MultiSignatureScriptSignature]] */
private def multiSigScriptSigGenHelper(
privateKeys: Seq[ECPrivateKey],
scriptPubKey: MultiSignatureScriptPubKey,
unsignedWtxSigComponent: WitnessTxSigComponent,
hashType: HashType): MultiSignatureScriptSignature = {
privateKeys: Seq[ECPrivateKey],
scriptPubKey: MultiSignatureScriptPubKey,
unsignedWtxSigComponent: WitnessTxSigComponent,
hashType: HashType): MultiSignatureScriptSignature = {
val requiredSigs = scriptPubKey.requiredSigs
val txSignatures = for {
i <- 0 until requiredSigs
} yield TransactionSignatureCreator.createSig(unsignedWtxSigComponent, privateKeys(i), hashType)
} yield
TransactionSignatureCreator.createSig(unsignedWtxSigComponent,
privateKeys(i),
hashType)
//add the signature to the scriptSig instead of having an empty scriptSig
val signedScriptSig = MultiSignatureScriptSignature(txSignatures)
signedScriptSig
}
def csvEscrowTimeoutGenHelper(privateKeys: Seq[ECPrivateKey], scriptPubKey: EscrowTimeoutScriptPubKey,
unsignedWtxSigComponent: WitnessTxSigComponent,
hashType: HashType): EscrowTimeoutScriptSignature = {
def csvEscrowTimeoutGenHelper(
privateKeys: Seq[ECPrivateKey],
scriptPubKey: EscrowTimeoutScriptPubKey,
unsignedWtxSigComponent: WitnessTxSigComponent,
hashType: HashType): EscrowTimeoutScriptSignature = {
if (scriptPubKey.escrow.requiredSigs == 0) {
EscrowTimeoutScriptSignature.fromMultiSig(MultiSignatureScriptSignature(Nil))
EscrowTimeoutScriptSignature.fromMultiSig(
MultiSignatureScriptSignature(Nil))
} else if (privateKeys.size == 1) {
val signature = csvEscrowTimeoutGenSignature(privateKeys.head, unsignedWtxSigComponent, hashType)
EscrowTimeoutScriptSignature.fromMultiSig(MultiSignatureScriptSignature(Seq(signature)))
val signature = csvEscrowTimeoutGenSignature(privateKeys.head,
unsignedWtxSigComponent,
hashType)
EscrowTimeoutScriptSignature.fromMultiSig(
MultiSignatureScriptSignature(Seq(signature)))
} else {
val multiSig = multiSigScriptSigGenHelper(privateKeys, scriptPubKey.escrow, unsignedWtxSigComponent, hashType)
val multiSig = multiSigScriptSigGenHelper(privateKeys,
scriptPubKey.escrow,
unsignedWtxSigComponent,
hashType)
EscrowTimeoutScriptSignature.fromMultiSig(multiSig)
}
}
def csvEscrowTimeoutGenSignature(
privKey: ECPrivateKey,
unsignedWtxSigComponent: WitnessTxSigComponent, hashType: HashType): ECDigitalSignature = {
privKey: ECPrivateKey,
unsignedWtxSigComponent: WitnessTxSigComponent,
hashType: HashType): ECDigitalSignature = {
val signature = TransactionSignatureCreator.createSig(unsignedWtxSigComponent, privKey, hashType)
val signature = TransactionSignatureCreator.createSig(
unsignedWtxSigComponent,
privKey,
hashType)
signature
}
/** Generates a random [[org.bitcoins.core.protocol.script.P2WPKHWitnessV0]] */
def p2wpkhWitnessV0: Gen[P2WPKHWitnessV0] = for {
publicKey <- CryptoGenerators.publicKey
sig <- CryptoGenerators.digitalSignature
} yield P2WPKHWitnessV0(publicKey, sig)
def p2wpkhWitnessV0: Gen[P2WPKHWitnessV0] =
for {
publicKey <- CryptoGenerators.publicKey
sig <- CryptoGenerators.digitalSignature
} yield P2WPKHWitnessV0(publicKey, sig)
/** Generates a random [[org.bitcoins.core.protocol.script.P2WSHWitnessV0]] */
def p2wshWitnessV0: Gen[P2WSHWitnessV0] = for {
(redeem, _) <- ScriptGenerators.scriptPubKey
scriptSig <- ScriptGenerators.scriptSignature
} yield P2WSHWitnessV0(redeem, scriptSig)
def p2wshWitnessV0: Gen[P2WSHWitnessV0] =
for {
(redeem, _) <- ScriptGenerators.scriptPubKey
scriptSig <- ScriptGenerators.scriptSignature
} yield P2WSHWitnessV0(redeem, scriptSig)
/** Takes a signed [[ScriptWitness]] and an unsignedTx and adds the witness to the unsigned [[WitnessTransaction]] */
def createSignedWTxComponent(witness: ScriptWitness, unsignedWTxComponent: WitnessTxSigComponent): (TransactionWitness, WitnessTxSigComponent) = {
def createSignedWTxComponent(
witness: ScriptWitness,
unsignedWTxComponent: WitnessTxSigComponent): (
TransactionWitness,
WitnessTxSigComponent) = {
val signedTxWitness = TransactionWitness.fromWitOpt(Vector(Some(witness)))
val unsignedSpendingTx = unsignedWTxComponent.transaction
val signedSpendingTx = WitnessTransaction(unsignedSpendingTx.version, unsignedSpendingTx.inputs, unsignedSpendingTx.outputs,
unsignedSpendingTx.lockTime, signedTxWitness)
val signedSpendingTx = WitnessTransaction(unsignedSpendingTx.version,
unsignedSpendingTx.inputs,
unsignedSpendingTx.outputs,
unsignedSpendingTx.lockTime,
signedTxWitness)
val signedWtxSigComponent = unsignedWTxComponent match {
case wtxP2SH: WitnessTxSigComponentP2SH =>
WitnessTxSigComponent(signedSpendingTx, unsignedWTxComponent.inputIndex,
wtxP2SH.output, unsignedWTxComponent.flags)
WitnessTxSigComponent(signedSpendingTx,
unsignedWTxComponent.inputIndex,
wtxP2SH.output,
unsignedWTxComponent.flags)
case wtxRaw: WitnessTxSigComponentRaw =>
WitnessTxSigComponent(signedSpendingTx, unsignedWTxComponent.inputIndex,
wtxRaw.output, unsignedWTxComponent.flags)
WitnessTxSigComponent(signedSpendingTx,
unsignedWTxComponent.inputIndex,
wtxRaw.output,
unsignedWTxComponent.flags)
}
(signedTxWitness, signedWtxSigComponent)
}
/** Creates a unsigned [[WitnessTxSigComponent]] from the given parameters */
def createUnsignedRawWTxSigComponent(witScriptPubKey: WitnessScriptPubKey, amount: CurrencyUnit,
unsignedScriptWitness: ScriptWitness, sequence: Option[UInt32]): WitnessTxSigComponentRaw = {
def createUnsignedRawWTxSigComponent(
witScriptPubKey: WitnessScriptPubKey,
amount: CurrencyUnit,
unsignedScriptWitness: ScriptWitness,
sequence: Option[UInt32]): WitnessTxSigComponentRaw = {
val tc = TransactionConstants
val flags = Policy.standardScriptVerifyFlags
val witness = TransactionWitness.fromWitOpt(Vector(Some(unsignedScriptWitness)))
val (creditingTx, outputIndex) = TransactionGenerators.buildCreditingTransaction(witScriptPubKey, amount)
val (unsignedSpendingTx, inputIndex) = TransactionGenerators.buildSpendingTransaction(tc.validLockVersion, creditingTx,
EmptyScriptSignature, outputIndex, tc.lockTime,
sequence.getOrElse(tc.sequence), witness)
val witness =
TransactionWitness.fromWitOpt(Vector(Some(unsignedScriptWitness)))
val (creditingTx, outputIndex) =
TransactionGenerators.buildCreditingTransaction(witScriptPubKey, amount)
val (unsignedSpendingTx, inputIndex) =
TransactionGenerators.buildSpendingTransaction(
tc.validLockVersion,
creditingTx,
EmptyScriptSignature,
outputIndex,
tc.lockTime,
sequence.getOrElse(tc.sequence),
witness)
val output = creditingTx.outputs(outputIndex.toInt)
val unsignedWtxSigComponent = WitnessTxSigComponentRaw(unsignedSpendingTx, inputIndex, output, flags)
val unsignedWtxSigComponent =
WitnessTxSigComponentRaw(unsignedSpendingTx, inputIndex, output, flags)
unsignedWtxSigComponent
}
}

View file

@ -7,27 +7,32 @@ import org.scalacheck.Gen
trait LnCurrencyUnitGen {
def milliBitcoin: Gen[MilliBitcoins] = for {
amount <- Gen.choose(MilliBitcoins.min.toLong, MilliBitcoins.max.toLong)
} yield MilliBitcoins(amount)
def milliBitcoin: Gen[MilliBitcoins] =
for {
amount <- Gen.choose(MilliBitcoins.min.toLong, MilliBitcoins.max.toLong)
} yield MilliBitcoins(amount)
def microBitcoin: Gen[MicroBitcoins] = for {
amount <- Gen.choose(MicroBitcoins.min.toLong, MicroBitcoins.max.toLong)
} yield MicroBitcoins(amount)
def microBitcoin: Gen[MicroBitcoins] =
for {
amount <- Gen.choose(MicroBitcoins.min.toLong, MicroBitcoins.max.toLong)
} yield MicroBitcoins(amount)
def nanoBitcoin: Gen[NanoBitcoins] = for {
amount <- Gen.choose(NanoBitcoins.min.toLong, NanoBitcoins.max.toLong)
} yield NanoBitcoins(amount)
def nanoBitcoin: Gen[NanoBitcoins] =
for {
amount <- Gen.choose(NanoBitcoins.min.toLong, NanoBitcoins.max.toLong)
} yield NanoBitcoins(amount)
def picoBitcoin: Gen[PicoBitcoins] = for {
amount <- Gen.choose(PicoBitcoins.min.toLong, PicoBitcoins.max.toLong)
} yield PicoBitcoins(amount)
def picoBitcoin: Gen[PicoBitcoins] =
for {
amount <- Gen.choose(PicoBitcoins.min.toLong, PicoBitcoins.max.toLong)
} yield PicoBitcoins(amount)
def positivePicoBitcoin: Gen[PicoBitcoins] = {
Gen.choose(0, PicoBitcoins.max.toLong).map(PicoBitcoins(_))
}
def lnCurrencyUnit: Gen[LnCurrencyUnit] = Gen.oneOf(milliBitcoin, microBitcoin, nanoBitcoin, picoBitcoin)
def lnCurrencyUnit: Gen[LnCurrencyUnit] =
Gen.oneOf(milliBitcoin, microBitcoin, nanoBitcoin, picoBitcoin)
def lnCurrencyUnitOpt: Gen[Option[LnCurrencyUnit]] = {
Gen.option(lnCurrencyUnit)
@ -45,9 +50,10 @@ trait LnCurrencyUnitGen {
lnCurrencyUnit.suchThat(_ < LnCurrencyUnits.zero)
}
def milliSatoshis: Gen[MilliSatoshis] = for {
i64 <- NumberGenerator.uInt64
} yield MilliSatoshis(i64.toBigInt)
def milliSatoshis: Gen[MilliSatoshis] =
for {
i64 <- NumberGenerator.uInt64
} yield MilliSatoshis(i64.toBigInt)
}
object LnCurrencyUnitGen extends LnCurrencyUnitGen
object LnCurrencyUnitGen extends LnCurrencyUnitGen

View file

@ -12,27 +12,25 @@ import org.scalacheck.Gen
sealed abstract class LnInvoiceGen {
/**
* Generates a [[org.bitcoins.core.protocol.ln.LnHumanReadablePart]]
* that does not contain a amount
* @return
*/
* Generates a [[org.bitcoins.core.protocol.ln.LnHumanReadablePart]]
* that does not contain a amount
* @return
*/
def lnHrpNoAmt: Gen[LnHumanReadablePart] = {
ChainParamsGenerator.lnNetworkParams.flatMap {
lnParam =>
LnHumanReadablePart.fromLnParams(lnParam)
ChainParamsGenerator.lnNetworkParams.flatMap { lnParam =>
LnHumanReadablePart.fromLnParams(lnParam)
}
}
/**
* Generates a [[org.bitcoins.core.protocol.ln.LnHumanReadablePart]]
* with an amount encoded
*/
* Generates a [[org.bitcoins.core.protocol.ln.LnHumanReadablePart]]
* with an amount encoded
*/
def lnHrpAmt: Gen[LnHumanReadablePart] = {
ChainParamsGenerator.lnNetworkParams.flatMap { lnParam =>
LnCurrencyUnitGen.realisticLnInvoice.map { lcu =>
LnHumanReadablePart.fromParamsAmount(
network = lnParam,
amount = Some(lcu))
LnHumanReadablePart.fromParamsAmount(network = lnParam,
amount = Some(lcu))
}
}
}
@ -41,7 +39,6 @@ sealed abstract class LnInvoiceGen {
Gen.oneOf(lnHrpAmt, lnHrpNoAmt)
}
def nodeId: Gen[NodeId] = {
CryptoGenerators.publicKey.map(NodeId(_))
}
@ -64,7 +61,8 @@ sealed abstract class LnInvoiceGen {
}
}
def descriptionOrDescriptionHashTag: Gen[Either[LnTag.DescriptionTag, LnTag.DescriptionHashTag]] = {
def descriptionOrDescriptionHashTag: Gen[
Either[LnTag.DescriptionTag, LnTag.DescriptionHashTag]] = {
if (scala.util.Random.nextBoolean()) {
descriptionTag.map(Left(_))
} else {
@ -102,59 +100,61 @@ sealed abstract class LnInvoiceGen {
/** Generated a tagged fields with an explicit [[LnTag.NodeIdTag]]
* */
def taggedFields(nodeIdOpt: Option[NodeId]): Gen[LnTaggedFields] = for {
paymentHash <- paymentHashTag
descOrHashTag <- descriptionOrDescriptionHashTag
def taggedFields(nodeIdOpt: Option[NodeId]): Gen[LnTaggedFields] =
for {
paymentHash <- paymentHashTag
descOrHashTag <- descriptionOrDescriptionHashTag
//optional fields
expiryTime <- Gen.option(expiryTime)
cltvExpiry <- Gen.option(cltvExpiry)
fallbackAddress <- Gen.option(fallbackAddress)
routes <- Gen.option(routingInfo)
} yield LnTaggedFields(
paymentHash = paymentHash,
descriptionOrHash = descOrHashTag,
expiryTime = expiryTime,
cltvExpiry = cltvExpiry,
fallbackAddress = fallbackAddress,
nodeId = nodeIdOpt.map(NodeIdTag(_)),
routingInfo = routes)
//optional fields
expiryTime <- Gen.option(expiryTime)
cltvExpiry <- Gen.option(cltvExpiry)
fallbackAddress <- Gen.option(fallbackAddress)
routes <- Gen.option(routingInfo)
} yield
LnTaggedFields(
paymentHash = paymentHash,
descriptionOrHash = descOrHashTag,
expiryTime = expiryTime,
cltvExpiry = cltvExpiry,
fallbackAddress = fallbackAddress,
nodeId = nodeIdOpt.map(NodeIdTag(_)),
routingInfo = routes
)
def signatureVersion: Gen[UInt8] = {
Gen.choose(0, 3).map(UInt8(_))
}
def lnInvoiceSignature: Gen[LnInvoiceSignature] = for {
sig <- CryptoGenerators.digitalSignature
version <- signatureVersion
} yield LnInvoiceSignature(version, sig)
def lnInvoiceSignature: Gen[LnInvoiceSignature] =
for {
sig <- CryptoGenerators.digitalSignature
version <- signatureVersion
} yield LnInvoiceSignature(version, sig)
def invoiceTimestamp: Gen[UInt64] = {
Gen.choose(0, LnInvoice.MAX_TIMESTAMP_U64.toLong).map(UInt64(_))
}
def lnInvoice(privateKey: ECPrivateKey): Gen[LnInvoice] = for {
hrp <- lnHrp
//timestamp is 35 bits according to BOLT11
timestamp <- invoiceTimestamp
nodeIdOpt <- Gen.option(NodeId(privateKey.publicKey))
tags <- taggedFields(nodeIdOpt)
} yield {
val signature = LnInvoice.buildLnInvoiceSignature(
hrp = hrp,
timestamp = timestamp,
lnTags = tags,
privateKey = privateKey
)
LnInvoice(
hrp = hrp,
timestamp = timestamp,
lnTags = tags,
signature = signature)
}
def lnInvoice(privateKey: ECPrivateKey): Gen[LnInvoice] =
for {
hrp <- lnHrp
//timestamp is 35 bits according to BOLT11
timestamp <- invoiceTimestamp
nodeIdOpt <- Gen.option(NodeId(privateKey.publicKey))
tags <- taggedFields(nodeIdOpt)
} yield {
val signature = LnInvoice.buildLnInvoiceSignature(
hrp = hrp,
timestamp = timestamp,
lnTags = tags,
privateKey = privateKey
)
LnInvoice(hrp = hrp,
timestamp = timestamp,
lnTags = tags,
signature = signature)
}
def lnInvoice: Gen[LnInvoice] = {
CryptoGenerators.privateKey.flatMap { p =>

View file

@ -1,49 +1,57 @@
package org.bitcoins.core.gen.ln
import org.bitcoins.core.gen.{ CryptoGenerators, NumberGenerator }
import org.bitcoins.core.gen.{CryptoGenerators, NumberGenerator}
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.ln.ShortChannelId
import org.bitcoins.core.protocol.ln.currency.MilliSatoshis
import org.bitcoins.core.protocol.ln.fee.{ FeeBaseMSat, FeeProportionalMillionths }
import org.bitcoins.core.protocol.ln.fee.{
FeeBaseMSat,
FeeProportionalMillionths
}
import org.bitcoins.core.protocol.ln.routing.LnRoute
import org.scalacheck.Gen
trait LnRouteGen {
def shortChannelId: Gen[ShortChannelId] = {
NumberGenerator.uInt64s.map { u64 =>
ShortChannelId(u64)
}
}
def feeBaseMSat: Gen[FeeBaseMSat] = for {
//note that the feebase msat is only 4 bytes
u32 <- NumberGenerator.uInt32s
} yield {
val ms = MilliSatoshis(u32.toBigInt)
FeeBaseMSat(ms)
}
def feeBaseMSat: Gen[FeeBaseMSat] =
for {
//note that the feebase msat is only 4 bytes
u32 <- NumberGenerator.uInt32s
} yield {
val ms = MilliSatoshis(u32.toBigInt)
FeeBaseMSat(ms)
}
def feeProportionalMillionths: Gen[FeeProportionalMillionths] = for {
fee <- NumberGenerator.uInt32s
} yield FeeProportionalMillionths(fee)
def feeProportionalMillionths: Gen[FeeProportionalMillionths] =
for {
fee <- NumberGenerator.uInt32s
} yield FeeProportionalMillionths(fee)
def route: Gen[LnRoute] = for {
pubKey <- CryptoGenerators.publicKey
id <- shortChannelId
baseFee <- feeBaseMSat
feeProp <- feeProportionalMillionths
cltvExpiryDelta <- NumberGenerator.positiveShort
} yield LnRoute(
pubkey = pubKey,
shortChannelID = id,
feeBaseMsat = baseFee,
feePropMilli = feeProp,
cltvExpiryDelta = cltvExpiryDelta)
def route: Gen[LnRoute] =
for {
pubKey <- CryptoGenerators.publicKey
id <- shortChannelId
baseFee <- feeBaseMSat
feeProp <- feeProportionalMillionths
cltvExpiryDelta <- NumberGenerator.positiveShort
} yield
LnRoute(pubkey = pubKey,
shortChannelID = id,
feeBaseMsat = baseFee,
feePropMilli = feeProp,
cltvExpiryDelta = cltvExpiryDelta)
def routes: Gen[Vector[LnRoute]] = {
Gen.choose(1, 5)
Gen
.choose(1, 5)
.flatMap(n => Gen.listOfN(n, route).map(_.toVector))
}
}
object LnRouteGen extends LnRouteGen
object LnRouteGen extends LnRouteGen

View file

@ -1,11 +1,12 @@
name := "bitcoin-s-core-test"
libraryDependencies ++= Deps.coreTest
publishArtifact := false
testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-verbosity", "2")
testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck,
"-verbosity",
"2")
coverageExcludedPackages := ".*gen"

View file

@ -1,20 +1,21 @@
package org.bitcoins.core.bloom
import org.bitcoins.core.gen.BloomFilterGenerator
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
import scodec.bits.ByteVector
/**
* Created by chris on 8/3/16.
*/
* Created by chris on 8/3/16.
*/
class BloomFilterSpec extends Properties("BloomFilterSpec") {
property("No false negatives && serialization symmetry") =
Prop.forAll(BloomFilterGenerator.loadedBloomFilter) {
case (loadedFilter: BloomFilter, byteVectors: Seq[ByteVector]) =>
val containsAllHashes = byteVectors.map(bytes => loadedFilter.contains(bytes))
val containsAllHashes =
byteVectors.map(bytes => loadedFilter.contains(bytes))
!containsAllHashes.exists(_ == false) &&
BloomFilter(loadedFilter.hex) == loadedFilter
BloomFilter(loadedFilter.hex) == loadedFilter
}
}

File diff suppressed because one or more lines are too long

View file

@ -1,20 +1,21 @@
package org.bitcoins.core.channels
import org.bitcoins.core.crypto.ECPrivateKey
import org.bitcoins.core.currency.{ CurrencyUnits, Satoshis }
import org.bitcoins.core.currency.{CurrencyUnits, Satoshis}
import org.bitcoins.core.gen.ScriptGenerators
import org.bitcoins.core.number.Int64
import org.bitcoins.core.policy.Policy
import org.bitcoins.core.protocol.script.{ P2SHScriptPubKey, P2WSHWitnessSPKV0 }
import org.bitcoins.core.protocol.script.{P2SHScriptPubKey, P2WSHWitnessSPKV0}
import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.util.BitcoinSLogger
import org.scalatest.{ Assertion, AsyncFlatSpec, MustMatchers }
import org.scalatest.{Assertion, AsyncFlatSpec, MustMatchers}
import scala.concurrent.Future
import scala.concurrent.duration.DurationInt
/**
* Created by chris on 5/31/17.
*/
* Created by chris on 5/31/17.
*/
class ChannelTest extends AsyncFlatSpec with MustMatchers {
private val logger = BitcoinSLogger.logger
val timeout = 5.seconds
@ -23,7 +24,10 @@ class ChannelTest extends AsyncFlatSpec with MustMatchers {
val p2sh = P2SHScriptPubKey(lock)
val amount = Policy.minChannelAmount - Satoshis.one
val output = TransactionOutput(amount, p2sh)
val tx = BaseTransaction(TransactionConstants.version, Nil, Seq(output), TransactionConstants.lockTime)
val tx = BaseTransaction(TransactionConstants.version,
Nil,
Seq(output),
TransactionConstants.lockTime)
val chan = ChannelAwaitingAnchorTx(tx, lock)
chan.isFailure must be(true)
}
@ -34,13 +38,19 @@ class ChannelTest extends AsyncFlatSpec with MustMatchers {
val p2sh = P2SHScriptPubKey(randomScript)
val amount = Policy.minChannelAmount
val output = TransactionOutput(amount, p2sh)
val tx = BaseTransaction(TransactionConstants.version, Nil, Seq(output), TransactionConstants.lockTime)
val tx = BaseTransaction(TransactionConstants.version,
Nil,
Seq(output),
TransactionConstants.lockTime)
val chan = ChannelAwaitingAnchorTx(tx, lock)
chan.isFailure must be(true)
//it must also fail if we do not have a p2sh output at all
val output2 = TransactionOutput(amount, randomScript)
val tx2 = BaseTransaction(TransactionConstants.version, Nil, Seq(output2), TransactionConstants.lockTime)
val tx2 = BaseTransaction(TransactionConstants.version,
Nil,
Seq(output2),
TransactionConstants.lockTime)
val chan2 = ChannelAwaitingAnchorTx(tx2, lock)
chan2.isFailure must be(true)
}
@ -75,12 +85,16 @@ class ChannelTest extends AsyncFlatSpec with MustMatchers {
val p2wsh = P2WSHWitnessSPKV0(lock)
val amount = CurrencyUnits.oneBTC
val output = TransactionOutput(amount, p2wsh)
val tx = BaseTransaction(TransactionConstants.version, Nil, Seq(output), TransactionConstants.lockTime)
val tx = BaseTransaction(TransactionConstants.version,
Nil,
Seq(output),
TransactionConstants.lockTime)
val chan = ChannelAwaitingAnchorTx(tx, lock, Policy.confirmations)
chan.isSuccess must be(true)
val inProgress = chan.get.clientSign(clientSPK, amount, keys.head)
val f: Future[Assertion] = inProgress.flatMap { _ =>
val closed = inProgress.flatMap(_.close(serverSPK, keys(1), CurrencyUnits.zero))
val closed =
inProgress.flatMap(_.close(serverSPK, keys(1), CurrencyUnits.zero))
closed.map { c =>
assert(c.serverAmount.get == amount)
}
@ -96,12 +110,18 @@ class ChannelTest extends AsyncFlatSpec with MustMatchers {
val p2wsh = P2WSHWitnessSPKV0(lock)
val amount = CurrencyUnits.oneBTC * Satoshis(Int64(2))
val output = TransactionOutput(amount, p2wsh)
val tx = BaseTransaction(TransactionConstants.version, Nil, Seq(output), TransactionConstants.lockTime)
val tx = BaseTransaction(TransactionConstants.version,
Nil,
Seq(output),
TransactionConstants.lockTime)
val chan = ChannelAwaitingAnchorTx(tx, lock, Policy.confirmations)
val inProgress = chan.get.clientSign(clientSPK, CurrencyUnits.oneBTC, keys.head)
val inProgress =
chan.get.clientSign(clientSPK, CurrencyUnits.oneBTC, keys.head)
val serverSign = inProgress.flatMap(_.serverSign(keys(1)))
val inProgress2 = serverSign.flatMap(_.clientSign(CurrencyUnits.oneBTC, keys.head))
val closed = inProgress2.flatMap(_.close(serverSPK, keys(1), CurrencyUnits.zero))
val inProgress2 =
serverSign.flatMap(_.clientSign(CurrencyUnits.oneBTC, keys.head))
val closed =
inProgress2.flatMap(_.close(serverSPK, keys(1), CurrencyUnits.zero))
closed.map { c =>
assert(c.serverAmount.get == amount)
}
@ -114,11 +134,15 @@ class ChannelTest extends AsyncFlatSpec with MustMatchers {
val p2wsh = P2WSHWitnessSPKV0(lock)
val amount = CurrencyUnits.oneBTC
val output = TransactionOutput(amount, p2wsh)
val tx = BaseTransaction(TransactionConstants.version, Nil, Seq(output), TransactionConstants.lockTime)
val tx = BaseTransaction(TransactionConstants.version,
Nil,
Seq(output),
TransactionConstants.lockTime)
val chan = ChannelAwaitingAnchorTx(tx, lock, Policy.confirmations)
val inProgress = chan.get.clientSign(clientSPK, amount, keys.head)
//Note the fee here, we try and spend too much money
val closed = inProgress.flatMap(_.close(serverSPK, keys(1), CurrencyUnits.oneBTC + Satoshis.one))
val closed = inProgress.flatMap(
_.close(serverSPK, keys(1), CurrencyUnits.oneBTC + Satoshis.one))
recoverToSucceededIf[IllegalArgumentException](closed)
}

View file

@ -1,8 +1,8 @@
package org.bitcoins.core.channels
import org.bitcoins.core.crypto.TxSigComponent
import org.bitcoins.core.currency.{ CurrencyUnit, Satoshis }
import org.bitcoins.core.gen.{ ChannelGenerators, ScriptGenerators }
import org.bitcoins.core.currency.{CurrencyUnit, Satoshis}
import org.bitcoins.core.gen.{ChannelGenerators, ScriptGenerators}
import org.bitcoins.core.number.Int64
import org.bitcoins.core.policy.Policy
import org.bitcoins.core.protocol.script.EmptyScriptPubKey
@ -11,20 +11,22 @@ import org.bitcoins.core.script.PreExecutionScriptProgram
import org.bitcoins.core.script.interpreter.ScriptInterpreter
import org.bitcoins.core.script.result.ScriptOk
import org.bitcoins.core.util.BitcoinSLogger
import org.scalacheck.{ Gen, Prop, Properties }
import org.scalacheck.{Gen, Prop, Properties}
import scala.annotation.tailrec
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.DurationInt
import scala.util.Try
/**
* Created by chris on 4/18/17.
*/
* Created by chris on 4/18/17.
*/
class ChannelsSpec extends Properties("ChannelProperties") {
private val logger = BitcoinSLogger.logger
val timeout = 5.seconds
property("spend a anchor transaction with the first spendingTx in a payment channel") = {
property(
"spend a anchor transaction with the first spendingTx in a payment channel") = {
Prop.forAllNoShrink(ChannelGenerators.freshChannelInProgress) {
case (inProgress, _) =>
val p = PreExecutionScriptProgram(inProgress.current)
@ -33,10 +35,15 @@ class ChannelsSpec extends Properties("ChannelProperties") {
}
}
property("fail to increment a payment channel when the values are larger than the locked output") = {
property(
"fail to increment a payment channel when the values are larger than the locked output") = {
Prop.forAllNoShrink(ChannelGenerators.freshChannelInProgress) {
case (inProgress, privKeys) =>
val inc = Try(Await.result(inProgress.clientSign(inProgress.lockedAmount + Satoshis.one, privKeys.head), timeout))
val inc = Try(
Await.result(
inProgress.clientSign(inProgress.lockedAmount + Satoshis.one,
privKeys.head),
timeout))
inc.isFailure
}
}
@ -45,24 +52,38 @@ class ChannelsSpec extends Properties("ChannelProperties") {
Prop.forAllNoShrink(ChannelGenerators.freshChannelInProgress) {
case (inProgress, privKeys) =>
val num = Gen.choose(1, 20).sample.get
val serverScriptPubKey = ScriptGenerators.p2pkhScriptPubKey.sample.get._1
val serverScriptPubKey =
ScriptGenerators.p2pkhScriptPubKey.sample.get._1
val amount = Policy.dustThreshold
val fee = Satoshis(Int64(100))
val (clientKey, serverKey) = (privKeys.head, privKeys(1))
val simulated = ChannelGenerators.simulate(num, inProgress, amount, clientKey, serverKey)
val simulated = ChannelGenerators.simulate(num,
inProgress,
amount,
clientKey,
serverKey)
val clientSigned = simulated.flatMap(_.clientSign(amount, clientKey))
val closedFuture = clientSigned.flatMap(_.close(serverScriptPubKey, serverKey, fee))
val closed = Await.result(closedFuture.map(closed => verifyChannel(closed, amount, fee)), timeout)
val closedFuture =
clientSigned.flatMap(_.close(serverScriptPubKey, serverKey, fee))
val closed = Await.result(
closedFuture.map(closed => verifyChannel(closed, amount, fee)),
timeout)
closed
}
}
property("close a payment channel awaiting anchor tx with the timeout branch") = {
property(
"close a payment channel awaiting anchor tx with the timeout branch") = {
Prop.forAllNoShrink(ChannelGenerators.channelAwaitingAnchorTxNotConfirmed) {
case (awaiting, privKeys) =>
val channelClosedWithTimeout = awaiting.closeWithTimeout(EmptyScriptPubKey, privKeys(2), Satoshis.one)
val program = channelClosedWithTimeout.map(c => PreExecutionScriptProgram(c.current))
val result = Await.result(program.map(p => ScriptInterpreter.run(p)), timeout)
val channelClosedWithTimeout =
awaiting.closeWithTimeout(EmptyScriptPubKey,
privKeys(2),
Satoshis.one)
val program = channelClosedWithTimeout.map(c =>
PreExecutionScriptProgram(c.current))
val result =
Await.result(program.map(p => ScriptInterpreter.run(p)), timeout)
result == ScriptOk
}
}
@ -70,14 +91,20 @@ class ChannelsSpec extends Properties("ChannelProperties") {
property("close a payment channel in progress with the timeout branch") = {
Prop.forAllNoShrink(ChannelGenerators.baseInProgress) {
case (inProgress, privKeys) =>
val channelClosedWithTimeout = inProgress.closeWithTimeout(privKeys(2), Satoshis.one)
val program = channelClosedWithTimeout.map(c => PreExecutionScriptProgram(c.current))
val result = Await.result(program.map(p => ScriptInterpreter.run(p)), timeout)
val channelClosedWithTimeout =
inProgress.closeWithTimeout(privKeys(2), Satoshis.one)
val program = channelClosedWithTimeout.map(c =>
PreExecutionScriptProgram(c.current))
val result =
Await.result(program.map(p => ScriptInterpreter.run(p)), timeout)
result == ScriptOk
}
}
def verifyChannel(p: ChannelClosed, amount: CurrencyUnit, fee: CurrencyUnit): Boolean = {
def verifyChannel(
p: ChannelClosed,
amount: CurrencyUnit,
fee: CurrencyUnit): Boolean = {
@tailrec
def loop(last: TxSigComponent, remaining: Seq[TxSigComponent]): Boolean = {
if (remaining.isEmpty) true
@ -86,10 +113,14 @@ class ChannelsSpec extends Properties("ChannelProperties") {
val program = PreExecutionScriptProgram(current)
val interpreterResult = ScriptInterpreter.run(program)
val isValidTx = interpreterResult == ScriptOk
if (!isValidTx) logger.error("Invalid tx when verifying payment channel, got error: " + interpreterResult)
if (!isValidTx)
logger.error(
"Invalid tx when verifying payment channel, got error: " + interpreterResult)
val lastClientOutput = last.transaction.outputs.head
val currentClientOutput = current.transaction.outputs.head
val expectedClientOutput = TransactionOutput(lastClientOutput.value - amount, lastClientOutput.scriptPubKey)
val expectedClientOutput = TransactionOutput(
lastClientOutput.value - amount,
lastClientOutput.scriptPubKey)
val serverOutputIsValid = if (remaining.size == 1) {
//check server output
val serverOutput = current.transaction.outputs(1)

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.config
import org.bitcoins.core.util.BitcoinSUtil
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 6/10/16.
*/
* Created by chris on 6/10/16.
*/
class NetworkParametersTest extends FlatSpec with MustMatchers {
//test case answers are from this link

File diff suppressed because one or more lines are too long

View file

@ -1,16 +1,21 @@
package org.bitcoins.core.crypto
import org.bitcoins.core.util.NumberUtil
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 3/23/16.
*/
* Created by chris on 3/23/16.
*/
class DERSignatureUtilTest extends FlatSpec with MustMatchers {
val p2shSignature = ECDigitalSignature("304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001")
val p2pkhSignature = ECDigitalSignature("3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac01")
val p2pkSignature = ECDigitalSignature("304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001")
val p2shSignature = ECDigitalSignature(
"304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001")
val p2pkhSignature = ECDigitalSignature(
"3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac01")
val p2pkSignature = ECDigitalSignature(
"304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001")
"DERSignatureUtil" must "say that a signature taken from a p2sh transaction is a valid DER encoded signature" in {
DERSignatureUtil.isValidSignatureEncoding(p2shSignature) must be(true)
@ -18,31 +23,45 @@ class DERSignatureUtilTest extends FlatSpec with MustMatchers {
it must "say that signature taken from a p2pkh transaction is a valid DER encoded signature" in {
//need to remove the hash type byte to check for der encoding
val hashTypeByteRemoved = p2pkhSignature.bytes.slice(0, p2pkhSignature.bytes.size - 1)
val hashTypeByteRemoved =
p2pkhSignature.bytes.slice(0, p2pkhSignature.bytes.size - 1)
DERSignatureUtil.isDEREncoded(hashTypeByteRemoved) must be(true)
}
it must "say that a signature taken from a p2pk transaction is a valid DER encoded signature" in {
val hashTypeByteRemoved = p2pkSignature.bytes.slice(0, p2pkSignature.bytes.size - 1)
val hashTypeByteRemoved =
p2pkSignature.bytes.slice(0, p2pkSignature.bytes.size - 1)
DERSignatureUtil.isDEREncoded(hashTypeByteRemoved) must be(true)
}
it must "retrieve the (r,s) values for a p2sh signature in bitcoin" in {
val (r, s) = DERSignatureUtil.decodeSignature(p2shSignature)
r must be(NumberUtil.toBigInt("5b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb"))
s must be(NumberUtil.toBigInt("2e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf80"))
r must be(
NumberUtil.toBigInt(
"5b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb"))
s must be(
NumberUtil.toBigInt(
"2e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf80"))
}
it must "retrieve the (r,s) values for a p2pkh signature in bitcoin" in {
val (r, s) = DERSignatureUtil.decodeSignature(p2pkhSignature)
r must be(NumberUtil.toBigInt("16ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca03"))
s must be(NumberUtil.toBigInt("119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac"))
r must be(
NumberUtil.toBigInt(
"16ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca03"))
s must be(
NumberUtil.toBigInt(
"119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac"))
}
it must "retrieve the (r,s) values from a p2pk signature in bitcoin" in {
val (r, s) = DERSignatureUtil.decodeSignature(p2pkSignature)
r must be(NumberUtil.toBigInt("0a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa1"))
s must be(NumberUtil.toBigInt("1fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b7420"))
r must be(
NumberUtil.toBigInt(
"0a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa1"))
s must be(
NumberUtil.toBigInt(
"1fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b7420"))
}
it must "say that a signature taken from a p2sh transaction is a valid stirctly DER encoded signature" in {
@ -59,18 +78,21 @@ class DERSignatureUtilTest extends FlatSpec with MustMatchers {
}
it must "say that the empty signature is a valid strictly encoded DER signature" in {
DERSignatureUtil.isValidSignatureEncoding(ECDigitalSignature("")) must be(true)
DERSignatureUtil.isValidSignatureEncoding(EmptyDigitalSignature) must be(true)
DERSignatureUtil.isValidSignatureEncoding(ECDigitalSignature("")) must be(
true)
DERSignatureUtil.isValidSignatureEncoding(EmptyDigitalSignature) must be(
true)
}
it must "say that an overly long signature is NOT strict der encoded" in {
val sig = ECDigitalSignature("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
val sig = ECDigitalSignature(
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
DERSignatureUtil.isValidSignatureEncoding(sig) must be(false)
}
it must "determine if a signature is encoded with a low s value" in {
val highS = ECDigitalSignature("304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001".toLowerCase)
val highS = ECDigitalSignature(
"304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001".toLowerCase)
DERSignatureUtil.isLowS(highS) must be(false)
}
}

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.crypto
import org.bitcoins.core.gen.CryptoGenerators
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 8/16/16.
*/
* Created by chris on 8/16/16.
*/
class ECDigitalSignatureSpec extends Properties("ECDigitalSignatureSpec") {
property("must be der encoded") =
@ -19,14 +19,17 @@ class ECDigitalSignatureSpec extends Properties("ECDigitalSignatureSpec") {
}
property("must create and verify a digital signature") =
Prop.forAll(CryptoGenerators.doubleSha256Digest, CryptoGenerators.privateKey) {
Prop.forAll(CryptoGenerators.doubleSha256Digest,
CryptoGenerators.privateKey) {
case (hash, key) =>
val sig = key.sign(hash)
key.publicKey.verify(hash, sig)
}
property("must not reuse r values") = {
Prop.forAll(CryptoGenerators.privateKey, CryptoGenerators.doubleSha256Digest, CryptoGenerators.doubleSha256Digest) {
Prop.forAll(CryptoGenerators.privateKey,
CryptoGenerators.doubleSha256Digest,
CryptoGenerators.doubleSha256Digest) {
case (key, hash1, hash2) =>
val sig1 = key.sign(hash1)
val sig2 = key.sign(hash2)

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.crypto
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.ByteVector
/**
* Created by chris on 3/22/16.
*/
* Created by chris on 3/22/16.
*/
class ECDigitalSignatureTest extends FlatSpec with MustMatchers {
"ECDigitalSignature" must "say that empty signature is a valid DER encoded signature" in {
@ -15,17 +15,20 @@ class ECDigitalSignatureTest extends FlatSpec with MustMatchers {
}
it must "say that a signature taken from a p2sh transaction is a valid DER encoded signature" in {
val signature = ECDigitalSignature("304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf80")
val signature = ECDigitalSignature(
"304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf80")
signature.isDEREncoded must be(true)
}
it must "say that signature taken from a p2pkh transaction is a valid DER encoded signature" in {
val signature = ECDigitalSignature("3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac")
val signature = ECDigitalSignature(
"3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac")
signature.isDEREncoded must be(true)
}
it must "say that a signature taken from a p2pk transaction is a valid DER encoded signature" in {
val signature = ECDigitalSignature("304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b7420")
val signature = ECDigitalSignature(
"304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b7420")
signature.isDEREncoded must be(true)
}
@ -36,7 +39,8 @@ class ECDigitalSignatureTest extends FlatSpec with MustMatchers {
it must "create a digital signature from it's r,s components" in {
//from the tx 44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff
val rawDigitalSignature = "3044022040f91c48f4011bf2e2edb6621bfa8fb802241de939cb86f1872c99c580ef0fe402204fc27388bc525e1b655b5f5b35f9d601d28602432dd5672f29e0a47f5b8bbb26"
val rawDigitalSignature =
"3044022040f91c48f4011bf2e2edb6621bfa8fb802241de939cb86f1872c99c580ef0fe402204fc27388bc525e1b655b5f5b35f9d601d28602432dd5672f29e0a47f5b8bbb26"
val digitalSignature = ECDigitalSignature(rawDigitalSignature)
val (r, s) = (digitalSignature.r, digitalSignature.s)
val digitalSignatureFromRS = ECDigitalSignature(r, s)

View file

@ -1,23 +1,25 @@
package org.bitcoins.core.crypto
import org.bitcoins.core.config.{ MainNet, RegTest, TestNet3 }
import org.bitcoins.core.gen.{ ChainParamsGenerator, CryptoGenerators }
import org.scalacheck.{ Prop, Properties }
import org.bitcoins.core.config.{MainNet, RegTest, TestNet3}
import org.bitcoins.core.gen.{ChainParamsGenerator, CryptoGenerators}
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 7/25/16.
*/
* Created by chris on 7/25/16.
*/
class ECPrivateKeySpec extends Properties("ECPrivateKeySpec") {
property("Serialization symmetry for WIF format") =
Prop.forAll(CryptoGenerators.privateKey, ChainParamsGenerator.networkParams) { (privKey, network) =>
val wif = privKey.toWIF(network)
val isCorrectNetwork = network match {
case MainNet => ECPrivateKey.parseNetworkFromWIF(wif).get == network
case TestNet3 | RegTest => ECPrivateKey.parseNetworkFromWIF(wif).get == TestNet3
}
ECPrivateKey.fromWIFToPrivateKey(wif) == privKey && isCorrectNetwork
property("Serialization symmetry for WIF format") = Prop.forAll(
CryptoGenerators.privateKey,
ChainParamsGenerator.networkParams) { (privKey, network) =>
val wif = privKey.toWIF(network)
val isCorrectNetwork = network match {
case MainNet => ECPrivateKey.parseNetworkFromWIF(wif).get == network
case TestNet3 | RegTest =>
ECPrivateKey.parseNetworkFromWIF(wif).get == TestNet3
}
ECPrivateKey.fromWIFToPrivateKey(wif) == privKey && isCorrectNetwork
}
property("Serialization symmetry") =
Prop.forAll(CryptoGenerators.privateKey) { privKey =>
@ -25,7 +27,8 @@ class ECPrivateKeySpec extends Properties("ECPrivateKeySpec") {
}
property("unique key generation") =
Prop.forAll(CryptoGenerators.privateKey, CryptoGenerators.privateKey) { (privKey1, privKey2) =>
privKey1 != privKey2
Prop.forAll(CryptoGenerators.privateKey, CryptoGenerators.privateKey) {
(privKey1, privKey2) =>
privKey1 != privKey2
}
}

View file

@ -1,24 +1,27 @@
package org.bitcoins.core.crypto
import org.bitcoins.core.config.TestNet3
import org.bitcoins.core.util.{ BitcoinSLogger, BitcoinSUtil, CryptoTestUtil }
import org.scalatest.{ FlatSpec, MustMatchers }
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil, CryptoTestUtil}
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.ByteVector
/**
* Created by chris on 3/7/16.
*/
* Created by chris on 3/7/16.
*/
class ECPrivateKeyTest extends FlatSpec with MustMatchers {
private def logger = BitcoinSLogger.logger
"ECPrivateKey" must "have the same byte representation as a bitcoinj private key" in {
val bitcoinjPrivateKey = CryptoTestUtil.bitcoinjPrivateKey.getPrivateKeyAsHex
val bitcoinjPrivateKey =
CryptoTestUtil.bitcoinjPrivateKey.getPrivateKeyAsHex
CryptoTestUtil.privateKey.hex must be(bitcoinjPrivateKey)
}
it must "derive the same public from a private key as bitcoinj" in {
val bitcoinjPublicKeyBytes = ByteVector(CryptoTestUtil.bitcoinjPrivateKey.getPubKey)
CryptoTestUtil.privateKey.publicKey.hex must be(BitcoinSUtil.encodeHex(bitcoinjPublicKeyBytes))
val bitcoinjPublicKeyBytes =
ByteVector(CryptoTestUtil.bitcoinjPrivateKey.getPubKey)
CryptoTestUtil.privateKey.publicKey.hex must be(
BitcoinSUtil.encodeHex(bitcoinjPublicKeyBytes))
}
it must "create a bitcoin-s private key from a bitcoinj private key, then convert to the same public key" in {
@ -32,7 +35,8 @@ class ECPrivateKeyTest extends FlatSpec with MustMatchers {
it must "create a bitcionj private key from a bitcoins private key and get the same public key" in {
val bitcoinsPrivKey = ECPrivateKey.freshPrivateKey
val bitcoinjPrivKey = org.bitcoinj.core.ECKey.fromPrivate(bitcoinsPrivKey.bytes.toArray)
val bitcoinjPrivKey =
org.bitcoinj.core.ECKey.fromPrivate(bitcoinsPrivKey.bytes.toArray)
val bitcoinjPublicKey = bitcoinjPrivKey.getPubKey
val bitcoinsPublicKey = bitcoinsPrivKey.publicKey
@ -42,18 +46,21 @@ class ECPrivateKeyTest extends FlatSpec with MustMatchers {
it must "create a private key from the dumped base58 in bitcoin-cli" in {
val bitcoinjDumpedPrivateKey = CryptoTestUtil.bitcoinjDumpedPrivateKey
val bitcoinjPrivateKey = bitcoinjDumpedPrivateKey.getKey
val privateKey = ECPrivateKey.fromWIFToPrivateKey(CryptoTestUtil.privateKeyBase58)
val privateKey =
ECPrivateKey.fromWIFToPrivateKey(CryptoTestUtil.privateKeyBase58)
privateKey.hex must be(bitcoinjPrivateKey.getPrivateKeyAsHex)
}
it must "create a private key from a sequence of bytes that has the same byte representation of bitcoinj ECKeys" in {
val bitcoinJKey = CryptoTestUtil.bitcoinjPrivateKey
val privateKey: ECPrivateKey = ECPrivateKey(ByteVector(bitcoinJKey.getPrivKeyBytes))
val privateKey: ECPrivateKey =
ECPrivateKey(ByteVector(bitcoinJKey.getPrivKeyBytes))
privateKey.hex must be(bitcoinJKey.getPrivateKeyAsHex)
}
it must "create a private key from its hex representation" in {
val privateKeyHex = "180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19"
val privateKeyHex =
"180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19"
val key: ECPrivateKey = ECPrivateKey(privateKeyHex)
key.hex must be(privateKeyHex)
}
@ -78,7 +85,8 @@ class ECPrivateKeyTest extends FlatSpec with MustMatchers {
}
it must "serialize a private key to WIF when the private key is prefixed with 0 bytes" in {
val hex = "00fc391adf4d6063a16a2e38b14d2be10133c4dacd4348b49d23ee0ce5ff4f1701"
val hex =
"00fc391adf4d6063a16a2e38b14d2be10133c4dacd4348b49d23ee0ce5ff4f1701"
val privKey = ECPrivateKey(hex)
val wif = privKey.toWIF(TestNet3)
val privKeyFromWIF = ECPrivateKey.fromWIFToPrivateKey(wif)
@ -86,15 +94,18 @@ class ECPrivateKeyTest extends FlatSpec with MustMatchers {
}
it must "correctly decode a private key from WIF" in {
val privateKey = ECPrivateKey.fromWIFToPrivateKey("cTPg4Zc5Jis2EZXy3NXShgbn487GWBTapbU63BerLDZM3w2hQSjC")
val privateKey = ECPrivateKey.fromWIFToPrivateKey(
"cTPg4Zc5Jis2EZXy3NXShgbn487GWBTapbU63BerLDZM3w2hQSjC")
//derived hex on bitcore's playground
privateKey.hex must be("ad59fb6aadf617fb0f93469741fcd9a9f48700f1d1f465ddc0f26fa7f7bfa1ac")
privateKey.hex must be(
"ad59fb6aadf617fb0f93469741fcd9a9f48700f1d1f465ddc0f26fa7f7bfa1ac")
}
it must "decode a WIF private key corresponding to uncompressed public key" in {
val wif = "5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"
val privKey = ECPrivateKey.fromWIFToPrivateKey(wif)
privKey.publicKey.hex must be("045b81f0017e2091e2edcd5eecf10d5bdd120a5514cb3ee65b8447ec18bfc4575c6d5bf415e54e03b1067934a0f0ba76b01c6b9ab227142ee1d543764b69d901e0")
privKey.publicKey.hex must be(
"045b81f0017e2091e2edcd5eecf10d5bdd120a5514cb3ee65b8447ec18bfc4575c6d5bf415e54e03b1067934a0f0ba76b01c6b9ab227142ee1d543764b69d901e0")
}
}

View file

@ -3,28 +3,31 @@ package org.bitcoins.core.crypto
import org.bitcoinj.core.Sha256Hash
import org.bitcoins.core.gen.CryptoGenerators
import org.scalatest.prop.PropertyChecks
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.ByteVector
/**
* Created by chris on 2/29/16.
*/
* Created by chris on 2/29/16.
*/
class ECPublicKeyTest extends FlatSpec with MustMatchers {
"ECPublicKey" must "verify that a arbitrary piece of data was signed by the private key corresponding to a public key" in {
val privateKeyHex = "180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19"
val privateKeyHex =
"180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19"
val key: ECPrivateKey = ECPrivateKey(privateKeyHex)
val hash = DoubleSha256Digest(ByteVector(Sha256Hash.ZERO_HASH.getBytes))
val signature: ECDigitalSignature = key.sign(hash)
val isValid: Boolean = key.publicKey.verify(ByteVector(Sha256Hash.ZERO_HASH.getBytes), signature)
val isValid: Boolean =
key.publicKey.verify(ByteVector(Sha256Hash.ZERO_HASH.getBytes), signature)
isValid must be(true)
}
it must "fail to verify a piece of data if the wrong public key is given" in {
val privateKeyHex = "180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19"
val privateKeyHex =
"180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19"
val key: ECPrivateKey = ECPrivateKey(privateKeyHex)
val hash = DoubleSha256Digest(ByteVector(Sha256Hash.ZERO_HASH.getBytes))
val signature: ECDigitalSignature = key.sign(hash)
@ -37,9 +40,11 @@ class ECPublicKeyTest extends FlatSpec with MustMatchers {
it must "verify a piece of data signed with a bitcoinj private key" in {
val bitcoinjPrivKey = new org.bitcoinj.core.ECKey
val bitcoinjSignature = bitcoinjPrivKey.sign(Sha256Hash.ZERO_HASH)
val bitcoinsSignature = ECDigitalSignature(ByteVector(bitcoinjSignature.encodeToDER()))
val bitcoinsSignature =
ECDigitalSignature(ByteVector(bitcoinjSignature.encodeToDER()))
val bitcoinsPublicKey = ECPublicKey(ByteVector(bitcoinjPrivKey.getPubKey))
bitcoinsPublicKey.verify(ByteVector(Sha256Hash.ZERO_HASH.getBytes), bitcoinsSignature) must be(true)
bitcoinsPublicKey.verify(ByteVector(Sha256Hash.ZERO_HASH.getBytes),
bitcoinsSignature) must be(true)
}
@ -47,10 +52,10 @@ class ECPublicKeyTest extends FlatSpec with MustMatchers {
val bitcoinsPrivKey = ECPrivateKey.freshPrivateKey
val hash = DoubleSha256Digest(ByteVector(Sha256Hash.ZERO_HASH.getBytes))
val bitcoinsSignature = bitcoinsPrivKey.sign(hash)
val bitcoinjPublicKey = org.bitcoinj.core.ECKey.fromPublicOnly(bitcoinsPrivKey.publicKey.bytes.toArray)
bitcoinjPublicKey.verify(
Sha256Hash.ZERO_HASH.getBytes,
bitcoinsSignature.bytes.toArray) must be(true)
val bitcoinjPublicKey = org.bitcoinj.core.ECKey
.fromPublicOnly(bitcoinsPrivKey.publicKey.bytes.toArray)
bitcoinjPublicKey.verify(Sha256Hash.ZERO_HASH.getBytes,
bitcoinsSignature.bytes.toArray) must be(true)
}
it must "have serialization symmetry from ECPublicKey -> ECPoint -> ECPublicKey" in {

View file

@ -3,7 +3,7 @@ package org.bitcoins.core.crypto
import org.bitcoins.core.gen.CryptoGenerators
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.util.BitcoinSLogger
import org.scalacheck.{ Gen, Prop, Properties }
import org.scalacheck.{Gen, Prop, Properties}
import scala.util.Success
@ -12,32 +12,76 @@ class ExtKeySpec extends Properties("ExtKeySpec") {
property("serialization symmetry") = {
Prop.forAll(CryptoGenerators.extKey) { extKey =>
ExtKey.fromString(extKey.toString) == Success(extKey) &&
ExtKey(extKey.bytes) == extKey
ExtKey(extKey.bytes) == extKey
}
}
private def nonHardened: Gen[UInt32] = Gen.choose(0L, ((1L << 31) - 1)).map(UInt32(_))
private def hardened: Gen[UInt32] = Gen.choose(1L << 31, (1L << 32) - 1).map(UInt32(_))
private def nonHardened: Gen[UInt32] =
Gen.choose(0L, ((1L << 31) - 1)).map(UInt32(_))
private def hardened: Gen[UInt32] =
Gen.choose(1L << 31, (1L << 32) - 1).map(UInt32(_))
property("derivation identity 1") = {
Prop.forAllNoShrink(CryptoGenerators.extPrivateKey, nonHardened, nonHardened, nonHardened) { (m, a, b, c) =>
Prop.forAllNoShrink(CryptoGenerators.extPrivateKey,
nonHardened,
nonHardened,
nonHardened) { (m, a, b, c) =>
//https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#the-key-tree
//N(m/a/b/c) = N(m/a/b)/c = N(m/a)/b/c = N(m)/a/b/c = M/a/b/c
val path1 = m.deriveChildPrivKey(a).deriveChildPrivKey(b).deriveChildPrivKey(c).extPublicKey
val path2 = m.deriveChildPrivKey(a).deriveChildPrivKey(b).extPublicKey.deriveChildPubKey(c).get
val path3 = m.deriveChildPrivKey(a).extPublicKey.deriveChildPubKey(b).get.deriveChildPubKey(c).get
val path4 = m.extPublicKey.deriveChildPubKey(a).get.deriveChildPubKey(b).get.deriveChildPubKey(c).get
val path1 = m
.deriveChildPrivKey(a)
.deriveChildPrivKey(b)
.deriveChildPrivKey(c)
.extPublicKey
val path2 = m
.deriveChildPrivKey(a)
.deriveChildPrivKey(b)
.extPublicKey
.deriveChildPubKey(c)
.get
val path3 = m
.deriveChildPrivKey(a)
.extPublicKey
.deriveChildPubKey(b)
.get
.deriveChildPubKey(c)
.get
val path4 = m.extPublicKey
.deriveChildPubKey(a)
.get
.deriveChildPubKey(b)
.get
.deriveChildPubKey(c)
.get
path1 == path2 && path2 == path3 && path3 == path4
}
}
property("derivation identity 2") = {
Prop.forAllNoShrink(CryptoGenerators.extPrivateKey, hardened, nonHardened, nonHardened) { (m, aH, b, c) =>
Prop.forAllNoShrink(CryptoGenerators.extPrivateKey,
hardened,
nonHardened,
nonHardened) { (m, aH, b, c) =>
//https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#the-key-tree
//N(m/aH/b/c) = N(m/aH/b)/c = N(m/aH)/b/c
val path1 = m.deriveChildPrivKey(aH).deriveChildPrivKey(b).deriveChildPrivKey(c).extPublicKey
val path2 = m.deriveChildPrivKey(aH).deriveChildPrivKey(b).extPublicKey.deriveChildPubKey(c).get
val path3 = m.deriveChildPrivKey(aH).extPublicKey.deriveChildPubKey(b).get.deriveChildPubKey(c).get
val path1 = m
.deriveChildPrivKey(aH)
.deriveChildPrivKey(b)
.deriveChildPrivKey(c)
.extPublicKey
val path2 = m
.deriveChildPrivKey(aH)
.deriveChildPrivKey(b)
.extPublicKey
.deriveChildPubKey(c)
.get
val path3 = m
.deriveChildPrivKey(aH)
.extPublicKey
.deriveChildPubKey(b)
.get
.deriveChildPubKey(c)
.get
path1 == path2 && path2 == path3
}
}

View file

@ -2,7 +2,7 @@ package org.bitcoins.core.crypto
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.util.BitcoinSUtil
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
class ExtKeyTest extends FlatSpec with MustMatchers {
@ -11,104 +11,138 @@ class ExtKeyTest extends FlatSpec with MustMatchers {
//master key
val seed = BitcoinSUtil.decodeHex("000102030405060708090a0b0c0d0e0f")
val masterPriv = ExtPrivateKey(MainNetPriv, Some(seed))
masterPriv.toString must be("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi")
masterPriv.toString must be(
"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi")
//master public key
val masterPub = masterPriv.extPublicKey
masterPub.toString must be("xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8")
masterPub.toString must be(
"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8")
//derive child
val hidx = ExtKey.hardenedIdx
val m0h = masterPriv.deriveChildPrivKey(hidx)
m0h.toString must be("xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7")
m0h.toString must be(
"xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7")
val m0hPub = m0h.extPublicKey
m0hPub.toString must be("xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw")
m0hPub.toString must be(
"xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw")
val m0h1 = m0h.deriveChildPrivKey(UInt32.one)
m0h1.toString must be("xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs")
m0h1.toString must be(
"xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs")
val m0h1Pub = m0h1.extPublicKey
m0h1Pub.toString must be("xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ")
m0h1Pub.toString must be(
"xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ")
val m0h12h = m0h1.deriveChildPrivKey(UInt32(2) + ExtKey.hardenedIdx)
m0h12h.toString must be("xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM")
m0h12h.toString must be(
"xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM")
val m0h12hPub = m0h12h.extPublicKey
m0h12hPub.toString must be("xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5")
m0h12hPub.toString must be(
"xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5")
val m0h12h2 = m0h12h.deriveChildPrivKey(UInt32(2))
m0h12h2.toString must be("xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334")
m0h12h2.toString must be(
"xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334")
val m0h12h2Pub = m0h12h2.extPublicKey
m0h12h2Pub.toString must be("xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV")
m0h12h2Pub.toString must be(
"xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV")
val m0h12h21000000000 = m0h12h2.deriveChildPrivKey(UInt32(1000000000))
m0h12h21000000000.toString must be("xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76")
m0h12h21000000000.toString must be(
"xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76")
val m0h12h21000000000Pub = m0h12h21000000000.extPublicKey
m0h12h21000000000Pub.toString must be("xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy")
m0h12h21000000000Pub.toString must be(
"xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy")
}
it must "pass test vector 2 in BIP32" in {
val seed = BitcoinSUtil.decodeHex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542")
val seed = BitcoinSUtil.decodeHex(
"fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542")
val masterPriv = ExtPrivateKey(MainNetPriv, Some(seed))
masterPriv.toString must be("xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U")
masterPriv.toString must be(
"xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U")
val masterPub = masterPriv.extPublicKey
masterPub.toString must be("xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB")
masterPub.toString must be(
"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB")
val m0 = masterPriv.deriveChildPrivKey(UInt32.zero)
m0.toString must be("xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt")
m0.toString must be(
"xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt")
val m0Pub = m0.extPublicKey
m0Pub.toString must be("xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH")
m0Pub.toString must be(
"xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH")
val m02147483647h = m0.deriveChildPrivKey(ExtKey.hardenedIdx + UInt32(2147483647))
m02147483647h.toString must be("xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9")
val m02147483647h =
m0.deriveChildPrivKey(ExtKey.hardenedIdx + UInt32(2147483647))
m02147483647h.toString must be(
"xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9")
val m02147483647hPub = m02147483647h.extPublicKey
m02147483647hPub.toString must be("xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a")
m02147483647hPub.toString must be(
"xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a")
val m02147483647h1 = m02147483647h.deriveChildPrivKey(UInt32.one)
m02147483647h1.toString must be("xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef")
m02147483647h1.toString must be(
"xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef")
val m02147483647h1Pub = m02147483647h1.extPublicKey
m02147483647h1Pub.toString must be("xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon")
m02147483647h1Pub.toString must be(
"xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon")
val m02147483647h12147483646h = m02147483647h1.deriveChildPrivKey(ExtKey.hardenedIdx + UInt32(2147483646))
m02147483647h12147483646h.toString must be("xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc")
val m02147483647h12147483646h =
m02147483647h1.deriveChildPrivKey(ExtKey.hardenedIdx + UInt32(2147483646))
m02147483647h12147483646h.toString must be(
"xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc")
val m02147483647h12147483646hPub = m02147483647h12147483646h.extPublicKey
m02147483647h12147483646hPub.toString must be("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL")
m02147483647h12147483646hPub.toString must be(
"xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL")
val m02147483647h12147483646h2 = m02147483647h12147483646h.deriveChildPrivKey(UInt32(2))
m02147483647h12147483646h2.toString must be("xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j")
val m02147483647h12147483646h2 =
m02147483647h12147483646h.deriveChildPrivKey(UInt32(2))
m02147483647h12147483646h2.toString must be(
"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j")
val m02147483647h12147483646h2Pub = m02147483647h12147483646h2.extPublicKey
m02147483647h12147483646h2Pub.toString must be("xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt")
m02147483647h12147483646h2Pub.toString must be(
"xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt")
}
it must "pass test vector 3 in BIP32" in {
val seed = BitcoinSUtil.decodeHex("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be")
val seed = BitcoinSUtil.decodeHex(
"4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be")
val masterPrivKey = ExtPrivateKey(MainNetPriv, Some(seed))
masterPrivKey.toString must be("xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6")
masterPrivKey.toString must be(
"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6")
val masterPubKey = masterPrivKey.extPublicKey
masterPubKey.toString must be("xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13")
masterPubKey.toString must be(
"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13")
val m0h = masterPrivKey.deriveChildPrivKey(ExtKey.hardenedIdx)
m0h.toString must be("xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L")
m0h.toString must be(
"xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L")
val m0hPub = m0h.extPublicKey
m0hPub.toString must be("xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y")
m0hPub.toString must be(
"xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y")
}
it must "have derivation symmetry with (1<<31)-1, last i before hardened keys" in {
//xprv9s21ZrQH143K4QWHDnxmxUbzAQYiDavkg14kQcmZjP2KaSB1PZs5BUsyNGSrWXTzZ9qwyJo5yzvDe3fWybykc8CQPDZMaKupTeVbkfG7osL
//actual priv key 68e5ed2b2c8fc5a6605107d29d074e3d6ccb119c2811007e32f48305176f814c
val str = "xprv9s21ZrQH143K4LCRq4tUZUt3fiTNZr6QTiep3HGzMxtSwfxKAhBmNJJnsmoyWuYZCPC4DNsiVwToHJbxZtq4iEkozBhMzWNTiCH4tzJNjPi"
val str =
"xprv9s21ZrQH143K4LCRq4tUZUt3fiTNZr6QTiep3HGzMxtSwfxKAhBmNJJnsmoyWuYZCPC4DNsiVwToHJbxZtq4iEkozBhMzWNTiCH4tzJNjPi"
val masterPriv = ExtKey.fromString(str).get.asInstanceOf[ExtPrivateKey]
val idx = UInt32((1L << 31) - 1)
val path1 = masterPriv.deriveChildPrivKey(idx).extPublicKey.key

View file

@ -1,10 +1,10 @@
package org.bitcoins.core.crypto
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 3/31/16.
*/
* Created by chris on 3/31/16.
*/
class TransactionSignatureCheckerResultTest extends FlatSpec with MustMatchers {
"TransactionSignatureCheckerResult" must "have isValid set correctly for the different outcomes of TransactionSignatureCheckerResult" in {

View file

@ -1,9 +1,8 @@
package org.bitcoins.core.crypto
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 2/29/16.
*/
class TransactionSignatureCheckerTest extends FlatSpec with MustMatchers {
}
* Created by chris on 2/29/16.
*/
class TransactionSignatureCheckerTest extends FlatSpec with MustMatchers {}

View file

@ -5,19 +5,21 @@ import org.bitcoins.core.script.PreExecutionScriptProgram
import org.bitcoins.core.script.interpreter.ScriptInterpreter
import org.bitcoins.core.script.result._
import org.bitcoins.core.util.BitcoinSLogger
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 7/25/16.
*/
class TransactionSignatureCreatorSpec extends Properties("TransactionSignatureCreatorSpec") {
* Created by chris on 7/25/16.
*/
class TransactionSignatureCreatorSpec
extends Properties("TransactionSignatureCreatorSpec") {
private val logger = BitcoinSLogger.logger
property("Must generate a valid signature for a p2pk transaction") =
Prop.forAll(TransactionGenerators.signedP2PKTransaction) {
case (txSignatureComponent: TxSigComponent, _) =>
//run it through the interpreter
val program: PreExecutionScriptProgram = PreExecutionScriptProgram(txSignatureComponent)
val program: PreExecutionScriptProgram =
PreExecutionScriptProgram(txSignatureComponent)
val result = ScriptInterpreter.run(program)
result == ScriptOk
}
@ -41,37 +43,47 @@ class TransactionSignatureCreatorSpec extends Properties("TransactionSignatureCr
Seq(ScriptOk, ScriptErrorPushSize).contains(result)
}
property("generate a valid signature for a valid and spendable cltv transaction") =
Prop.forAllNoShrink(TransactionGenerators.spendableCLTVTransaction :| "cltv_spendable") {
property(
"generate a valid signature for a valid and spendable cltv transaction") =
Prop.forAllNoShrink(
TransactionGenerators.spendableCLTVTransaction :| "cltv_spendable") {
case (txSignatureComponent: TxSigComponent, _) =>
val program = PreExecutionScriptProgram(txSignatureComponent)
val result = ScriptInterpreter.run(program)
result == ScriptOk
}
property("fail to verify a transaction with a locktime that has not yet been met") =
Prop.forAllNoShrink(TransactionGenerators.unspendableCLTVTransaction :| "cltv_unspendable") {
property(
"fail to verify a transaction with a locktime that has not yet been met") =
Prop.forAllNoShrink(
TransactionGenerators.unspendableCLTVTransaction :| "cltv_unspendable") {
case (txSignatureComponent: TxSigComponent, _) =>
val program = PreExecutionScriptProgram(txSignatureComponent)
val result = ScriptInterpreter.run(program)
Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains(result)
Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains(
result)
}
property("generate a valid signature for a valid and spendable csv transaction") =
Prop.forAllNoShrink(TransactionGenerators.spendableCSVTransaction :| "spendable csv") {
property(
"generate a valid signature for a valid and spendable csv transaction") =
Prop.forAllNoShrink(
TransactionGenerators.spendableCSVTransaction :| "spendable csv") {
case (txSignatureComponent: TxSigComponent, _) =>
//run it through the interpreter
val program = PreExecutionScriptProgram(txSignatureComponent)
val result = ScriptInterpreter.run(program)
Seq(ScriptOk, ScriptErrorPushSize).contains(result)
}
property("fail to verify a transaction with a relative locktime that has not been satisfied yet") =
Prop.forAllNoShrink(TransactionGenerators.unspendableCSVTransaction :| "unspendable csv") {
property(
"fail to verify a transaction with a relative locktime that has not been satisfied yet") =
Prop.forAllNoShrink(
TransactionGenerators.unspendableCSVTransaction :| "unspendable csv") {
case (txSignatureComponent: TxSigComponent, _) =>
//run it through the interpreter
val program = PreExecutionScriptProgram(txSignatureComponent)
val result = ScriptInterpreter.run(program)
Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains(result)
Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains(
result)
}
@ -83,14 +95,16 @@ class TransactionSignatureCreatorSpec extends Properties("TransactionSignatureCr
result == ScriptOk
}
property("generate a valid signature for a p2wsh(old scriptPubkey tx) witness transaction") =
property(
"generate a valid signature for a p2wsh(old scriptPubkey tx) witness transaction") =
Prop.forAllNoShrink(TransactionGenerators.signedP2WSHTransaction) {
case (wtxSigComponent, privKeys) =>
val program = PreExecutionScriptProgram(wtxSigComponent)
val result = ScriptInterpreter.run(program)
Seq(ScriptErrorPushSize, ScriptOk).contains(result)
}
property("generate a valid signature from a p2sh(p2wpkh) witness transaction") =
property(
"generate a valid signature from a p2sh(p2wpkh) witness transaction") =
Prop.forAllNoShrink(TransactionGenerators.signedP2SHP2WPKHTransaction) {
case (wtxSigComponent, privKeys) =>
val program = PreExecutionScriptProgram(wtxSigComponent)
@ -99,7 +113,8 @@ class TransactionSignatureCreatorSpec extends Properties("TransactionSignatureCr
result == ScriptOk
}
property("generate a valid signature from a p2sh(p2wsh) witness tranasction") =
property(
"generate a valid signature from a p2sh(p2wsh) witness tranasction") =
Prop.forAllNoShrink(TransactionGenerators.signedP2SHP2WSHTransaction) {
case (wtxSigComponent, privKeys) =>
val program = PreExecutionScriptProgram(wtxSigComponent)
@ -109,22 +124,25 @@ class TransactionSignatureCreatorSpec extends Properties("TransactionSignatureCr
}
property("generate a valid signature for a escrow timeout transaction") =
Prop.forAll(TransactionGenerators.spendableEscrowTimeoutTransaction) { txSigComponent: TxSigComponent =>
val program = PreExecutionScriptProgram(txSigComponent)
val result = ScriptInterpreter.run(program)
result == ScriptOk
Prop.forAll(TransactionGenerators.spendableEscrowTimeoutTransaction) {
txSigComponent: TxSigComponent =>
val program = PreExecutionScriptProgram(txSigComponent)
val result = ScriptInterpreter.run(program)
result == ScriptOk
}
property("fail to evaluate a locktime escrow timeout transaction") = {
Prop.forAll(TransactionGenerators.unspendableEscrowTimeoutTransaction) { txSigComponent: TxSigComponent =>
val program = PreExecutionScriptProgram(txSigComponent)
val result = ScriptInterpreter.run(program)
result != ScriptOk
Prop.forAll(TransactionGenerators.unspendableEscrowTimeoutTransaction) {
txSigComponent: TxSigComponent =>
val program = PreExecutionScriptProgram(txSigComponent)
val result = ScriptInterpreter.run(program)
result != ScriptOk
}
}
property("generate a valid signature for a P2WSH(EscrowTimeout) tx") = {
Prop.forAllNoShrink(TransactionGenerators.signedP2WSHEscrowTimeoutTransaction) {
Prop.forAllNoShrink(
TransactionGenerators.signedP2WSHEscrowTimeoutTransaction) {
case (txSigComponent, _) =>
val program = PreExecutionScriptProgram(txSigComponent)
val result = ScriptInterpreter.run(program)

View file

@ -9,34 +9,45 @@ 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, TransactionTestUtil}
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.ByteVector
import scala.concurrent.Future
/**
* Created by chris on 7/21/16.
*/
class TransactionSignatureCreatorTest extends FlatSpec with MustMatchers with ScalaFutures {
* Created by chris on 7/21/16.
*/
class TransactionSignatureCreatorTest
extends FlatSpec
with MustMatchers
with ScalaFutures {
private def logger = BitcoinSLogger.logger
"TransactionSignatureCreator" must "create a signature for a scriptSignature in a transaction" in {
//this is a signed tx, but since TransactionSignatureSerializer removes scriptSigs, it will work for testing this
//from fe6ef8e20a9ca9cb5d59cb1c0f30eff2b23be2e3cc2bf4b4cfff519414e9a300 on testnet
//"30440220357864ae2beba3d6ec34c0ce42262c1c12939502f0f8f4bd338c9d8b307593420220656687c327589dc3e464700fa7b784c7efc2b465c627a60c2f1ce402d05fc39d01"
val expectedSig = ECDigitalSignature("30440220357864ae2beba3d6ec34c0ce42262c1c12939502f0f8f4bd338c9d8b307593420220656687c327589dc3e464700fa7b784c7efc2b465c627a60c2f1ce402d05fc39d01")
val rawTx = "01000000021d50bf7c05b6169ea8d8fb5b79dd2978bbd2ac756a656a777279da43b19fd9d9000000006b4830450221008f2c818a55045a1c9dcda54fcd5b6377f5d09723a9ccd8c71df76ee4bdf7c16802201817cbd71d8148a5d53b11d33c9c58ad1086fe7ddf308da2a7cceb7d85df293e01210381c82dc267a958be06f1c920dc635bcd191d698c167e67a45a882a551c57ce1dfeffffffd4a6a37abfe003a9d10155df215e662f88d5b878b908d1a3772a9fbd195d008d010000006a4730440220357864ae2beba3d6ec34c0ce42262c1c12939502f0f8f4bd338c9d8b307593420220656687c327589dc3e464700fa7b784c7efc2b465c627a60c2f1ce402d05fc39d0121036301d848aec3dfc47789a63ee3c85c6d3bf757162ef77cb1580981b422838ed7feffffff0200e1f505000000001976a9146d39bac171d0bf450698fa0ebd93f51e79dcb6ac88ac35a96d00000000001976a914e11753f499ac7a910148e53156ab273557ed517e88acd6090b00"
val expectedSig = ECDigitalSignature(
"30440220357864ae2beba3d6ec34c0ce42262c1c12939502f0f8f4bd338c9d8b307593420220656687c327589dc3e464700fa7b784c7efc2b465c627a60c2f1ce402d05fc39d01")
val rawTx =
"01000000021d50bf7c05b6169ea8d8fb5b79dd2978bbd2ac756a656a777279da43b19fd9d9000000006b4830450221008f2c818a55045a1c9dcda54fcd5b6377f5d09723a9ccd8c71df76ee4bdf7c16802201817cbd71d8148a5d53b11d33c9c58ad1086fe7ddf308da2a7cceb7d85df293e01210381c82dc267a958be06f1c920dc635bcd191d698c167e67a45a882a551c57ce1dfeffffffd4a6a37abfe003a9d10155df215e662f88d5b878b908d1a3772a9fbd195d008d010000006a4730440220357864ae2beba3d6ec34c0ce42262c1c12939502f0f8f4bd338c9d8b307593420220656687c327589dc3e464700fa7b784c7efc2b465c627a60c2f1ce402d05fc39d0121036301d848aec3dfc47789a63ee3c85c6d3bf757162ef77cb1580981b422838ed7feffffff0200e1f505000000001976a9146d39bac171d0bf450698fa0ebd93f51e79dcb6ac88ac35a96d00000000001976a914e11753f499ac7a910148e53156ab273557ed517e88acd6090b00"
val transaction = Transaction(rawTx)
val scriptPubKey = ScriptPubKey("1976a914d7b4717a934386601ac3f980d01b48c83b8a0b4b88ac")
val txSignatureComponent = BaseTxSigComponent(
transaction = transaction,
inputIndex = UInt32.one,
output = TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
val privateKey = ECPrivateKey.fromWIFToPrivateKey("cTPg4Zc5Jis2EZXy3NXShgbn487GWBTapbU63BerLDZM3w2hQSjC")
val txSignature = TransactionSignatureCreator.createSig(txSignatureComponent, privateKey, HashType.sigHashAll)
val scriptPubKey =
ScriptPubKey("1976a914d7b4717a934386601ac3f980d01b48c83b8a0b4b88ac")
val txSignatureComponent =
BaseTxSigComponent(transaction = transaction,
inputIndex = UInt32.one,
output =
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
val privateKey = ECPrivateKey.fromWIFToPrivateKey(
"cTPg4Zc5Jis2EZXy3NXShgbn487GWBTapbU63BerLDZM3w2hQSjC")
val txSignature =
TransactionSignatureCreator.createSig(txSignatureComponent,
privateKey,
HashType.sigHashAll)
txSignature.r must be(expectedSig.r)
txSignature.s must be(expectedSig.s)
txSignature.hex must be(expectedSig.hex)
@ -44,17 +55,25 @@ class TransactionSignatureCreatorTest extends FlatSpec with MustMatchers with Sc
}
it must "create the correct digital signature for a transaction with 1 input" in {
//66f48fa8ef5db20a3b4be6b13f024b6e23480fd83df26ffbe7449110b113a665 on testnet
val expectedSig = ECDigitalSignature("3044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a201")
val rawTx = "0100000001b8a1278696acfa85f1f576836aa30d335207b69bdaff43d9464cc1db40fe19ae000000006a473044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a2012102a01aaa27b468ec3fb2ae0c2a9fa1d5dce9b79b35062178f479156d8daa6c0e50feffffff02a0860100000000001976a914775bd9c79a9e988c0d6177a9205a611a50b7229188acb6342900000000001976a914f23a46f930320ab3cc7ad8c1660325f4c434d11688ac63b70d00"
val expectedSig = ECDigitalSignature(
"3044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a201")
val rawTx =
"0100000001b8a1278696acfa85f1f576836aa30d335207b69bdaff43d9464cc1db40fe19ae000000006a473044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a2012102a01aaa27b468ec3fb2ae0c2a9fa1d5dce9b79b35062178f479156d8daa6c0e50feffffff02a0860100000000001976a914775bd9c79a9e988c0d6177a9205a611a50b7229188acb6342900000000001976a914f23a46f930320ab3cc7ad8c1660325f4c434d11688ac63b70d00"
val transaction = Transaction(rawTx)
val scriptPubKey = ScriptPubKey("1976a914cd0385f813ec73f8fc340b7069daf566878a0d6b88ac")
val txSignatureComponent = BaseTxSigComponent(
transaction = transaction,
inputIndex = UInt32.zero,
output = TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
val privateKey = ECPrivateKey.fromWIFToPrivateKey("cTTh7jNtZhg3vHTjvYK8zcHkLfsMAS8iqL7pfZ6eVAVHHF8fN1qy")
val txSignature = TransactionSignatureCreator.createSig(txSignatureComponent, privateKey, HashType.sigHashAll)
val scriptPubKey =
ScriptPubKey("1976a914cd0385f813ec73f8fc340b7069daf566878a0d6b88ac")
val txSignatureComponent =
BaseTxSigComponent(transaction = transaction,
inputIndex = UInt32.zero,
output =
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
val privateKey = ECPrivateKey.fromWIFToPrivateKey(
"cTTh7jNtZhg3vHTjvYK8zcHkLfsMAS8iqL7pfZ6eVAVHHF8fN1qy")
val txSignature =
TransactionSignatureCreator.createSig(txSignatureComponent,
privateKey,
HashType.sigHashAll)
txSignature.r must be(expectedSig.r)
txSignature.s must be(expectedSig.s)
txSignature.hex must be(expectedSig.hex)
@ -62,140 +81,181 @@ class TransactionSignatureCreatorTest extends FlatSpec with MustMatchers with Sc
it must "create a p2pk scriptPubKey, create a crediting tx for scriptPubKey, " +
"then create spending tx and make sure it evaluates to true in the interpreter" in {
val privateKey = ECPrivateKey()
val publicKey = privateKey.publicKey
val scriptPubKey = P2PKScriptPubKey(publicKey)
val (creditingTx, outputIndex) = TransactionTestUtil.buildCreditingTransaction(scriptPubKey)
val scriptSig = P2PKScriptSignature(EmptyDigitalSignature)
val (spendingTx, inputIndex) = TransactionTestUtil.buildSpendingTransaction(
creditingTx,
scriptSig,
outputIndex)
val privateKey = ECPrivateKey()
val publicKey = privateKey.publicKey
val scriptPubKey = P2PKScriptPubKey(publicKey)
val (creditingTx, outputIndex) =
TransactionTestUtil.buildCreditingTransaction(scriptPubKey)
val scriptSig = P2PKScriptSignature(EmptyDigitalSignature)
val (spendingTx, inputIndex) =
TransactionTestUtil.buildSpendingTransaction(creditingTx,
scriptSig,
outputIndex)
val txSignatureComponent = BaseTxSigComponent(
transaction = spendingTx,
inputIndex = inputIndex,
output = TransactionOutput(CurrencyUnits.zero, scriptPubKey),
flags = Policy.standardScriptVerifyFlags)
val txSignatureComponent =
BaseTxSigComponent(transaction = spendingTx,
inputIndex = inputIndex,
output =
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
flags = Policy.standardScriptVerifyFlags)
val txSignature = TransactionSignatureCreator.createSig(
txSignatureComponent,
privateKey,
HashType.sigHashAll)
val txSignature =
TransactionSignatureCreator.createSig(txSignatureComponent,
privateKey,
HashType.sigHashAll)
//add the signature to the scriptSig instead of having an empty scriptSig
val signedScriptSig = P2PKScriptSignature(txSignature)
val (signedTx, _) = TransactionTestUtil.buildSpendingTransaction(creditingTx, signedScriptSig,
outputIndex)
//add the signature to the scriptSig instead of having an empty scriptSig
val signedScriptSig = P2PKScriptSignature(txSignature)
val (signedTx, _) =
TransactionTestUtil.buildSpendingTransaction(creditingTx,
signedScriptSig,
outputIndex)
val signedTxSigComponent = BaseTxSigComponent(
transaction = signedTx,
inputIndex = inputIndex,
output = TransactionOutput(CurrencyUnits.zero, scriptPubKey),
flags = Policy.standardScriptVerifyFlags)
val signedTxSigComponent =
BaseTxSigComponent(transaction = signedTx,
inputIndex = inputIndex,
output =
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
flags = Policy.standardScriptVerifyFlags)
//run it through the interpreter
val program = PreExecutionScriptProgram(signedTxSigComponent)
//run it through the interpreter
val program = PreExecutionScriptProgram(signedTxSigComponent)
val result = ScriptInterpreter.run(program)
val result = ScriptInterpreter.run(program)
result must be(ScriptOk)
}
result must be(ScriptOk)
}
it must "create a p2pkh scriptPubKey, create a crediting tx for the scriptPubkey" +
"then create a spending tx and make sure it evaluates to true in the interpreter" in {
val privateKey = ECPrivateKey()
val publicKey = privateKey.publicKey
val scriptPubKey = P2PKHScriptPubKey(publicKey)
val (creditingTx, outputIndex) = TransactionTestUtil.buildCreditingTransaction(scriptPubKey)
val scriptSig = P2PKHScriptSignature(EmptyDigitalSignature, publicKey)
val (spendingTx, inputIndex) = TransactionTestUtil.buildSpendingTransaction(creditingTx, scriptSig, outputIndex)
val txSignatureComponent = BaseTxSigComponent(
transaction = spendingTx,
inputIndex = inputIndex,
output = TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
val txSignature = TransactionSignatureCreator.createSig(txSignatureComponent, privateKey, HashType.sigHashAll)
val privateKey = ECPrivateKey()
val publicKey = privateKey.publicKey
val scriptPubKey = P2PKHScriptPubKey(publicKey)
val (creditingTx, outputIndex) =
TransactionTestUtil.buildCreditingTransaction(scriptPubKey)
val scriptSig = P2PKHScriptSignature(EmptyDigitalSignature, publicKey)
val (spendingTx, inputIndex) =
TransactionTestUtil.buildSpendingTransaction(creditingTx,
scriptSig,
outputIndex)
val txSignatureComponent =
BaseTxSigComponent(transaction = spendingTx,
inputIndex = inputIndex,
output =
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
val txSignature =
TransactionSignatureCreator.createSig(txSignatureComponent,
privateKey,
HashType.sigHashAll)
//add the signature to the scriptSig instead of having an empty scriptSig
val signedScriptSig = P2PKHScriptSignature(txSignature, publicKey)
val (signedTx, _) = TransactionTestUtil.buildSpendingTransaction(creditingTx, signedScriptSig, outputIndex)
//add the signature to the scriptSig instead of having an empty scriptSig
val signedScriptSig = P2PKHScriptSignature(txSignature, publicKey)
val (signedTx, _) =
TransactionTestUtil.buildSpendingTransaction(creditingTx,
signedScriptSig,
outputIndex)
//run it through the interpreter
val signedTxSigComponent = BaseTxSigComponent(
transaction = signedTx,
inputIndex = inputIndex,
output = TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
val program = PreExecutionScriptProgram(signedTxSigComponent)
val result = ScriptInterpreter.run(program)
//run it through the interpreter
val signedTxSigComponent =
BaseTxSigComponent(transaction = signedTx,
inputIndex = inputIndex,
output =
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
val program = PreExecutionScriptProgram(signedTxSigComponent)
val result = ScriptInterpreter.run(program)
result must be(ScriptOk)
}
result must be(ScriptOk)
}
it must "create a multisignature scriptPubKey, create a crediting tx for the scriptPubkey, " +
"then create a spending tx and make sure it evaluates to true in the interpreter" in {
val privateKey = ECPrivateKey()
val publicKey = privateKey.publicKey
val scriptPubKey = MultiSignatureScriptPubKey(1, Seq(publicKey))
val (creditingTx, outputIndex) = TransactionTestUtil.buildCreditingTransaction(scriptPubKey)
val scriptSig = MultiSignatureScriptSignature(Seq(EmptyDigitalSignature))
val (spendingTx, inputIndex) = TransactionTestUtil.buildSpendingTransaction(creditingTx, scriptSig, outputIndex)
val txSignatureComponent = BaseTxSigComponent(
transaction = spendingTx,
inputIndex = inputIndex,
output = TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
val txSignature = TransactionSignatureCreator.createSig(txSignatureComponent, privateKey, HashType.sigHashAll)
val privateKey = ECPrivateKey()
val publicKey = privateKey.publicKey
val scriptPubKey = MultiSignatureScriptPubKey(1, Seq(publicKey))
val (creditingTx, outputIndex) =
TransactionTestUtil.buildCreditingTransaction(scriptPubKey)
val scriptSig = MultiSignatureScriptSignature(Seq(EmptyDigitalSignature))
val (spendingTx, inputIndex) =
TransactionTestUtil.buildSpendingTransaction(creditingTx,
scriptSig,
outputIndex)
val txSignatureComponent =
BaseTxSigComponent(transaction = spendingTx,
inputIndex = inputIndex,
output =
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
val txSignature =
TransactionSignatureCreator.createSig(txSignatureComponent,
privateKey,
HashType.sigHashAll)
//add the signature to the scriptSig instead of having an empty scriptSig
val signedScriptSig = MultiSignatureScriptSignature(Seq(txSignature))
val (signedTx, _) = TransactionTestUtil.buildSpendingTransaction(creditingTx, signedScriptSig, outputIndex)
//add the signature to the scriptSig instead of having an empty scriptSig
val signedScriptSig = MultiSignatureScriptSignature(Seq(txSignature))
val (signedTx, _) =
TransactionTestUtil.buildSpendingTransaction(creditingTx,
signedScriptSig,
outputIndex)
val signedTxSigComponent = BaseTxSigComponent(
transaction = signedTx,
inputIndex = inputIndex,
output = TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
//run it through the interpreter
val program = PreExecutionScriptProgram(signedTxSigComponent)
val signedTxSigComponent =
BaseTxSigComponent(transaction = signedTx,
inputIndex = inputIndex,
output =
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
//run it through the interpreter
val program = PreExecutionScriptProgram(signedTxSigComponent)
val result = ScriptInterpreter.run(program)
val result = ScriptInterpreter.run(program)
result must be(ScriptOk)
}
result must be(ScriptOk)
}
it must "create a p2sh scriptPubKey, create a crediting tx for the scriptPubKey, " +
"then create a spending tx and make sure it evaluates to true in the interpreter" in {
val privateKey = ECPrivateKey()
val publicKey = privateKey.publicKey
val redeemScript = MultiSignatureScriptPubKey(1, Seq(publicKey))
val scriptPubKey = P2SHScriptPubKey(redeemScript)
val (creditingTx, outputIndex) = TransactionTestUtil.buildCreditingTransaction(scriptPubKey)
val scriptSig = MultiSignatureScriptSignature(Seq(EmptyDigitalSignature))
val privateKey = ECPrivateKey()
val publicKey = privateKey.publicKey
val redeemScript = MultiSignatureScriptPubKey(1, Seq(publicKey))
val scriptPubKey = P2SHScriptPubKey(redeemScript)
val (creditingTx, outputIndex) =
TransactionTestUtil.buildCreditingTransaction(scriptPubKey)
val scriptSig = MultiSignatureScriptSignature(Seq(EmptyDigitalSignature))
val (spendingTx, inputIndex) = TransactionTestUtil.buildSpendingTransaction(creditingTx, scriptSig, outputIndex)
val txSignatureComponent = BaseTxSigComponent(
transaction = spendingTx,
inputIndex = inputIndex,
output = TransactionOutput(CurrencyUnits.zero, redeemScript),
Policy.standardScriptVerifyFlags)
val txSignature = TransactionSignatureCreator.createSig(txSignatureComponent, privateKey, HashType.sigHashAll)
val (spendingTx, inputIndex) =
TransactionTestUtil.buildSpendingTransaction(creditingTx,
scriptSig,
outputIndex)
val txSignatureComponent =
BaseTxSigComponent(transaction = spendingTx,
inputIndex = inputIndex,
output =
TransactionOutput(CurrencyUnits.zero, redeemScript),
Policy.standardScriptVerifyFlags)
val txSignature =
TransactionSignatureCreator.createSig(txSignatureComponent,
privateKey,
HashType.sigHashAll)
val signedScriptSig = MultiSignatureScriptSignature(Seq(txSignature))
val p2shScriptSig = P2SHScriptSignature(signedScriptSig, redeemScript)
val (signedTx, _) = TransactionTestUtil.buildSpendingTransaction(creditingTx, p2shScriptSig, outputIndex)
val signedScriptSig = MultiSignatureScriptSignature(Seq(txSignature))
val p2shScriptSig = P2SHScriptSignature(signedScriptSig, redeemScript)
val (signedTx, _) =
TransactionTestUtil.buildSpendingTransaction(creditingTx,
p2shScriptSig,
outputIndex)
val signedTxSigComponent = BaseTxSigComponent(
transaction = signedTx,
inputIndex = inputIndex,
output = TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
//run it through the interpreter
val program = PreExecutionScriptProgram(signedTxSigComponent)
val result = ScriptInterpreter.run(program)
result must be(ScriptOk)
}
val signedTxSigComponent =
BaseTxSigComponent(transaction = signedTx,
inputIndex = inputIndex,
output =
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardScriptVerifyFlags)
//run it through the interpreter
val program = PreExecutionScriptProgram(signedTxSigComponent)
val result = ScriptInterpreter.run(program)
result must be(ScriptOk)
}
it must "be able to use a sign function that returns a Future[ECDigitalSignature] and have the sig validate" in {
import scala.concurrent.ExecutionContext.Implicits.global
@ -203,24 +263,37 @@ class TransactionSignatureCreatorTest extends FlatSpec with MustMatchers with Sc
val publicKey = privateKey.publicKey
val redeemScript = MultiSignatureScriptPubKey(1, Seq(publicKey))
val scriptPubKey = P2SHScriptPubKey(redeemScript)
val (creditingTx, outputIndex) = TransactionTestUtil.buildCreditingTransaction(scriptPubKey)
val (creditingTx, outputIndex) =
TransactionTestUtil.buildCreditingTransaction(scriptPubKey)
val scriptSig = MultiSignatureScriptSignature(Seq(EmptyDigitalSignature))
val (spendingTx, inputIndex) = TransactionTestUtil.buildSpendingTransaction(creditingTx, scriptSig, outputIndex)
val txSignatureComponent = BaseTxSigComponent(
transaction = spendingTx,
inputIndex = inputIndex,
output = TransactionOutput(CurrencyUnits.zero, redeemScript),
flags = Policy.standardScriptVerifyFlags)
val sign: ByteVector => Future[ECDigitalSignature] = {
bytes: ByteVector => Future(privateKey.sign(bytes))
val (spendingTx, inputIndex) =
TransactionTestUtil.buildSpendingTransaction(creditingTx,
scriptSig,
outputIndex)
val txSignatureComponent =
BaseTxSigComponent(transaction = spendingTx,
inputIndex = inputIndex,
output =
TransactionOutput(CurrencyUnits.zero, redeemScript),
flags = Policy.standardScriptVerifyFlags)
val sign: ByteVector => Future[ECDigitalSignature] = { bytes: ByteVector =>
Future(privateKey.sign(bytes))
}
val txSignature = TransactionSignatureCreator.createSig(txSignatureComponent, sign, HashType.sigHashAll)
val txSignature =
TransactionSignatureCreator.createSig(txSignatureComponent,
sign,
HashType.sigHashAll)
val signedScriptSig = txSignature.map(sig => MultiSignatureScriptSignature(Seq(sig)))
val p2shScriptSig = signedScriptSig.map(ss => P2SHScriptSignature(ss, redeemScript))
val signedTxFuture: Future[(Transaction, UInt32)] = p2shScriptSig.map { ss =>
TransactionTestUtil.buildSpendingTransaction(creditingTx, ss, outputIndex)
val signedScriptSig =
txSignature.map(sig => MultiSignatureScriptSignature(Seq(sig)))
val p2shScriptSig =
signedScriptSig.map(ss => P2SHScriptSignature(ss, redeemScript))
val signedTxFuture: Future[(Transaction, UInt32)] = p2shScriptSig.map {
ss =>
TransactionTestUtil.buildSpendingTransaction(creditingTx,
ss,
outputIndex)
}
//run it through the interpreter
val program = signedTxFuture.map {

View file

@ -1,141 +1,165 @@
package org.bitcoins.core.crypto
import org.bitcoins.core.currency.{ Bitcoins, CurrencyUnits, Satoshis }
import org.bitcoins.core.number.{ Int32, Int64, UInt32 }
import org.bitcoins.core.currency.{Bitcoins, CurrencyUnits, Satoshis}
import org.bitcoins.core.number.{Int32, Int64, UInt32}
import org.bitcoins.core.policy.Policy
import org.bitcoins.core.protocol.script._
import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.script.crypto._
import org.bitcoins.core.serializers.script.ScriptParser
import org.bitcoins.core.util._
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import scala.util.Try
/**
* Created by chris on 2/19/16.
*/
* Created by chris on 2/19/16.
*/
class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
private def logger = BitcoinSLogger.logger
val scriptPubKey = BitcoinjConversions.toScriptPubKey(BitcoinJTestUtil.multiSigScript)
val scriptPubKey =
BitcoinjConversions.toScriptPubKey(BitcoinJTestUtil.multiSigScript)
"TransactionSignatureSerializer" must "correctly serialize an input that is being checked where another input in the same tx is using SIGHASH_ANYONECANPAY" in {
//this is from a test case inside of tx_valid.json
//https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L91
val rawTx = "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000"
val rawTx =
"01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000"
val inputIndex = UInt32.zero
val spendingTx = Transaction(rawTx)
val scriptPubKeyFromString = ScriptParser.fromString("0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG")
val scriptPubKeyFromString = ScriptParser.fromString(
"0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG")
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val txSigComponent = BaseTxSigComponent(
spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val txSigComponent =
BaseTxSigComponent(spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val serializedTxForSig: String = BitcoinSUtil.encodeHex(
TransactionSignatureSerializer.serializeForSignature(txSigComponent, HashType.sigHashAll))
TransactionSignatureSerializer.serializeForSignature(txSigComponent,
HashType.sigHashAll))
//serialization is from bitcoin core
serializedTxForSig must be("01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac0100000000020000000000000000000000000000000000000000000000000000000000000000000000ffffffff01010000000000000001510000000001000000")
serializedTxForSig must be(
"01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac0100000000020000000000000000000000000000000000000000000000000000000000000000000000ffffffff01010000000000000001510000000001000000")
}
it must "correctly serialize a tx for signing with multiple inputs using SIGHASH_SINGLE" in {
//this is from a test case inside of tx_valid.json
//https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L96
val rawTx = "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000"
val rawTx =
"010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000"
val inputIndex = UInt32.zero
val spendingTx = Transaction(rawTx)
val scriptPubKeyFromString = ScriptParser.fromString("DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG")
val scriptPubKeyFromString = ScriptParser.fromString(
"DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG")
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val txSigComponent = BaseTxSigComponent(
spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val txSigComponent =
BaseTxSigComponent(spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val serializedTxForSig: String = BitcoinSUtil.encodeHex(
TransactionSignatureSerializer.serializeForSignature(txSigComponent, HashType.sigHashSingle))
TransactionSignatureSerializer
.serializeForSignature(txSigComponent, HashType.sigHashSingle))
//serialization is from bitcoin core
serializedTxForSig must be("010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000000000003f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee0100000000000000000180841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac0000000003000000")
serializedTxForSig must be(
"010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000000000003f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee0100000000000000000180841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac0000000003000000")
}
it must "correctly serialize a tx for signing with the last input using SIGHASH_SINGLE" in {
//this is from a test case inside of tx_valid.json
//https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L96
val rawTx = "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000"
val rawTx =
"010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000"
val inputIndex = UInt32(2)
val spendingTx = Transaction(rawTx)
val scriptPubKeyFromString = ScriptParser.fromString("DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG")
val scriptPubKeyFromString = ScriptParser.fromString(
"DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG")
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val txSigComponent = BaseTxSigComponent(
spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val txSigComponent =
BaseTxSigComponent(spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val serializedTxForSig: String = BitcoinSUtil.encodeHex(
TransactionSignatureSerializer.serializeForSignature(txSigComponent, HashType.sigHashSingle))
TransactionSignatureSerializer
.serializeForSignature(txSigComponent, HashType.sigHashSingle))
//serialization is from bitcoin core
serializedTxForSig must be("010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf630000000000000000007d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000000000003f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff03ffffffffffffffff00ffffffffffffffff00e0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac0000000003000000")
serializedTxForSig must be(
"010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf630000000000000000007d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000000000003f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff03ffffffffffffffff00ffffffffffffffff00e0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac0000000003000000")
}
it must "correctly serialize a tx which spends an input that pushes using a PUSHDATA1 that is negative when read as signed" in {
//this is from a test case inside of tx_valid.json
//https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L102
val rawTx = "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000"
val rawTx =
"0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000"
val inputIndex = UInt32.zero
val spendingTx = Transaction(rawTx)
val scriptPubKeyFromString = ScriptParser.fromString("0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG")
val scriptPubKeyFromString = ScriptParser.fromString(
"0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG")
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val txSigComponent = BaseTxSigComponent(
spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val txSigComponent =
BaseTxSigComponent(spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val serializedTxForSig: String = BitcoinSUtil.encodeHex(
TransactionSignatureSerializer.serializeForSignature(txSigComponent, HashType.sigHashAll))
TransactionSignatureSerializer.serializeForSignature(txSigComponent,
HashType.sigHashAll))
//serialization is from bitcoin core
serializedTxForSig must be("0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c500000000ca4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288acffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac0000000001000000")
serializedTxForSig must be(
"0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c500000000ca4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288acffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac0000000001000000")
}
it must "correctly hash a tx with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature" in {
//this is from a test case inside of tx_invalid.json
//https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L75
val rawTx = "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000"
val rawTx =
"01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000"
val inputIndex = UInt32.zero
val spendingTx = Transaction(rawTx)
val scriptPubKeyFromString = ScriptParser.fromString("0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG")
val scriptPubKeyFromString = ScriptParser.fromString(
"0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG")
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val txSigComponent = BaseTxSigComponent(
spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val txSigComponent =
BaseTxSigComponent(spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val serializedTxForSig: String = BitcoinSUtil.encodeHex(
TransactionSignatureSerializer.serializeForSignature(txSigComponent, HashType.sigHashAll))
serializedTxForSig must be("01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac01000000000200000000000000000000000000000000000000000000000000000000000000000000000100000001010000000000000001510000000001000000")
TransactionSignatureSerializer.serializeForSignature(txSigComponent,
HashType.sigHashAll))
serializedTxForSig must be(
"01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac01000000000200000000000000000000000000000000000000000000000000000000000000000000000100000001010000000000000001510000000001000000")
}
it must "serialize a p2wpkh with SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" in {
val rawTx = "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff05540b0000000000000151d0070000000000000151840300000000000001513c0f00000000000001512c010000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71000000000000"
val rawTx =
"0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff05540b0000000000000151d0070000000000000151840300000000000001513c0f00000000000001512c010000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71000000000000"
val inputIndex = UInt32(1)
val wtx = WitnessTransaction(rawTx)
val witScriptPubKey = P2WPKHWitnessSPKV0("1600144c9c3dfac4207d5d8cb89df5722cb3d712385e3f")
val witScriptPubKey =
P2WPKHWitnessSPKV0("1600144c9c3dfac4207d5d8cb89df5722cb3d712385e3f")
val amount = Satoshis(Int64(2000))
val txSigComponent = WitnessTxSigComponentRaw(
wtx,
inputIndex,
TransactionOutput(amount, witScriptPubKey),
Policy.standardFlags)
val txSigComponent =
WitnessTxSigComponentRaw(wtx,
inputIndex,
TransactionOutput(amount, witScriptPubKey),
Policy.standardFlags)
val serializedForSig = TransactionSignatureSerializer.serializeForSignature(
txSigComponent,
HashType.sigHashSingleAnyoneCanPay)
BitcoinSUtil.encodeHex(serializedForSig) must be("01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88acd007000000000000ffffffff2d793f9722ac8cbea9b2e0a2929cda4007b8312c6ec3b997088439e48e7aa64e0000000083000000")
BitcoinSUtil.encodeHex(serializedForSig) must be(
"01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88acd007000000000000ffffffff2d793f9722ac8cbea9b2e0a2929cda4007b8312c6ec3b997088439e48e7aa64e0000000083000000")
}
it must "work with the p2sh(p2wpkh) example in BIP143" in {
@ -154,12 +178,15 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
"01000000"
}
val expectedHash = DoubleSha256Digest.fromHex("64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6")
val expectedHash = DoubleSha256Digest.fromHex(
"64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6")
val inputIndex = UInt32.zero
val p2sh = P2SHScriptPubKey.fromAsmHex("a9144733f37cf4db86fbc2efed2500b4f4e49f31202387")
val redeemScript = P2WPKHWitnessSPKV0.fromAsmHex("001479091972186c449eb1ded22b78e40d009bdf0089")
val p2sh = P2SHScriptPubKey.fromAsmHex(
"a9144733f37cf4db86fbc2efed2500b4f4e49f31202387")
val redeemScript = P2WPKHWitnessSPKV0.fromAsmHex(
"001479091972186c449eb1ded22b78e40d009bdf0089")
val amount = Bitcoins(10)
@ -167,25 +194,31 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
//https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#p2sh-p2wpkh
val unsignedTx = "0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000"
val unsignedTx =
"0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000"
val ubtx = BaseTransaction.fromHex(unsignedTx)
val p2shScriptSig = P2SHScriptSignature(redeemScript)
val oldInput = ubtx.inputs(inputIndex.toInt)
val updatedInput = TransactionInput(oldInput.previousOutput, p2shScriptSig, oldInput.sequence)
val updatedInput = TransactionInput(oldInput.previousOutput,
p2shScriptSig,
oldInput.sequence)
val updatedInputs = ubtx.inputs.updated(inputIndex.toInt, updatedInput)
val uwtx = WitnessTransaction(ubtx.version, updatedInputs, ubtx.outputs, ubtx.lockTime, EmptyWitness)
val uwtx = WitnessTransaction(ubtx.version,
updatedInputs,
ubtx.outputs,
ubtx.lockTime,
EmptyWitness)
val wtxSigComp = {
WitnessTxSigComponentP2SH(
transaction = uwtx,
inputIndex = inputIndex,
output = output,
flags = Policy.standardFlags)
WitnessTxSigComponentP2SH(transaction = uwtx,
inputIndex = inputIndex,
output = output,
flags = Policy.standardFlags)
}
val serialized = TransactionSignatureSerializer.serializeForSignature(
@ -214,36 +247,44 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
val bitcoins = Bitcoins(9.87654321)
val p2wsh = P2WSHWitnessSPKV0.fromAsmHex("0020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54")
val p2wsh = P2WSHWitnessSPKV0.fromAsmHex(
"0020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54")
val p2shSPK = P2SHScriptPubKey.fromAsmHex("a9149993a429037b5d912407a71c252019287b8d27a587")
val p2shSPK = P2SHScriptPubKey.fromAsmHex(
"a9149993a429037b5d912407a71c252019287b8d27a587")
val p2shScriptSig = P2SHScriptSignature(
witnessScriptPubKey = p2wsh)
val p2shScriptSig = P2SHScriptSignature(witnessScriptPubKey = p2wsh)
val oldInput = ubtx.inputs(inputIndex.toInt)
val updatedInput = TransactionInput(oldInput.previousOutput, p2shScriptSig, oldInput.sequence)
val updatedInput = TransactionInput(oldInput.previousOutput,
p2shScriptSig,
oldInput.sequence)
val updatedInputs = ubtx.inputs.updated(inputIndex.toInt, updatedInput)
val m = MultiSignatureScriptPubKey.fromAsmHex("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae")
val m = MultiSignatureScriptPubKey.fromAsmHex(
"56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae")
val witnessScript = P2WSHWitnessV0(m)
val txWit = TransactionWitness(Vector(witnessScript))
val uwtx = WitnessTransaction(ubtx.version, updatedInputs, ubtx.outputs, ubtx.lockTime, txWit)
val uwtx = WitnessTransaction(ubtx.version,
updatedInputs,
ubtx.outputs,
ubtx.lockTime,
txWit)
val output = TransactionOutput(bitcoins, p2shSPK)
val wtxSigComp = {
WitnessTxSigComponentP2SH(
transaction = uwtx,
inputIndex = inputIndex,
output = output,
flags = Policy.standardFlags)
WitnessTxSigComponentP2SH(transaction = uwtx,
inputIndex = inputIndex,
output = output,
flags = Policy.standardFlags)
}
val expectedSerialization = "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa03bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504436641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffffbc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc0000000001000000"
val expectedSerialization =
"0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa03bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504436641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffffbc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc0000000001000000"
val serialization = TransactionSignatureSerializer.serializeForSignature(
txSigComponent = wtxSigComp,
@ -253,33 +294,41 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
//with a SIGHASH_NONE
val expectedSigHashNone = "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000002000000"
val expectedSigHashNone =
"0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000002000000"
val serializationSigHashNone = TransactionSignatureSerializer.serializeForSignature(
txSigComponent = wtxSigComp,
hashType = HashType.sigHashNone)
val serializationSigHashNone =
TransactionSignatureSerializer.serializeForSignature(
txSigComponent = wtxSigComp,
hashType = HashType.sigHashNone)
serializationSigHashNone.toHex must be(expectedSigHashNone)
//with sighash single
val expectedSigHashSingle = "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000003000000"
val expectedSigHashSingle =
"0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000003000000"
val serializationSigHashSingle = TransactionSignatureSerializer.serializeForSignature(
txSigComponent = wtxSigComp,
hashType = HashType.sigHashSingle)
val serializationSigHashSingle =
TransactionSignatureSerializer.serializeForSignature(
txSigComponent = wtxSigComp,
hashType = HashType.sigHashSingle)
serializationSigHashSingle.toHex must be(expectedSigHashSingle)
val expectedSigHashAllAnyoneCanPay = "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffffbc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc0000000081000000"
val expectedSigHashAllAnyoneCanPay =
"010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffffbc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc0000000081000000"
val serializationSigHashAllAnyoneCanPay = TransactionSignatureSerializer.serializeForSignature(
txSigComponent = wtxSigComp,
hashType = HashType.sigHashAllAnyoneCanPay)
val serializationSigHashAllAnyoneCanPay =
TransactionSignatureSerializer.serializeForSignature(
txSigComponent = wtxSigComp,
hashType = HashType.sigHashAllAnyoneCanPay)
serializationSigHashAllAnyoneCanPay.toHex must be(expectedSigHashAllAnyoneCanPay)
serializationSigHashAllAnyoneCanPay.toHex must be(
expectedSigHashAllAnyoneCanPay)
val expectedSigHashNoneAnyoneCanPay = "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000082000000"
val expectedSigHashNoneAnyoneCanPay =
"010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000082000000"
val serializationSigHashNoneAnyoneCanPay = {
TransactionSignatureSerializer.serializeForSignature(
@ -287,49 +336,59 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
hashType = HashType.sigHashNoneAnyoneCanPay)
}
serializationSigHashNoneAnyoneCanPay.toHex must be(expectedSigHashNoneAnyoneCanPay)
serializationSigHashNoneAnyoneCanPay.toHex must be(
expectedSigHashNoneAnyoneCanPay)
val expectedSigHashSingleAnyoneCanPay = "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000083000000"
val expectedSigHashSingleAnyoneCanPay =
"010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000083000000"
val serializationSigHashSingleAnyoneCanPay = {
TransactionSignatureSerializer.serializeForSignature(
txSigComponent = wtxSigComp,
hashType = HashType.sigHashSingleAnyoneCanPay)
}
serializationSigHashSingleAnyoneCanPay.toHex must be(expectedSigHashSingleAnyoneCanPay)
serializationSigHashSingleAnyoneCanPay.toHex must be(
expectedSigHashSingleAnyoneCanPay)
}
it must "make sure FindAndDelete is not applied to the BIP143 serialization algorithm" in {
val unsignedTx = "010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff0101000000000000000000000000"
val unsignedTx =
"010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff0101000000000000000000000000"
val ubtx = BaseTransaction.fromHex(unsignedTx)
val inputIndex = UInt32.zero
val p2wsh = P2WSHWitnessSPKV0.fromAsmHex("00209e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19")
val p2wsh = P2WSHWitnessSPKV0.fromAsmHex(
"00209e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19")
val amount = Satoshis(Int64(200000))
val output = TransactionOutput(amount, p2wsh)
//OP_CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01>
val redeemScript = NonStandardScriptPubKey.fromAsmHex("ad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01")
val redeemScript = NonStandardScriptPubKey.fromAsmHex(
"ad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01")
val scriptWit = P2WSHWitnessV0(redeemScript)
val txWit = TransactionWitness(Vector(scriptWit))
val uwtx = WitnessTransaction(ubtx.version, ubtx.inputs, ubtx.outputs, ubtx.lockTime, txWit)
val uwtx = WitnessTransaction(ubtx.version,
ubtx.inputs,
ubtx.outputs,
ubtx.lockTime,
txWit)
val wtxSigCompRaw = {
WitnessTxSigComponentRaw(
transaction = uwtx,
inputIndex = inputIndex,
output = output,
flags = Policy.standardFlags)
WitnessTxSigComponentRaw(transaction = uwtx,
inputIndex = inputIndex,
output = output,
flags = Policy.standardFlags)
}
val serialized = TransactionSignatureSerializer.serializeForSignature(
txSigComponent = wtxSigCompRaw,
hashType = HashType.sigHashAll)
val expectedSerialization = "01000000b67c76d200c6ce72962d919dc107884b9d5d0e26f2aea7474b46a1904c53359f3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504469c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d00004aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01400d030000000000ffffffffe5d196bfb21caca9dbd654cafb3b4dc0c4882c8927d2eb300d9539dd0b9342280000000001000000"
val expectedSerialization =
"01000000b67c76d200c6ce72962d919dc107884b9d5d0e26f2aea7474b46a1904c53359f3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504469c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d00004aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01400d030000000000ffffffffe5d196bfb21caca9dbd654cafb3b4dc0c4882c8927d2eb300d9539dd0b9342280000000001000000"
serialized.toHex must be(expectedSerialization)
}

View file

@ -2,13 +2,13 @@ package org.bitcoins.core.currency
import org.bitcoins.core.gen.CurrencyUnitGenerator
import org.bitcoins.core.number.Int64
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
import scala.util.Try
/**
* Created by chris on 6/23/16.
*/
* Created by chris on 6/23/16.
*/
class CurrencyUnitSpec extends Properties("CurrencyUnitSpec") {
property("Symmetrical serialization for satoshis") =
@ -16,31 +16,35 @@ class CurrencyUnitSpec extends Properties("CurrencyUnitSpec") {
Satoshis(satoshis.hex) == satoshis
}
property("additive identity") =
Prop.forAll(CurrencyUnitGenerator.satoshis) { satoshis =>
property("additive identity") = Prop.forAll(CurrencyUnitGenerator.satoshis) {
satoshis =>
satoshis + CurrencyUnits.zero == satoshis
}
}
property("add two satoshis") =
Prop.forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { (num1: Satoshis, num2: Satoshis) =>
property("add two satoshis") = Prop.forAll(CurrencyUnitGenerator.satoshis,
CurrencyUnitGenerator.satoshis) {
(num1: Satoshis, num2: Satoshis) =>
val result: Try[Int64] = Try(Int64(num1.toBigInt + num2.toBigInt))
if (result.isSuccess && result.get >= Int64(Satoshis.min.toLong) &&
result.get <= Int64(Satoshis.max.toLong)) num1 + num2 == Satoshis(result.get)
result.get <= Int64(Satoshis.max.toLong))
num1 + num2 == Satoshis(result.get)
else Try(num1 + num2).isFailure
}
}
property("Subtractive identity for satoshis") =
Prop.forAll(CurrencyUnitGenerator.satoshis) { satoshis =>
satoshis - CurrencyUnits.zero == satoshis
}
property("Subtract two satoshi values") =
Prop.forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { (num1: Satoshis, num2: Satoshis) =>
val result: Try[Int64] = Try(Int64(num1.toBigInt - num2.toBigInt))
if (result.isSuccess && result.get >= Int64(Satoshis.min.toLong) &&
result.get <= Int64(Satoshis.max.toLong)) num1 - num2 == Satoshis(result.get)
else Try(num1 - num2).isFailure
}
property("Subtract two satoshi values") = Prop.forAll(
CurrencyUnitGenerator.satoshis,
CurrencyUnitGenerator.satoshis) { (num1: Satoshis, num2: Satoshis) =>
val result: Try[Int64] = Try(Int64(num1.toBigInt - num2.toBigInt))
if (result.isSuccess && result.get >= Int64(Satoshis.min.toLong) &&
result.get <= Int64(Satoshis.max.toLong))
num1 - num2 == Satoshis(result.get)
else Try(num1 - num2).isFailure
}
property("Multiply satoshis by zero") =
Prop.forAll(CurrencyUnitGenerator.satoshis) { satoshis =>
@ -53,28 +57,33 @@ class CurrencyUnitSpec extends Properties("CurrencyUnitSpec") {
}
property("Multiply two satoshi values") =
Prop.forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { (num1: Satoshis, num2: Satoshis) =>
val result: Try[Int64] = Try(Int64(num1.toBigInt * num2.toBigInt))
if (result.isSuccess && result.get >= Int64(Satoshis.min.toLong) &&
result.get <= Int64(Satoshis.max.toLong)) num1 * num2 == Satoshis(result.get)
else Try(num1 * num2).isFailure
}
property("Multiply two satoshi values") = Prop.forAll(
CurrencyUnitGenerator.satoshis,
CurrencyUnitGenerator.satoshis) { (num1: Satoshis, num2: Satoshis) =>
val result: Try[Int64] = Try(Int64(num1.toBigInt * num2.toBigInt))
if (result.isSuccess && result.get >= Int64(Satoshis.min.toLong) &&
result.get <= Int64(Satoshis.max.toLong))
num1 * num2 == Satoshis(result.get)
else Try(num1 * num2).isFailure
}
property("< & >=") =
Prop.forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { (num1: Satoshis, num2: Satoshis) =>
property("< & >=") = Prop.forAll(CurrencyUnitGenerator.satoshis,
CurrencyUnitGenerator.satoshis) {
(num1: Satoshis, num2: Satoshis) =>
(num1 < num2) || (num1 >= num2)
}
}
property("<= & >") =
Prop.forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { (num1: Satoshis, num2: Satoshis) =>
property("<= & >") = Prop.forAll(CurrencyUnitGenerator.satoshis,
CurrencyUnitGenerator.satoshis) {
(num1: Satoshis, num2: Satoshis) =>
(num1 <= num2) || (num1 > num2)
}
}
property("== & !=") =
Prop.forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.satoshis) { (num1: Satoshis, num2: Satoshis) =>
property("== & !=") = Prop.forAll(CurrencyUnitGenerator.satoshis,
CurrencyUnitGenerator.satoshis) {
(num1: Satoshis, num2: Satoshis) =>
(num1 == num2) || (num1 != num2)
}
}
property("convert satoshis to bitcoin and then back to satoshis") = {
Prop.forAll(CurrencyUnitGenerator.satoshis) { satoshis: Satoshis =>
@ -84,13 +93,14 @@ class CurrencyUnitSpec extends Properties("CurrencyUnitSpec") {
}
property("be able to add two unique currency unit types") = {
Prop.forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.bitcoins) { (num1: Satoshis, num2: Bitcoins) =>
val result = Try(Satoshis(Int64(num1.toBigInt + num2.satoshis.toBigInt)))
val expected = result.map(Bitcoins(_))
val actual: Try[CurrencyUnit] = Try(num1 + num2)
if (actual.isSuccess && expected.isSuccess) actual.get == expected.get
else actual.isFailure && expected.isFailure
Prop.forAll(CurrencyUnitGenerator.satoshis, CurrencyUnitGenerator.bitcoins) {
(num1: Satoshis, num2: Bitcoins) =>
val result =
Try(Satoshis(Int64(num1.toBigInt + num2.satoshis.toBigInt)))
val expected = result.map(Bitcoins(_))
val actual: Try[CurrencyUnit] = Try(num1 + num2)
if (actual.isSuccess && expected.isSuccess) actual.get == expected.get
else actual.isFailure && expected.isFailure
}
}
}

View file

@ -1,89 +1,98 @@
package org.bitcoins.core.number
import org.bitcoins.core.gen.NumberGenerator
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
import scala.util.Try
/**
* Created by chris on 6/21/16.
*/
* Created by chris on 6/21/16.
*/
class Int32Spec extends Properties("Int32Spec") {
property("Serialization symmetry") =
Prop.forAll(NumberGenerator.int32s) { int32: Int32 =>
property("Serialization symmetry") = Prop.forAll(NumberGenerator.int32s) {
int32: Int32 =>
Int32(int32.hex) == int32
}
property("Additive identity") =
Prop.forAll(NumberGenerator.int32s) { int32: Int32 =>
}
property("Additive identity") = Prop.forAll(NumberGenerator.int32s) {
int32: Int32 =>
int32 + Int32.zero == int32
}
}
property("Add two arbitrary int32s") =
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) =>
val result = num1.toLong + num2.toLong
if (result <= Int32.max.toLong && result >= Int32.min.toLong) num1 + num2 == Int32(result)
else Try(num1 + num2).isFailure
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) {
(num1: Int32, num2: Int32) =>
val result = num1.toLong + num2.toLong
if (result <= Int32.max.toLong && result >= Int32.min.toLong)
num1 + num2 == Int32(result)
else Try(num1 + num2).isFailure
}
property("Subtractive identity") =
Prop.forAll(NumberGenerator.int32s) { int32: Int32 =>
property("Subtractive identity") = Prop.forAll(NumberGenerator.int32s) {
int32: Int32 =>
int32 - Int32.zero == int32
}
}
property("Subtract two arbitrary int32s") =
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) =>
val result = num1.toLong - num2.toLong
if (result >= Int32.min.toLong && result <= Int32.max.toLong) num1 - num2 == Int32(result)
else Try(num1 - num2).isFailure
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) {
(num1: Int32, num2: Int32) =>
val result = num1.toLong - num2.toLong
if (result >= Int32.min.toLong && result <= Int32.max.toLong)
num1 - num2 == Int32(result)
else Try(num1 - num2).isFailure
}
property("Multiplying by zero") =
Prop.forAll(NumberGenerator.int32s) { int32: Int32 =>
property("Multiplying by zero") = Prop.forAll(NumberGenerator.int32s) {
int32: Int32 =>
int32 * Int32.zero == Int32.zero
}
}
property("Multiplicative identity") =
Prop.forAll(NumberGenerator.int32s) { int32: Int32 =>
property("Multiplicative identity") = Prop.forAll(NumberGenerator.int32s) {
int32: Int32 =>
int32 * Int32.one == int32
}
}
property("Multiply two int32s") =
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) =>
val result = num1.toLong * num2.toLong
if (result >= Int32.min.toLong && result <= Int32.max.toLong) num1 * num2 == Int32(result.toInt)
else Try(num1 * num2).isFailure
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) {
(num1: Int32, num2: Int32) =>
val result = num1.toLong * num2.toLong
if (result >= Int32.min.toLong && result <= Int32.max.toLong)
num1 * num2 == Int32(result.toInt)
else Try(num1 * num2).isFailure
}
property("<= & >") =
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) =>
if (num1.toLong <= num2.toLong) num1 <= num2
else num1 > num2
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) {
(num1: Int32, num2: Int32) =>
if (num1.toLong <= num2.toLong) num1 <= num2
else num1 > num2
}
property("< & =>") =
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) =>
if (num1.toLong < num2.toLong) num1 < num2
else num1 >= num2
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) {
(num1: Int32, num2: Int32) =>
if (num1.toLong < num2.toLong) num1 < num2
else num1 >= num2
}
property("== & !=") =
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) =>
if (num1.toLong == num2.toLong) num1 == num2
else num1 != num2
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) {
(num1: Int32, num2: Int32) =>
if (num1.toLong == num2.toLong) num1 == num2
else num1 != num2
}
property("|") =
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) =>
property("|") = Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) {
(num1: Int32, num2: Int32) =>
Int32(num1.toLong | num2.toLong) == (num1 | num2)
}
}
property("&") =
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) =>
property("&") = Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) {
(num1: Int32, num2: Int32) =>
Int32(num1.toLong & num2.toLong) == (num1 & num2)
}
}
property("negation") = {
Prop.forAll(NumberGenerator.int32s) { int32 =>

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.number
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.ByteVector
/**
* Created by chris on 6/15/16.
*/
* Created by chris on 6/15/16.
*/
class Int32Test extends FlatSpec with MustMatchers {
"Int32" must "create the number zero" in {
@ -19,7 +19,8 @@ class Int32Test extends FlatSpec with MustMatchers {
}
it must "represent the number -1 with 4 bytes" in {
val int32 = Int32(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val int32 =
Int32(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
int32.toInt must be(-1)
}
@ -34,7 +35,8 @@ class Int32Test extends FlatSpec with MustMatchers {
}
it must "create the max number for an Int32" in {
val int32 = Int32(ByteVector(0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val int32 =
Int32(ByteVector(0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
int32.toInt must be(2147483647)
}

View file

@ -1,89 +1,98 @@
package org.bitcoins.core.number
import org.bitcoins.core.gen.NumberGenerator
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
import scala.util.Try
/**
* Created by chris on 6/21/16.
*/
* Created by chris on 6/21/16.
*/
class Int64Spec extends Properties("Int64Spec") {
property("Symmetrical serialization") =
Prop.forAll(NumberGenerator.int64s) { int64: Int64 =>
property("Symmetrical serialization") = Prop.forAll(NumberGenerator.int64s) {
int64: Int64 =>
Int64(int64.hex) == int64
}
}
property("Additive identity") =
Prop.forAll(NumberGenerator.int64s) { int64: Int64 =>
property("Additive identity") = Prop.forAll(NumberGenerator.int64s) {
int64: Int64 =>
int64 + Int64.zero == int64
}
}
property("Add two arbitrary int64s") =
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) =>
val result = num1.toBigInt + num2.toBigInt
if (result >= Int64.min.toLong && result <= Int64.max.toLong) num1 + num2 == Int64(result)
else Try(num1 + num2).isFailure
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) {
(num1: Int64, num2: Int64) =>
val result = num1.toBigInt + num2.toBigInt
if (result >= Int64.min.toLong && result <= Int64.max.toLong)
num1 + num2 == Int64(result)
else Try(num1 + num2).isFailure
}
property("Subtractive identity") =
Prop.forAll(NumberGenerator.int64s) { int64: Int64 =>
property("Subtractive identity") = Prop.forAll(NumberGenerator.int64s) {
int64: Int64 =>
int64 - Int64.zero == int64
}
}
property("Subtract two arbitrary int64s") =
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) =>
val result = num1.toBigInt - num2.toBigInt
if (result >= Int64.min.toLong && result <= Int64.max.toLong) num1 - num2 == Int64(result)
else Try(num1 - num2).isFailure
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) {
(num1: Int64, num2: Int64) =>
val result = num1.toBigInt - num2.toBigInt
if (result >= Int64.min.toLong && result <= Int64.max.toLong)
num1 - num2 == Int64(result)
else Try(num1 - num2).isFailure
}
property("Multiplying by zero") =
Prop.forAll(NumberGenerator.int64s) { int64: Int64 =>
property("Multiplying by zero") = Prop.forAll(NumberGenerator.int64s) {
int64: Int64 =>
int64 * Int64.zero == Int64.zero
}
}
property("Multiplicative identity") =
Prop.forAll(NumberGenerator.int64s) { int64: Int64 =>
property("Multiplicative identity") = Prop.forAll(NumberGenerator.int64s) {
int64: Int64 =>
int64 * Int64.one == int64
}
}
property("Multiply two arbitrary int64s") =
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) =>
val result = num1.toBigInt * num2.toBigInt
if (result >= Int64.min.toLong && result <= Int64.max.toLong) num1 * num2 == Int64(result)
else Try(num1 * num2).isFailure
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) {
(num1: Int64, num2: Int64) =>
val result = num1.toBigInt * num2.toBigInt
if (result >= Int64.min.toLong && result <= Int64.max.toLong)
num1 * num2 == Int64(result)
else Try(num1 * num2).isFailure
}
property("<= & >") =
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) =>
if (num1.toLong <= num2.toLong) num1 <= num2
else num1 > num2
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) {
(num1: Int64, num2: Int64) =>
if (num1.toLong <= num2.toLong) num1 <= num2
else num1 > num2
}
property("< & =>") =
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) =>
if (num1.toLong < num2.toLong) num1 < num2
else num1 >= num2
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) {
(num1: Int64, num2: Int64) =>
if (num1.toLong < num2.toLong) num1 < num2
else num1 >= num2
}
property("== & !=") =
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) =>
if (num1.toLong == num2.toLong) num1 == num2
else num1 != num2
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) {
(num1: Int64, num2: Int64) =>
if (num1.toLong == num2.toLong) num1 == num2
else num1 != num2
}
property("|") =
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) =>
property("|") = Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) {
(num1: Int64, num2: Int64) =>
Int64(num1.toLong | num2.toLong) == (num1 | num2)
}
}
property("&") =
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) =>
property("&") = Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) {
(num1: Int64, num2: Int64) =>
Int64(num1.toLong & num2.toLong) == (num1 & num2)
}
}
property("negation") = {
Prop.forAll(NumberGenerator.int64s) { int64 =>
@ -92,4 +101,3 @@ class Int64Spec extends Properties("Int64Spec") {
}
}

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.number
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.ByteVector
/**
* Created by chris on 6/15/16.
*/
* Created by chris on 6/15/16.
*/
class Int64Test extends FlatSpec with MustMatchers {
"Int64" must "represent the nubmer zero" in {
@ -22,12 +22,20 @@ class Int64Test extends FlatSpec with MustMatchers {
}
it must "represent the number -1 with 8 bytes" in {
val int64 = Int64(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte,
0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val int64 = Int64(
ByteVector(0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte))
int64.toLong must be(-1)
}
it must "represent the Int32 max value" in {
val int64 = Int64(ByteVector(0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val int64 =
Int64(ByteVector(0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
int64.toLong must be(2147483647)
}
@ -37,29 +45,59 @@ class Int64Test extends FlatSpec with MustMatchers {
}
it must "represent the Int32 max value + 1" in {
val int64 = Int64(ByteVector(0x0.toByte, 0x80.toByte, 0.toByte, 0.toByte, 0.toByte))
val int64 =
Int64(ByteVector(0x0.toByte, 0x80.toByte, 0.toByte, 0.toByte, 0.toByte))
int64.toLong must be(2147483648L)
}
it must "represent the Int32 min value - 1" in {
val int64 = Int64(ByteVector(0xff.toByte, 0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val int64 = Int64(
ByteVector(0xff.toByte,
0x7f.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte))
int64.toLong must be(-2147483649L)
}
it must "represent the minimum value for int64" in {
val int64 = Int64(ByteVector(0x80.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
val int64 = Int64(
ByteVector(0x80.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte))
int64.toLong must be(-9223372036854775808L)
}
it must "represent the maximum value for a int64" in {
val int64 = Int64(ByteVector(0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte,
0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val int64 = Int64(
ByteVector(0x7f.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte))
int64.toLong must be(9223372036854775807L)
}
it must "throw an exception when trying to create a Int64 out of 9 bytes or more" in {
intercept[IllegalArgumentException] {
Int64(ByteVector(0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
Int64(
ByteVector(0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte))
}
}

View file

@ -2,13 +2,13 @@ package org.bitcoins.core.number
import org.bitcoins.core.gen.NumberGenerator
import org.bitcoins.core.util.BitcoinSLogger
import org.scalacheck.{ Gen, Prop, Properties }
import org.scalacheck.{Gen, Prop, Properties}
import scala.util.Try
/**
* Created by chris on 6/16/16.
*/
* Created by chris on 6/16/16.
*/
class UInt32Spec extends Properties("UInt32") {
private val logger = BitcoinSLogger.logger
@ -19,32 +19,36 @@ class UInt32Spec extends Properties("UInt32") {
}
}
property("additive identity") = Prop.forAll(NumberGenerator.uInt32s) { num: UInt32 =>
num + UInt32.zero == num
property("additive identity") = Prop.forAll(NumberGenerator.uInt32s) {
num: UInt32 =>
num + UInt32.zero == num
}
property("Negative numbers in UInt32 throw an exception") = Prop.forAll(NumberGenerator.negativeLongs) { num: Long =>
val uint32 = Try(UInt32(num))
uint32.isFailure
}
property("Negative numbers in UInt32 throw an exception") =
Prop.forAll(NumberGenerator.negativeLongs) { num: Long =>
val uint32 = Try(UInt32(num))
uint32.isFailure
}
property("add two uint32s and get the mathematical sum of the two numbers") =
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) { (num1: UInt32, num2: UInt32) =>
val result = num1.toLong + num2.toLong
if (result <= UInt32.max.toLong) num1 + num2 == UInt32(result.toLong)
else Try(num1 + num2).isFailure
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) {
(num1: UInt32, num2: UInt32) =>
val result = num1.toLong + num2.toLong
if (result <= UInt32.max.toLong) num1 + num2 == UInt32(result.toLong)
else Try(num1 + num2).isFailure
}
property("subtractive identity") =
Prop.forAll(NumberGenerator.uInt32s) { uInt32: UInt32 =>
property("subtractive identity") = Prop.forAll(NumberGenerator.uInt32s) {
uInt32: UInt32 =>
uInt32 - UInt32.zero == uInt32
}
}
property("subtract a uint32 from another uint32 and get the correct result") =
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) { (num1: UInt32, num2: UInt32) =>
val result = num1.toLong - num2.toLong
if (result >= 0) num1 - num2 == UInt32(result)
else Try(num1 - num2).isFailure
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) {
(num1: UInt32, num2: UInt32) =>
val result = num1.toLong - num2.toLong
if (result >= 0) num1 - num2 == UInt32(result)
else Try(num1 - num2).isFailure
}
@ -53,49 +57,55 @@ class UInt32Spec extends Properties("UInt32") {
uInt32 * UInt32.zero == UInt32.zero
}
property("multiplicative identity") =
Prop.forAll(NumberGenerator.uInt32s) { uInt32: UInt32 =>
property("multiplicative identity") = Prop.forAll(NumberGenerator.uInt32s) {
uInt32: UInt32 =>
uInt32 * UInt32.one == uInt32
}
}
property("multiply two UInt32s") =
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) { (num1: UInt32, num2: UInt32) =>
val bigInt1 = num1.toBigInt
val bigInt2 = num2.toBigInt
if (bigInt1 * bigInt2 <= UInt32.max.toLong) {
num1 * num2 ==
UInt32(num1.toLong * num2.toLong)
} else Try(num1 * num2).isFailure
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) {
(num1: UInt32, num2: UInt32) =>
val bigInt1 = num1.toBigInt
val bigInt2 = num2.toBigInt
if (bigInt1 * bigInt2 <= UInt32.max.toLong) {
num1 * num2 ==
UInt32(num1.toLong * num2.toLong)
} else Try(num1 * num2).isFailure
}
property("< & >=") =
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) { (num1: UInt32, num2: UInt32) =>
if (num1.toLong < num2.toLong) num1 < num2
else num1 >= num2
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) {
(num1: UInt32, num2: UInt32) =>
if (num1.toLong < num2.toLong) num1 < num2
else num1 >= num2
}
property("<= & >") = {
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) { (num1: UInt32, num2: UInt32) =>
if (num1.toLong <= num2.toLong) num1 <= num2
else num1 > num2
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) {
(num1: UInt32, num2: UInt32) =>
if (num1.toLong <= num2.toLong) num1 <= num2
else num1 > num2
}
}
property("== & !=") = {
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) { (num1: UInt32, num2: UInt32) =>
if (num1.toLong == num2.toLong) num1 == num2
else num1 != num2
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) {
(num1: UInt32, num2: UInt32) =>
if (num1.toLong == num2.toLong) num1 == num2
else num1 != num2
}
}
property("|") =
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) { (num1: UInt32, num2: UInt32) =>
UInt32(num1.toLong | num2.toLong) == (num1 | num2)
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) {
(num1: UInt32, num2: UInt32) =>
UInt32(num1.toLong | num2.toLong) == (num1 | num2)
}
property("&") =
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) { (num1: UInt32, num2: UInt32) =>
UInt32(num1.toLong & num2.toLong) == (num1 & num2)
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) {
(num1: UInt32, num2: UInt32) =>
UInt32(num1.toLong & num2.toLong) == (num1 & num2)
}
property("<<") =
@ -110,11 +120,10 @@ class UInt32Spec extends Properties("UInt32") {
}
}
property(">>") =
Prop.forAll(NumberGenerator.uInt32s, Gen.choose(0, 100)) {
case (u32, shift) =>
val r = u32 >> shift
val expected = if (shift >= 64) 0 else u32.toLong >> shift
r == UInt32(expected)
}
property(">>") = Prop.forAll(NumberGenerator.uInt32s, Gen.choose(0, 100)) {
case (u32, shift) =>
val r = u32 >> shift
val expected = if (shift >= 64) 0 else u32.toLong >> shift
r == UInt32(expected)
}
}

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.number
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.ByteVector
/**
* Created by chris on 6/14/16.
*/
* Created by chris on 6/14/16.
*/
class UInt32Test extends FlatSpec with MustMatchers {
"UInt32" must "create the number zero as an unsigned 32 bit integer" in {
@ -45,7 +45,8 @@ class UInt32Test extends FlatSpec with MustMatchers {
it must "create the number 4294967295" in {
//this is UInt32_t's max value
val uInt32 = UInt32(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val uInt32 =
UInt32(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
uInt32.toLong must be(4294967295L)
uInt32.hex must be("ffffffff")
}

View file

@ -2,7 +2,7 @@ package org.bitcoins.core.number
import org.bitcoins.core.gen.NumberGenerator
import org.scalatest.prop.PropertyChecks
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import org.slf4j.LoggerFactory
class UInt5Test extends FlatSpec with MustMatchers with PropertyChecks {

View file

@ -1,90 +1,100 @@
package org.bitcoins.core.number
import org.bitcoins.core.gen.NumberGenerator
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
import scala.util.Try
/**
* Created by chris on 6/20/16.
*/
* Created by chris on 6/20/16.
*/
class UInt64Spec extends Properties("UInt64Spec") {
property("Serialization symmetry") =
Prop.forAll(NumberGenerator.uInt64s) { uInt64: UInt64 =>
property("Serialization symmetry") = Prop.forAll(NumberGenerator.uInt64s) {
uInt64: UInt64 =>
UInt64(uInt64.hex) == uInt64
UInt64(uInt64.hex).hex == uInt64.hex
}
}
property("additive identity") =
Prop.forAll(NumberGenerator.uInt64s) { uInt64: UInt64 =>
if (uInt64.toBigInt <= UInt64.max.toBigInt) uInt64 + UInt64.zero == UInt64(uInt64.toBigInt)
property("additive identity") = Prop.forAll(NumberGenerator.uInt64s) {
uInt64: UInt64 =>
if (uInt64.toBigInt <= UInt64.max.toBigInt)
uInt64 + UInt64.zero == UInt64(uInt64.toBigInt)
else uInt64 + UInt64.zero == uInt64
}
}
property("add two arbitrary uInt64s") =
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) { (num1: UInt64, num2: UInt64) =>
val result: BigInt = num1.toBigInt + num2.toBigInt
if (result <= UInt64.max.toBigInt) num1 + num2 == UInt64(result)
else Try(num1 + num2).isFailure
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) {
(num1: UInt64, num2: UInt64) =>
val result: BigInt = num1.toBigInt + num2.toBigInt
if (result <= UInt64.max.toBigInt) num1 + num2 == UInt64(result)
else Try(num1 + num2).isFailure
}
property("subtractive identity") =
Prop.forAll(NumberGenerator.uInt64s) { uInt64: UInt64 =>
if (uInt64.toBigInt <= UInt64.max.toBigInt) uInt64 - UInt64.zero == UInt64(uInt64.toBigInt)
property("subtractive identity") = Prop.forAll(NumberGenerator.uInt64s) {
uInt64: UInt64 =>
if (uInt64.toBigInt <= UInt64.max.toBigInt)
uInt64 - UInt64.zero == UInt64(uInt64.toBigInt)
else uInt64 - UInt64.zero == uInt64
}
}
property("subtract a uint64 from a uint64") =
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) { (num1: UInt64, num2: UInt64) =>
val result = num1.toBigInt - num2.toBigInt
if (result < 0) Try(num1 - num2).isFailure
else num1 - num2 == UInt64(result)
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) {
(num1: UInt64, num2: UInt64) =>
val result = num1.toBigInt - num2.toBigInt
if (result < 0) Try(num1 - num2).isFailure
else num1 - num2 == UInt64(result)
}
property("multiplying by zero") =
Prop.forAll(NumberGenerator.uInt64s) { uInt64: UInt64 =>
property("multiplying by zero") = Prop.forAll(NumberGenerator.uInt64s) {
uInt64: UInt64 =>
uInt64 * UInt64.zero == UInt64.zero
}
}
property("multiplicative identity") =
Prop.forAll(NumberGenerator.uInt64s) { uInt64: UInt64 =>
property("multiplicative identity") = Prop.forAll(NumberGenerator.uInt64s) {
uInt64: UInt64 =>
if (uInt64 == UInt64.zero) uInt64 * UInt64.one == UInt64.zero
else uInt64 * UInt64.one == uInt64
}
}
property("multiply two uInt64s") =
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) { (num1: UInt64, num2: UInt64) =>
val result = num1.toBigInt * num2.toBigInt
if (result <= UInt64.max.toBigInt) num1 * num2 == UInt64(result)
else Try(num1 * num2).isFailure
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) {
(num1: UInt64, num2: UInt64) =>
val result = num1.toBigInt * num2.toBigInt
if (result <= UInt64.max.toBigInt) num1 * num2 == UInt64(result)
else Try(num1 * num2).isFailure
}
property("< & >= for uInt64s") =
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) { (num1: UInt64, num2: UInt64) =>
if (num1.toBigInt < num2.toBigInt) num1 < num2
else num1 >= num2
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) {
(num1: UInt64, num2: UInt64) =>
if (num1.toBigInt < num2.toBigInt) num1 < num2
else num1 >= num2
}
property("<= & > with two uInt64s") =
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) { (num1: UInt64, num2: UInt64) =>
if (num1.toBigInt <= num2.toBigInt) num1 <= num2
else num1 > num2
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) {
(num1: UInt64, num2: UInt64) =>
if (num1.toBigInt <= num2.toBigInt) num1 <= num2
else num1 > num2
}
property("== & != for two UInt64s") =
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) { (num1: UInt64, num2: UInt64) =>
if (num1.toBigInt == num2.toBigInt) num1 == num2
else num1 != num2
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) {
(num1: UInt64, num2: UInt64) =>
if (num1.toBigInt == num2.toBigInt) num1 == num2
else num1 != num2
}
property("|") =
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) { (num1: UInt64, num2: UInt64) =>
UInt64(num1.toBigInt | num2.toBigInt) == (num1 | num2)
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) {
(num1: UInt64, num2: UInt64) =>
UInt64(num1.toBigInt | num2.toBigInt) == (num1 | num2)
}
property("&") =
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) { (num1: UInt64, num2: UInt64) =>
UInt64(num1.toBigInt & num2.toBigInt) == (num1 & num2)
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) {
(num1: UInt64, num2: UInt64) =>
UInt64(num1.toBigInt & num2.toBigInt) == (num1 & num2)
}
}

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.number
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.ByteVector
/**
* Created by chris on 6/15/16.
*/
* Created by chris on 6/15/16.
*/
class UInt64Test extends FlatSpec with MustMatchers {
"UInt64" must "hold the number 0" in {
@ -22,25 +22,43 @@ class UInt64Test extends FlatSpec with MustMatchers {
it must "hold the max for a uint32_t" in {
//this is UInt32_t's max value
val uInt64 = UInt64(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val uInt64 =
UInt64(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
uInt64.toBigInt must be(4294967295L)
}
it must "hold the max for uint32_t + 1" in {
val uInt64 = UInt64(ByteVector(1.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
val uInt64 =
UInt64(ByteVector(1.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
uInt64.toBigInt must be(4294967296L)
}
it must "hold the max number for uint64_t" in {
val uInt64 = UInt64(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte,
0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val uInt64 = UInt64(
ByteVector(0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte,
0xff.toByte))
uInt64.toBigInt must be(BigInt("18446744073709551615"))
uInt64.hex must be("ffffffffffffffff")
}
it must "throw an exception if we try and create a number larger than 8 bytes" in {
intercept[IllegalArgumentException] {
UInt64(ByteVector(1.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
UInt64(
ByteVector(1.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte))
}
}

View file

@ -2,7 +2,7 @@ package org.bitcoins.core.number
import org.bitcoins.core.gen.NumberGenerator
import org.bitcoins.core.util.BitcoinSLogger
import org.scalacheck.{ Gen, Prop, Properties }
import org.scalacheck.{Gen, Prop, Properties}
import scala.util.Try
@ -38,7 +38,8 @@ class UInt8Spec extends Properties("UInt8Spec") {
Prop.forAllNoShrink(NumberGenerator.uInt8, Gen.choose(0, 100)) {
case (u8: UInt8, shift: Int) =>
val r = (u8 >> shift)
val expected = if (shift > 31) UInt8.zero else UInt8((u8.toLong >> shift).toShort)
val expected =
if (shift > 31) UInt8.zero else UInt8((u8.toLong >> shift).toShort)
if (r != expected) {
logger.warn("expected: " + expected)
logger.warn("r: " + r)

View file

@ -1,6 +1,6 @@
package org.bitcoins.core.number
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.ByteVector
class UInt8Test extends FlatSpec with MustMatchers {

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.policy
import org.bitcoins.core.script.flag._
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 5/2/16.
*/
* Created by chris on 5/2/16.
*/
class PolicyTest extends FlatSpec with MustMatchers {
"Policy" must "determine what the mandatory script verify flags are" in {

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol
import org.bitcoins.core.util.{ Base58, TestUtil }
import org.scalatest.{ FlatSpec, MustMatchers }
import org.bitcoins.core.util.{Base58, TestUtil}
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 3/30/16.
*/
* Created by chris on 3/30/16.
*/
class AddressFactoryTest extends FlatSpec with MustMatchers {
"AddressFactory" must "create an address from a base58 encoded string" in {

View file

@ -1,16 +1,19 @@
package org.bitcoins.core.protocol
import org.bitcoins.core.config.{ RegTest, TestNet3 }
import org.bitcoins.core.config.{RegTest, TestNet3}
import org.bitcoins.core.gen.AddressGenerator
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
class AddressSpec extends Properties("AddressSpec") {
property("serialization symmetry") = {
Prop.forAll(AddressGenerator.address) { addr =>
val bool1 = Address.fromScriptPubKey(addr.scriptPubKey, addr.networkParameters).get == addr
val bool1 = Address
.fromScriptPubKey(addr.scriptPubKey, addr.networkParameters)
.get == addr
val bool2 = if (addr.networkParameters == RegTest) {
Address.fromString(addr.value).get == Address(addr.scriptPubKey, TestNet3).get
Address.fromString(addr.value).get == Address(addr.scriptPubKey,
TestNet3).get
} else {
Address.fromString(addr.value).get == addr
}

View file

@ -1,10 +1,8 @@
package org.bitcoins.core.protocol
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 3/23/15.
*/
class AddressTest extends FlatSpec with MustMatchers {
}
* Created by chris on 3/23/15.
*/
class AddressTest extends FlatSpec with MustMatchers {}

View file

@ -1,17 +1,22 @@
package org.bitcoins.core.protocol
import org.bitcoins.core.gen.{ AddressGenerator, ChainParamsGenerator, ScriptGenerators }
import org.bitcoins.core.util.{ Bech32, BitcoinSLogger }
import org.scalacheck.{ Prop, Properties }
import org.bitcoins.core.gen.{
AddressGenerator,
ChainParamsGenerator,
ScriptGenerators
}
import org.bitcoins.core.util.{Bech32, BitcoinSLogger}
import org.scalacheck.{Prop, Properties}
import scala.annotation.tailrec
import scala.util.{ Random, Success }
import scala.util.{Random, Success}
class Bech32Spec extends Properties("Bech32Spec") {
private val logger = BitcoinSLogger.logger
property("serialization symmetry") = {
Prop.forAll(ScriptGenerators.witnessScriptPubKey, ChainParamsGenerator.networkParams) {
Prop.forAll(ScriptGenerators.witnessScriptPubKey,
ChainParamsGenerator.networkParams) {
case ((witSPK, _), network) =>
val addr = Bech32Address(witSPK, network)
val spk = Bech32Address.fromStringToWitSPK(addr.value)

View file

@ -1,14 +1,14 @@
package org.bitcoins.core.protocol
import org.bitcoins.core.config.{ MainNet, TestNet3 }
import org.bitcoins.core.config.{MainNet, TestNet3}
import org.bitcoins.core.crypto.ECPublicKey
import org.bitcoins.core.number.{ UInt5, UInt8 }
import org.bitcoins.core.number.{UInt5, UInt8}
import org.bitcoins.core.protocol.script._
import org.bitcoins.core.util.Bech32
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import org.slf4j.LoggerFactory
import scala.util.{ Success, Try }
import scala.util.{Success, Try}
class Bech32Test extends FlatSpec with MustMatchers {
private val logger = LoggerFactory.getLogger(this.getClass.getSimpleName)
@ -20,8 +20,10 @@ class Bech32Test extends FlatSpec with MustMatchers {
"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
"?1ezyfcl")
val results: Seq[Try[Bech32Address]] = valid.map(Bech32Address.fromString(_))
"?1ezyfcl"
)
val results: Seq[Try[Bech32Address]] =
valid.map(Bech32Address.fromString(_))
results.exists(_.isFailure) must be(false)
}
@ -38,14 +40,17 @@ class Bech32Test extends FlatSpec with MustMatchers {
"de1lg7wt\\xff",
"A1G7SGD8",
"10a06t8",
"1qzzfhee")
val results: Seq[Try[Bech32Address]] = invalid.map(Bech32Address.fromString(_))
"1qzzfhee"
)
val results: Seq[Try[Bech32Address]] =
invalid.map(Bech32Address.fromString(_))
results.exists(_.isSuccess) must be(false)
}
it must "follow the example in BIP173" in {
//https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#examples
val key = ECPublicKey("0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798".toLowerCase)
val key = ECPublicKey(
"0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798".toLowerCase)
val p2wpkh = P2WPKHWitnessSPKV0(key)
val addr = Bech32Address(p2wpkh, TestNet3)
addr.value must be("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx")
@ -63,22 +68,26 @@ class Bech32Test extends FlatSpec with MustMatchers {
val p2pk = P2PKScriptPubKey(key)
val p2wsh = P2WSHWitnessSPKV0(p2pk)
val addr1 = Bech32Address(p2wsh, TestNet3)
addr1.value must be("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7")
addr1.value must be(
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7")
//decode
val decoded1 = Bech32Address.fromStringToWitSPK(addr1.value)
decoded1 must be(Success(p2wsh))
val p2wshMain = Bech32Address(p2wsh, MainNet)
p2wshMain.value must be("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3")
p2wshMain.value must be(
"bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3")
val mp2wshDecoded = Bech32Address.fromStringToWitSPK(p2wshMain.value)
mp2wshDecoded must be(Success(p2wsh))
}
it must "expand the human readable part correctly" in {
Bech32Address.hrpExpand(bc) must be(Vector(UInt5(3), UInt5(3), UInt5(0), UInt5(2), UInt5(3)))
Bech32Address.hrpExpand(bc) must be(
Vector(UInt5(3), UInt5(3), UInt5(0), UInt5(2), UInt5(3)))
Bech32Address.hrpExpand(tb) must be(Vector(UInt5(3), UInt5(3), UInt5(0), UInt5(20), UInt5(2)))
Bech32Address.hrpExpand(tb) must be(
Vector(UInt5(3), UInt5(3), UInt5(0), UInt5(20), UInt5(2)))
}
it must "encode 0 byte correctly" in {
@ -106,17 +115,23 @@ class Bech32Test extends FlatSpec with MustMatchers {
encoded2 must be(Seq(16, 8).map(i => UInt5(i.toByte)))
//130.toByte == -126
val encoded3 = Bech32.from8bitTo5bit(Vector(255, 255).map(i => UInt8(i.toShort)))
val encoded3 =
Bech32.from8bitTo5bit(Vector(255, 255).map(i => UInt8(i.toShort)))
encoded3 must be(Seq(31, 31, 31, 16).map(i => UInt5(i.toByte)))
val encoded4 = Bech32.from8bitTo5bit(Vector(255, 255, 255, 255).map(i => UInt8(i.toShort)))
val encoded4 = Bech32.from8bitTo5bit(
Vector(255, 255, 255, 255).map(i => UInt8(i.toShort)))
encoded4 must be(Seq(31, 31, 31, 31, 31, 31, 24).map(i => UInt5(i.toByte)))
val encoded5 = Bech32.from8bitTo5bit(Vector(255, 255, 255, 255, 255).map(i => UInt8(i.toShort)))
encoded5 must be(Seq(31, 31, 31, 31, 31, 31, 31, 31).map(i => UInt5(i.toByte)))
val encoded5 = Bech32.from8bitTo5bit(
Vector(255, 255, 255, 255, 255).map(i => UInt8(i.toShort)))
encoded5 must be(
Seq(31, 31, 31, 31, 31, 31, 31, 31).map(i => UInt5(i.toByte)))
val encoded6 = Bech32.from8bitTo5bit(Vector(255, 255, 255, 255, 255, 255).map(i => UInt8(i.toByte)))
val encoded6 = Bech32.from8bitTo5bit(
Vector(255, 255, 255, 255, 255, 255).map(i => UInt8(i.toByte)))
encoded6 must be(Seq(31, 31, 31, 31, 31, 31, 31, 31, 31, 28).map(i => UInt5(i.toByte)))
encoded6 must be(
Seq(31, 31, 31, 31, 31, 31, 31, 31, 31, 28).map(i => UInt5(i.toByte)))
}
}

View file

@ -1,14 +1,18 @@
package org.bitcoins.core.protocol
import org.bitcoins.core.config.TestNet3
import org.bitcoins.core.gen.{ AddressGenerator, CryptoGenerators, ScriptGenerators }
import org.bitcoins.core.gen.{
AddressGenerator,
CryptoGenerators,
ScriptGenerators
}
import org.bitcoins.core.protocol.script.P2SHScriptPubKey
import org.bitcoins.core.util.CryptoUtil
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 7/21/16.
*/
* Created by chris on 7/21/16.
*/
class BitcoinAddressSpec extends Properties("BitcoinAddressSpec") {
property("get the same p2sh address no matter what factory function we use") =
@ -16,7 +20,8 @@ class BitcoinAddressSpec extends Properties("BitcoinAddressSpec") {
case (scriptPubKey, _) =>
//we should get the same address no matter which factory function we use
val p2shScriptPubKey = P2SHScriptPubKey(scriptPubKey)
P2SHAddress(scriptPubKey, TestNet3) == P2SHAddress(p2shScriptPubKey, TestNet3)
P2SHAddress(scriptPubKey, TestNet3) == P2SHAddress(p2shScriptPubKey,
TestNet3)
}
@ -28,7 +33,8 @@ class BitcoinAddressSpec extends Properties("BitcoinAddressSpec") {
P2SHAddress.isValid(addr.toString)
}
property("get the same p2pkh address no matter what factory function we use") =
property(
"get the same p2pkh address no matter what factory function we use") =
Prop.forAll(CryptoGenerators.publicKey) { pubKey =>
val hash = CryptoUtil.sha256Hash160(pubKey.bytes)
P2PKHAddress(pubKey, TestNet3) == P2PKHAddress(hash, TestNet3)

View file

@ -3,7 +3,7 @@ package org.bitcoins.core.protocol
import org.bitcoins.core.config.MainNet
import org.bitcoins.core.crypto.Sha256Hash160Digest
import org.bitcoins.core.protocol.script.ScriptPubKey
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import scala.util.Try
@ -50,9 +50,10 @@ class BitcoinAddressTest extends FlatSpec with MustMatchers {
it must "encode a scriptPubKey to an address" in {
//redeemScript from https://en.bitcoin.it/wiki/Pay_to_script_hash
val hex = "455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae"
val hex =
"455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae"
val scriptPubKey = ScriptPubKey(hex)
val addr = P2SHAddress(scriptPubKey, MainNet)
addr must be(BitcoinAddress("3P14159f73E4gFr7JterCCQh9QjiTjiZrG").get)
}
}
}

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol
import org.bitcoins.core.gen.NumberGenerator
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 6/29/16.
*/
* Created by chris on 6/29/16.
*/
class CompactSizeUIntSpec extends Properties("CompactSizeUIntSpec") {
property("Serialization symmetry") =

View file

@ -2,13 +2,13 @@ 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.scalatest.{ FlatSpec, MustMatchers }
import org.bitcoins.core.util.{BitcoinSUtil, TestUtil}
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.ByteVector
/**
* Created by chris on 7/26/15.
*/
* Created by chris on 7/26/15.
*/
class CompactSizeUIntTest extends FlatSpec with MustMatchers {
"CompactSizeUInt" must "serialize a VarInt with size 1 correctly" in {
@ -28,25 +28,29 @@ class CompactSizeUIntTest extends FlatSpec with MustMatchers {
}
it must "calculate the varint for the following hex string" in {
CompactSizeUInt.calculateCompactSizeUInt("00") must be(CompactSizeUInt(UInt64.one, 1))
CompactSizeUInt.calculateCompactSizeUInt("00") must be(
CompactSizeUInt(UInt64.one, 1))
//for a string that is 256 bytes long
val byteSeq256Size = ByteVector(Array.fill(256)(0.toByte))
CompactSizeUInt.calculateCompactSizeUInt(byteSeq256Size) must be(CompactSizeUInt(UInt64(256), 3))
CompactSizeUInt.calculateCompactSizeUInt(byteSeq256Size) must be(
CompactSizeUInt(UInt64(256), 3))
}
it must "calculate the correct compact size uint for a number 515 bytes long" in {
//from the bitcoin developer reference
//https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers
val byteSeq515Size = ByteVector(Array.fill(515)(0.toByte))
val compactSizeUInt = CompactSizeUInt.calculateCompactSizeUInt(byteSeq515Size)
val compactSizeUInt =
CompactSizeUInt.calculateCompactSizeUInt(byteSeq515Size)
compactSizeUInt must be(CompactSizeUInt(UInt64(515), 3))
compactSizeUInt.hex must be("fd0302")
}
it must "calculate correct compact size uint for a number 500,000 bytes long" in {
val byteSeq500000Size = ByteVector(Array.fill(500000)(0.toByte))
val compactSizeUInt = CompactSizeUInt.calculateCompactSizeUInt(byteSeq500000Size)
val compactSizeUInt =
CompactSizeUInt.calculateCompactSizeUInt(byteSeq500000Size)
compactSizeUInt must be(CompactSizeUInt(UInt64(500000), 5))
compactSizeUInt.hex must be("fe20a10700")
}
@ -59,24 +63,30 @@ class CompactSizeUIntTest extends FlatSpec with MustMatchers {
it must "parse a variable length integer (VarInt)" in {
val str = "fdfd00"
CompactSizeUInt.parseCompactSizeUInt(str) must be(CompactSizeUInt(UInt64(253), 3))
CompactSizeUInt.parseCompactSizeUInt(str) must be(
CompactSizeUInt(UInt64(253), 3))
val str1 = "00"
CompactSizeUInt.parseCompactSizeUInt(str1) must be(CompactSizeUInt(UInt64.zero, 1))
CompactSizeUInt.parseCompactSizeUInt(str1) must be(
CompactSizeUInt(UInt64.zero, 1))
val str2 = "fe20a10700"
CompactSizeUInt.parseCompactSizeUInt(str2) must be(CompactSizeUInt(UInt64(500000)))
CompactSizeUInt.parseCompactSizeUInt(str2) must be(
CompactSizeUInt(UInt64(500000)))
val str3 = "ffffffffff"
CompactSizeUInt.parseCompactSizeUInt(str3) must be(CompactSizeUInt(UInt64(4294967295L), 9))
CompactSizeUInt.parseCompactSizeUInt(str3) must be(
CompactSizeUInt(UInt64(4294967295L), 9))
}
it must "parse a variable length integer the same from a tx input and a script sig" in {
CompactSizeUInt.parseCompactSizeUInt(TestUtil.txInput.scriptSignature.bytes) must be(TestUtil.txInput.scriptSignature.compactSizeUInt)
CompactSizeUInt.parseCompactSizeUInt(TestUtil.txInput.scriptSignature.bytes) must be(
TestUtil.txInput.scriptSignature.compactSizeUInt)
}
it must "parse the variable length integer of the empty script" in {
CompactSizeUInt.parseCompactSizeUInt(ScriptSignature.empty) must be(CompactSizeUInt(UInt64.one, 1))
CompactSizeUInt.parseCompactSizeUInt(ScriptSignature.empty) must be(
CompactSizeUInt(UInt64.one, 1))
}
it must "parse variable length integer of script sig at least 0xffff bytes in length, and greater than 0xffffffff" in {
@ -85,8 +95,10 @@ class CompactSizeUIntTest extends FlatSpec with MustMatchers {
val s2NoCmpct = TestUtil.rawP2shInputScriptLargeSignature * 120
val s1 = c(s1NoCmpct).hex + s1NoCmpct
val s2 = c(s2NoCmpct).hex + s2NoCmpct
CompactSizeUInt.parseCompactSizeUInt(ScriptSignature(s1)) must be(CompactSizeUInt(UInt64(30453), 3))
CompactSizeUInt.parseCompactSizeUInt(ScriptSignature(s2)) must be(CompactSizeUInt(UInt64(73085), 5))
CompactSizeUInt.parseCompactSizeUInt(ScriptSignature(s1)) must be(
CompactSizeUInt(UInt64(30453), 3))
CompactSizeUInt.parseCompactSizeUInt(ScriptSignature(s2)) must be(
CompactSizeUInt(UInt64(73085), 5))
}
it must "parse 8 bit, 16 bit, 32 bit number and 64 bit number as compactsizeuints" in {

View file

@ -1,7 +1,7 @@
package org.bitcoins.core.protocol
import org.bitcoins.core.config.{ MainNet, TestNet3 }
import org.scalatest.{ FlatSpec, MustMatchers }
import org.bitcoins.core.config.{MainNet, TestNet3}
import org.scalatest.{FlatSpec, MustMatchers}
class HumanReadablePartTest extends FlatSpec with MustMatchers {

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol.blockchain
import org.bitcoins.core.gen.BlockchainElementsGenerator
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by tom on 7/6/16.
*/
* Created by tom on 7/6/16.
*/
class BlockHeaderSpec extends Properties("BlockHeaderSpec") {
property("serialization symmetry") =
Prop.forAll(BlockchainElementsGenerator.blockHeader) { header =>

View file

@ -2,11 +2,11 @@ package org.bitcoins.core.protocol.blockchain
import org.bitcoins.core.gen.BlockchainElementsGenerator
import org.bitcoins.core.util.BitcoinSLogger
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by tom on 7/6/16.
*/
* Created by tom on 7/6/16.
*/
class BlockSpec extends Properties("BlockSpec") {
private val logger = BitcoinSLogger.logger

View file

@ -1,15 +1,16 @@
package org.bitcoins.core.protocol.blockchain
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import org.slf4j.LoggerFactory
import scala.io.Source
/**
* Created by chris on 7/15/16.
*/
* Created by chris on 7/15/16.
*/
class BlockTest extends FlatSpec with MustMatchers {
private val logger = LoggerFactory.getLogger(this.getClass.getSimpleName)
def timeBlockParsing[R](block: => R): Long = {
val t0 = System.currentTimeMillis()
val result = block // call-by-name
@ -29,14 +30,16 @@ class BlockTest extends FlatSpec with MustMatchers {
it must "parse a large block 00000000000000000008513c860373da0484f065983aeb063ebf81c172e81d48" in {
val fileName = "/00000000000000000008513c860373da0484f065983aeb063ebf81c172e81d48.txt"
val fileName =
"/00000000000000000008513c860373da0484f065983aeb063ebf81c172e81d48.txt"
val lines = Source.fromURL(getClass.getResource(fileName)).mkString
val time = timeBlockParsing(Block.fromHex(lines))
assert(time <= 15000)
}
it must "parse a large block 000000000000000000050f70113ab1932c195442cb49bcc4ee4d7f426c8a3295" in {
val fileName = "/000000000000000000050f70113ab1932c195442cb49bcc4ee4d7f426c8a3295.txt"
val fileName =
"/000000000000000000050f70113ab1932c195442cb49bcc4ee4d7f426c8a3295.txt"
val lines = Source.fromURL(getClass.getResource(fileName)).mkString
val time = timeBlockParsing(Block.fromHex(lines))
assert(time <= 15000)

View file

@ -2,24 +2,36 @@ package org.bitcoins.core.protocol.blockchain
import org.bitcoins.core.currency.Satoshis
import org.bitcoins.core.number.Int64
import org.bitcoins.core.protocol.script.{ ScriptPubKey, ScriptSignature }
import org.bitcoins.core.protocol.transaction.{ CoinbaseInput, TransactionConstants, TransactionOutput }
import org.bitcoins.core.util.{ BitcoinSLogger, BitcoinSUtil }
import org.scalatest.{ FlatSpec, MustMatchers }
import org.bitcoins.core.protocol.script.{ScriptPubKey, ScriptSignature}
import org.bitcoins.core.protocol.transaction.{
CoinbaseInput,
TransactionConstants,
TransactionOutput
}
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil}
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 5/24/16.
*/
* Created by chris on 5/24/16.
*/
class ChainParamsTest extends FlatSpec with MustMatchers {
private def logger = BitcoinSLogger.logger
val genesisBlock = MainNetChainParams.genesisBlock
val genesisTransaction = genesisBlock.transactions.head
val expectedGenesisScriptSig = ScriptSignature("4D04FFFF001D0104455468652054696D65732030332F4A616E2F32303039204368616E63656C6C6F72206F6E206272696E6B206F66207365636F6E64206261696C6F757420666F722062616E6B73".toLowerCase())
val expectedGenesisInput = CoinbaseInput(expectedGenesisScriptSig, TransactionConstants.sequence)
val expectedGenesisScriptPubKey = ScriptPubKey("434104678AFDB0FE5548271967F1A67130B7105CD6A828E03909A67962E0EA1F61DEB649F6BC3F4CEF38C4F35504E51EC112DE5C384DF7BA0B8D578A4C702B6BF11D5FAC".toLowerCase)
val expectedGenesisOutput = TransactionOutput(Satoshis(Int64(5000000000L)), expectedGenesisScriptPubKey)
val expectedGenesisScriptSig = ScriptSignature(
"4D04FFFF001D0104455468652054696D65732030332F4A616E2F32303039204368616E63656C6C6F72206F6E206272696E6B206F66207365636F6E64206261696C6F757420666F722062616E6B73"
.toLowerCase())
val expectedGenesisInput =
CoinbaseInput(expectedGenesisScriptSig, TransactionConstants.sequence)
val expectedGenesisScriptPubKey = ScriptPubKey(
"434104678AFDB0FE5548271967F1A67130B7105CD6A828E03909A67962E0EA1F61DEB649F6BC3F4CEF38C4F35504E51EC112DE5C384DF7BA0B8D578A4C702B6BF11D5FAC".toLowerCase)
val expectedGenesisOutput =
TransactionOutput(Satoshis(Int64(5000000000L)), expectedGenesisScriptPubKey)
"ChainParams" must "generate correct block hex for genesis block" in {
val hex = "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e6" +
"7768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c010100000001000000000000000000000000000" +
@ -30,7 +42,8 @@ class ChainParamsTest extends FlatSpec with MustMatchers {
genesisBlock.hex must be(hex)
}
it must "hash the bitcoin genesis block" in {
genesisBlock.blockHeader.hash.hex must be("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000")
genesisBlock.blockHeader.hash.hex must be(
"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000")
}
it must "compute the script signature for the coinbase tx in the mainnet genesis block" in {
@ -41,8 +54,9 @@ class ChainParamsTest extends FlatSpec with MustMatchers {
it must "generate the input correctly for the genesis transaction's input" in {
val input = genesisBlock.transactions.head.inputs.head
input must be(expectedGenesisInput)
input.hex must be("0000000000000000000000000000000000000000000000000000000000000000FFFFFFFF".toLowerCase
+ expectedGenesisScriptSig.hex + "FFFFFFFF".toLowerCase)
input.hex must be(
"0000000000000000000000000000000000000000000000000000000000000000FFFFFFFF".toLowerCase
+ expectedGenesisScriptSig.hex + "FFFFFFFF".toLowerCase)
}
it must "generate the correct scriptPubKey for the genesis transaction's output" in {
@ -54,7 +68,8 @@ class ChainParamsTest extends FlatSpec with MustMatchers {
val output = genesisTransaction.outputs.head
output.value must be(Satoshis(Int64(5000000000L)))
output.scriptPubKey.hex must be(expectedGenesisScriptPubKey.hex)
output.hex must be("00F2052A01000000".toLowerCase + expectedGenesisScriptPubKey.hex)
output.hex must be(
"00F2052A01000000".toLowerCase + expectedGenesisScriptPubKey.hex)
}
it must "generate the correct txid for the genesis transaction" in {
@ -63,60 +78,88 @@ class ChainParamsTest extends FlatSpec with MustMatchers {
genesisTransaction.inputs must be(Seq(expectedGenesisInput))
genesisTransaction.outputs must be(Seq(expectedGenesisOutput))
genesisTransaction.txId.hex must be(BitcoinSUtil.flipEndianness("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"))
genesisTransaction.txId.hex must be(
BitcoinSUtil.flipEndianness(
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"))
}
it must "generate the correct merkle root for the testnet genesis block" in {
TestNetChainParams.genesisBlock.blockHeader.merkleRootHash.hex must be(BitcoinSUtil.flipEndianness("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"))
TestNetChainParams.genesisBlock.blockHeader.merkleRootHash.hex must be(
BitcoinSUtil.flipEndianness(
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"))
}
it must "generate the correct block hash for the testnet genesis block" in {
TestNetChainParams.genesisBlock.blockHeader.hash.hex must be(BitcoinSUtil.flipEndianness("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"))
TestNetChainParams.genesisBlock.blockHeader.hash.hex must be(
BitcoinSUtil.flipEndianness(
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"))
}
it must "generate the correct merkle root for the regtest genesis block" in {
RegTestNetChainParams.genesisBlock.blockHeader.merkleRootHash.hex must be(BitcoinSUtil.flipEndianness("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"))
RegTestNetChainParams.genesisBlock.blockHeader.merkleRootHash.hex must be(
BitcoinSUtil.flipEndianness(
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"))
}
it must "generate the correct block header hex for the regtest genesis block" in {
val regtestGenesisBlockHex = "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"
val regtestGenesisBlockHex =
"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"
val expectedHeaderHex = regtestGenesisBlockHex.slice(0, 160)
RegTestNetChainParams.genesisBlock.blockHeader.hex must be(expectedHeaderHex)
RegTestNetChainParams.genesisBlock.blockHeader.hex must be(
expectedHeaderHex)
}
it must "generate the correct block hex for the regtest genesis block" in {
val expectedHex = "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"
val expectedHex =
"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"
RegTestNetChainParams.genesisBlock.hex must be(expectedHex)
}
it must "generate the correct blockheader hash for the genesis block on regtest" in {
logger.debug("Regtest genesis block: " + RegTestNetChainParams.genesisBlock)
RegTestNetChainParams.genesisBlock.blockHeader.hash.hex must be(BitcoinSUtil.flipEndianness("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"))
RegTestNetChainParams.genesisBlock.blockHeader.hash.hex must be(
BitcoinSUtil.flipEndianness(
"0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"))
}
it must "have the correct base58 prefix for MainNet" in {
import Base58Type._
//correct answers taken from https://en.bitcoin.it/wiki/List_of_address_prefixes
BitcoinSUtil.encodeHex(MainNetChainParams.base58Prefixes(PubKeyAddress)) must be("00")
BitcoinSUtil.encodeHex(MainNetChainParams.base58Prefixes(ScriptAddress)) must be("05")
BitcoinSUtil.encodeHex(MainNetChainParams.base58Prefixes(SecretKey)) must be("80")
BitcoinSUtil.encodeHex(MainNetChainParams.base58Prefixes(ExtPublicKey)) must be("0488B21E".toLowerCase)
BitcoinSUtil.encodeHex(MainNetChainParams.base58Prefixes(ExtSecretKey)) must be("0488ADE4".toLowerCase)
BitcoinSUtil.encodeHex(MainNetChainParams.base58Prefixes(PubKeyAddress)) must be(
"00")
BitcoinSUtil.encodeHex(MainNetChainParams.base58Prefixes(ScriptAddress)) must be(
"05")
BitcoinSUtil.encodeHex(MainNetChainParams.base58Prefixes(SecretKey)) must be(
"80")
BitcoinSUtil.encodeHex(MainNetChainParams.base58Prefixes(ExtPublicKey)) must be(
"0488B21E".toLowerCase)
BitcoinSUtil.encodeHex(MainNetChainParams.base58Prefixes(ExtSecretKey)) must be(
"0488ADE4".toLowerCase)
}
it must "have the correct base58 prefix for TestNet" in {
import Base58Type._
BitcoinSUtil.encodeHex(TestNetChainParams.base58Prefixes(PubKeyAddress)) must be("6f")
BitcoinSUtil.encodeHex(TestNetChainParams.base58Prefixes(ScriptAddress)) must be("c4")
BitcoinSUtil.encodeHex(TestNetChainParams.base58Prefixes(SecretKey)) must be("ef")
BitcoinSUtil.encodeHex(TestNetChainParams.base58Prefixes(ExtPublicKey)) must be("043587CF".toLowerCase)
BitcoinSUtil.encodeHex(TestNetChainParams.base58Prefixes(ExtSecretKey)) must be("04358394".toLowerCase)
BitcoinSUtil.encodeHex(TestNetChainParams.base58Prefixes(PubKeyAddress)) must be(
"6f")
BitcoinSUtil.encodeHex(TestNetChainParams.base58Prefixes(ScriptAddress)) must be(
"c4")
BitcoinSUtil.encodeHex(TestNetChainParams.base58Prefixes(SecretKey)) must be(
"ef")
BitcoinSUtil.encodeHex(TestNetChainParams.base58Prefixes(ExtPublicKey)) must be(
"043587CF".toLowerCase)
BitcoinSUtil.encodeHex(TestNetChainParams.base58Prefixes(ExtSecretKey)) must be(
"04358394".toLowerCase)
}
it must "have the correct base58 prefix for RegTest" in {
import Base58Type._
BitcoinSUtil.encodeHex(RegTestNetChainParams.base58Prefixes(PubKeyAddress)) must be("6f")
BitcoinSUtil.encodeHex(RegTestNetChainParams.base58Prefixes(ScriptAddress)) must be("c4")
BitcoinSUtil.encodeHex(RegTestNetChainParams.base58Prefixes(SecretKey)) must be("ef")
BitcoinSUtil.encodeHex(RegTestNetChainParams.base58Prefixes(ExtPublicKey)) must be("043587CF".toLowerCase)
BitcoinSUtil.encodeHex(RegTestNetChainParams.base58Prefixes(ExtSecretKey)) must be("04358394".toLowerCase)
BitcoinSUtil.encodeHex(RegTestNetChainParams.base58Prefixes(PubKeyAddress)) must be(
"6f")
BitcoinSUtil.encodeHex(RegTestNetChainParams.base58Prefixes(ScriptAddress)) must be(
"c4")
BitcoinSUtil.encodeHex(RegTestNetChainParams.base58Prefixes(SecretKey)) must be(
"ef")
BitcoinSUtil.encodeHex(RegTestNetChainParams.base58Prefixes(ExtPublicKey)) must be(
"043587CF".toLowerCase)
BitcoinSUtil.encodeHex(RegTestNetChainParams.base58Prefixes(ExtSecretKey)) must be(
"04358394".toLowerCase)
}
}

View file

@ -2,23 +2,24 @@ package org.bitcoins.core.protocol.blockchain
import org.bitcoins.core.crypto.DoubleSha256Digest
import org.bitcoins.core.gen.MerkleGenerator
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 8/12/16.
*/
* Created by chris on 8/12/16.
*/
class MerkleBlockSpec extends Properties("MerkleBlockSpec") {
//TODO: This is *extremely* slow, this is currently the longest running property we have taking about 6 minutes to run
//I think it is the generator MerkleGenerator.merkleBlockWithInsertTxIds
property("contains all inserted txids when we directly create a merkle block from the txids && " +
"contains all txids matched by a bloom filter && " +
"serialization symmetry") =
property(
"contains all inserted txids when we directly create a merkle block from the txids && " +
"contains all txids matched by a bloom filter && " +
"serialization symmetry") =
Prop.forAllNoShrink(MerkleGenerator.merkleBlockWithInsertedTxIds) {
case (merkleBlock: MerkleBlock, _, txIds: Seq[DoubleSha256Digest]) =>
val extractedMatches = merkleBlock.partialMerkleTree.extractMatches
extractedMatches == txIds &&
extractedMatches.intersect(txIds) == txIds &&
MerkleBlock(merkleBlock.hex) == merkleBlock
extractedMatches.intersect(txIds) == txIds &&
MerkleBlock(merkleBlock.hex) == merkleBlock
}
}
}

File diff suppressed because one or more lines are too long

View file

@ -2,28 +2,31 @@ package org.bitcoins.core.protocol.blockchain
import org.bitcoins.core.crypto.DoubleSha256Digest
import org.bitcoins.core.gen.MerkleGenerator
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 2/13/17.
*/
* Created by chris on 2/13/17.
*/
class PartialMerkleTreeSpec extends Properties("PartialMerkleTreeSpec") {
property("must be able to extract all of the txids we indicated to be matches") =
property(
"must be able to extract all of the txids we indicated to be matches") =
Prop.forAll(MerkleGenerator.partialMerkleTree) {
case (partialMerkleTree: PartialMerkleTree, txMatches: Seq[(Boolean, DoubleSha256Digest)]) =>
case (partialMerkleTree: PartialMerkleTree,
txMatches: Seq[(Boolean, DoubleSha256Digest)]) =>
val matchedTxs = txMatches.filter(_._1).map(_._2)
partialMerkleTree.extractMatches == matchedTxs
}
property("must generate the same partial merkle tree from the same parameters") =
property(
"must generate the same partial merkle tree from the same parameters") =
Prop.forAll(MerkleGenerator.partialMerkleTree) {
case (partialMerkleTree: PartialMerkleTree, _) =>
val partialMerkleTree2 = PartialMerkleTree(
partialMerkleTree.transactionCount,
partialMerkleTree.hashes, partialMerkleTree.bits)
val partialMerkleTree2 =
PartialMerkleTree(partialMerkleTree.transactionCount,
partialMerkleTree.hashes,
partialMerkleTree.bits)
partialMerkleTree2 == partialMerkleTree
}
}

View file

@ -1,50 +1,55 @@
package org.bitcoins.core.protocol.blockchain
import org.bitcoins.core.bloom.{ BloomFilter, BloomUpdateAll }
import org.bitcoins.core.bloom.{BloomFilter, BloomUpdateAll}
import org.bitcoins.core.crypto.DoubleSha256Digest
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.util.{ BitcoinSUtil, Leaf, Node }
import org.scalatest.{ FlatSpec, MustMatchers }
import org.bitcoins.core.util.{BitcoinSUtil, Leaf, Node}
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.BitVector
/**
* Created by chris on 8/9/16.
*/
* Created by chris on 8/9/16.
*/
class PartialMerkleTreeTests extends FlatSpec with MustMatchers {
"PartialMerkleTree" must "from a list of txs and a bit indicating if the tx matched the filter" in {
//https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L185
val block = Block("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb68000000000000052752895" +
"58f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000" +
"000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100" +
"f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a816950" +
"7b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780" +
"da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c0" +
"8240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725" +
"dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100" +
"000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268" +
"ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f1" +
"1d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480c" +
"d0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000" +
"001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c" +
"7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d40" +
"31895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a6501" +
"3902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b" +
"25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b183" +
"68d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a47" +
"3044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c00" +
"3b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805" +
"c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001e" +
"c4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01" +
"f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc506" +
"33d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a9" +
"4fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e" +
"014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c7" +
"72c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc" +
"9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac00000000" +
"0100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000")
val block = Block(
"0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb68000000000000052752895" +
"58f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000" +
"000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100" +
"f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a816950" +
"7b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780" +
"da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c0" +
"8240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725" +
"dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100" +
"000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268" +
"ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f1" +
"1d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480c" +
"d0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000" +
"001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c" +
"7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d40" +
"31895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a6501" +
"3902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b" +
"25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b183" +
"68d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a47" +
"3044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c00" +
"3b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805" +
"c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001e" +
"c4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01" +
"f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc506" +
"33d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a9" +
"4fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e" +
"014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c7" +
"72c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc" +
"9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac00000000" +
"0100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000")
val hash1 = DoubleSha256Digest(BitcoinSUtil.flipEndianness("74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"))
val hash2 = DoubleSha256Digest(BitcoinSUtil.flipEndianness("dd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"))
val hash1 = DoubleSha256Digest(
BitcoinSUtil.flipEndianness(
"74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"))
val hash2 = DoubleSha256Digest(
BitcoinSUtil.flipEndianness(
"dd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"))
//5ef2374cf1cd1c0b8c1b795950c077fc571cca44866c375a1ed17ace665cfaaa
//d403489f6b1a2f7de72c6e4573e1cc7ac15745518e42a0bf884f58dc48f45533
@ -52,17 +57,30 @@ class PartialMerkleTreeTests extends FlatSpec with MustMatchers {
//5310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd
//201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674
val filter = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll).insert(hash1).insert(hash2)
val filter = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll)
.insert(hash1)
.insert(hash2)
val (merkleBlock, _) = MerkleBlock(block, filter)
val partialMerkleTree = merkleBlock.partialMerkleTree
partialMerkleTree.bits.slice(0, 8).toIndexedSeq must be(Seq(true, true, false, true, false, true, false, true))
partialMerkleTree.bits.slice(8, partialMerkleTree.bits.size).toIndexedSeq must be(Seq(true, true, true, true, false, false, false, false))
partialMerkleTree.hashes must be(Seq(
DoubleSha256Digest("5ef2374cf1cd1c0b8c1b795950c077fc571cca44866c375a1ed17ace665cfaaa"),
DoubleSha256Digest("d403489f6b1a2f7de72c6e4573e1cc7ac15745518e42a0bf884f58dc48f45533"),
DoubleSha256Digest("8719e60a59869e70a7a7a5d4ff6ceb979cd5abe60721d4402aaf365719ebd221"),
DoubleSha256Digest("5310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd"),
DoubleSha256Digest("201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674")))
partialMerkleTree.bits.slice(0, 8).toIndexedSeq must be(
Seq(true, true, false, true, false, true, false, true))
partialMerkleTree.bits
.slice(8, partialMerkleTree.bits.size)
.toIndexedSeq must be(
Seq(true, true, true, true, false, false, false, false))
partialMerkleTree.hashes must be(
Seq(
DoubleSha256Digest(
"5ef2374cf1cd1c0b8c1b795950c077fc571cca44866c375a1ed17ace665cfaaa"),
DoubleSha256Digest(
"d403489f6b1a2f7de72c6e4573e1cc7ac15745518e42a0bf884f58dc48f45533"),
DoubleSha256Digest(
"8719e60a59869e70a7a7a5d4ff6ceb979cd5abe60721d4402aaf365719ebd221"),
DoubleSha256Digest(
"5310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd"),
DoubleSha256Digest(
"201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674")
))
partialMerkleTree.extractMatches must be(Seq(hash2, hash1))
@ -73,15 +91,34 @@ class PartialMerkleTreeTests extends FlatSpec with MustMatchers {
//https://github.com/bitcoin/bitcoin/blob/f17032f703288d43a76cffe8fa89b87ade9e3074/src/test/bloom_tests.cpp#L185
val maxHeight = 4
val matchedTxs = List(
(false, DoubleSha256Digest("a3f3ac605d5e4727f4ea72e9346a5d586f0231460fd52ad9895bc8240d871def")),
(false, DoubleSha256Digest("076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9")),
(false, DoubleSha256Digest("2ee1e12587e497ada70d9bd10d31e83f0a924825b96cb8d04e8936d793fb60db")),
(false, DoubleSha256Digest("7ad8b910d0c7ba2369bc7f18bb53d80e1869ba2c32274996cebe1ae264bc0e22")),
(false, DoubleSha256Digest("4e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371")),
(false, DoubleSha256Digest("e0c28dbf9f266a8997e1a02ef44af3a1ee48202253d86161d71282d01e5e30fe")),
(false, DoubleSha256Digest("8719e60a59869e70a7a7a5d4ff6ceb979cd5abe60721d4402aaf365719ebd221")),
(true, DoubleSha256Digest("5310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd")),
(true, DoubleSha256Digest("201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674")))
(false,
DoubleSha256Digest(
"a3f3ac605d5e4727f4ea72e9346a5d586f0231460fd52ad9895bc8240d871def")),
(false,
DoubleSha256Digest(
"076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9")),
(false,
DoubleSha256Digest(
"2ee1e12587e497ada70d9bd10d31e83f0a924825b96cb8d04e8936d793fb60db")),
(false,
DoubleSha256Digest(
"7ad8b910d0c7ba2369bc7f18bb53d80e1869ba2c32274996cebe1ae264bc0e22")),
(false,
DoubleSha256Digest(
"4e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371")),
(false,
DoubleSha256Digest(
"e0c28dbf9f266a8997e1a02ef44af3a1ee48202253d86161d71282d01e5e30fe")),
(false,
DoubleSha256Digest(
"8719e60a59869e70a7a7a5d4ff6ceb979cd5abe60721d4402aaf365719ebd221")),
(true,
DoubleSha256Digest(
"5310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd")),
(true,
DoubleSha256Digest(
"201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674"))
)
// it must trivially match the merkle root
PartialMerkleTree.matchesTx(maxHeight, 0, 0, matchedTxs) must be(true)
@ -124,8 +161,13 @@ class PartialMerkleTreeTests extends FlatSpec with MustMatchers {
it must "match no transactions if we give a list of no transactions" in {
val maxHeight = 1
val matchedTxs = Seq(
(false, DoubleSha256Digest("a3f3ac605d5e4727f4ea72e9346a5d586f0231460fd52ad9895bc8240d871def")),
(false, DoubleSha256Digest("076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9")))
(false,
DoubleSha256Digest(
"a3f3ac605d5e4727f4ea72e9346a5d586f0231460fd52ad9895bc8240d871def")),
(false,
DoubleSha256Digest(
"076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9"))
)
PartialMerkleTree.matchesTx(maxHeight, 0, 0, matchedTxs) must be(false)
PartialMerkleTree.matchesTx(maxHeight, 1, 0, matchedTxs) must be(false)
@ -133,62 +175,110 @@ class PartialMerkleTreeTests extends FlatSpec with MustMatchers {
}
it must "build a partial merkle tree with no matches and 1 transaction in the original block" in {
val txMatches = Seq((false, DoubleSha256Digest("01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")))
val txMatches = Seq(
(false,
DoubleSha256Digest(
"01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")))
val partialMerkleTree = PartialMerkleTree(txMatches)
partialMerkleTree.bits.toIndexedSeq must be(Seq(false, false, false, false, false, false, false, false))
partialMerkleTree.tree must be(Leaf(DoubleSha256Digest("01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")))
partialMerkleTree.bits.toIndexedSeq must be(
Seq(false, false, false, false, false, false, false, false))
partialMerkleTree.tree must be(
Leaf(DoubleSha256Digest(
"01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")))
partialMerkleTree.transactionCount must be(UInt32(1))
partialMerkleTree.extractMatches.isEmpty must be(true)
}
it must "build a partial merkle tree with 1 match and 2 transactions inside the original block" in {
val txMatches = Seq(
(false, DoubleSha256Digest("01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")),
(true, DoubleSha256Digest("076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9")))
(false,
DoubleSha256Digest(
"01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")),
(true,
DoubleSha256Digest(
"076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9"))
)
val partialMerkleTree = PartialMerkleTree(txMatches)
partialMerkleTree.bits.toIndexedSeq must be(Seq(true, false, true, false, false, false, false, false))
partialMerkleTree.tree must be(Node(
DoubleSha256Digest("b130d701e65ac8c65f30dc4b20aabf349036b7c87f11f012f4f3f53f666791e6"),
Leaf(DoubleSha256Digest("01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")),
Leaf(DoubleSha256Digest("076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9"))))
partialMerkleTree.extractMatches must be(Seq(DoubleSha256Digest("076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9")))
partialMerkleTree.bits.toIndexedSeq must be(
Seq(true, false, true, false, false, false, false, false))
partialMerkleTree.tree must be(
Node(
DoubleSha256Digest(
"b130d701e65ac8c65f30dc4b20aabf349036b7c87f11f012f4f3f53f666791e6"),
Leaf(DoubleSha256Digest(
"01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")),
Leaf(DoubleSha256Digest(
"076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9"))
))
partialMerkleTree.extractMatches must be(
Seq(DoubleSha256Digest(
"076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9")))
}
it must "calculate bits correctly for a tree of height 1" in {
val matches = List((true, DoubleSha256Digest("caa02f1194fb44dea407a7cf713ddcf30e69f49c297f9275f9236fec42d945b2")))
val matches = List(
(true,
DoubleSha256Digest(
"caa02f1194fb44dea407a7cf713ddcf30e69f49c297f9275f9236fec42d945b2")))
val partialMerkleTree = PartialMerkleTree(matches)
partialMerkleTree.tree must be(Leaf(DoubleSha256Digest("caa02f1194fb44dea407a7cf713ddcf30e69f49c297f9275f9236fec42d945b2")))
partialMerkleTree.bits.toIndexedSeq must be(Seq(true, false, false, false, false, false, false, false))
partialMerkleTree.tree must be(
Leaf(DoubleSha256Digest(
"caa02f1194fb44dea407a7cf713ddcf30e69f49c297f9275f9236fec42d945b2")))
partialMerkleTree.bits.toIndexedSeq must be(
Seq(true, false, false, false, false, false, false, false))
}
it must "correctly compute a merkle tree that has an odd amount of txids on the merkle tree" in {
//this test is meant to prevent these failures on travis ci
//https://travis-ci.org/bitcoin-s/bitcoin-s-core/builds/205812075#L2774
val hashes: Seq[DoubleSha256Digest] = List(
DoubleSha256Digest("1563b82f187da1067f5000dabe3a4f4ae8650e207aa163e1d25ded8175e2bae1"),
DoubleSha256Digest("151cfc67334a38be8abdb5752f2346f8989c33336275d385b5c61af3edfa0a51"),
DoubleSha256Digest("f3309f2f4697a95be63e61eae9946b9f9e143909faafeec6fdda01284f5192f8"),
DoubleSha256Digest("0b38edce452a4ea17b5d76346c9e81ad03e9ecaa887d9a76edeb4da807ce8439"),
DoubleSha256Digest("ae2caf79fc55e3e887ddb39bcd7f8436f0423e1e8f1f37872ee84779ebdf28c1"),
DoubleSha256Digest("4c5db2bdd85cef0a37fe4e675b0c342c9b92df90fabe19c5258aa164bdcfddbc"),
DoubleSha256Digest("ec35eda50230cef0b04be44a070b3fcdbf1766f512cd0432f26a34df6249002a"),
DoubleSha256Digest("aee82970ace34438dc1d0f3655c62b60c5a28d5754a7d9903706f841fe760dcf"),
DoubleSha256Digest("584a8cd477057c6ddd3f17be8d47e02210e26a48ef77f3a35bd46903d29b47f8"),
DoubleSha256Digest("0b55b03bde4e82068f869f4f7f9560fb987f14c15b45b19eff352957ea7a5101"),
DoubleSha256Digest("f185de9349b800e635ec1dfa06fe0be3ae7cd694f2dbaeeff2d39c58dbebcfd2"),
DoubleSha256Digest("023175e3a4f7fa993b45a9ca3604b17835866e6af1aff740fa28bae82b8bc71e"),
DoubleSha256Digest("be6ce29d3dd0f7f777f188b94a5ae514bd763a5a0ff81055fea090596d3acc0b"),
DoubleSha256Digest("7f1f476304d88a844ff5f5ae2dc0b17e704aa560619fba3753744ca03dea029b"),
DoubleSha256Digest("9d6453d3573dfadbf93532953ef3e63f4731fc9543705af9988bb8038f060e30"),
DoubleSha256Digest("9d19dd76defcb7bf991ad62e3a468423ddca09ff3181b8f03d57dbc4e25a1596"),
DoubleSha256Digest("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"),
DoubleSha256Digest("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"))
DoubleSha256Digest(
"1563b82f187da1067f5000dabe3a4f4ae8650e207aa163e1d25ded8175e2bae1"),
DoubleSha256Digest(
"151cfc67334a38be8abdb5752f2346f8989c33336275d385b5c61af3edfa0a51"),
DoubleSha256Digest(
"f3309f2f4697a95be63e61eae9946b9f9e143909faafeec6fdda01284f5192f8"),
DoubleSha256Digest(
"0b38edce452a4ea17b5d76346c9e81ad03e9ecaa887d9a76edeb4da807ce8439"),
DoubleSha256Digest(
"ae2caf79fc55e3e887ddb39bcd7f8436f0423e1e8f1f37872ee84779ebdf28c1"),
DoubleSha256Digest(
"4c5db2bdd85cef0a37fe4e675b0c342c9b92df90fabe19c5258aa164bdcfddbc"),
DoubleSha256Digest(
"ec35eda50230cef0b04be44a070b3fcdbf1766f512cd0432f26a34df6249002a"),
DoubleSha256Digest(
"aee82970ace34438dc1d0f3655c62b60c5a28d5754a7d9903706f841fe760dcf"),
DoubleSha256Digest(
"584a8cd477057c6ddd3f17be8d47e02210e26a48ef77f3a35bd46903d29b47f8"),
DoubleSha256Digest(
"0b55b03bde4e82068f869f4f7f9560fb987f14c15b45b19eff352957ea7a5101"),
DoubleSha256Digest(
"f185de9349b800e635ec1dfa06fe0be3ae7cd694f2dbaeeff2d39c58dbebcfd2"),
DoubleSha256Digest(
"023175e3a4f7fa993b45a9ca3604b17835866e6af1aff740fa28bae82b8bc71e"),
DoubleSha256Digest(
"be6ce29d3dd0f7f777f188b94a5ae514bd763a5a0ff81055fea090596d3acc0b"),
DoubleSha256Digest(
"7f1f476304d88a844ff5f5ae2dc0b17e704aa560619fba3753744ca03dea029b"),
DoubleSha256Digest(
"9d6453d3573dfadbf93532953ef3e63f4731fc9543705af9988bb8038f060e30"),
DoubleSha256Digest(
"9d19dd76defcb7bf991ad62e3a468423ddca09ff3181b8f03d57dbc4e25a1596"),
DoubleSha256Digest(
"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"),
DoubleSha256Digest(
"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456")
)
val numTransactions = UInt32(20)
val bits = BitVector.bits(List(true, true, true, true, true, true, true, false, true, true, false, true,
true, true, false, true, true, true, true, false, true, true, true, true, true, true, true,
false, true, true, true, true, false, true, true, true, true, false, false, false))
val bits = BitVector.bits(
List(true, true, true, true, true, true, true, false, true, true, false,
true, true, true, false, true, true, true, true, false, true, true,
true, true, true, true, true, false, true, true, true, true, false,
true, true, true, true, false, false, false))
val tree = PartialMerkleTree(numTransactions, hashes, bits)
tree.extractMatches.contains(DoubleSha256Digest("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456")) must be(true)
tree.extractMatches.contains(DoubleSha256Digest(
"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456")) must be(
true)
}
}

View file

@ -1,9 +1,9 @@
package org.bitcoins.core.protocol.ln
import org.bitcoins.core.config.{ MainNet, RegTest, TestNet3 }
import org.bitcoins.core.config.{MainNet, RegTest, TestNet3}
import org.bitcoins.core.protocol.ln.LnParams._
import org.bitcoins.core.protocol.ln.currency.{ LnCurrencyUnits, MilliBitcoins }
import org.scalatest.{ FlatSpec, MustMatchers }
import org.bitcoins.core.protocol.ln.currency.{LnCurrencyUnits, MilliBitcoins}
import org.scalatest.{FlatSpec, MustMatchers}
import scala.util.Try
@ -15,9 +15,12 @@ class LnHumanReadablePartTest extends FlatSpec with MustMatchers {
LnHumanReadablePart(TestNet3) must be(LnHumanReadablePart(LnBitcoinTestNet))
LnHumanReadablePart(RegTest) must be(LnHumanReadablePart(LnBitcoinRegTest))
LnHumanReadablePart(MainNet, mBtc) must be(LnHumanReadablePart(LnBitcoinMainNet, mBtcOpt))
LnHumanReadablePart(TestNet3, mBtc) must be(LnHumanReadablePart(LnBitcoinTestNet, mBtcOpt))
LnHumanReadablePart(RegTest, mBtc) must be(LnHumanReadablePart(LnBitcoinRegTest, mBtcOpt))
LnHumanReadablePart(MainNet, mBtc) must be(
LnHumanReadablePart(LnBitcoinMainNet, mBtcOpt))
LnHumanReadablePart(TestNet3, mBtc) must be(
LnHumanReadablePart(LnBitcoinTestNet, mBtcOpt))
LnHumanReadablePart(RegTest, mBtc) must be(
LnHumanReadablePart(LnBitcoinRegTest, mBtcOpt))
}
it must "correctly serialize the hrp to string" in {
@ -43,13 +46,19 @@ class LnHumanReadablePartTest extends FlatSpec with MustMatchers {
it must "deserialize hrp from string" in {
LnHumanReadablePart.fromString("lnbc").get must be(LnHumanReadablePart(LnBitcoinMainNet))
LnHumanReadablePart.fromString("lntb").get must be(LnHumanReadablePart(LnBitcoinTestNet))
LnHumanReadablePart.fromString("lnbcrt").get must be(LnHumanReadablePart(LnBitcoinRegTest))
LnHumanReadablePart.fromString("lnbc").get must be(
LnHumanReadablePart(LnBitcoinMainNet))
LnHumanReadablePart.fromString("lntb").get must be(
LnHumanReadablePart(LnBitcoinTestNet))
LnHumanReadablePart.fromString("lnbcrt").get must be(
LnHumanReadablePart(LnBitcoinRegTest))
LnHumanReadablePart.fromString("lnbc1m").get must be(LnHumanReadablePart(LnBitcoinMainNet, mBtcOpt))
LnHumanReadablePart.fromString("lntb1m").get must be(LnHumanReadablePart(LnBitcoinTestNet, mBtcOpt))
LnHumanReadablePart.fromString("lnbcrt1m").get must be(LnHumanReadablePart(LnBitcoinRegTest, mBtcOpt))
LnHumanReadablePart.fromString("lnbc1m").get must be(
LnHumanReadablePart(LnBitcoinMainNet, mBtcOpt))
LnHumanReadablePart.fromString("lntb1m").get must be(
LnHumanReadablePart(LnBitcoinTestNet, mBtcOpt))
LnHumanReadablePart.fromString("lnbcrt1m").get must be(
LnHumanReadablePart(LnBitcoinRegTest, mBtcOpt))
}
it must "fail to deserialize hrp from invalid string" in {

View file

@ -2,15 +2,25 @@ package org.bitcoins.core.protocol.ln
import org.bitcoins.core.crypto._
import org.bitcoins.core.gen.ln.LnInvoiceGen
import org.bitcoins.core.number.{ UInt32, UInt64, UInt8 }
import org.bitcoins.core.protocol.ln.LnParams.{ LnBitcoinMainNet, LnBitcoinTestNet }
import org.bitcoins.core.protocol.ln.currency.{ MicroBitcoins, MilliBitcoins, MilliSatoshis }
import org.bitcoins.core.protocol.ln.fee.{ FeeBaseMSat, FeeProportionalMillionths }
import org.bitcoins.core.number.{UInt32, UInt64, UInt8}
import org.bitcoins.core.protocol.ln.LnParams.{
LnBitcoinMainNet,
LnBitcoinTestNet
}
import org.bitcoins.core.protocol.ln.currency.{
MicroBitcoins,
MilliBitcoins,
MilliSatoshis
}
import org.bitcoins.core.protocol.ln.fee.{
FeeBaseMSat,
FeeProportionalMillionths
}
import org.bitcoins.core.protocol.ln.routing.LnRoute
import org.bitcoins.core.protocol.{ Bech32Address, P2PKHAddress, P2SHAddress }
import org.bitcoins.core.protocol.{Bech32Address, P2PKHAddress, P2SHAddress}
import org.bitcoins.core.util.CryptoUtil
import org.scalatest.prop.PropertyChecks
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import org.slf4j.LoggerFactory
import scodec.bits.ByteVector
@ -20,12 +30,17 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
private val logger = LoggerFactory.getLogger(getClass.getSimpleName)
val hrpEmpty = LnHumanReadablePart(LnBitcoinMainNet)
val hrpMicro = LnHumanReadablePart(LnBitcoinMainNet, Some(MicroBitcoins(2500)))
val hrpMicro =
LnHumanReadablePart(LnBitcoinMainNet, Some(MicroBitcoins(2500)))
val hrpMilli = LnHumanReadablePart(LnBitcoinMainNet, Some(MilliBitcoins(20)))
val hrpTestNetMilli = LnHumanReadablePart(LnBitcoinTestNet, Some(MilliBitcoins(20)))
val hrpTestNetMilli =
LnHumanReadablePart(LnBitcoinTestNet, Some(MilliBitcoins(20)))
val time = UInt64(1496314658)
val paymentHash = Sha256Digest.fromHex("0001020304050607080900010203040506070809000102030405060708090102")
val paymentHash = Sha256Digest.fromHex(
"0001020304050607080900010203040506070809000102030405060708090102")
val paymentTag = LnTag.PaymentHashTag(paymentHash)
val description = {
@ -40,15 +55,18 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
it must "parse BOLT11 example 1" in {
//BOLT11 Example #1
val descriptionTagE = Left(LnTag.DescriptionTag("Please consider supporting this project"))
val lnTags = LnTaggedFields(
paymentHash = paymentTag,
descriptionOrHash = descriptionTagE)
val descriptionTagE =
Left(LnTag.DescriptionTag("Please consider supporting this project"))
val lnTags = LnTaggedFields(paymentHash = paymentTag,
descriptionOrHash = descriptionTagE)
val sigData = "6c6e62630b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404081a1fa83632b0b9b29031b7b739b4b232b91039bab83837b93a34b733903a3434b990383937b532b1ba0"
val hashSigData = Sha256Digest.fromHex("c3d4e83f646fa79a393d75277b1d858db1d1f7ab7137dcb7835db2ecd518e1c9")
val sigData =
"6c6e62630b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404081a1fa83632b0b9b29031b7b739b4b232b91039bab83837b93a34b733903a3434b990383937b532b1ba0"
val hashSigData = Sha256Digest.fromHex(
"c3d4e83f646fa79a393d75277b1d858db1d1f7ab7137dcb7835db2ecd518e1c9")
val signature = ECDigitalSignature.fromRS("38ec6891345e204145be8a3a99de38e98a39d6a569434e1845c8af7205afcfcc7f425fcd1463e93c32881ead0d6e356d467ec8c02553f9aab15e5738b11f127f")
val signature = ECDigitalSignature.fromRS(
"38ec6891345e204145be8a3a99de38e98a39d6a569434e1845c8af7205afcfcc7f425fcd1463e93c32881ead0d6e356d467ec8c02553f9aab15e5738b11f127f")
val version = UInt8.zero
val lnSig = LnInvoiceSignature(version, signature)
@ -57,7 +75,8 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
invoice.signatureData.toHex must be(sigData)
val serialized = invoice.toString
serialized must be("lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w")
serialized must be(
"lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w")
val deserialized = LnInvoice.fromString(serialized)
@ -69,12 +88,12 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
val descriptionTagE = Left(LnTag.DescriptionTag("1 cup coffee"))
val expiryTimeTag = LnTag.ExpiryTimeTag(UInt32(60))
val lnTags = LnTaggedFields(
paymentTag,
descriptionOrHash = descriptionTagE,
expiryTime = Some(expiryTimeTag))
val lnTags = LnTaggedFields(paymentTag,
descriptionOrHash = descriptionTagE,
expiryTime = Some(expiryTimeTag))
val signature = ECDigitalSignature.fromRS("e89639ba6814e36689d4b91bf125f10351b55da057b00647a8dabaeb8a90c95f160f9d5a6e0f79d1fc2b964238b944e2fa4aa677c6f020d466472ab842bd750e")
val signature = ECDigitalSignature.fromRS(
"e89639ba6814e36689d4b91bf125f10351b55da057b00647a8dabaeb8a90c95f160f9d5a6e0f79d1fc2b964238b944e2fa4aa677c6f020d466472ab842bd750e")
val version = UInt8.one
val lnSig = LnInvoiceSignature(version, signature)
@ -82,7 +101,8 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
val serialized = invoice.toString
serialized must be("lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp")
serialized must be(
"lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp")
val deserialized = LnInvoice.fromString(serialized)
@ -94,12 +114,16 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
val descriptionTagE = Left(LnTag.DescriptionTag("ナンセンス 1杯"))
val expiryTag = LnTag.ExpiryTimeTag(UInt32(60))
val lnTags = LnTaggedFields(
paymentTag, descriptionTagE, None,
Some(expiryTag), None, None,
None)
val lnTags = LnTaggedFields(paymentTag,
descriptionTagE,
None,
Some(expiryTag),
None,
None,
None)
val signature = ECDigitalSignature.fromRS("259f04511e7ef2aa77f6ff04d51b4ae9209504843e5ab9672ce32a153681f687515b73ce57ee309db588a10eb8e41b5a2d2bc17144ddf398033faa49ffe95ae6")
val signature = ECDigitalSignature.fromRS(
"259f04511e7ef2aa77f6ff04d51b4ae9209504843e5ab9672ce32a153681f687515b73ce57ee309db588a10eb8e41b5a2d2bc17144ddf398033faa49ffe95ae6")
val version = UInt8.zero
val lnSig = LnInvoiceSignature(version, signature)
@ -107,7 +131,8 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
val serialized = invoice.toString
invoice.toString must be("lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny")
invoice.toString must be(
"lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny")
val deserialized = LnInvoice.fromString(serialized)
@ -117,15 +142,19 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
it must "parse BOLT11 example 4" in {
//BOLT11 Example #4
val descriptionHash = Sha256Digest.fromHex("3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1")
val descriptionHash = Sha256Digest.fromHex(
"3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1")
val descriptionHashTagE = Right(LnTag.DescriptionHashTag(descriptionHash))
val lnTags = LnTaggedFields(
paymentHash = paymentTag,
descriptionOrHash = descriptionHashTagE,
None, None, None,
None, None)
val lnTags = LnTaggedFields(paymentHash = paymentTag,
descriptionOrHash = descriptionHashTagE,
None,
None,
None,
None,
None)
val signature = ECDigitalSignature.fromRS("c63486e81f8c878a105bc9d959af1973854c4dc552c4f0e0e0c7389603d6bdc67707bf6be992a8ce7bf50016bb41d8a9b5358652c4960445a170d049ced4558c")
val signature = ECDigitalSignature.fromRS(
"c63486e81f8c878a105bc9d959af1973854c4dc552c4f0e0e0c7389603d6bdc67707bf6be992a8ce7bf50016bb41d8a9b5358652c4960445a170d049ced4558c")
val version = UInt8.zero
val lnSig = LnInvoiceSignature(version, signature)
@ -133,7 +162,8 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
val serialized = invoice.toString
invoice.toString must be("lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7khhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7")
invoice.toString must be(
"lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7khhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7")
val deserialized = LnInvoice.fromString(serialized)
@ -143,16 +173,18 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
it must "parse BOLT11 example 5" in {
//BOLT11 Example #5
val descriptionHash = Sha256Digest.fromHex("3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1")
val descriptionHash = Sha256Digest.fromHex(
"3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1")
val descriptionHashTagE = Right(LnTag.DescriptionHashTag(descriptionHash))
val fallbackAddr = LnTag.FallbackAddressTag(P2PKHAddress.fromString("mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP").get)
val fallbackAddr = LnTag.FallbackAddressTag(
P2PKHAddress.fromString("mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP").get)
val lnTags = LnTaggedFields(
paymentHash = paymentTag,
descriptionOrHash = descriptionHashTagE,
fallbackAddress = Some(fallbackAddr))
val lnTags = LnTaggedFields(paymentHash = paymentTag,
descriptionOrHash = descriptionHashTagE,
fallbackAddress = Some(fallbackAddr))
val signature = ECDigitalSignature.fromRS("b6c42b8a61e0dc5823ea63e76ff148ab5f6c86f45f9722af0069c7934daff70d5e315893300774c897995e3a7476c8193693d144a36e2645a0851e6ebafc9d0a")
val signature = ECDigitalSignature.fromRS(
"b6c42b8a61e0dc5823ea63e76ff148ab5f6c86f45f9722af0069c7934daff70d5e315893300774c897995e3a7476c8193693d144a36e2645a0851e6ebafc9d0a")
val version = UInt8.one
val lnSig = LnInvoiceSignature(version, signature)
@ -160,7 +192,8 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
val serialized = invoice.toString
serialized must be("lntb20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3x9et2e20v6pu37c5d9vax37wxq72un98kmzzhznpurw9sgl2v0nklu2g4d0keph5t7tj9tcqd8rexnd07ux4uv2cjvcqwaxgj7v4uwn5wmypjd5n69z2xm3xgksg28nwht7f6zsp2mh7qm")
serialized must be(
"lntb20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3x9et2e20v6pu37c5d9vax37wxq72un98kmzzhznpurw9sgl2v0nklu2g4d0keph5t7tj9tcqd8rexnd07ux4uv2cjvcqwaxgj7v4uwn5wmypjd5n69z2xm3xgksg28nwht7f6zsp2mh7qm")
//In example #5, the order in which tags are encoded in the invoice has been changed to demonstrate the ability to move tags as needed.
//For that reason, the example #5 output we are matching against has been modified to fit the order in which we encode our invoices.
//TODO: Add checksum data to check
@ -170,43 +203,46 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
deserialized.get.toString must be(serialized)
}
it must "parse BOLT11 example 6" in {
val expected = "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzqj9n4evl6mr5aj9f58zp6fyjzup6ywn3x6sk8akg5v4tgn2q8g4fhx05wf6juaxu9760yp46454gpg5mtzgerlzezqcqvjnhjh8z3g2qqdhhwkj"
val expected =
"lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzqj9n4evl6mr5aj9f58zp6fyjzup6ywn3x6sk8akg5v4tgn2q8g4fhx05wf6juaxu9760yp46454gpg5mtzgerlzezqcqvjnhjh8z3g2qqdhhwkj"
val fallbackAddr = LnTag.FallbackAddressTag(P2PKHAddress.fromString("1RustyRX2oai4EYYDpQGWvEL62BBGqN9T").get)
val fallbackAddr = LnTag.FallbackAddressTag(
P2PKHAddress.fromString("1RustyRX2oai4EYYDpQGWvEL62BBGqN9T").get)
val signature = ECDigitalSignature.fromRS(
"91675cb3fad8e9d915343883a49242e074474e26d42c7ed914655689a8074553733e8e4ea5ce9b85f69e40d755a55014536b12323f8b220600c94ef2b9c51428")
val lnInvoiceSig = LnInvoiceSignature(
version = UInt8.zero,
signature = signature)
val lnInvoiceSig =
LnInvoiceSignature(version = UInt8.zero, signature = signature)
val route1 = LnRoute(
pubkey = ECPublicKey.fromHex("029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"),
pubkey = ECPublicKey.fromHex(
"029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"),
shortChannelID = ShortChannelId.fromHex("0102030405060708"),
feeBaseMsat = FeeBaseMSat(MilliSatoshis.one),
feePropMilli = FeeProportionalMillionths(UInt32(20)),
cltvExpiryDelta = 3)
cltvExpiryDelta = 3
)
val route2 = LnRoute(
pubkey = ECPublicKey.fromHex("039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"),
pubkey = ECPublicKey.fromHex(
"039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"),
shortChannelID = ShortChannelId.fromHex("030405060708090a"),
feeBaseMsat = FeeBaseMSat(MilliSatoshis(2)),
feePropMilli = FeeProportionalMillionths(UInt32(30)),
cltvExpiryDelta = 4)
cltvExpiryDelta = 4
)
val route = LnTag.RoutingInfo(Vector(route1, route2))
val lnTags = LnTaggedFields(
paymentHash = paymentTag,
descriptionOrHash = descpriptionHashTag,
fallbackAddress = Some(fallbackAddr),
routingInfo = Some(route))
val lnTags = LnTaggedFields(paymentHash = paymentTag,
descriptionOrHash = descpriptionHashTag,
fallbackAddress = Some(fallbackAddr),
routingInfo = Some(route))
val lnInvoice = LnInvoice(
hrp = hrpMilli,
timestamp = time,
lnTags = lnTags,
signature = lnInvoiceSig)
val lnInvoice = LnInvoice(hrp = hrpMilli,
timestamp = time,
lnTags = lnTags,
signature = lnInvoiceSig)
val serialized = lnInvoice.toString
serialized must be(expected)
@ -222,22 +258,21 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
"dph2q7z9kmrgvr7xlaqm47apw3d48zm203kzcq357a4ls9al2ea73r8jcceyjtya6fu5wzzpe50zrge6ulk" +
"4nvjcpxlekvmxl6qcs9j3tz0469gqsjurz5"
val fallbackAddr = LnTag.FallbackAddressTag(P2SHAddress.fromString("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX").get)
val fallbackAddr = LnTag.FallbackAddressTag(
P2SHAddress.fromString("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX").get)
val lnTags = LnTaggedFields(
paymentHash = paymentTag,
descriptionOrHash = descpriptionHashTag,
fallbackAddress = Some(fallbackAddr))
val lnTags = LnTaggedFields(paymentHash = paymentTag,
descriptionOrHash = descpriptionHashTag,
fallbackAddress = Some(fallbackAddr))
val signature = ECDigitalSignature.fromRS("b6c6860fc6ff41bafba1745b538b6a7c6c2c0234f76bf817bf567be88cf2c632492c9dd279470841cd1e21a33ae7ed59b25809bf9b3366fe81881651589f5d15")
val lnInvoiceSig = LnInvoiceSignature(
signature = signature,
version = UInt8.zero)
val lnInvoice = LnInvoice(
hrp = hrpMilli,
timestamp = time,
lnTags = lnTags,
signature = lnInvoiceSig)
val signature = ECDigitalSignature.fromRS(
"b6c6860fc6ff41bafba1745b538b6a7c6c2c0234f76bf817bf567be88cf2c632492c9dd279470841cd1e21a33ae7ed59b25809bf9b3366fe81881651589f5d15")
val lnInvoiceSig =
LnInvoiceSignature(signature = signature, version = UInt8.zero)
val lnInvoice = LnInvoice(hrp = hrpMilli,
timestamp = time,
lnTags = lnTags,
signature = lnInvoiceSig)
val serialized = lnInvoice.toString
@ -258,24 +293,25 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
"2ur5j5cr03890fa7k2pypgttmh4897d3raaq85a293e9jpuqwl0rnfu" +
"wzam7yr8e690nd2ypcq9hlkdwdvycqe4x4ch"
val fallbackAddr = LnTag.FallbackAddressTag(Bech32Address.fromString("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4").get)
val fallbackAddr = LnTag.FallbackAddressTag(
Bech32Address
.fromString("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
.get)
val lnTags = LnTaggedFields(
paymentHash = paymentTag,
descriptionOrHash = descpriptionHashTag,
fallbackAddress = Some(fallbackAddr))
val lnTags = LnTaggedFields(paymentHash = paymentTag,
descriptionOrHash = descpriptionHashTag,
fallbackAddress = Some(fallbackAddr))
val signature = ECDigitalSignature.fromRS("c8583b8f65853d7cc90f0eb4ae0e92a606f89caf4f7d65048142d7bbd4e5f3623ef407a75458e4b20f00efbc734f1c2eefc419f3a2be6d51038016ffb35cd613")
val signature = ECDigitalSignature.fromRS(
"c8583b8f65853d7cc90f0eb4ae0e92a606f89caf4f7d65048142d7bbd4e5f3623ef407a75458e4b20f00efbc734f1c2eefc419f3a2be6d51038016ffb35cd613")
val lnInvoiceSig = LnInvoiceSignature(
signature = signature,
version = UInt8.zero)
val lnInvoiceSig =
LnInvoiceSignature(signature = signature, version = UInt8.zero)
val lnInvoice = LnInvoice(
hrp = hrpMilli,
timestamp = time,
lnTags = lnTags,
signature = lnInvoiceSig)
val lnInvoice = LnInvoice(hrp = hrpMilli,
timestamp = time,
lnTags = lnTags,
signature = lnInvoiceSig)
val serialized = lnInvoice.toString
@ -294,24 +330,26 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
"q28j0v3rwgy9pvjnd48ee2pl8xrpxysd5g44td63g6xcjcu003j3qe8" +
"878hluqlvl3km8rm92f5stamd3jw763n3hck0ct7p8wwj463cqm8cxgy"
val fallbackAddr = LnTag.FallbackAddressTag(Bech32Address.fromString("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3").get)
val fallbackAddr = LnTag.FallbackAddressTag(
Bech32Address
.fromString(
"bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3")
.get)
val lnTags = LnTaggedFields(
paymentHash = paymentTag,
descriptionOrHash = descpriptionHashTag,
fallbackAddress = Some(fallbackAddr))
val lnTags = LnTaggedFields(paymentHash = paymentTag,
descriptionOrHash = descpriptionHashTag,
fallbackAddress = Some(fallbackAddr))
val signature = ECDigitalSignature.fromRS("51e4f6446e410a164a6da9f39507e730c26241b4456ab6ea28d1b12c71ef8ca20c9cfe3dffc07d9f8db671ecaa4d20beedb193bda8ce37c59f85f82773a55d47")
val signature = ECDigitalSignature.fromRS(
"51e4f6446e410a164a6da9f39507e730c26241b4456ab6ea28d1b12c71ef8ca20c9cfe3dffc07d9f8db671ecaa4d20beedb193bda8ce37c59f85f82773a55d47")
val lnInvoiceSig = LnInvoiceSignature(
signature = signature,
version = UInt8.zero)
val lnInvoiceSig =
LnInvoiceSignature(signature = signature, version = UInt8.zero)
val lnInvoice = LnInvoice(
hrp = hrpMilli,
timestamp = time,
lnTags = lnTags,
signature = lnInvoiceSig)
val lnInvoice = LnInvoice(hrp = hrpMilli,
timestamp = time,
lnTags = lnTags,
signature = lnInvoiceSig)
val serialized = lnInvoice.toString
@ -324,7 +362,8 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
it must "deserialize and reserialize a invoice with a explicity expiry time" in {
//from eclair
val bech32 = "lnbcrt1m1pd6ssf3pp5mqcepx6yzx7uu0uagw5x3c7kqhnpwr3mfn844hjux8tlza6ztr7sdqqxqrrss0rl3gzer9gfc54fs84rd4xk6g8nf0syharnnyljc9za933memdzxrjz0v2v94ntuhdxduk3z0nlmpmznryvvvl4gzgu28kjkm4ey98gpmyhjfa"
val bech32 =
"lnbcrt1m1pd6ssf3pp5mqcepx6yzx7uu0uagw5x3c7kqhnpwr3mfn844hjux8tlza6ztr7sdqqxqrrss0rl3gzer9gfc54fs84rd4xk6g8nf0syharnnyljc9za933memdzxrjz0v2v94ntuhdxduk3z0nlmpmznryvvvl4gzgu28kjkm4ey98gpmyhjfa"
val invoiceT = LnInvoice.fromString(bech32)
@ -349,32 +388,29 @@ class LnInvoiceUnitTest extends FlatSpec with MustMatchers with PropertyChecks {
it must "fail to create an invoice if the digital signature is invalid" in {
intercept[IllegalArgumentException] {
val sig = EmptyDigitalSignature
val tags = LnTaggedFields(
paymentHash = paymentTag,
descriptionOrHash = Right(LnTag.DescriptionHashTag(descriptionHash)))
val lnSig = LnInvoiceSignature(
version = UInt8.zero,
signature = sig)
LnInvoice(
hrp = hrpEmpty,
timestamp = UInt64.zero,
lnTags = tags,
signature = lnSig)
val tags =
LnTaggedFields(paymentHash = paymentTag,
descriptionOrHash =
Right(LnTag.DescriptionHashTag(descriptionHash)))
val lnSig = LnInvoiceSignature(version = UInt8.zero, signature = sig)
LnInvoice(hrp = hrpEmpty,
timestamp = UInt64.zero,
lnTags = tags,
signature = lnSig)
}
}
it must "create a valid digital signature for an invoice" in {
val privKey = ECPrivateKey.freshPrivateKey
val tags = LnTaggedFields(
paymentHash = paymentTag,
descriptionOrHash = Right(LnTag.DescriptionHashTag(descriptionHash)))
val tags =
LnTaggedFields(paymentHash = paymentTag,
descriptionOrHash =
Right(LnTag.DescriptionHashTag(descriptionHash)))
val invoice = LnInvoice.build(
hrp = hrpEmpty,
lnTags = tags,
privateKey = privKey)
val invoice =
LnInvoice.build(hrp = hrpEmpty, lnTags = tags, privateKey = privKey)
assert(invoice.isValidSignature())
}
}
}

View file

@ -2,7 +2,7 @@ package org.bitcoins.core.protocol.ln.currency
import org.bitcoins.core.currency.Satoshis
import org.bitcoins.core.gen.ln.LnCurrencyUnitGen
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
import scala.util.Try
@ -14,11 +14,13 @@ class LnCurrencyUnitSpec extends Properties("LnCurrencyUnitSpec") {
}
property("Add two LnCurrencyUnits") =
Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { (num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
val result: Try[LnCurrencyUnit] = Try(num1 + num2)
if (result.isSuccess && result.get >= PicoBitcoins.min &&
result.get <= PicoBitcoins.max) num1 + num2 == result.get
else Try(num1 + num2).isFailure
Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit,
LnCurrencyUnitGen.lnCurrencyUnit) {
(num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
val result: Try[LnCurrencyUnit] = Try(num1 + num2)
if (result.isSuccess && result.get >= PicoBitcoins.min &&
result.get <= PicoBitcoins.max) num1 + num2 == result.get
else Try(num1 + num2).isFailure
}
property("Subtractive identity for LnCurrencyUnits") =
@ -27,11 +29,13 @@ class LnCurrencyUnitSpec extends Properties("LnCurrencyUnitSpec") {
}
property("Subtract two LnCurrencyUnit values") =
Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { (num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
val result: Try[LnCurrencyUnit] = Try(num1 - num2)
if (result.isSuccess && result.get >= PicoBitcoins.min &&
result.get <= PicoBitcoins.max) num1 - num2 == result.get
else Try(num1 - num2).isFailure
Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit,
LnCurrencyUnitGen.lnCurrencyUnit) {
(num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
val result: Try[LnCurrencyUnit] = Try(num1 - num2)
if (result.isSuccess && result.get >= PicoBitcoins.min &&
result.get <= PicoBitcoins.max) num1 - num2 == result.get
else Try(num1 - num2).isFailure
}
property("Multiply LnCurrencyUnit by zero") =
@ -45,11 +49,13 @@ class LnCurrencyUnitSpec extends Properties("LnCurrencyUnitSpec") {
}
property("Multiply two LnCurrencyUnit values") =
Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { (num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
val result: Try[LnCurrencyUnit] = Try(num1 * num2)
if (result.isSuccess && result.get >= PicoBitcoins.min &&
result.get <= PicoBitcoins.max) num1 * num2 == result.get
else Try(num1 * num2).isFailure
Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit,
LnCurrencyUnitGen.lnCurrencyUnit) {
(num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
val result: Try[LnCurrencyUnit] = Try(num1 * num2)
if (result.isSuccess && result.get >= PicoBitcoins.min &&
result.get <= PicoBitcoins.max) num1 * num2 == result.get
else Try(num1 * num2).isFailure
}
property("Convert negative LnCurrencyUnit value to Satoshis") =
@ -57,19 +63,21 @@ class LnCurrencyUnitSpec extends Properties("LnCurrencyUnitSpec") {
lnUnit.toSatoshis <= Satoshis.zero
}
property("< & >=") =
Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { (num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
property("< & >=") = Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit,
LnCurrencyUnitGen.lnCurrencyUnit) {
(num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
(num1 < num2) || (num1 >= num2)
}
}
property("<= & >") =
Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { (num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
property("<= & >") = Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit,
LnCurrencyUnitGen.lnCurrencyUnit) {
(num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
(num1 <= num2) || (num1 > num2)
}
}
property("== & !=") =
Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit, LnCurrencyUnitGen.lnCurrencyUnit) { (num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
property("== & !=") = Prop.forAll(LnCurrencyUnitGen.lnCurrencyUnit,
LnCurrencyUnitGen.lnCurrencyUnit) {
(num1: LnCurrencyUnit, num2: LnCurrencyUnit) =>
(num1 == num2) || (num1 != num2)
}
}
}

View file

@ -2,7 +2,7 @@ package org.bitcoins.core.protocol.ln.currency
import org.bitcoins.core.currency.Satoshis
import org.bitcoins.core.protocol.ln.LnPolicy
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
class LnCurrencyUnitTest extends FlatSpec with MustMatchers {
it must "serialize MilliBitcoins to string" in {
@ -164,4 +164,4 @@ class LnCurrencyUnitTest extends FlatSpec with MustMatchers {
NanoBitcoins.one must be(NanoBitcoins(1))
PicoBitcoins.one must be(PicoBitcoins(1))
}
}
}

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.ScriptGenerators
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by tom on 8/23/16.
*/
* Created by tom on 8/23/16.
*/
class CLTVScriptPubKeySpec extends Properties("CLTVScriptPubKeySpec") {
property("Serialization symmetry") =
Prop.forAll(ScriptGenerators.cltvScriptPubKey) {

View file

@ -2,26 +2,40 @@ 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.crypto.{ OP_CHECKSIG, OP_HASH160 }
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.script.stack.{OP_DROP, OP_DUP}
import org.bitcoins.core.util.TestUtil
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by tom on 9/21/16.
*/
* Created by tom on 9/21/16.
*/
class CLTVScriptPubKeyTest extends FlatSpec with MustMatchers {
val expectedAsm: Seq[ScriptToken] =
List(OP_DUP, OP_HASH160, BytesToPushOntoStack(20), ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"), OP_EQUALVERIFY, OP_CHECKSIG)
List(OP_DUP,
OP_HASH160,
BytesToPushOntoStack(20),
ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"),
OP_EQUALVERIFY,
OP_CHECKSIG)
//from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc
val rawScriptPubKey = TestUtil.rawP2PKHScriptPubKey
val scriptPubKey = ScriptPubKey(rawScriptPubKey)
"CLTVScriptPubKey" must "return the expected asm from hex" in {
val expectedCLTVAsm: Seq[ScriptToken] =
List(BytesToPushOntoStack(4), ScriptConstant("2b07ae57"), OP_CHECKLOCKTIMEVERIFY, OP_DROP) ++ expectedAsm
List(BytesToPushOntoStack(4),
ScriptConstant("2b07ae57"),
OP_CHECKLOCKTIMEVERIFY,
OP_DROP) ++ expectedAsm
val cltv = CLTVScriptPubKey(ScriptNumber(1471022891), scriptPubKey)
cltv.asm must be(expectedCLTVAsm)
}

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.ScriptGenerators
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by tom on 8/23/16.
*/
* Created by tom on 8/23/16.
*/
class CSVScriptPubKeySpec extends Properties("CSVScriptPubKeySpec") {
property("Serialization Symmetry") =
Prop.forAll(ScriptGenerators.csvScriptPubKey) {

View file

@ -2,26 +2,40 @@ 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.crypto.{ OP_CHECKSIG, OP_HASH160 }
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.script.stack.{OP_DROP, OP_DUP}
import org.bitcoins.core.util.TestUtil
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by tom on 9/21/16.
*/
* Created by tom on 9/21/16.
*/
class CSVScriptPubKeyTest extends FlatSpec with MustMatchers {
val expectedAsm: Seq[ScriptToken] =
List(OP_DUP, OP_HASH160, BytesToPushOntoStack(20), ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"), OP_EQUALVERIFY, OP_CHECKSIG)
List(OP_DUP,
OP_HASH160,
BytesToPushOntoStack(20),
ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"),
OP_EQUALVERIFY,
OP_CHECKSIG)
//from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc
val rawScriptPubKey = TestUtil.rawP2PKHScriptPubKey
val scriptPubKey = ScriptPubKey(rawScriptPubKey)
"CSVScriptPubKey" must "return the expected asm from hex" in {
val expectedCSVAsm: Seq[ScriptToken] =
List(BytesToPushOntoStack(4), ScriptConstant("6202b257"), OP_CHECKSEQUENCEVERIFY, OP_DROP) ++ expectedAsm
List(BytesToPushOntoStack(4),
ScriptConstant("6202b257"),
OP_CHECKSEQUENCEVERIFY,
OP_DROP) ++ expectedAsm
val csv = CSVScriptPubKey(ScriptNumber(1471283810), scriptPubKey)
csv.asm must be(expectedCSVAsm)
}

View file

@ -1,16 +1,17 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.ScriptGenerators
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 3/28/17.
*/
class EscrowTimeoutScriptSigSpec extends Properties("EscrowWithTimeoutScriptSigSpec") {
* Created by chris on 3/28/17.
*/
class EscrowTimeoutScriptSigSpec
extends Properties("EscrowWithTimeoutScriptSigSpec") {
property("serialization symmetry") =
Prop.forAll(ScriptGenerators.escrowTimeoutScriptSig) { scriptSig =>
EscrowTimeoutScriptSignature(scriptSig.hex) == scriptSig &&
EscrowTimeoutScriptSignature.fromAsm(scriptSig.asm) == scriptSig
EscrowTimeoutScriptSignature.fromAsm(scriptSig.asm) == scriptSig
}
}

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.ScriptGenerators
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 3/27/17.
*/
* Created by chris on 3/27/17.
*/
class EscrowTimeoutSpec extends Properties("CSVEscrowWithTimeoutSpec") {
property("serialization symmetry") = {

View file

@ -1,12 +1,13 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.ScriptGenerators
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 6/22/16.
*/
class MultiSignatureScriptPubKeySpec extends Properties("MultiSignatureScriptPubKeySpec") {
* Created by chris on 6/22/16.
*/
class MultiSignatureScriptPubKeySpec
extends Properties("MultiSignatureScriptPubKeySpec") {
property("Serialization symmetry") =
Prop.forAll(ScriptGenerators.multiSigScriptPubKey) {

View file

@ -2,11 +2,11 @@ package org.bitcoins.core.protocol.script
import org.bitcoins.core.crypto.ECPublicKey
import org.bitcoins.core.util.TestUtil
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 3/8/16.
*/
* Created by chris on 3/8/16.
*/
class MultiSignatureScriptPubKeyTest extends FlatSpec with MustMatchers {
"MultiSignatureScriptPubKey" must "derive the amount of required signatures from a multisignature script" in {
@ -15,7 +15,8 @@ class MultiSignatureScriptPubKeyTest extends FlatSpec with MustMatchers {
val scriptPubKey = ScriptPubKey(multiSigRawScriptPubKeyHex)
val multiSigScriptPubKey: MultiSignatureScriptPubKey = scriptPubKey match {
case s: MultiSignatureScriptPubKey => s
case _ => throw new RuntimeException("Should be a multisig script pub key")
case _ =>
throw new RuntimeException("Should be a multisig script pub key")
}
multiSigScriptPubKey.requiredSigs must be(2)
@ -30,13 +31,19 @@ class MultiSignatureScriptPubKeyTest extends FlatSpec with MustMatchers {
val scriptPubKey = ScriptPubKey(multiSigRawScriptPubKeyHex)
val multiSigScriptPubKey: MultiSignatureScriptPubKey = scriptPubKey match {
case s: MultiSignatureScriptPubKey => s
case _ => throw new RuntimeException("Should be a multisig script pub key")
case _ =>
throw new RuntimeException("Should be a multisig script pub key")
}
multiSigScriptPubKey.publicKeys must be(Seq(
ECPublicKey("025878e270211662a27181cf4d6ad4d2cf0e69a98a3815c086f587c7e9388d8718"),
ECPublicKey("03fc85980e3fac1f3d8a5c3223c3ef5bffc1bd42d2cc42add8c3899cc66e7f1906"),
ECPublicKey("0215b5bd050869166a70a7341b4f216e268b7c6c7504576dcea2cce7d11cc9a35f")))
multiSigScriptPubKey.publicKeys must be(
Seq(
ECPublicKey(
"025878e270211662a27181cf4d6ad4d2cf0e69a98a3815c086f587c7e9388d8718"),
ECPublicKey(
"03fc85980e3fac1f3d8a5c3223c3ef5bffc1bd42d2cc42add8c3899cc66e7f1906"),
ECPublicKey(
"0215b5bd050869166a70a7341b4f216e268b7c6c7504576dcea2cce7d11cc9a35f")
))
}
@ -48,7 +55,8 @@ class MultiSignatureScriptPubKeyTest extends FlatSpec with MustMatchers {
val scriptPubKey = ScriptPubKey(multiSigRawScriptPubKeyHex)
val multiSigScriptPubKey: MultiSignatureScriptPubKey = scriptPubKey match {
case s: MultiSignatureScriptPubKey => s
case _ => throw new RuntimeException("Should be a multisig script pub key")
case _ =>
throw new RuntimeException("Should be a multisig script pub key")
}
multiSigScriptPubKey.maxSigs must be(3)

View file

@ -1,16 +1,18 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.ScriptGenerators
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 6/22/16.
*/
class MultiSignatureScriptSignatureSpec extends Properties("MultiSignatureScriptSigSpec") {
* Created by chris on 6/22/16.
*/
class MultiSignatureScriptSignatureSpec
extends Properties("MultiSignatureScriptSigSpec") {
property("Serialization symmetry") =
Prop.forAll(ScriptGenerators.multiSignatureScriptSignature) { multiSigScriptSig =>
MultiSignatureScriptSignature(multiSigScriptSig.hex) == multiSigScriptSig
Prop.forAll(ScriptGenerators.multiSignatureScriptSignature) {
multiSigScriptSig =>
MultiSignatureScriptSignature(multiSigScriptSig.hex) == multiSigScriptSig
}
}

View file

@ -1,15 +1,16 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.util.TransactionTestUtil
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 3/8/16.
*/
* Created by chris on 3/8/16.
*/
class MultiSignatureScriptSignatureTest extends FlatSpec with MustMatchers {
"MultiSignatureScriptSignature" must "find all of the digital signatures for a multisignature scriptSig" in {
val (spendingTx, inputIndex, _, _) = TransactionTestUtil.signedMultiSignatureTransaction
val (spendingTx, inputIndex, _, _) =
TransactionTestUtil.signedMultiSignatureTransaction
val scriptSig = spendingTx.inputs(inputIndex).scriptSignature
scriptSig.signatures.size must be(2)
}

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.{ CryptoGenerators, ScriptGenerators }
import org.scalacheck.{ Prop, Properties }
import org.bitcoins.core.gen.{CryptoGenerators, ScriptGenerators}
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 6/22/16.
*/
* Created by chris on 6/22/16.
*/
class P2PKHScriptPubKeySpec extends Properties("P2PKHScriptPubKeySpec") {
property("Serialization symmetry") =

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.CryptoGenerators
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 9/22/16.
*/
* Created by chris on 9/22/16.
*/
class P2PKHScriptPubKeyTest extends FlatSpec with MustMatchers {
"P2PKHScriptPubKey" must "return the pubkeyhash" in {

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.ScriptGenerators
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 6/22/16.
*/
* Created by chris on 6/22/16.
*/
class P2PKHScriptSignatureSpec extends Properties("P2PKHSpec") {
property("Serialization symmetry") =

View file

@ -3,28 +3,31 @@ 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.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
import scodec.bits.ByteVector
/**
* Created by chris on 4/1/16.
*/
* Created by chris on 4/1/16.
*/
class P2PKHScriptSignatureTest extends FlatSpec with MustMatchers {
"P2PKHScriptSignature" must "be able to identify it's own hash type" in {
val p2pkhScriptSig = TestUtil.p2pkhScriptSig match {
case s: P2PKHScriptSignature => s
case _ => throw new RuntimeException("Must be p2pkh scriptSig")
case _ => throw new RuntimeException("Must be p2pkh scriptSig")
}
HashType.fromBytes(ByteVector.fromByte(p2pkhScriptSig.signatures.head.bytes.last)) must be(HashType.sigHashAll)
HashType.fromBytes(
ByteVector.fromByte(p2pkhScriptSig.signatures.head.bytes.last)) must be(
HashType.sigHashAll)
}
it must "be able to identify the signature in a p2pkh scriptSig" in {
val p2pkhScriptSig = TestUtil.p2pkhScriptSig match {
case s: P2PKHScriptSignature => s
case _ => throw new RuntimeException("Must be p2pkh scriptSig")
case _ => throw new RuntimeException("Must be p2pkh scriptSig")
}
p2pkhScriptSig.signature must be(ECDigitalSignature("3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac01"))
p2pkhScriptSig.signature must be(ECDigitalSignature(
"3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac01"))
}
}

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.ScriptGenerators
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 6/22/16.
*/
* Created by chris on 6/22/16.
*/
class P2PKScriptPubKeySpec extends Properties("P2PKScriptPubKeySpec") {
property("Serialization symmetry") =

View file

@ -2,19 +2,21 @@ package org.bitcoins.core.protocol.script
import org.bitcoins.core.crypto.ECPublicKey
import org.bitcoins.core.util.TestUtil
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 4/1/16.
*/
* Created by chris on 4/1/16.
*/
class P2PKScriptPubKeyTest extends FlatSpec with MustMatchers {
"P2PKScriptPubKeyTest" must "find the public key in a p2pk scriptPubKey" in {
val p2pkScriptPubKey = TestUtil.p2pkScriptPubKey match {
case s: P2PKScriptPubKey => s
case _ => throw new RuntimeException("should have been p2pk script pub key")
case _ =>
throw new RuntimeException("should have been p2pk script pub key")
}
p2pkScriptPubKey.publicKey must be(ECPublicKey("0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"))
p2pkScriptPubKey.publicKey must be(ECPublicKey(
"0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"))
}
}

View file

@ -2,11 +2,11 @@ package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.ScriptGenerators
import org.bitcoins.core.util.BitcoinSLogger
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 6/22/16.
*/
* Created by chris on 6/22/16.
*/
class P2PKScriptSignatureSpec extends Properties("P2PKSpec") {
private def logger = BitcoinSLogger.logger

View file

@ -2,19 +2,20 @@ package org.bitcoins.core.protocol.script
import org.bitcoins.core.crypto.ECDigitalSignature
import org.bitcoins.core.util.TestUtil
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 3/16/16.
*/
* Created by chris on 3/16/16.
*/
class P2PKScriptSignatureTest extends FlatSpec with MustMatchers {
"P2PKScriptSignature" must "find the signature inside of a p2pk scriptSig" in {
val p2pkScriptSig = TestUtil.p2pkScriptSig match {
case s: P2PKScriptSignature => s
case _ => throw new RuntimeException("SHould have been a p2pk scriptSig")
case _ => throw new RuntimeException("SHould have been a p2pk scriptSig")
}
p2pkScriptSig.signature must be(ECDigitalSignature("304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001"))
p2pkScriptSig.signature must be(ECDigitalSignature(
"304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001"))
}
}

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.ScriptGenerators
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 6/24/16.
*/
* Created by chris on 6/24/16.
*/
class P2SHScriptPubKeySpec extends Properties("P2SHScriptPubKeySpec") {
property("Symmetrical serialization") =

View file

@ -1,11 +1,11 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.gen.ScriptGenerators
import org.scalacheck.{ Prop, Properties }
import org.scalacheck.{Prop, Properties}
/**
* Created by chris on 6/24/16.
*/
* Created by chris on 6/24/16.
*/
class P2SHScriptSignatureSpec extends Properties("P2SHScriptSignatureSpec") {
property("Symmetrical serialization") =
@ -14,7 +14,8 @@ class P2SHScriptSignatureSpec extends Properties("P2SHScriptSignatureSpec") {
}
property("place a witness scriptPubKey in a p2shScriptSig, then extract the witScriptPubKey again") =
property(
"place a witness scriptPubKey in a p2shScriptSig, then extract the witScriptPubKey again") =
Prop.forAll(ScriptGenerators.witnessScriptPubKeyV0) {
case (witScriptPubKey, privKeys) =>
val p2shScriptSig = P2SHScriptSignature(witScriptPubKey)

View file

@ -1,25 +1,34 @@
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.scalatest.{ FlatSpec, MustMatchers }
import org.bitcoins.core.script.constant.{
BytesToPushOntoStack,
OP_0,
ScriptConstant
}
import org.bitcoins.core.util.{BitcoinSLogger, TestUtil}
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 3/8/16.
*/
* Created by chris on 3/8/16.
*/
class P2SHScriptSignatureTest extends FlatSpec with MustMatchers {
private def logger = BitcoinSLogger.logger
"P2SHScriptSignature" must "find the public keys embedded inside of the redeemScript" in {
val rawP2SHScriptSig = TestUtil.rawP2shInputScript2Of2
val p2shScriptSig: P2SHScriptSignature = ScriptSignature(rawP2SHScriptSig) match {
case x: P2SHScriptSignature => x
case y => throw new RuntimeException("Must be p2sh script sig: " + y)
}
p2shScriptSig.publicKeys must be(Seq(
ECPublicKey("0369d26ebd086523384a0f89f293d4c327a65fa73332d8efd1097cb35231295b83"),
ECPublicKey("02480863e5c4a4e9763f5380c44fcfe6a3b7787397076cf9ea1049303a9d34f721")))
val p2shScriptSig: P2SHScriptSignature =
ScriptSignature(rawP2SHScriptSig) match {
case x: P2SHScriptSignature => x
case y => throw new RuntimeException("Must be p2sh script sig: " + y)
}
p2shScriptSig.publicKeys must be(
Seq(
ECPublicKey(
"0369d26ebd086523384a0f89f293d4c327a65fa73332d8efd1097cb35231295b83"),
ECPublicKey(
"02480863e5c4a4e9763f5380c44fcfe6a3b7787397076cf9ea1049303a9d34f721")
))
}
@ -27,20 +36,28 @@ class P2SHScriptSignatureTest extends FlatSpec with MustMatchers {
val p2shScriptSig = TestUtil.p2shInputScript2Of2 match {
case s: P2SHScriptSignature => s
case _ => throw new RuntimeException("Should be p2sh scriptSig")
case _ => throw new RuntimeException("Should be p2sh scriptSig")
}
p2shScriptSig.scriptSignatureNoRedeemScript.asm must be(Seq(
OP_0, BytesToPushOntoStack(71), ScriptConstant("304402207d764cb90c9fd84b74d33a47cf3a0ffead9ded98333776becd6acd32c4426dac02203905a0d064e7f53d07793e86136571b6e4f700c1cfb888174e84d78638335b8101"),
BytesToPushOntoStack(72),
ScriptConstant("3045022100906aaca39f022acd8b7a38fd2f92aca9e9f35cfeaee69a6f13e1d083ae18222602204c9ed96fc6c4de56fd85c679fc59c16ee1ccc80c42563b86174e1a506fc007c801")))
p2shScriptSig.scriptSignatureNoRedeemScript.asm must be(
Seq(
OP_0,
BytesToPushOntoStack(71),
ScriptConstant(
"304402207d764cb90c9fd84b74d33a47cf3a0ffead9ded98333776becd6acd32c4426dac02203905a0d064e7f53d07793e86136571b6e4f700c1cfb888174e84d78638335b8101"),
BytesToPushOntoStack(72),
ScriptConstant(
"3045022100906aaca39f022acd8b7a38fd2f92aca9e9f35cfeaee69a6f13e1d083ae18222602204c9ed96fc6c4de56fd85c679fc59c16ee1ccc80c42563b86174e1a506fc007c801")
))
}
it must "coreclty parse a EscrowTimeoutScriptSig and it's redeem script" in {
val hex = "ba00473044022051737de0cf47b6c367011ea0a9f164e878c228bbea1f4ea1b9a98183c24c34ce022050455ca8729d2275d3d9d4dfb712703c8e2ecd0adfe34fa333cf3b020c8e15d683514c6e63522103ebbcabd4878fe28998d518324587b3950eb868ef0bd25ff45e0a3649ee630c3b21038333b9faf7629d8b2e514ea8ec0d0645774a3c0ea66d797d45607069b0ec08c952ae67089ceb36b39e806a65b27576a91429dd76a8b34f5d6eafe1f24e3b255768ea28310b88ac68"
val hex =
"ba00473044022051737de0cf47b6c367011ea0a9f164e878c228bbea1f4ea1b9a98183c24c34ce022050455ca8729d2275d3d9d4dfb712703c8e2ecd0adfe34fa333cf3b020c8e15d683514c6e63522103ebbcabd4878fe28998d518324587b3950eb868ef0bd25ff45e0a3649ee630c3b21038333b9faf7629d8b2e514ea8ec0d0645774a3c0ea66d797d45607069b0ec08c952ae67089ceb36b39e806a65b27576a91429dd76a8b34f5d6eafe1f24e3b255768ea28310b88ac68"
val p2sh = P2SHScriptSignature(hex)
p2sh.redeemScript.isInstanceOf[EscrowTimeoutScriptPubKey] must be(true)
p2sh.scriptSignatureNoRedeemScript.isInstanceOf[EscrowTimeoutScriptSignature] must be(true)
p2sh.scriptSignatureNoRedeemScript
.isInstanceOf[EscrowTimeoutScriptSignature] must be(true)
}
}

View file

@ -1,7 +1,7 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.crypto.ECPrivateKey
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
class P2WPKHWitnessSPKV0Test extends FlatSpec with MustMatchers {
@ -12,4 +12,3 @@ class P2WPKHWitnessSPKV0Test extends FlatSpec with MustMatchers {
}
}
}

View file

@ -2,7 +2,7 @@ package org.bitcoins.core.protocol.script
import org.bitcoins.core.crypto.ECPrivateKey
import org.bitcoins.core.script.constant.ScriptNumber
import org.scalatest.{ FlatSpec, MustMatchers }
import org.scalatest.{FlatSpec, MustMatchers}
class P2WSHWitnessSPKV0Test extends FlatSpec with MustMatchers {
val uncompressed = ECPrivateKey(false).publicKey

View file

@ -1,17 +1,18 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.util.{ BitcoinSUtil, TestUtil }
import org.scalatest.{ FlatSpec, MustMatchers }
import org.bitcoins.core.util.{BitcoinSUtil, TestUtil}
import org.scalatest.{FlatSpec, MustMatchers}
/**
* Created by chris on 3/2/16.
*/
* Created by chris on 3/2/16.
*/
class ScriptPubKeyFactoryTest extends FlatSpec with MustMatchers {
"ScriptPubKeyFactory" must "create a scriptPubKey from a sequences of bytes and hex and get the same thing" in {
//from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc
val rawScriptPubKey = TestUtil.rawP2PKHScriptPubKey
val scriptPubKeyFromBytes = ScriptPubKey(BitcoinSUtil.decodeHex(rawScriptPubKey))
val scriptPubKeyFromBytes =
ScriptPubKey(BitcoinSUtil.decodeHex(rawScriptPubKey))
val scriptPubKeyFromHex = ScriptPubKey(rawScriptPubKey)
scriptPubKeyFromBytes must be(scriptPubKeyFromHex)
@ -27,18 +28,19 @@ class ScriptPubKeyFactoryTest extends FlatSpec with MustMatchers {
val scriptPubKey = ScriptPubKey(rawScriptPubKey)
val result = scriptPubKey match {
case script: P2PKScriptPubKey => true
case _ => false
case _ => false
}
result must be(true)
}
it must "create a multisignature scriptPubKey from a script using OP_CHECKMULTISIGVERIFY" in {
val multiSigRawScriptPubKeyHex = "695221025878e270211662a27181cf4d6ad4d2cf0e69a98a3815c086f587c7e9388d87182103fc85980e3fac1f3d8a5c3223c3ef5bffc1bd42d2cc42add8c3899cc66e7f1906210215b5bd050869166a70a7341b4f216e268b7c6c7504576dcea2cce7d11cc9a35f53af"
val multiSigRawScriptPubKeyHex =
"695221025878e270211662a27181cf4d6ad4d2cf0e69a98a3815c086f587c7e9388d87182103fc85980e3fac1f3d8a5c3223c3ef5bffc1bd42d2cc42add8c3899cc66e7f1906210215b5bd050869166a70a7341b4f216e268b7c6c7504576dcea2cce7d11cc9a35f53af"
val scriptPubKey = ScriptPubKey(multiSigRawScriptPubKeyHex)
val isMultiSigScriptPubKey: Boolean = scriptPubKey match {
case s: MultiSignatureScriptPubKey => true
case _ => false
case _ => false
}
isMultiSigScriptPubKey must be(true)

Some files were not shown because too many files have changed in this diff Show more