mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-13 11:35:40 +01:00
Added scalafmt and ran it (#264)
This commit is contained in:
parent
4a407ccdf1
commit
b8dbd302cb
379 changed files with 20498 additions and 12663 deletions
12
.scalafmt.conf
Normal file
12
.scalafmt.conf
Normal 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
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
35
build.sbt
35
build.sbt
|
@ -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)
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
name := "bitcoin-s-core-gen"
|
||||
|
||||
libraryDependencies ++= Deps.coreGen
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 =>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 =>
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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") {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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") =
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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 =>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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") = {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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") =
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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") =
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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") =
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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") =
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Add table
Reference in a new issue