Migration to scodec

Src is compiling

tests compiling

All unit tests passing now

fix compiler issue in ScriptParser

bump timeout to run on travis ci

Fixing two unit tests that had types failing

Turn down excessive logging

Uncomment rpc tests

fixing nits
This commit is contained in:
Daniel James 2018-05-22 19:39:58 -04:00 committed by Chris Stewart
parent c83959a2a6
commit 5b5852bf72
115 changed files with 1333 additions and 1504 deletions

View file

@ -49,6 +49,8 @@ lazy val rpc = project
.dependsOn(
core,
coreGen % "test->test"
).settings(
testOptions in Test += Tests.Argument("-oF")
)
publishArtifact in root := false

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.crypto
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
/**
* Created by chris on 3/22/16.
@ -8,7 +9,7 @@ import org.scalatest.{ FlatSpec, MustMatchers }
class ECDigitalSignatureTest extends FlatSpec with MustMatchers {
"ECDigitalSignature" must "say that empty signature is a valid DER encoded signature" in {
val emptySiganture = ECDigitalSignature(Seq())
val emptySiganture = ECDigitalSignature(ByteVector.empty)
emptySiganture.isDEREncoded must be(true)
}
@ -44,7 +45,7 @@ class ECDigitalSignatureTest extends FlatSpec with MustMatchers {
it must "create an empty digital signature when given 0 in hex or byte format" in {
val hex = ECDigitalSignature("00")
val byte = ECDigitalSignature(Seq(0.toByte))
val byte = ECDigitalSignature(scodec.bits.ByteVector.low(1))
val emptySignature = ECDigitalSignature("")
byte must be(emptySignature)
hex must be(emptySignature)

View file

@ -5,6 +5,7 @@ import java.math.BigInteger
import org.bitcoinj.core.Sha256Hash
import org.bitcoins.core.util.BitcoinSUtil
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
/**
* Created by chris on 2/29/16.
@ -16,17 +17,17 @@ class ECPublicKeyTest extends FlatSpec with MustMatchers {
val privateKeyHex = "180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19"
val key: ECPrivateKey = ECPrivateKey(privateKeyHex)
val hash = DoubleSha256Digest(Sha256Hash.ZERO_HASH.getBytes.toSeq)
val hash = DoubleSha256Digest(ByteVector(Sha256Hash.ZERO_HASH.getBytes))
val signature: ECDigitalSignature = key.sign(hash)
val isValid: Boolean = key.publicKey.verify(Sha256Hash.ZERO_HASH.getBytes.toSeq, 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 key: ECPrivateKey = ECPrivateKey(privateKeyHex)
val hash = DoubleSha256Digest(Sha256Hash.ZERO_HASH.getBytes.toSeq)
val hash = DoubleSha256Digest(ByteVector(Sha256Hash.ZERO_HASH.getBytes))
val signature: ECDigitalSignature = key.sign(hash)
val wrongPublicKey = ECPublicKey.freshPublicKey
@ -37,15 +38,15 @@ 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(bitcoinjSignature.encodeToDER())
val bitcoinsPublicKey = ECPublicKey(bitcoinjPrivKey.getPubKey)
bitcoinsPublicKey.verify(Sha256Hash.ZERO_HASH.getBytes, bitcoinsSignature) must be(true)
val bitcoinsSignature = ECDigitalSignature(ByteVector(bitcoinjSignature.encodeToDER()))
val bitcoinsPublicKey = ECPublicKey(ByteVector(bitcoinjPrivKey.getPubKey))
bitcoinsPublicKey.verify(ByteVector(Sha256Hash.ZERO_HASH.getBytes), bitcoinsSignature) must be(true)
}
it must "verify a piece of data was signed with a bitcoins private key inside of bitcoinj" in {
val bitcoinsPrivKey = ECPrivateKey.freshPrivateKey
val hash = DoubleSha256Digest(Sha256Hash.ZERO_HASH.getBytes)
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(

View file

@ -211,8 +211,8 @@ class TransactionSignatureCreatorTest extends FlatSpec with MustMatchers with Sc
inputIndex = inputIndex,
output = TransactionOutput(CurrencyUnits.zero, redeemScript),
flags = Policy.standardScriptVerifyFlags)
val sign: Seq[Byte] => Future[ECDigitalSignature] = {
bytes: Seq[Byte] => Future(privateKey.sign(bytes))
val sign: scodec.bits.ByteVector => Future[ECDigitalSignature] = {
bytes: scodec.bits.ByteVector => Future(privateKey.sign(bytes))
}
val txSignature = TransactionSignatureCreator.createSig(txSignatureComponent, sign, HashType.sigHashAll)

View file

@ -9,6 +9,7 @@ import org.bitcoins.core.script.crypto._
import org.bitcoins.core.serializers.script.ScriptParser
import org.bitcoins.core.util._
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
/**
* Created by chris on 2/19/16.
@ -17,278 +18,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
private def logger = BitcoinSLogger.logger
val scriptPubKey = BitcoinjConversions.toScriptPubKey(BitcoinJTestUtil.multiSigScript)
"TransactionSignatureSerializer" must "serialize a transaction for SIGHASH_ALL correctly" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val sigBytes: Seq[Byte] = TransactionSignatureSerializer.serializeForSignature(txSigComponent, HashType.sigHashAll)
val bitcoinjSerialization = BitcoinSUtil.encodeHex(
BitcoinJSignatureSerialization.serializeForSignature(BitcoinJTestUtil.multiSigTransaction, 0,
BitcoinJTestUtil.multiSigScript.getProgram(), HashType.sigHashAllByte))
BitcoinSUtil.encodeHex(sigBytes) must be(bitcoinjSerialization)
}
it must "hash a tranasction with SIGHASH_ALL correfctly" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val bitcoinsTxSigHash = TransactionSignatureSerializer.hashForSignature(txSigComponent, HashType.sigHashAll)
val bitcoinjTxSigHash = BitcoinSUtil.encodeHex(
BitcoinJSignatureSerialization.hashForSignature(BitcoinJTestUtil.multiSigTransaction, 0,
BitcoinJTestUtil.multiSigScript.getProgram(), HashType.sigHashAllByte))
bitcoinsTxSigHash.hex must be(bitcoinjTxSigHash)
}
it must "serialize a transaction for a SIGHASH_SINGLE transaction correctly" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val serializedTxForSig: Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(txSigComponent, HashType.sigHashSingle)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram, HashType.sigHashSingleByte))
BitcoinSUtil.encodeHex(serializedTxForSig) must be(bitcoinjSigSerialization)
}
it must "hash a transaction for a SIGHASH_SINGLE signature correctly" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(txSigComponent, HashType.sigHashSingle)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram, HashType.sigHashSingleByte))
hashedTxForSig.hex must be(bitcoinjSigSerialization)
}
it must "serialize a transaction for SIGHASH_NONE signature correctly" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val serializedTxForSig: Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(txSigComponent, HashType.sigHashNone)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram, HashType.sigHashNoneByte))
BitcoinSUtil.encodeHex(serializedTxForSig) must be(bitcoinjSigSerialization)
}
it must "hash a transaction for a SIGHASH_NONE signature correctly" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(txSigComponent, HashType.sigHashNone)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram, HashType.sigHashNoneByte))
hashedTxForSig.hex must be(bitcoinjSigSerialization)
}
it must "serialize a transaction that has the SIGHASH_ANYONECANPAY flag set" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val serializedTxForSig: Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(
txSigComponent,
HashType.sigHashAnyoneCanPay)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram, HashType.sigHashAnyoneCanPayByte))
BitcoinSUtil.encodeHex(serializedTxForSig) must be(bitcoinjSigSerialization)
}
it must "hash a transaction for SIGHASH_ANYONECANPAY correctly" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(txSigComponent, HashType.sigHashAnyoneCanPay)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram, HashType.sigHashAnyoneCanPayByte))
hashedTxForSig.hex must be(bitcoinjSigSerialization)
}
it must "serialize a transaction that uses both SIGHASH_ANYONECANPAY & SIGHASH_ALL" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val serializedTxForSig: Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(txSigComponent, HashType.sigHashAnyoneCanPay)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram, HashType.sigHashAnyoneCanPayByte))
BitcoinSUtil.encodeHex(serializedTxForSig) must be(bitcoinjSigSerialization)
}
it must "serialize a transaction that uses both SIGHASH_ANYONECANPAY & SIGHASH_SINGLE" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val serializedTxForSig: Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(
txSigComponent,
HashType.sigHashSingleAnyoneCanPay)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram,
HashType.sigHashSingleAnyoneCanPayByte))
BitcoinSUtil.encodeHex(serializedTxForSig) must be(bitcoinjSigSerialization)
}
it must "serialize a transaction that uses both SIGHASH_ANYONECANPAY & SIGHASH_NONE" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val serializedTxForSig: Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(txSigComponent, HashType.sigHashNoneAnyoneCanPay)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram, HashType.sigHashNoneAnyoneCanPayByte))
BitcoinSUtil.encodeHex(serializedTxForSig) must be(bitcoinjSigSerialization)
}
it must "hash a transaction that uses both SIGHASH_ANYONECANPAY & SIGHASH_ALL" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(txSigComponent, HashType.sigHashAllAnyoneCanPay)
val bitcoinjTxHashForSig = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram, HashType.sigHashAllAnyoneCanPayByte))
hashedTxForSig.hex must be(bitcoinjTxHashForSig)
}
it must "hash a transaction that uses both SIGHASH_ANYONECANPAY & SIGHASH_SINGLE" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(txSigComponent, HashType.sigHashSingleAnyoneCanPay)
val bitcoinjTxHashForSig = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram, HashType.sigHashSingleAnyoneCanPayByte))
hashedTxForSig.hex must be(bitcoinjTxHashForSig)
}
it must "hash a transaction that uses both SIGHASH_ANYONECANPAY & SIGHASH_NONE" in {
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be(BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val txSigComponent = BaseTxSigComponent(
spendingTx,
UInt32.zero,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(txSigComponent, HashType.sigHashNoneAnyoneCanPay)
val bitcoinjTxHashForSig = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction, 0, BitcoinJTestUtil.multiSigScript.getProgram, HashType.sigHashNoneAnyoneCanPayByte))
hashedTxForSig.hex must be(bitcoinjTxHashForSig)
}
it must "hash a transaction that has script operations after OP_CHECKSIGVERIFY" in {
//this example is from tx_valid.json
val rawTx = "01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000"
val inputIndex = UInt32.zero
val spendingTx = Transaction(rawTx)
val scriptPubKeyFromString = ScriptParser.fromString("DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 " +
"EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed02" +
"2026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01")
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val bitcoinjTx = BitcoinjConversions.transaction(spendingTx)
val bitcoinjHashForSig: Seq[Byte] = BitcoinJSignatureSerialization.hashForSignature(
bitcoinjTx, inputIndex.toInt, scriptPubKey.asmBytes.toArray, HashType.sigHashAllByte)
val txSigComponent = BaseTxSigComponent(
spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(txSigComponent, HashType.sigHashAll)
hashedTxForSig.hex must be(BitcoinSUtil.encodeHex(bitcoinjHashForSig))
}
it must "correctly serialize an input that is being checked where another input in the same tx is using SIGHASH_ANYONECANPAY" in {
"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"
@ -310,30 +40,6 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
}
it must "correctly serialize an input that is using the SIGHASH_ANYONECANPAY flag in conjunction with another input that uses SIGHASH_ALL" 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 inputIndex = UInt32.one
val spendingTx = Transaction(rawTx)
val scriptPubKeyFromString = ScriptParser.fromString("0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG")
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val bitcoinjTx = BitcoinjConversions.transaction(spendingTx)
val bitcoinjHashForSig: Seq[Byte] = BitcoinJSignatureSerialization.hashForSignature(
bitcoinjTx, inputIndex.toInt, scriptPubKey.bytes.toArray, HashType.sigHashAllAnyoneCanPayByte)
val txSigComponent = BaseTxSigComponent(
spendingTx,
inputIndex,
TransactionOutput(CurrencyUnits.zero, scriptPubKey),
Policy.standardFlags)
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(txSigComponent, HashType.sigHashAllAnyoneCanPay)
//hash is from bitcoin core
hashedTxForSig.hex must be("57f5a54d548db73fa8ef7a43d011120f9935fe792f0a0630d28ee70b4c72a7e8")
}
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

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.number
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
/**
* Created by chris on 6/15/16.
@ -8,43 +9,43 @@ import org.scalatest.{ FlatSpec, MustMatchers }
class Int32Test extends FlatSpec with MustMatchers {
"Int32" must "create the number zero" in {
val int32 = Int32(Seq(0.toByte))
val int32 = Int32(scodec.bits.ByteVector.low(1))
int32.toInt must be(0)
}
it must "represent the number -1" in {
val int32 = Int32(Seq(0xff.toByte))
val int32 = Int32(scodec.bits.ByteVector(0xff.toByte))
int32.toInt must be(-1)
}
it must "represent the number -1 with 4 bytes" in {
val int32 = Int32(Seq(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val int32 = Int32(scodec.bits.ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
int32.toInt must be(-1)
}
it must "create the max number for a single byte" in {
val int32 = Int32(Seq(0x7f.toByte))
val int32 = Int32(scodec.bits.ByteVector(0x7f.toByte))
int32.toInt must be(127)
}
it must "create the min number for a single byte" in {
val int32 = Int32(Seq(0x80.toByte))
val int32 = Int32(scodec.bits.ByteVector(0x80.toByte))
int32.toInt must be(-128)
}
it must "create the max number for an Int32" in {
val int32 = Int32(Seq(0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val int32 = Int32(scodec.bits.ByteVector(0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
int32.toInt must be(2147483647)
}
it must "create the minimum number for an Int32" in {
val int32 = Int32(Seq(0x80.toByte, 0.toByte, 0.toByte, 0.toByte))
val int32 = Int32(scodec.bits.ByteVector(0x80.toByte, 0.toByte, 0.toByte, 0.toByte))
int32.toInt must be(-2147483648)
}
it must "throw an exception if we try and create an Int32 with more than 4 bytes" in {
intercept[IllegalArgumentException] {
Int32(Seq(0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
Int32(ByteVector(0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
}
}

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.number
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
/**
* Created by chris on 6/15/16.
@ -8,57 +9,57 @@ import org.scalatest.{ FlatSpec, MustMatchers }
class Int64Test extends FlatSpec with MustMatchers {
"Int64" must "represent the nubmer zero" in {
val int64 = Int64(Seq(0.toByte))
val int64 = Int64(scodec.bits.ByteVector.low(1))
int64.toLong must be(0)
}
it must "represent the number 1" in {
val int64 = Int64(Seq(1.toByte))
val int64 = Int64(ByteVector(1.toByte))
int64.toLong must be(1)
}
it must "represent the number -1 with 1 byte" in {
val int64 = Int64(Seq(0xff.toByte))
val int64 = Int64(scodec.bits.ByteVector(0xff.toByte))
int64.toLong must be(-1)
}
it must "represent the number -1 with 8 bytes" in {
val int64 = Int64(Seq(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte,
val int64 = Int64(scodec.bits.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(Seq(0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val int64 = Int64(scodec.bits.ByteVector(0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
int64.toLong must be(2147483647)
}
it must "represent the Int32 min value" in {
val int64 = Int64(Seq(0x80.toByte, 0.toByte, 0.toByte, 0.toByte))
val int64 = Int64(scodec.bits.ByteVector(0x80.toByte, 0.toByte, 0.toByte, 0.toByte))
int64.toLong must be(-2147483648L)
}
it must "represent the Int32 max value + 1" in {
val int64 = Int64(Seq(0x0.toByte, 0x80.toByte, 0.toByte, 0.toByte, 0.toByte))
val int64 = Int64(scodec.bits.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(Seq(0xff.toByte, 0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val int64 = Int64(scodec.bits.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(Seq(0x80.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
val int64 = Int64(scodec.bits.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(Seq(0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte,
val int64 = Int64(scodec.bits.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(Seq(0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
Int64(ByteVector(0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
}
}

View file

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

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.number
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
/**
* Created by chris on 6/15/16.
@ -8,7 +9,7 @@ import org.scalatest.{ FlatSpec, MustMatchers }
class UInt64Test extends FlatSpec with MustMatchers {
"UInt64" must "hold the number 0" in {
val uInt64 = UInt64(Seq(0.toByte))
val uInt64 = UInt64(scodec.bits.ByteVector.low(1))
uInt64.hex must be("0000000000000000")
uInt64.toBigInt must be(0)
}
@ -21,17 +22,17 @@ 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(Seq(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
val uInt64 = UInt64(scodec.bits.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(Seq(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(Seq(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte,
val uInt64 = UInt64(scodec.bits.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")
@ -39,7 +40,7 @@ class UInt64Test extends FlatSpec with MustMatchers {
it must "throw an exception if we try and create a number larger than 8 bytes" in {
intercept[IllegalArgumentException] {
UInt64(Seq(1.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
UInt64(ByteVector(1.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
}
}

View file

@ -4,6 +4,7 @@ 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 scodec.bits.ByteVector
/**
* Created by chris on 7/26/15.
@ -30,21 +31,21 @@ class CompactSizeUIntTest extends FlatSpec with MustMatchers {
CompactSizeUInt.calculateCompactSizeUInt("00") must be(CompactSizeUInt(UInt64.one, 1))
//for a string that is 256 bytes long
val byteSeq256Size = for (_ <- 0 until 256) yield 0.toByte
val byteSeq256Size = ByteVector(Array.fill(256)(0.toByte))
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 = for (_ <- 0 until 515) yield 0.toByte
val byteSeq515Size = ByteVector(Array.fill(515)(0.toByte))
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 = for (_ <- 0 until 500000) yield 0.toByte
val byteSeq500000Size = ByteVector(Array.fill(500000)(0.toByte))
val compactSizeUInt = CompactSizeUInt.calculateCompactSizeUInt(byteSeq500000Size)
compactSizeUInt must be(CompactSizeUInt(UInt64(500000), 5))
compactSizeUInt.hex must be("fe20a10700")
@ -101,7 +102,7 @@ class CompactSizeUIntTest extends FlatSpec with MustMatchers {
it must "intercept a failed requirement when the byte array size is zero" in {
intercept[IllegalArgumentException] {
val emptyBytes: Seq[Byte] = Seq()
val emptyBytes: scodec.bits.ByteVector = ByteVector.empty
CompactSizeUInt.parseCompactSizeUInt(emptyBytes)
}
}

View file

@ -1,14 +1,28 @@
package org.bitcoins.core.protocol.blockchain
import java.io.File
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.script.RawScriptSignatureParser
import org.bitcoins.core.util.BitcoinSLogger
import org.scalatest.{ FlatSpec, MustMatchers }
import org.slf4j.LoggerFactory
import scala.io.Source
/**
* 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
val t1 = System.currentTimeMillis()
val time = t1 - t0
logger.info("Elapsed time: " + (time) + "ms")
time
}
"Block" must "deserialize and serialize a block with two txs" in {
val hex = "b0aa0dced271237b5badb4365c33bc42b8fdb05c3defa03e75dcae425f42ddd210d69b8695e0f3cdf1eb9f56d0daa3c1e384204faa20792217d3103217773f4177b6b0f067079ac1ee733798f3bef9a0" +
@ -17,4 +31,19 @@ class BlockTest extends FlatSpec with MustMatchers {
val block = Block(hex)
block.hex must be(hex)
}
it must "parse a large block 00000000000000000008513c860373da0484f065983aeb063ebf81c172e81d48" in {
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 lines = Source.fromURL(getClass.getResource(fileName)).mkString
val time = timeBlockParsing(Block.fromHex(lines))
assert(time <= 15000)
}
}

View file

@ -246,7 +246,7 @@ class MerkleBlockTests extends FlatSpec with MustMatchers {
partialMerkleTree must be(merkleBlock.partialMerkleTree)
merkleBlock.partialMerkleTree.extractMatches must be(txIds)
partialMerkleTree.extractMatches must be(txIds)
partialMerkleTree.bits must be(List(true, true, true, true, true, true, true, false))
partialMerkleTree.bits.toIndexedSeq must be(List(true, true, true, true, true, true, true, false))
}
it must "create a merkle block from a sequence of txids and a block" in {

View file

@ -5,6 +5,7 @@ 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 scodec.bits.BitVector
/**
* Created by chris on 8/9/16.
@ -54,8 +55,8 @@ class PartialMerkleTreeTests extends FlatSpec with MustMatchers {
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) must be(Seq(true, true, false, true, false, true, false, true))
partialMerkleTree.bits.slice(8, partialMerkleTree.bits.size) must be(Seq(true, true, true, true, false, false, false, false))
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"),
@ -134,7 +135,7 @@ 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 partialMerkleTree = PartialMerkleTree(txMatches)
partialMerkleTree.bits must be(Seq(false, false, false, false, false, false, false, false))
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)
@ -145,7 +146,7 @@ class PartialMerkleTreeTests extends FlatSpec with MustMatchers {
(false, DoubleSha256Digest("01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")),
(true, DoubleSha256Digest("076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9")))
val partialMerkleTree = PartialMerkleTree(txMatches)
partialMerkleTree.bits must be(Seq(true, false, true, false, false, false, false, false))
partialMerkleTree.bits.toIndexedSeq must be(Seq(true, false, true, false, false, false, false, false))
partialMerkleTree.tree must be(Node(
DoubleSha256Digest("b130d701e65ac8c65f30dc4b20aabf349036b7c87f11f012f4f3f53f666791e6"),
Leaf(DoubleSha256Digest("01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")),
@ -157,7 +158,7 @@ class PartialMerkleTreeTests extends FlatSpec with MustMatchers {
val matches = List((true, DoubleSha256Digest("caa02f1194fb44dea407a7cf713ddcf30e69f49c297f9275f9236fec42d945b2")))
val partialMerkleTree = PartialMerkleTree(matches)
partialMerkleTree.tree must be(Leaf(DoubleSha256Digest("caa02f1194fb44dea407a7cf713ddcf30e69f49c297f9275f9236fec42d945b2")))
partialMerkleTree.bits must be(Seq(true, false, false, false, false, false, false, false))
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 {
@ -183,9 +184,9 @@ class PartialMerkleTreeTests extends FlatSpec with MustMatchers {
DoubleSha256Digest("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"),
DoubleSha256Digest("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"))
val numTransactions = UInt32(20)
val bits = List(true, true, true, true, true, true, true, false, true, true, false, true,
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)
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)
}

View file

@ -1,9 +1,10 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.crypto.ECDigitalSignature
import org.bitcoins.core.script.crypto.{ SIGHASH_ALL, HashType }
import org.bitcoins.core.script.crypto.{ HashType, SIGHASH_ALL }
import org.bitcoins.core.util.TestUtil
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
/**
* Created by chris on 4/1/16.
@ -15,7 +16,7 @@ class P2PKHScriptSignatureTest extends FlatSpec with MustMatchers {
case s: P2PKHScriptSignature => s
case _ => throw new RuntimeException("Must be p2pkh scriptSig")
}
HashType.fromBytes(Seq(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 {

View file

@ -13,7 +13,7 @@ class ScriptSignatureFactoryTest extends FlatSpec with MustMatchers {
"ScriptSignatureFactory" must "give the exact same result whether parsing bytes or parsing hex" in {
val signatureHex = "30450221008949f0cb400094ad2b5eb399d59d01c14d73d8fe6e96df1a7150deb388ab8935022079656090d7" +
"f6bac4c9a94e0aad311a4268e082a725f8aeae0573fb12ff866a5f01"
val signatureBytes: Seq[Byte] = BitcoinSUtil.decodeHex(signatureHex)
val signatureBytes: scodec.bits.ByteVector = BitcoinSUtil.decodeHex(signatureHex)
val scriptSigFromHex = ScriptSignature(signatureHex)
val scriptSigFromBytes = ScriptSignature(signatureBytes)

View file

@ -10,6 +10,7 @@ import org.bitcoins.core.script.crypto.{ HashType, SIGHASH_ALL, SIGHASH_SINGLE }
import org.bitcoins.core.serializers.script.RawScriptSignatureParser
import org.bitcoins.core.util.{ BitcoinSLogger, BitcoinSUtil, TestUtil }
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
import spray.json._
import scala.io.Source
@ -26,7 +27,7 @@ class ScriptSignatureTest extends FlatSpec with MustMatchers {
}
it must "derive the signature hash type from the signature" in {
HashType(Seq(TestUtil.scriptSig.signatures.head.bytes.last)) must be(HashType.sigHashAll)
HashType(ByteVector.fromByte(TestUtil.scriptSig.signatures.head.bytes.last)) must be(HashType.sigHashAll)
}
it must "find the digital signature for a p2sh script signature" in {
@ -52,7 +53,7 @@ class ScriptSignatureTest extends FlatSpec with MustMatchers {
ECDigitalSignature("30440220257b57cb09386d82c4328461f8fe200c2f381d6b635e2a2f4ea40c8d945e9ec102201ec67d58d51a309af4d8896e9147a42944e9f9833a456f733ea5fa6954ed2fed01")))
}
it must "find the hash type for a p2sh script signature" in {
HashType(Seq(TestUtil.p2shInputScript2Of2.signatures.head.bytes.last)) must be(HashType.sigHashAll)
HashType(ByteVector.fromByte(TestUtil.p2shInputScript2Of2.signatures.head.bytes.last)) must be(HashType.sigHashAll)
}
it must "find the digital signature and hash type for a SIGHASH_SINGLE" in {
@ -69,7 +70,7 @@ class ScriptSignatureTest extends FlatSpec with MustMatchers {
it must "have an empty script signature" in {
EmptyScriptSignature.hex must be("00")
EmptyScriptSignature.bytes must be(Seq(0.toByte))
EmptyScriptSignature.bytes must be(scodec.bits.ByteVector.low(1))
EmptyScriptSignature.asm must be(Nil)
EmptyScriptSignature.signatures must be(Nil)
}

View file

@ -120,13 +120,6 @@ class TransactionTest extends FlatSpec with MustMatchers {
tx = testCase.spendingTx
(input, inputIndex) = findInput(tx, outPoint).getOrElse((EmptyTransactionInput, 0))
} yield {
logger.debug("Raw test case: " + testCase.raw)
logger.debug("Parsed ScriptSig: " + tx.inputs(inputIndex).scriptSignature)
logger.debug("Sequence number: " + tx.inputs(inputIndex).sequence)
logger.debug("ScriptPubKey: " + scriptPubKey)
logger.debug("OutPoint: " + outPoint)
logger.debug("Flags after parsing: " + testCase.flags)
logger.debug("Satoshis: " + amountOpt)
require(
outPoint.txId == input.previousOutput.txId,
"OutPoint txId not the same as input prevout txid\noutPoint.txId: " + outPoint.txId + "\n" +
@ -203,12 +196,6 @@ class TransactionTest extends FlatSpec with MustMatchers {
tx = testCase.spendingTx
(input, inputIndex) = findInput(tx, outPoint).getOrElse((EmptyTransactionInput, 0))
} yield {
logger.debug("Raw test case: " + testCase.raw)
logger.debug("ScriptPubKey: " + scriptPubKey)
logger.debug("OutPoint: " + outPoint)
logger.debug("Flags after parsing: " + testCase.flags)
logger.debug("spending tx: " + testCase.spendingTx)
logger.debug("" + testCase.scriptPubKeys)
val isValidTx = ScriptInterpreter.checkTransaction(tx)
if (isValidTx) {
val txSigComponent = amountOpt match {

View file

@ -7,6 +7,7 @@ import org.bitcoins.core.script.flag.{ ScriptFlag, ScriptVerifyMinimalData }
import org.bitcoins.core.script.result.{ ScriptErrorBadOpCode, ScriptErrorMinimalData }
import org.bitcoins.core.util.{ ScriptProgramTestUtil, TestUtil }
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
/**
* Created by chris on 1/24/16.
@ -15,7 +16,7 @@ class ConstantInterpreterTest extends FlatSpec with MustMatchers {
val CI = ConstantInterpreter
"ConstantInterpreter" must "interpret OP_PUSHDATA1 correctly" in {
val byteConstantSize = 76
val byteConstant = for { x <- 0 until byteConstantSize } yield 0x0.toByte
val byteConstant = ByteVector(Array.fill(byteConstantSize)(0.toByte))
val scriptConstant = ScriptConstant(byteConstant)
val stack = List()
val script = List(OP_PUSHDATA1, ScriptNumber(byteConstantSize), scriptConstant, OP_7, OP_EQUAL)
@ -27,7 +28,7 @@ class ConstantInterpreterTest extends FlatSpec with MustMatchers {
it must "interpret OP_PUSHDATA2 correctly" in {
val byteConstantSize = 256
val byteConstant = for { x <- 0 until byteConstantSize } yield 0x0.toByte
val byteConstant = ByteVector(Array.fill(byteConstantSize)(0.toByte))
val scriptConstant = ScriptConstant(byteConstant)
val stack = List()
val script = List(OP_PUSHDATA2, ScriptNumber(256), scriptConstant, OP_8, OP_EQUAL)
@ -39,7 +40,7 @@ class ConstantInterpreterTest extends FlatSpec with MustMatchers {
it must "interpret OP_PUSHDATA4 correctly" in {
val byteConstantSize = 65536
val byteConstant = for { x <- 0 until byteConstantSize } yield 0x0.toByte
val byteConstant = ByteVector(Array.fill(byteConstantSize)(0.toByte))
val scriptConstant = ScriptConstant(byteConstant)
val stack = List()
val script = List(OP_PUSHDATA4, ScriptNumber(byteConstantSize), scriptConstant, OP_9, OP_EQUAL)

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.script.constant
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
import scala.util.Try
@ -124,7 +125,7 @@ class ConstantsTest extends FlatSpec with MustMatchers {
}
it must "create the number zero from an empty sequence" in {
val number: Try[ScriptNumber] = ScriptNumber(Seq(), true)
val number: Try[ScriptNumber] = ScriptNumber(ByteVector.empty, true)
number.isSuccess must be(true)
number.get must be(ScriptNumber.zero)
}

View file

@ -31,7 +31,7 @@ class HashTypeTest extends FlatSpec with MustMatchers {
}
it must "default to SIGHASH_ALL if the given string/byte is not known" in {
HashType(Seq(0x124.toByte)) must be(SIGHASH_ALL(Int32(36)))
HashType(scodec.bits.ByteVector(0x124.toByte)) must be(SIGHASH_ALL(Int32(36)))
}
it must "find hashType for number 1190874345" in {

View file

@ -36,17 +36,9 @@ class ScriptInterpreterTest extends FlatSpec with MustMatchers {
(creditingTx, outputIndex) = TransactionTestUtil.buildCreditingTransaction(testCase.scriptPubKey, testCase.witness.map(_._2))
(tx, inputIndex) = TransactionTestUtil.buildSpendingTransaction(creditingTx, testCase.scriptSig, outputIndex, testCase.witness)
} yield {
logger.info("Raw test case: " + testCase.raw)
logger.info("Parsed ScriptSig: " + testCase.scriptSig)
logger.info("Parsed ScriptPubKey: " + testCase.scriptPubKey)
logger.info("Parsed tx: " + tx.hex)
logger.info("Flags: " + testCase.flags)
logger.info("Comments: " + testCase.comments)
val scriptPubKey = ScriptPubKey.fromAsm(testCase.scriptPubKey.asm)
val flags = ScriptFlagFactory.fromList(testCase.flags)
val witness = testCase.witness
logger.info("Flags after parsing: " + flags)
logger.info("Witness after parsing: " + witness)
val txSigComponent = witness match {
case Some((w, amount)) => scriptPubKey match {
case p2sh: P2SHScriptPubKey =>

View file

@ -0,0 +1,32 @@
package org.bitcoins.core.serializers
import org.bitcoins.core.number.UInt64
import org.bitcoins.core.protocol.{ CompactSizeUInt, NetworkElement }
import org.bitcoins.core.protocol.transaction.{ EmptyTransactionOutput, TransactionInput, TransactionOutput }
import org.bitcoins.core.serializers.transaction.{ RawTransactionInputParser, RawTransactionOutputParser }
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
class RawSerializerHelperTest extends FlatSpec with MustMatchers {
"RawBitcoinSerializerHelper" must "serialize an empty vector" in {
val bytes = ByteVector(0.toByte)
val construct: ByteVector => TransactionInput = RawTransactionInputParser.read(_)
val (inputs, _) = RawSerializerHelper.parseCmpctSizeUIntSeq(bytes, construct)
val serialize = RawTransactionInputParser.write(_)
val write = RawSerializerHelper.writeCmpctSizeUInt(inputs, serialize)
write must be(bytes)
}
it must "serialize one element in a vector correctly" in {
val bytes = CompactSizeUInt(UInt64.one).bytes ++ EmptyTransactionOutput.bytes
val constructor: ByteVector => TransactionOutput = RawTransactionOutputParser.read(_)
val (outputs, _) = RawSerializerHelper.parseCmpctSizeUIntSeq(bytes, constructor)
val serialize = RawTransactionOutputParser.write(_)
val write = RawSerializerHelper.writeCmpctSizeUInt(outputs, serialize)
write must be(bytes)
}
}

View file

@ -1,16 +1,17 @@
package org.bitcoins.core.serializers
import org.bitcoins.core.gen.TransactionGenerators
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.protocol.transaction.{ Transaction, TransactionInput, TransactionOutput }
import org.scalacheck.{ Prop, Properties }
import scodec.bits.ByteVector
class RawSerializerHelperSpec extends Properties("RawSerializerHelperSpec") {
property("serialization symmetry of txs") = {
Prop.forAll(TransactionGenerators.smallTransactions) { txs: Seq[Transaction] =>
val serialized = RawSerializerHelper.writeCmpctSizeUInt[Transaction](txs, { tx: Transaction => tx.bytes })
val (deserialized, remaining) = RawSerializerHelper.parseCmpctSizeUIntSeq(serialized, Transaction(_: Seq[Byte]))
deserialized == txs && remaining == Nil
Prop.forAll(TransactionGenerators.smallOutputs) { txs: Seq[TransactionOutput] =>
val serialized = RawSerializerHelper.writeCmpctSizeUInt(txs, { tx: TransactionOutput => tx.bytes })
val (deserialized, remaining) = RawSerializerHelper.parseCmpctSizeUIntSeq(serialized, TransactionOutput(_: scodec.bits.ByteVector))
deserialized == txs && remaining == ByteVector.empty
}
}

View file

@ -20,7 +20,7 @@ class RawBlockHeaderSerializerTest extends FlatSpec with MustMatchers {
val nBits = "FFFF001D".toLowerCase
val nonce = "1DAC2B7C".toLowerCase
val hash = "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000"
val encode = BitcoinSUtil.encodeHex(_: Seq[Byte])
val encode = BitcoinSUtil.encodeHex(_: scodec.bits.ByteVector)
val hex = version + prevBlockHash + merkleRoot + timeStamp + nBits + nonce
"BlockHeader" must "parse genesis block header" in {
val blockHeader = RawBlockHeaderSerializer.read(hex)

View file

@ -31,7 +31,7 @@ class RawBlockSerializerTest extends FlatSpec with MustMatchers {
val txSeq = List(tx1)
val uInt = CompactSizeUInt(UInt64.one, 1)
val hex = header + uInt.hex + rawTx1
val encode = BitcoinSUtil.encodeHex(_: Seq[Byte])
val encode = BitcoinSUtil.encodeHex(_: scodec.bits.ByteVector)
"RawBlockSerializer" must "parse genesis block" in {
val block = RawBlockSerializer.read(hex)
block.txCount.num must be(UInt64(txSeq.size))
@ -115,4 +115,4 @@ class RawBlockSerializerTest extends FlatSpec with MustMatchers {
block.txCount.num must be(UInt64(txSeq.size))
block.hex must be(hex)
}
}
}

View file

@ -5,6 +5,7 @@ import org.bitcoins.core.number.{ Int32, UInt32 }
import org.bitcoins.core.protocol.blockchain.{ BlockHeader, MerkleBlock, PartialMerkleTree }
import org.bitcoins.core.util.{ BitcoinSUtil, Leaf, Node }
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.BitVector
/**
* Created by chris on 8/22/16.
@ -22,7 +23,7 @@ class RawMerkleBlockSerializerTest extends FlatSpec with MustMatchers {
Leaf(DoubleSha256Digest(
"442abdc8e74ad35ebd9571f88fda91ff511dcda8d241a5aed52cea1e00d69e03")),
UInt32(1),
List(false, false, false, false, false, false, false, false),
BitVector.bits(Vector(false, false, false, false, false, false, false, false)),
List(DoubleSha256Digest("442abdc8e74ad35ebd9571f88fda91ff511dcda8d241a5aed52cea1e00d69e03")))), List())
val hex = "bcfaed026cf34aac6e3de2bf4b429d114ed4572a7ce4b1c44f2091ae6825ee9774dbae2f4487def8ba376b38c1e4e5910d3c9efd27e740cb9be8d452598cbf2e243fad8a6c2858af42dfee60e037a5640100000001442abdc8e74ad35ebd9571f88fda91ff511dcda8d241a5aed52cea1e00d69e030100"
@ -51,7 +52,10 @@ class RawMerkleBlockSerializerTest extends FlatSpec with MustMatchers {
Leaf(DoubleSha256Digest("77352045b2995c9e0dfff9089e5563cd13914eb4b0723cdd54675c5c3f1c4f6a")),
Leaf(DoubleSha256Digest("7ae10c30932c07e4ed25abab233565f9ab279eabbcd60e1bc028c6cdc400361b")))),
Leaf(DoubleSha256Digest("8ca2e6b66c55fbb63cb7c9b5ccd19be508034eedcd8511d216b9fe93aafc2ceb"))),
UInt32(6), List(true, true, true, false, true, true, false, true, false, false, false, false, false, false, false, false),
UInt32(6),
BitVector.bits(List(true, true, true, false, true, true,
false, true, false, false, false,
false, false, false, false, false)),
List(
DoubleSha256Digest("e4aeaf729035a7fb939e12c4f6a2072a9b2e7da784207ce7852d398593210a45"),
DoubleSha256Digest("010506d2103d0feb477224926eedaf3d7478fe3d93b54bd24e5eb2c0adc309b3"),
@ -85,7 +89,13 @@ class RawMerkleBlockSerializerTest extends FlatSpec with MustMatchers {
it must "serialize and deserialize a merkle block with two bytes worth of bit flags" in {
//https://github.com/bitcoinj/bitcoinj/blob/840df06b79beac1b984e6e247e90fcdedc4ad6e0/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java#L129
val hex = "0100000006e533fd1ada86391f3f6c343204b0d278d4aaec1c0b20aa27ba0300000000006abbb3eb3d733a9fe18967fd7d4c117e4ccbbac5bec4d910d900b3ae0793e77f54241b4d4c86041b4089cc9b0c000000084c30b63cfcdc2d35e3329421b9805ef0c6565d35381ca857762ea0b3a5a128bbca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefbbb15ac1d57d0182aaee61c74743a9c4f785895e563909bafec45c9a2b0ff3181d77706be8b1dcc91112eada86d424e2d0a8907c3488b6e44fda5a74a25cbc7d6bb4fa04245f4ac8a1a571d5537eac24adca1454d65eda446055479af6c6d4dd3c9ab658448c10b6921b7a4ce3021eb22ed6bb6a7fde1e5bcc4b1db6615c6abc5ca042127bfaf9f44ebce29cb29c6df9d05b47f35b2edff4f0064b578ab741fa78276222651209fe1a2c4c0fa1c58510aec8b090dd1eb1f82f9d261b8273b525b02ff1a"
val hex = "0100000006e533fd1ada86391f3f6c343204b0d278d4aaec1c0b20aa27ba0300000000006abbb3eb3d733a9fe18967fd7d4c117" +
"e4ccbbac5bec4d910d900b3ae0793e77f54241b4d4c86041b4089cc9b0c000000084c30b63cfcdc2d35e3329421b9805ef0c6565d35381c" +
"a857762ea0b3a5a128bbca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefbbb15ac1d57d0182aaee61c74743" +
"a9c4f785895e563909bafec45c9a2b0ff3181d77706be8b1dcc91112eada86d424e2d0a8907c3488b6e44fda5a74a25cbc7d6bb4fa04245" +
"f4ac8a1a571d5537eac24adca1454d65eda446055479af6c6d4dd3c9ab658448c10b6921b7a4ce3021eb22ed6bb6a7fde1e5bcc4b1db661" +
"5c6abc5ca042127bfaf9f44ebce29cb29c6df9d05b47f35b2edff4f0064b578ab741fa78276222651209fe1a2c4c0fa1c58510aec8b090d" +
"d1eb1f82f9d261b8273b525b02ff1a"
val merkleBlock = MerkleBlock(hex)
merkleBlock.hex must be(hex)
}

View file

@ -13,7 +13,7 @@ import org.scalatest.{ FlatSpec, MustMatchers }
* Created by chris on 1/12/16.
*/
class RawScriptPubKeyParserTest extends FlatSpec with MustMatchers {
val encode = BitcoinSUtil.encodeHex(_: Seq[Byte])
val encode = BitcoinSUtil.encodeHex(_: scodec.bits.ByteVector)
"RawScriptPubKeyParser" must "read then write the scriptPubKey and get the original scriptPubKey" in {
val scriptPubKey: ScriptPubKey = RawScriptPubKeyParser.read(TestUtil.rawScriptPubKey)
encode(RawScriptPubKeyParser.write(scriptPubKey)) must be(TestUtil.rawScriptPubKey)

View file

@ -14,7 +14,7 @@ class RawScriptSignatureParserTest extends FlatSpec with MustMatchers {
//from bitcoin developer examples
//https://bitcoin.org/en/developer-reference#raw-transaction-format
val rawScriptSig = "4a494830450221008949f0cb400094ad2b5eb399d59d01c14d73d8fe6e96df1a7150deb388ab8935022079656090d7f6bac4c9a94e0aad311a4268e082a725f8aeae0573fb12ff866a5f01"
val encode = BitcoinSUtil.encodeHex(_: Seq[Byte])
val encode = BitcoinSUtil.encodeHex(_: scodec.bits.ByteVector)
"RawScriptSignatureParser" must "write a raw script sig" in {
val scriptSig = RawScriptSignatureParser.read(rawScriptSig)
encode(RawScriptSignatureParser.write(scriptSig)) must be(rawScriptSig)

View file

@ -9,6 +9,7 @@ import org.bitcoins.core.script.reserved.OP_NOP
import org.bitcoins.core.script.stack.OP_PICK
import org.bitcoins.core.util.{ BitcoinSUtil, TestUtil }
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
/**
* Created by chris on 1/7/16.
@ -16,7 +17,7 @@ import org.scalatest.{ FlatSpec, MustMatchers }
class ScriptParserTest extends FlatSpec with MustMatchers {
"ScriptParser" must "parse 0x00 to a OP_0" in {
ScriptParser.fromBytes(List(0.toByte)) must be(List(OP_0))
ScriptParser.fromBytes(ByteVector(List(0.toByte))) must be(List(OP_0))
}
it must "parse the number 0 as an OP_0" in {
@ -47,7 +48,7 @@ class ScriptParserTest extends FlatSpec with MustMatchers {
}
it must "parse a p2pkh output script from a byte array to script tokens" in {
val bytes: Seq[Byte] = BitcoinSUtil.decodeHex(TestUtil.p2pkhOutputScript).tail
val bytes: scodec.bits.ByteVector = BitcoinSUtil.decodeHex(TestUtil.p2pkhOutputScript).tail
ScriptParser.fromBytes(bytes) must be(TestUtil.p2pkhOutputScriptAsm)
}

View file

@ -9,7 +9,7 @@ import org.scalatest.{ FlatSpec, MustMatchers }
* Created by chris on 1/14/16.
*/
class RawBaseTransactionParserTest extends FlatSpec with MustMatchers {
val encode = BitcoinSUtil.encodeHex(_: Seq[Byte])
val encode = BitcoinSUtil.encodeHex(_: scodec.bits.ByteVector)
"RawBaseTransactionParser" must "parse a raw transaction" in {
val tx: Transaction = RawBaseTransactionParser.read(TestUtil.rawTransaction)
tx.version must be(Int32.one)

View file

@ -12,7 +12,7 @@ class RawTransactionInputParserTest extends FlatSpec with MustMatchers {
private val logger = BitcoinSLogger.logger
//txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6
val rawTxInput = "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000" + "6f0047304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f00125512102b022902a0fdd71e831c37e4136c2754a59887be0618fb75336d7ab67e2982ff551ae" + "ffffffff"
val encode = BitcoinSUtil.encodeHex(_: Seq[Byte])
val encode = BitcoinSUtil.encodeHex(_: scodec.bits.ByteVector)
"RawTransactionInputParser" must "parse a raw serialized transaction input" in {
val txInput = RawTransactionInputParser.read(rawTxInput)
txInput.previousOutput.vout must be(UInt32.zero)
@ -55,7 +55,6 @@ class RawTransactionInputParserTest extends FlatSpec with MustMatchers {
txInput.previousOutput.txId.hex must be(BitcoinSUtil.flipEndianness("e99eb3e6551844d0db252ef242c043796b3b0ccfb126c0ae09f9dd0230e2f10d"))
txInput.previousOutput.vout must be(UInt32.zero)
txInput.scriptSignature.hex must be("fdfd00004730440220028c02f14654a0cc12c7e3229adb09d5d35bebb6ba1057e39adb1b2706607b0d0220564fab12c6da3d5acef332406027a7ff1cbba980175ffd880e1ba1bf40598f6b014830450221009362f8d67b60773745e983d07ba10efbe566127e244b724385b2ca2e47292dda022033def393954c320653843555ddbe7679b35cc1cacfe1dad923977de8cd6cc6d7014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53ae")
txInput.scriptSignature.compactSizeUInt.num must be(UInt64(txInput.scriptSignature.asm.flatMap(_.bytes).size))
txInput.sequence must be(UInt32(4294967295L))
encode(RawTransactionInputParser.write(txInput)) must be(rawTxInput)

View file

@ -11,7 +11,7 @@ class RawTransactionOutPointParserTest extends FlatSpec with MustMatchers {
//txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6
val rawOutPoint = "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000"
val rawOutPointLargeVout = "df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd0400134000000"
val encode = BitcoinSUtil.encodeHex(_: Seq[Byte])
val encode = BitcoinSUtil.encodeHex(_: scodec.bits.ByteVector)
"RawTransactionOutPointParser" must "read a raw outpoint into a native scala TransactionOutPoint" in {
val outPoint = RawTransactionOutPointParser.read(rawOutPoint)
outPoint.txId.hex must be(BitcoinSUtil.flipEndianness("e17d316006850c1764301befcf82c8c84cd1794f3f0d0382b296df2edab0d685"))

View file

@ -18,7 +18,7 @@ class RawTransactionOutputParserTest extends FlatSpec with MustMatchers {
//txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6
val rawTxOutput = "204e00000000000017a914eda8ae08b5c9f973f49543e90a7c292367b3337c87"
val encode = BitcoinSUtil.encodeHex(_: Seq[Byte])
val encode = BitcoinSUtil.encodeHex(_: scodec.bits.ByteVector)
"RawTransactionOutputTest" must "read a serialized tx output" in {
val txOutput: TransactionOutput = RawTransactionOutputParser.read(rawTxOutput)

View file

@ -34,7 +34,7 @@ class Base58Test extends FlatSpec with MustMatchers {
it must "decode and return same result as bitcoinj" in {
val address = "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"
val bitcoinj = org.bitcoinj.core.Base58.decode(address)
Base58.decode(address) must be(bitcoinj)
Base58.decode(address).toArray must be(bitcoinj)
}
it must "encode tests in base58_encode_decode.json" in {

View file

@ -19,12 +19,6 @@ class BitcoinSUtilSpec extends Properties("BitcoinSUtilSpec") {
property("Convert a byte to a bit vector, convert it back to the original byte") =
Prop.forAll { byte: Byte =>
BitcoinSUtil.bitVectorToByte(BitcoinSUtil.byteToBitVector(byte)) == byte
}
property("Convert a sequence of bit vectors to a sequence of bytes") =
Prop.forAll(NumberGenerator.bitVectors) { bitVectors: Seq[Seq[Boolean]] =>
BitcoinSUtil.bytesToBitVectors(BitcoinSUtil.bitVectorsToBytes(bitVectors)) == bitVectors
BitcoinSUtil.bitVectorToBytes(BitcoinSUtil.byteToBitVector(byte)).toByte() == byte
}
}

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.util
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.BitVector
/**
* Created by chris on 4/1/16.
@ -23,33 +24,33 @@ class BitcoinSUtilTest extends FlatSpec with MustMatchers {
it must "convert a byte to a bit vector" in {
val byte = 0.toByte
BitcoinSUtil.byteToBitVector(byte) must be(Seq(false, false, false, false, false, false, false, false))
BitcoinSUtil.byteToBitVector(byte).toIndexedSeq must be(Seq(false, false, false, false, false, false, false, false))
val byte1 = 1.toByte
BitcoinSUtil.byteToBitVector(byte1) must be(Seq(false, false, false, false, false, false, false, true))
BitcoinSUtil.byteToBitVector(byte1).toIndexedSeq must be(Seq(false, false, false, false, false, false, false, true))
val byte2 = 2.toByte
BitcoinSUtil.byteToBitVector(byte2) must be(Seq(false, false, false, false, false, false, true, false))
BitcoinSUtil.byteToBitVector(byte2).toIndexedSeq must be(Seq(false, false, false, false, false, false, true, false))
val byte3 = 3.toByte
BitcoinSUtil.byteToBitVector(byte3) must be(Seq(false, false, false, false, false, false, true, true))
BitcoinSUtil.byteToBitVector(byte3).toIndexedSeq must be(Seq(false, false, false, false, false, false, true, true))
val maxByte = 0xff.toByte
BitcoinSUtil.byteToBitVector(maxByte) must be(Seq(true, true, true, true, true, true, true, true))
BitcoinSUtil.byteToBitVector(maxByte).toIndexedSeq must be(Seq(true, true, true, true, true, true, true, true))
}
it must "convert a bit vector to a byte" in {
val bitVector0 = Seq(false, false, false, false, false, false, false, false)
BitcoinSUtil.bitVectorToByte(bitVector0) must be(0.toByte)
val bitVector0 = BitVector.bits(Seq(false, false, false, false, false, false, false, false))
BitcoinSUtil.bitVectorToBytes(bitVector0).toByte() must be(0.toByte)
val bitVector1 = Seq(false, false, false, false, false, false, false, true)
BitcoinSUtil.bitVectorToByte(bitVector1) must be(1.toByte)
val bitVector1 = BitVector.bits(Seq(false, false, false, false, false, false, false, true))
BitcoinSUtil.bitVectorToBytes(bitVector1).toByte() must be(1.toByte)
val bitVector2 = Seq(false, false, false, false, false, false, true, false)
BitcoinSUtil.bitVectorToByte(bitVector2) must be(2.toByte)
val bitVector2 = BitVector.bits(Seq(false, false, false, false, false, false, true, false))
BitcoinSUtil.bitVectorToBytes(bitVector2).toByte() must be(2.toByte)
val bitVectorMax = Seq(true, true, true, true, true, true, true, true)
BitcoinSUtil.bitVectorToByte(bitVectorMax) must be(0xff.toByte)
val bitVectorMax = BitVector.bits(Seq(true, true, true, true, true, true, true, true))
BitcoinSUtil.bitVectorToBytes(bitVectorMax).toByte() must be(0xff.toByte)
}
}

View file

@ -1,17 +1,15 @@
package org.bitcoins.core.util
import org.bitcoin.NativeSecp256k1
import org.bitcoins.core.crypto.{ ECPrivateKey, ECPublicKey }
import org.bitcoins.core.protocol.script.{ SigVersionBase, SigVersionWitnessV0 }
import org.bitcoins.core.script.bitwise.{ OP_EQUALVERIFY, OP_OR }
import org.bitcoins.core.script.constant._
import org.bitcoins.core.script.crypto._
import org.bitcoins.core.script.flag.ScriptVerifyWitnessPubKeyType
import org.bitcoins.core.script.locktime.OP_CHECKLOCKTIMEVERIFY
import org.bitcoins.core.script.reserved.{ OP_NOP, OP_RESERVED }
import org.bitcoins.core.script.result.ScriptErrorWitnessPubKeyType
import org.bitcoins.core.script.stack.OP_DUP
import org.scalatest.{ FlatSpec, MustMatchers }
import scodec.bits.ByteVector
/**
* Created by chris on 3/2/16.
@ -26,10 +24,6 @@ class BitcoinScriptUtilTest extends FlatSpec with MustMatchers {
BitcoinScriptUtil.asmToHex(asm) must be(asm.flatMap(_.hex).mkString)
}
it must "give us the correct byte representation of an asm script" in {
BitcoinScriptUtil.asmToBytes(asm) must be(asm.flatMap(_.bytes))
}
it must "filter out all of the push operations in a scriptSig" in {
BitcoinScriptUtil.filterPushOps(Seq(OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4) ++
BytesToPushOntoStack.operations).isEmpty must be(true)
@ -118,43 +112,43 @@ class BitcoinScriptUtilTest extends FlatSpec with MustMatchers {
it must "determine that a OP_PUSHDATA1 operation is the minimal push op for a 76 byte script constant" in {
val byteConstantSize = 76
val byteConstant = for { x <- 0 to byteConstantSize } yield 0x0.toByte
val scriptConstant = ScriptConstant(byteConstant)
val byteConstant = Array.fill(byteConstantSize)(0.toByte)
val scriptConstant = ScriptConstant(ByteVector(byteConstant))
BitcoinScriptUtil.isMinimalPush(OP_PUSHDATA1, scriptConstant) must be(true)
}
it must "determine that a OP_PUSHDATA1 operation is NOT the minimal push op for a 75 byte script constant" in {
val byteConstantSize = 75
val byteConstant = for { x <- 0 until byteConstantSize } yield 0x0.toByte
val scriptConstant = ScriptConstant(byteConstant)
val byteConstant = Array.fill(byteConstantSize)(0.toByte)
val scriptConstant = ScriptConstant(ByteVector(byteConstant))
BitcoinScriptUtil.isMinimalPush(OP_PUSHDATA1, scriptConstant) must be(false)
}
it must "determine that a OP_PUSHDATA2 operation is NOT the minimal push op for a 255 byte script constant" in {
val byteConstantSize = 255
val byteConstant = for { x <- 0 until byteConstantSize } yield 0x0.toByte
val scriptConstant = ScriptConstant(byteConstant)
val byteConstant = Array.fill(byteConstantSize)(0.toByte)
val scriptConstant = ScriptConstant(ByteVector(byteConstant))
BitcoinScriptUtil.isMinimalPush(OP_PUSHDATA2, scriptConstant) must be(false)
}
it must "determine that a OP_PUSHDATA2 operation is the minimal push op for a 256 byte script constant" in {
val byteConstantSize = 256
val byteConstant = for { x <- 0 until byteConstantSize } yield 0x0.toByte
val scriptConstant = ScriptConstant(byteConstant)
val byteConstant = Array.fill(byteConstantSize)(0.toByte)
val scriptConstant = ScriptConstant(ByteVector(byteConstant))
BitcoinScriptUtil.isMinimalPush(OP_PUSHDATA2, scriptConstant) must be(true)
}
it must "determine that a OP_PUSHDATA4 operation is NOT the minimal push op for a 65535 byte script constant" in {
val byteConstantSize = 65535
val byteConstant = for { x <- 0 until byteConstantSize } yield 0x0.toByte
val scriptConstant = ScriptConstant(byteConstant)
val byteConstant = Array.fill(byteConstantSize)(0.toByte)
val scriptConstant = ScriptConstant(ByteVector(byteConstant))
BitcoinScriptUtil.isMinimalPush(OP_PUSHDATA4, scriptConstant) must be(false)
}
it must "determine that a OP_PUSHDATA4 operation is the minimal push op for a 65536 byte script constant" in {
val byteConstantSize = 65536
val byteConstant = for { x <- 0 until byteConstantSize } yield 0x0.toByte
val scriptConstant = ScriptConstant(byteConstant)
val byteConstant = Array.fill(byteConstantSize)(0.toByte)
val scriptConstant = ScriptConstant(ByteVector(byteConstant))
BitcoinScriptUtil.isMinimalPush(OP_PUSHDATA4, scriptConstant) must be(true)
}
@ -222,7 +216,7 @@ class BitcoinScriptUtilTest extends FlatSpec with MustMatchers {
it must "cast a script token to a boolean value" in {
BitcoinScriptUtil.castToBool(ScriptConstant("")) must be(false)
BitcoinScriptUtil.castToBool(ScriptConstant(Seq(0x80.toByte))) must be(false)
BitcoinScriptUtil.castToBool(ScriptConstant(scodec.bits.ByteVector(0x80.toByte))) must be(false)
BitcoinScriptUtil.castToBool(ScriptConstant("000000")) must be(false)
BitcoinScriptUtil.castToBool(ScriptConstant("00000080")) must be(false)

View file

@ -8,6 +8,7 @@ import org.bitcoins.core.protocol.{ CompactSizeUInt, NetworkElement }
import org.bitcoins.core.script.constant.{ ScriptConstant, ScriptToken }
import org.bitcoins.core.serializers.bloom.RawBloomFilterSerializer
import org.bitcoins.core.util.{ BitcoinSLogger, BitcoinSUtil, Factory }
import scodec.bits.{ BitVector, ByteVector }
import scala.annotation.tailrec
import scala.util.hashing.MurmurHash3
@ -24,7 +25,7 @@ sealed abstract class BloomFilter extends NetworkElement {
def filterSize: CompactSizeUInt
/** The bits that are set inside of the bloom filter */
def data: Seq[Byte]
def data: scodec.bits.ByteVector
/** The number of hash functions used in the bloom filter */
def hashFuncs: UInt32
@ -40,11 +41,11 @@ sealed abstract class BloomFilter extends NetworkElement {
def flags: BloomFlag
/** Inserts a sequence of bytes into the [[BloomFilter]] */
def insert(bytes: Seq[Byte]): BloomFilter = {
def insert(bytes: scodec.bits.ByteVector): BloomFilter = {
//these are the bit indexes that need to be set inside of data
val bitIndexes = (0 until hashFuncs.toInt).map(i => murmurHash(i, bytes))
@tailrec
def loop(remainingBitIndexes: Seq[Int], accum: Seq[Byte]): Seq[Byte] = {
def loop(remainingBitIndexes: Seq[Int], accum: scodec.bits.ByteVector): scodec.bits.ByteVector = {
if (remainingBitIndexes.isEmpty) accum
else {
val currentIndex = remainingBitIndexes.head
@ -56,7 +57,7 @@ sealed abstract class BloomFilter extends NetworkElement {
val byte = accum(byteIndex)
val setBitByte: Byte = (byte | bitIndex).toByte
//replace old byte with new byte with bit set
val newAccum: Seq[Byte] = accum.updated(byteIndex, setBitByte)
val newAccum: scodec.bits.ByteVector = accum.update(byteIndex, setBitByte)
loop(remainingBitIndexes.tail, newAccum)
}
}
@ -77,12 +78,13 @@ sealed abstract class BloomFilter extends NetworkElement {
def insert(outPoint: TransactionOutPoint): BloomFilter = insert(outPoint.bytes)
/** Checks if [[data]] contains the given sequence of bytes */
def contains(bytes: Seq[Byte]): Boolean = {
def contains(bytes: scodec.bits.ByteVector): Boolean = {
val bitIndexes = (0 until hashFuncs.toInt).map(i => murmurHash(i, bytes))
@tailrec
def loop(remainingBitIndexes: Seq[Int], accum: Seq[Boolean]): Boolean = {
if (remainingBitIndexes.isEmpty) !accum.exists(_ == false)
else {
def loop(remainingBitIndexes: Seq[Int], accum: scodec.bits.BitVector): Boolean = {
if (remainingBitIndexes.isEmpty) {
!accum.toIndexedSeq.exists(_ == false)
} else {
val currentIndex = remainingBitIndexes.head
val byteIndex = currentIndex >>> 3
val bitIndex = (1 << (7 & currentIndex)).toByte
@ -91,7 +93,7 @@ sealed abstract class BloomFilter extends NetworkElement {
loop(remainingBitIndexes.tail, isBitSet +: accum)
}
}
loop(bitIndexes, Nil)
loop(bitIndexes, BitVector.empty)
}
/** Checks if [[data]] contains a [[DoubleSha256Digest]] */
@ -211,7 +213,7 @@ sealed abstract class BloomFilter extends NetworkElement {
* @param bytes the bytes of the data that needs to be inserted into the [[BloomFilter]]
* @return the index of the bit inside of [[data]] that needs to be set to 1
*/
private def murmurHash(hashNum: Int, bytes: Seq[Byte]): Int = {
private def murmurHash(hashNum: Int, bytes: scodec.bits.ByteVector): Int = {
//TODO: The call of .toInt is probably the source of a bug here, need to come back and look at this
//since this isn't consensus critical though I'm leaving this for now
val seed = (hashNum * murmurConstant.toLong + tweak.toLong).toInt
@ -228,9 +230,9 @@ sealed abstract class BloomFilter extends NetworkElement {
private def murmurConstant = UInt32("fba4c795")
/** Adds a sequence of byte vectors to our bloom filter then returns that new filter*/
def insertByteVectors(bytes: Seq[Seq[Byte]]): BloomFilter = {
def insertByteVectors(bytes: Seq[scodec.bits.ByteVector]): BloomFilter = {
@tailrec
def loop(remainingByteVectors: Seq[Seq[Byte]], accumBloomFilter: BloomFilter): BloomFilter = {
def loop(remainingByteVectors: Seq[scodec.bits.ByteVector], accumBloomFilter: BloomFilter): BloomFilter = {
if (remainingByteVectors.isEmpty) accumBloomFilter
else loop(remainingByteVectors.tail, accumBloomFilter.insert(remainingByteVectors.head))
}
@ -242,7 +244,7 @@ sealed abstract class BloomFilter extends NetworkElement {
object BloomFilter extends Factory[BloomFilter] {
private case class BloomFilterImpl(filterSize: CompactSizeUInt, data: Seq[Byte], hashFuncs: UInt32,
private case class BloomFilterImpl(filterSize: CompactSizeUInt, data: scodec.bits.ByteVector, hashFuncs: UInt32,
tweak: UInt32, flags: BloomFlag) extends BloomFilter
/** Max bloom filter size as per [[https://bitcoin.org/en/developer-reference#filterload]] */
val maxSize = UInt32(36000)
@ -269,14 +271,14 @@ object BloomFilter extends Factory[BloomFilter] {
//BIP37 places a limit on the amount of hashFuncs we can use, which is 50
val actualHashFuncs: Int = max(1, min(optimalHashFuncs, maxHashFuncs.toInt)).toInt
val emptyByteArray = Seq.fill(actualFilterSize)(0.toByte)
val emptyByteArray = ByteVector(Array.fill(actualFilterSize)(0.toByte))
BloomFilter(CompactSizeUInt(UInt64(actualFilterSize)), emptyByteArray, UInt32(actualHashFuncs), tweak, flags)
}
def apply(filterSize: CompactSizeUInt, data: Seq[Byte], hashFuncs: UInt32, tweak: UInt32, flags: BloomFlag): BloomFilter = {
def apply(filterSize: CompactSizeUInt, data: scodec.bits.ByteVector, hashFuncs: UInt32, tweak: UInt32, flags: BloomFlag): BloomFilter = {
BloomFilterImpl(filterSize, data, hashFuncs, tweak, flags)
}
override def fromBytes(bytes: Seq[Byte]): BloomFilter = RawBloomFilterSerializer.read(bytes)
override def fromBytes(bytes: scodec.bits.ByteVector): BloomFilter = RawBloomFilterSerializer.read(bytes)
}

View file

@ -41,6 +41,6 @@ object BloomFlag extends Factory[BloomFlag] {
else throw new IllegalArgumentException("The given byte was not defined for BloomFlag, got: " + byte)
}
def fromBytes(bytes: Seq[Byte]): BloomFlag = BloomFlag(bytes.head)
def fromBytes(bytes: scodec.bits.ByteVector): BloomFlag = BloomFlag(bytes.head)
}

View file

@ -9,9 +9,9 @@ sealed abstract class NetworkParameters {
/** The parameters of the blockchain we are connecting to */
def chainParams: ChainParams
def p2pkhNetworkByte: Seq[Byte] = chainParams.base58Prefix(Base58Type.PubKeyAddress)
def p2shNetworkByte: Seq[Byte] = chainParams.base58Prefix(Base58Type.ScriptAddress)
def privateKey: Seq[Byte] = chainParams.base58Prefix(Base58Type.SecretKey)
def p2pkhNetworkByte: scodec.bits.ByteVector = chainParams.base58Prefix(Base58Type.PubKeyAddress)
def p2shNetworkByte: scodec.bits.ByteVector = chainParams.base58Prefix(Base58Type.ScriptAddress)
def privateKey: scodec.bits.ByteVector = chainParams.base58Prefix(Base58Type.SecretKey)
def port: Int
def rpcPort: Int
@ -25,7 +25,7 @@ sealed abstract class NetworkParameters {
* a large 32-bit integer with any alignment.
* https://github.com/bitcoin/bitcoin/blob/master/src/chainparams.cpp#L108
*/
def magicBytes: Seq[Byte]
def magicBytes: scodec.bits.ByteVector
/** In bitcoin, the network recaculates the difficulty for the network every 2016 blocks */
def difficultyChangeThreshold: Int
@ -46,7 +46,7 @@ sealed abstract class MainNet extends BitcoinNetwork {
override def dnsSeeds = Seq("seed.bitcoin.sipa.be", "dnsseed.bluematt.me", "dnsseed.bitcoin.dashjr.org",
"seed.bitcoinstats.com", "bitseed.xf2.org", "seed.bitcoin.jonasschnelli.ch")
override def magicBytes = Seq(0xf9.toByte, 0xbe.toByte, 0xb4.toByte, 0xd9.toByte)
override def magicBytes = scodec.bits.ByteVector(0xf9, 0xbe, 0xb4, 0xd9)
override def difficultyChangeThreshold: Int = 2016
}
@ -60,7 +60,7 @@ sealed abstract class TestNet3 extends BitcoinNetwork {
override def dnsSeeds = Seq(
"testnet-seed.bitcoin.petertodd.org",
"testnet-seed.bluematt.me", "testnet-seed.bitcoin.schildbach.de")
override def magicBytes = Seq(0x0b.toByte, 0x11.toByte, 0x09.toByte, 0x07.toByte)
override def magicBytes = scodec.bits.ByteVector(0x0b, 0x11, 0x09, 0x07)
override def difficultyChangeThreshold: Int = 2016
}
@ -72,7 +72,7 @@ sealed abstract class RegTest extends BitcoinNetwork {
override def port = 18444
override def rpcPort = TestNet3.rpcPort
override def dnsSeeds = Nil
override def magicBytes = Seq(0xfa.toByte, 0xbf.toByte, 0xb5.toByte, 0xda.toByte)
override def magicBytes = scodec.bits.ByteVector(0xfa, 0xbf, 0xb5, 0xda)
override def difficultyChangeThreshold: Int = 2016
}
@ -84,7 +84,7 @@ object Networks {
val p2pkhNetworkBytes = knownNetworks.map(_.p2pkhNetworkByte)
val p2shNetworkBytes = knownNetworks.map(_.p2shNetworkByte)
def bytesToNetwork: Map[Seq[Byte], NetworkParameters] = Map(
def bytesToNetwork: Map[scodec.bits.ByteVector, NetworkParameters] = Map(
MainNet.p2shNetworkByte -> MainNet,
MainNet.p2pkhNetworkByte -> MainNet,
MainNet.privateKey -> MainNet,

View file

@ -5,10 +5,10 @@ import org.bitcoins.core.util.Factory
sealed abstract class ChainCode extends NetworkElement
object ChainCode extends Factory[ChainCode] {
private case class ChainCodeImpl(bytes: Seq[Byte]) extends ChainCode {
private case class ChainCodeImpl(bytes: scodec.bits.ByteVector) extends ChainCode {
require(bytes.size == 32, "ChainCode must be 32 bytes in size, got: " + bytes.size)
}
def fromBytes(bytes: Seq[Byte]): ChainCode = ChainCodeImpl(bytes)
def fromBytes(bytes: scodec.bits.ByteVector): ChainCode = ChainCodeImpl(bytes)
}

View file

@ -25,7 +25,7 @@ sealed abstract class DERSignatureUtil {
* This will fail if this signature contains the hash type appended to the end of it
* @return boolean representing if the signature is a valid
*/
def isDEREncoded(bytes: Seq[Byte]): Boolean = {
def isDEREncoded(bytes: scodec.bits.ByteVector): Boolean = {
//signature is trivially valid if the signature is empty
if (bytes.nonEmpty && bytes.size < 9) false
else if (bytes.nonEmpty) {
@ -65,7 +65,7 @@ sealed abstract class DERSignatureUtil {
* @param bytes
* @return
*/
def decodeSignature(bytes: Seq[Byte]): (BigInt, BigInt) = {
def decodeSignature(bytes: scodec.bits.ByteVector): (BigInt, BigInt) = {
logger.debug("Signature to decode: " + BitcoinSUtil.encodeHex(bytes))
val asn1InputStream = new ASN1InputStream(bytes.toArray)
//TODO: this is nasty, is there any way to get rid of all this casting???
@ -124,7 +124,7 @@ sealed abstract class DERSignatureUtil {
* @param bytes the bytes to check if they are strictly der encoded
* @return boolean indicating whether the bytes were der encoded or not
*/
def isValidSignatureEncoding(bytes: Seq[Byte]): Boolean = {
def isValidSignatureEncoding(bytes: scodec.bits.ByteVector): Boolean = {
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
// * total-length: 1-byte length descriptor of everything that follows,
// excluding the sighash byte.
@ -219,7 +219,7 @@ sealed abstract class DERSignatureUtil {
* @param signature
* @return if the S value is the low version
*/
def isLowS(signature: Seq[Byte]): Boolean = {
def isLowS(signature: scodec.bits.ByteVector): Boolean = {
val result = Try {
val (r, s) = decodeSignature(signature)
s.bigInteger.compareTo(CryptoParams.halfCurveOrder) <= 0

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.crypto
import org.bitcoins.core.util.{ BitcoinSLogger, BitcoinSUtil, Factory }
import scodec.bits.ByteVector
/**
* Created by chris on 2/26/16.
*/
@ -9,7 +10,7 @@ sealed abstract class ECDigitalSignature {
def hex: String = BitcoinSUtil.encodeHex(bytes)
def bytes: Seq[Byte]
def bytes: scodec.bits.ByteVector
def isEmpty = bytes.isEmpty
@ -44,7 +45,7 @@ sealed abstract class ECDigitalSignature {
}
case object EmptyDigitalSignature extends ECDigitalSignature {
override val bytes = Nil
override val bytes = ByteVector.empty
override def r = java.math.BigInteger.valueOf(0)
override def s = r
}
@ -57,13 +58,13 @@ case object EmptyDigitalSignature extends ECDigitalSignature {
* https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm
*/
case object DummyECDigitalSignature extends ECDigitalSignature {
override val bytes = 0.until(72).map(_ => 0.toByte)
override val bytes = ByteVector(Array.fill(72)(0.toByte))
}
object ECDigitalSignature extends Factory[ECDigitalSignature] {
private case class ECDigitalSignatureImpl(bytes: Seq[Byte]) extends ECDigitalSignature
private case class ECDigitalSignatureImpl(bytes: scodec.bits.ByteVector) extends ECDigitalSignature
override def fromBytes(bytes: Seq[Byte]): ECDigitalSignature = {
override def fromBytes(bytes: scodec.bits.ByteVector): ECDigitalSignature = {
//this represents the empty signature
if (bytes.size == 1 && bytes.head == 0x0) EmptyDigitalSignature
else if (bytes.size == 0) EmptyDigitalSignature
@ -89,8 +90,13 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] {
def fromRS(r: BigInt, s: BigInt): ECDigitalSignature = {
val rsSize = r.toByteArray.size + s.toByteArray.size
val totalSize = 4 + rsSize
val bytes: Seq[Byte] = Seq(0x30.toByte, totalSize.toByte, 0x2.toByte, r.toByteArray.size.toByte) ++
r.toByteArray.toSeq ++ Seq(0x2.toByte, s.toByteArray.size.toByte) ++ s.toByteArray.toSeq
val bytes: scodec.bits.ByteVector = {
ByteVector(Array(0x30.toByte, totalSize.toByte, 0x2.toByte, r.toByteArray.size.toByte))
.++(ByteVector(r.toByteArray))
.++(ByteVector(Array(0x2.toByte, s.toByteArray.size.toByte)))
.++(ByteVector(s.toByteArray))
}
fromBytes(bytes)
}
}

View file

@ -12,6 +12,7 @@ import org.bouncycastle.crypto.digests.SHA256Digest
import org.bouncycastle.crypto.generators.ECKeyPairGenerator
import org.bouncycastle.crypto.params.{ ECKeyGenerationParameters, ECPrivateKeyParameters, ECPublicKeyParameters }
import org.bouncycastle.crypto.signers.{ ECDSASigner, HMacDSAKCalculator }
import scodec.bits.ByteVector
import scala.annotation.tailrec
import scala.concurrent.ExecutionContext.Implicits
@ -23,7 +24,7 @@ import scala.util.{ Failure, Success, Try }
*/
sealed abstract class BaseECKey extends NetworkElement with Sign {
override def signFunction: Seq[Byte] => Future[ECDigitalSignature] = { bytes =>
override def signFunction: scodec.bits.ByteVector => Future[ECDigitalSignature] = { bytes =>
import scala.concurrent.ExecutionContext.Implicits.global
Future(sign(bytes))
}
@ -33,13 +34,13 @@ sealed abstract class BaseECKey extends NetworkElement with Sign {
* @param signingKey the key to sign the bytes with
* @return the digital signature
*/
private def sign(dataToSign: Seq[Byte], signingKey: BaseECKey): ECDigitalSignature = {
private def sign(dataToSign: scodec.bits.ByteVector, signingKey: BaseECKey): ECDigitalSignature = {
require(dataToSign.length == 32 && signingKey.bytes.length <= 32)
val signature = NativeSecp256k1.sign(dataToSign.toArray, signingKey.bytes.toArray)
ECDigitalSignature(signature)
ECDigitalSignature(scodec.bits.ByteVector(signature))
}
override def sign(dataToSign: Seq[Byte]): ECDigitalSignature = sign(dataToSign, this)
override def sign(dataToSign: scodec.bits.ByteVector): ECDigitalSignature = sign(dataToSign, this)
def sign(hash: HashDigest, signingKey: BaseECKey): ECDigitalSignature = sign(hash.bytes, signingKey)
@ -48,7 +49,7 @@ sealed abstract class BaseECKey extends NetworkElement with Sign {
def signFuture(hash: HashDigest)(implicit ec: ExecutionContext): Future[ECDigitalSignature] = Future(sign(hash))
@deprecated("Deprecated in favor of signing algorithm inside of secp256k1", "2/20/2017")
private def oldSign(dataToSign: Seq[Byte], signingKey: BaseECKey): ECDigitalSignature = {
private def oldSign(dataToSign: scodec.bits.ByteVector, signingKey: BaseECKey): ECDigitalSignature = {
val signer: ECDSASigner = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()))
val privKey: ECPrivateKeyParameters = new ECPrivateKeyParameters(
new BigInteger(1, signingKey.bytes.toArray), CryptoParams.curve)
@ -76,9 +77,11 @@ sealed abstract class ECPrivateKey extends BaseECKey {
/** Derives the public for a the private key */
def publicKey: ECPublicKey = {
val pubKeyBytes: Seq[Byte] = NativeSecp256k1.computePubkey(bytes.toArray, isCompressed)
require(NativeSecp256k1.isValidPubKey(pubKeyBytes.toArray), "secp256k1 failed to generate a valid public key, got: " + BitcoinSUtil.encodeHex(pubKeyBytes))
ECPublicKey(pubKeyBytes)
val pubKeyBytes: Array[Byte] = NativeSecp256k1.computePubkey(bytes.toArray, isCompressed)
require(
NativeSecp256k1.isValidPubKey(pubKeyBytes),
s"secp256k1 failed to generate a valid public key, got: ${BitcoinSUtil.encodeHex(ByteVector(pubKeyBytes))}")
ECPublicKey(ByteVector(pubKeyBytes))
}
/**
@ -89,7 +92,7 @@ sealed abstract class ECPrivateKey extends BaseECKey {
def toWIF(network: NetworkParameters): String = {
val networkByte = network.privateKey
//append 1 byte to the end of the priv key byte representation if we need a compressed pub key
val fullBytes = if (isCompressed) networkByte ++ (bytes ++ Seq(1.toByte)) else networkByte ++ bytes
val fullBytes = if (isCompressed) networkByte ++ (bytes ++ scodec.bits.ByteVector(1)) else networkByte ++ bytes
val hash = CryptoUtil.doubleSHA256(fullBytes)
val checksum = hash.bytes.take(4)
val encodedPrivKey = fullBytes ++ checksum
@ -101,25 +104,23 @@ sealed abstract class ECPrivateKey extends BaseECKey {
object ECPrivateKey extends Factory[ECPrivateKey] {
private case class ECPrivateKeyImpl(override val bytes: Seq[Byte], isCompressed: Boolean, ec: ExecutionContext) extends ECPrivateKey {
private case class ECPrivateKeyImpl(override val bytes: scodec.bits.ByteVector, isCompressed: Boolean, ec: ExecutionContext) extends ECPrivateKey {
require(NativeSecp256k1.secKeyVerify(bytes.toArray), "Invalid key according to secp256k1, hex: " + BitcoinSUtil.encodeHex(bytes))
}
def apply(bytes: Seq[Byte], isCompressed: Boolean)(implicit ec: ExecutionContext): ECPrivateKey = {
def apply(bytes: scodec.bits.ByteVector, isCompressed: Boolean)(implicit ec: ExecutionContext): ECPrivateKey = {
ECPrivateKeyImpl(bytes, isCompressed, ec)
}
override def fromBytes(bytes: Seq[Byte]): ECPrivateKey = fromBytes(bytes, true)
override def fromBytes(bytes: scodec.bits.ByteVector): ECPrivateKey = fromBytes(bytes, true)
@tailrec
def fromBytes(bytes: Seq[Byte], isCompressed: Boolean): ECPrivateKey = {
def fromBytes(bytes: scodec.bits.ByteVector, isCompressed: Boolean): ECPrivateKey = {
if (bytes.size == 32) ECPrivateKeyImpl(bytes, isCompressed, Implicits.global)
else if (bytes.size < 32) {
//means we need to pad the private key with 0 bytes so we have 32 bytes
val paddingNeeded = 32 - bytes.size
val padding = for { _ <- 0 until paddingNeeded } yield 0.toByte
ECPrivateKey.fromBytes(padding ++ bytes, isCompressed)
ECPrivateKey.fromBytes(bytes.padLeft(32), isCompressed)
} //this is for the case when java serialies a BigInteger to 33 bytes to hold the signed num representation
else if (bytes.size == 33) ECPrivateKey.fromBytes(bytes.slice(1, 33), isCompressed)
else throw new IllegalArgumentException("Private keys cannot be greater than 33 bytes in size, got: " +
@ -144,7 +145,7 @@ object ECPrivateKey extends Factory[ECPrivateKey] {
val keypair: AsymmetricCipherKeyPair = generator.generateKeyPair
val privParams: ECPrivateKeyParameters = keypair.getPrivate.asInstanceOf[ECPrivateKeyParameters]
val priv: BigInteger = privParams.getD
val bytes = priv.toByteArray
val bytes = ByteVector(priv.toByteArray)
ECPrivateKey.fromBytes(bytes, isCompressed)
}
/**
@ -169,8 +170,8 @@ object ECPrivateKey extends Factory[ECPrivateKey] {
* @param bytes private key in bytes
* @return
*/
def isCompressed(bytes: Seq[Byte]): Boolean = {
val validCompressedBytes: Seq[Seq[Byte]] = Networks.secretKeyBytes
def isCompressed(bytes: scodec.bits.ByteVector): Boolean = {
val validCompressedBytes: Seq[scodec.bits.ByteVector] = Networks.secretKeyBytes
val validCompressedBytesInHex: Seq[String] = validCompressedBytes.map(b => BitcoinSUtil.encodeHex(b))
val firstByteHex = BitcoinSUtil.encodeHex(bytes.head)
if (validCompressedBytesInHex.contains(firstByteHex)) bytes(bytes.length - 5) == 0x01.toByte
@ -189,7 +190,7 @@ object ECPrivateKey extends Factory[ECPrivateKey] {
* @param WIF Wallet Import Format. Encoded in Base58
* @return
*/
private def trimFunction(WIF: String): Seq[Byte] = {
private def trimFunction(WIF: String): scodec.bits.ByteVector = {
val bytesChecked = Base58.decodeCheck(WIF)
//see https://en.bitcoin.it/wiki/List_of_address_prefixes
@ -232,7 +233,7 @@ sealed abstract class ECPublicKey extends BaseECKey {
def verify(hash: HashDigest, signature: ECDigitalSignature): Boolean = verify(hash.bytes, signature)
/** Verifies if a given piece of data is signed by the [[ECPrivateKey]]'s corresponding [[ECPublicKey]]. */
def verify(data: Seq[Byte], signature: ECDigitalSignature): Boolean = {
def verify(data: scodec.bits.ByteVector, signature: ECDigitalSignature): Boolean = {
val result = NativeSecp256k1.verify(data.toArray, signature.bytes.toArray, bytes.toArray)
if (!result) {
//if signature verification fails with libsecp256k1 we need to use our old
@ -250,7 +251,7 @@ sealed abstract class ECPublicKey extends BaseECKey {
override def toString = "ECPublicKey(" + hex + ")"
@deprecated("Deprecated in favor of using verify functionality inside of secp256k1", "2/20/2017")
private def oldVerify(data: Seq[Byte], signature: ECDigitalSignature): Boolean = {
private def oldVerify(data: scodec.bits.ByteVector, signature: ECDigitalSignature): Boolean = {
/** The elliptic curve used by bitcoin. */
def curve = CryptoParams.curve
/** This represents this public key in the bouncy castle library */
@ -280,13 +281,16 @@ sealed abstract class ECPublicKey extends BaseECKey {
/** Returns the decompressed version of this [[ECPublicKey]] */
def decompressed: ECPublicKey = {
if (isCompressed) ECPublicKey.fromBytes(NativeSecp256k1.decompress(bytes.toArray)) else this
if (isCompressed) {
val decompressed = NativeSecp256k1.decompress(bytes.toArray)
ECPublicKey.fromBytes(ByteVector(decompressed))
} else this
}
}
object ECPublicKey extends Factory[ECPublicKey] {
private case class ECPublicKeyImpl(override val bytes: Seq[Byte], ec: ExecutionContext) extends ECPublicKey {
private case class ECPublicKeyImpl(override val bytes: scodec.bits.ByteVector, ec: ExecutionContext) extends ECPublicKey {
//unfortunately we cannot place ANY invariants here
//because of old transactions on the blockchain that have weirdly formatted public keys. Look at example in script_tests.json
//https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_tests.json#L457
@ -295,7 +299,7 @@ object ECPublicKey extends Factory[ECPublicKey] {
//Eventually we would like this to be CPubKey::IsFullyValid() but since we are remaining backwards compatible
//we cannot do this. If there ever is a hard fork this would be a good thing to add.
}
override def fromBytes(bytes: Seq[Byte]): ECPublicKey = {
override def fromBytes(bytes: scodec.bits.ByteVector): ECPublicKey = {
ECPublicKeyImpl(bytes, Implicits.global)
}
@ -309,11 +313,11 @@ object ECPublicKey extends Factory[ECPublicKey] {
* Mimics this function in bitcoin core
* [[https://github.com/bitcoin/bitcoin/blob/27765b6403cece54320374b37afb01a0cfe571c3/src/pubkey.cpp#L207-L212]]
*/
def isFullyValid(bytes: Seq[Byte]): Boolean = Try(NativeSecp256k1.isValidPubKey(bytes.toArray)).isSuccess && isValid(bytes)
def isFullyValid(bytes: scodec.bits.ByteVector): Boolean = Try(NativeSecp256k1.isValidPubKey(bytes.toArray)).isSuccess && isValid(bytes)
/**
* Mimics the CPubKey::IsValid function in Bitcoin core, this is a consensus rule
* [[https://github.com/bitcoin/bitcoin/blob/27765b6403cece54320374b37afb01a0cfe571c3/src/pubkey.h#L158]]
*/
def isValid(bytes: Seq[Byte]): Boolean = bytes.nonEmpty
def isValid(bytes: scodec.bits.ByteVector): Boolean = bytes.nonEmpty
}

View file

@ -6,6 +6,7 @@ import org.bitcoin.NativeSecp256k1
import org.bitcoins.core.number.{ UInt32, UInt8 }
import org.bitcoins.core.protocol.NetworkElement
import org.bitcoins.core.util._
import scodec.bits.ByteVector
import scala.util.{ Failure, Success, Try }
@ -20,7 +21,7 @@ sealed abstract class ExtKey extends NetworkElement {
/** 0 for master nodes, 1 for level-1 derived keys, .... */
def depth: UInt8
/** The fingerprint of the parent key */
def fingerprint: Seq[Byte]
def fingerprint: scodec.bits.ByteVector
/**
* Child number. This is ser32(i) for i in xi = xpar/i, with xi the key being serialized.
* (0x00000000 if master key)
@ -48,10 +49,10 @@ sealed abstract class ExtKey extends NetworkElement {
Try(UInt32(idx)).flatMap(deriveChildPubKey(_))
}
override def bytes: Seq[Byte] = key match {
override def bytes: scodec.bits.ByteVector = key match {
case priv: ECPrivateKey =>
version.bytes ++ depth.bytes ++ fingerprint ++
childNum.bytes ++ chainCode.bytes ++ Seq(0.toByte) ++ priv.bytes
childNum.bytes ++ chainCode.bytes ++ scodec.bits.ByteVector.low(1) ++ priv.bytes
case pub: ECPublicKey =>
version.bytes ++ depth.bytes ++ fingerprint ++
childNum.bytes ++ chainCode.bytes ++ pub.bytes
@ -70,7 +71,7 @@ object ExtKey extends Factory[ExtKey] {
/** Takes in a base58 string and tries to convert it to an extended key */
def fromString(base58: String): Try[ExtKey] = {
val decoded: Try[Seq[Byte]] = Base58.decodeCheck(base58)
val decoded: Try[scodec.bits.ByteVector] = Base58.decodeCheck(base58)
val extKey = decoded.flatMap { bytes =>
require(bytes.size == 78, "Not 78 bytes")
val version: Try[ExtKeyVersion] = ExtKeyVersion(bytes.take(4)) match {
@ -95,7 +96,7 @@ object ExtKey extends Factory[ExtKey] {
extKey
}
override def fromBytes(bytes: Seq[Byte]): ExtKey = {
override def fromBytes(bytes: scodec.bits.ByteVector): ExtKey = {
val privTry = Try(ExtPrivateKey(bytes))
if (privTry.isSuccess) privTry.get
else {
@ -108,7 +109,7 @@ sealed abstract class ExtPrivateKey extends ExtKey {
override def key: ECPrivateKey
def deriveChildPrivKey(idx: UInt32): ExtPrivateKey = {
val data: Seq[Byte] = if (idx >= ExtKey.hardenedIdx) {
val data: scodec.bits.ByteVector = if (idx >= ExtKey.hardenedIdx) {
//derive hardened key
0.toByte +: ((key.bytes) ++ idx.bytes)
} else {
@ -119,7 +120,8 @@ sealed abstract class ExtPrivateKey extends ExtKey {
val (il, ir) = hmac.splitAt(32)
//should be ECGroup addition
//parse256(IL) + kpar (mod n)
val childKey = ECPrivateKey(NativeSecp256k1.privKeyTweakAdd(il.toArray, key.bytes.toArray))
val tweak = NativeSecp256k1.privKeyTweakAdd(il.toArray, key.bytes.toArray)
val childKey = ECPrivateKey(ByteVector(tweak))
val fp = CryptoUtil.sha256Hash160(key.publicKey.bytes).bytes.take(4)
ExtPrivateKey(version, depth + UInt8.one, fp, idx,
ChainCode(ir), childKey)
@ -137,12 +139,12 @@ sealed abstract class ExtPrivateKey extends ExtKey {
}
object ExtPrivateKey extends Factory[ExtPrivateKey] {
private case class ExtPrivateKeyImpl(version: ExtKeyVersion, depth: UInt8,
fingerprint: Seq[Byte], childNum: UInt32,
fingerprint: scodec.bits.ByteVector, childNum: UInt32,
chainCode: ChainCode, key: ECPrivateKey) extends ExtPrivateKey {
require(fingerprint.size == 4, "Fingerprint must be 4 bytes in size, got: " + fingerprint)
}
override def fromBytes(bytes: Seq[Byte]): ExtPrivateKey = {
override def fromBytes(bytes: scodec.bits.ByteVector): ExtPrivateKey = {
require(bytes.size == 78, "ExtPrivateKey can only be 78 bytes")
val base58 = Base58.encode(bytes ++ CryptoUtil.doubleSHA256(bytes).bytes.take(4))
ExtKey.fromString(base58) match {
@ -152,7 +154,7 @@ object ExtPrivateKey extends Factory[ExtPrivateKey] {
}
}
def apply(version: ExtKeyVersion, depth: UInt8,
fingerprint: Seq[Byte], child: UInt32,
fingerprint: scodec.bits.ByteVector, child: UInt32,
chainCode: ChainCode, privateKey: ECPrivateKey): ExtPrivateKey = {
ExtPrivateKeyImpl(version, depth, fingerprint, child, chainCode, privateKey)
}
@ -161,12 +163,12 @@ object ExtPrivateKey extends Factory[ExtPrivateKey] {
* Generates a master private key
* https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#master-key-generation
*/
def apply(version: ExtKeyVersion, seedOpt: Option[Seq[Byte]] = None): ExtPrivateKey = {
def apply(version: ExtKeyVersion, seedOpt: Option[scodec.bits.ByteVector] = None): ExtPrivateKey = {
val seed = seedOpt match {
case Some(bytes) => bytes
case None => ECPrivateKey().bytes
}
val i = CryptoUtil.hmac512("Bitcoin seed".map(_.toByte), seed)
val i = CryptoUtil.hmac512(scodec.bits.ByteVector.encodeAscii("Bitcoin seed").right.get, seed)
val (il, ir) = i.splitAt(32)
val masterPrivKey = ECPrivateKey(il)
val fp = UInt32.zero.bytes
@ -190,7 +192,7 @@ sealed abstract class ExtPublicKey extends ExtKey {
key.bytes.toArray,
hmac.toArray,
priv.isCompressed)
val childPubKey = ECPublicKey(tweaked)
val childPubKey = ECPublicKey(ByteVector(tweaked))
val bi = BigInt(new BigInteger(1, priv.bytes.toArray))
//we do not handle this case since it is impossible
//In case parse256(IL) n or Ki is the point at infinity, the resulting key is invalid,
@ -205,15 +207,15 @@ sealed abstract class ExtPublicKey extends ExtKey {
object ExtPublicKey extends Factory[ExtPublicKey] {
private case class ExtPublicKeyImpl(version: ExtKeyVersion, depth: UInt8,
fingerprint: Seq[Byte], childNum: UInt32,
fingerprint: scodec.bits.ByteVector, childNum: UInt32,
chainCode: ChainCode, key: ECPublicKey) extends ExtPublicKey
def apply(version: ExtKeyVersion, depth: UInt8,
fingerprint: Seq[Byte], child: UInt32, chainCode: ChainCode, publicKey: ECPublicKey): ExtPublicKey = {
fingerprint: scodec.bits.ByteVector, child: UInt32, chainCode: ChainCode, publicKey: ECPublicKey): ExtPublicKey = {
ExtPublicKeyImpl(version, depth, fingerprint, child, chainCode, publicKey)
}
override def fromBytes(bytes: Seq[Byte]): ExtPublicKey = {
override def fromBytes(bytes: scodec.bits.ByteVector): ExtPublicKey = {
require(bytes.size == 78, "ExtPublicKey can only be 78 bytes")
val base58 = Base58.encode(bytes ++ CryptoUtil.doubleSHA256(bytes).bytes.take(4))
ExtKey.fromString(base58) match {

View file

@ -4,28 +4,28 @@ import org.bitcoins.core.protocol.NetworkElement
import org.bitcoins.core.util.BitcoinSUtil
sealed abstract class ExtKeyVersion extends NetworkElement {
def bytes: Seq[Byte]
def bytes: scodec.bits.ByteVector
override def hex = BitcoinSUtil.encodeHex(bytes)
}
case object MainNetPub extends ExtKeyVersion {
override def bytes = Seq(0x04, 0x88, 0xb2, 0x1E).map(_.toByte)
override def bytes = scodec.bits.ByteVector(0x04, 0x88, 0xb2, 0x1E)
}
case object MainNetPriv extends ExtKeyVersion {
override def bytes = Seq(0x04, 0x88, 0xAD, 0xE4).map(_.toByte)
override def bytes = scodec.bits.ByteVector(0x04, 0x88, 0xAD, 0xE4)
}
case object TestNet3Pub extends ExtKeyVersion {
override def bytes = Seq(0x04, 0x35, 0x87, 0xCF).map(_.toByte)
override def bytes = scodec.bits.ByteVector(0x04, 0x35, 0x87, 0xCF)
}
case object TestNet3Priv extends ExtKeyVersion {
override def bytes = Seq(0x04, 0x35, 0x83, 0x94).map(_.toByte)
override def bytes = scodec.bits.ByteVector(0x04, 0x35, 0x83, 0x94)
}
object ExtKeyVersion {
private val all: Seq[ExtKeyVersion] = Seq(MainNetPriv, MainNetPub, TestNet3Pub, TestNet3Priv)
def apply(bytes: Seq[Byte]): Option[ExtKeyVersion] = all.find(_.bytes == bytes)
def apply(bytes: scodec.bits.ByteVector): Option[ExtKeyVersion] = all.find(_.bytes == bytes)
}

View file

@ -7,6 +7,8 @@ import org.bitcoins.core.util.{ BitcoinSUtil, Factory }
* Created by chris on 5/24/16.
*/
sealed abstract class HashDigest extends NetworkElement {
/** The message digest represented in bytes */
def bytes: scodec.bits.ByteVector
/**
* Flips the endianness of the byte sequence.
* Since bitcoin unfortunately has inconsistent endianness between the protocol
@ -24,10 +26,10 @@ sealed abstract class Sha1Digest extends HashDigest {
}
object Sha1Digest extends Factory[Sha1Digest] {
private case class Sha1DigestImpl(bytes: Seq[Byte]) extends Sha1Digest {
private case class Sha1DigestImpl(bytes: scodec.bits.ByteVector) extends Sha1Digest {
override def toString = s"Sha1DigestImpl($hex)"
}
override def fromBytes(bytes: Seq[Byte]): Sha1Digest = Sha1DigestImpl(bytes)
override def fromBytes(bytes: scodec.bits.ByteVector): Sha1Digest = Sha1DigestImpl(bytes)
}
/**
@ -38,11 +40,11 @@ sealed abstract class Sha256Digest extends HashDigest {
}
object Sha256Digest extends Factory[Sha256Digest] {
private case class Sha256DigestImpl(bytes: Seq[Byte]) extends Sha256Digest {
private case class Sha256DigestImpl(bytes: scodec.bits.ByteVector) extends Sha256Digest {
require(bytes.length == 32, "Sha256Digest must be 32 bytes in size, got: " + bytes.length)
override def toString = s"Sha256DigestImpl($hex)"
}
override def fromBytes(bytes: Seq[Byte]): Sha256Digest = Sha256DigestImpl(bytes)
override def fromBytes(bytes: scodec.bits.ByteVector): Sha256Digest = Sha256DigestImpl(bytes)
}
/**
@ -53,11 +55,11 @@ sealed abstract class DoubleSha256Digest extends HashDigest {
}
object DoubleSha256Digest extends Factory[DoubleSha256Digest] {
private case class DoubleSha256DigestImpl(bytes: Seq[Byte]) extends DoubleSha256Digest {
private case class DoubleSha256DigestImpl(bytes: scodec.bits.ByteVector) extends DoubleSha256Digest {
require(bytes.length == 32, "DoubleSha256Digest must always be 32 bytes, got: " + bytes.length)
override def toString = s"DoubleSha256DigestImpl($hex)"
}
override def fromBytes(bytes: Seq[Byte]): DoubleSha256Digest = DoubleSha256DigestImpl(bytes)
override def fromBytes(bytes: scodec.bits.ByteVector): DoubleSha256Digest = DoubleSha256DigestImpl(bytes)
}
@ -69,11 +71,11 @@ sealed abstract class RipeMd160Digest extends HashDigest {
}
object RipeMd160Digest extends Factory[RipeMd160Digest] {
private case class RipeMd160DigestImpl(bytes: Seq[Byte]) extends RipeMd160Digest {
private case class RipeMd160DigestImpl(bytes: scodec.bits.ByteVector) extends RipeMd160Digest {
require(bytes.length == 20, "RIPEMD160Digest must always be 20 bytes, got: " + bytes.length)
override def toString = s"RipeMd160DigestImpl($hex)"
}
override def fromBytes(bytes: Seq[Byte]): RipeMd160Digest = RipeMd160DigestImpl(bytes)
override def fromBytes(bytes: scodec.bits.ByteVector): RipeMd160Digest = RipeMd160DigestImpl(bytes)
}
/**
@ -84,9 +86,9 @@ sealed abstract class Sha256Hash160Digest extends HashDigest {
}
object Sha256Hash160Digest extends Factory[Sha256Hash160Digest] {
private case class Sha256Hash160DigestImpl(bytes: Seq[Byte]) extends Sha256Hash160Digest {
private case class Sha256Hash160DigestImpl(bytes: scodec.bits.ByteVector) extends Sha256Hash160Digest {
require(bytes.length == 20, "Sha256Hash160Digest must always be 20 bytes, got: " + bytes.length)
override def toString = s"Sha256Hash160DigestImpl($hex)"
}
override def fromBytes(bytes: Seq[Byte]): Sha256Hash160Digest = Sha256Hash160DigestImpl(bytes)
}
override def fromBytes(bytes: scodec.bits.ByteVector): Sha256Hash160Digest = Sha256Hash160DigestImpl(bytes)
}

View file

@ -6,23 +6,23 @@ import scala.concurrent.duration.DurationInt
/**
* This is meant to be an abstraction for a [[org.bitcoins.core.crypto.ECPrivateKey]], sometimes we will not
* have direct access to a private key in memory -- for instance if that key is on a hardware device -- so we need to create an
* abstraction of the signing process. Fundamentally a private key takes in a Seq[Byte] and returns a [[ECDigitalSignature]]
* abstraction of the signing process. Fundamentally a private key takes in a scodec.bits.ByteVector and returns a [[ECDigitalSignature]]
* That is what this abstraction is meant to represent. If you have a [[ECPrivateKey]] in your application, you can get it's
* [[Sign]] type by doing this:
*
* val key = ECPrivateKey()
* val sign: Seq[Byte] => Future[ECDigitalSignature] = key.signFunction
* val sign: scodec.bits.ByteVector => Future[ECDigitalSignature] = key.signFunction
*
* If you have a hardware wallet, you will need to implement the protocol to send a message to the hardware device. The
* type signature of the function you implement must be Seq[Byte] => Future[ECDigitalSignature]
* type signature of the function you implement must be scodec.bits.ByteVector => Future[ECDigitalSignature]
*
*/
trait Sign {
def signFunction: Seq[Byte] => Future[ECDigitalSignature]
def signFunction: scodec.bits.ByteVector => Future[ECDigitalSignature]
def signFuture(bytes: Seq[Byte]): Future[ECDigitalSignature] = signFunction(bytes)
def signFuture(bytes: scodec.bits.ByteVector): Future[ECDigitalSignature] = signFunction(bytes)
def sign(bytes: Seq[Byte]): ECDigitalSignature = {
def sign(bytes: scodec.bits.ByteVector): ECDigitalSignature = {
Await.result(signFuture(bytes), 30.seconds)
}
@ -30,9 +30,9 @@ trait Sign {
}
object Sign {
private case class SignImpl(signFunction: Seq[Byte] => Future[ECDigitalSignature], publicKey: ECPublicKey) extends Sign
private case class SignImpl(signFunction: scodec.bits.ByteVector => Future[ECDigitalSignature], publicKey: ECPublicKey) extends Sign
def apply(signFunction: Seq[Byte] => Future[ECDigitalSignature], pubKey: ECPublicKey): Sign = {
def apply(signFunction: scodec.bits.ByteVector => Future[ECDigitalSignature], pubKey: ECPublicKey): Sign = {
SignImpl(signFunction, pubKey)
}
@ -45,6 +45,6 @@ object Sign {
* a specific private key on another server
*/
def dummySign(publicKey: ECPublicKey): Sign = {
SignImpl({ _: Seq[Byte] => Future.successful(EmptyDigitalSignature) }, publicKey)
SignImpl({ _: scodec.bits.ByteVector => Future.successful(EmptyDigitalSignature) }, publicKey)
}
}

View file

@ -7,6 +7,7 @@ import org.bitcoins.core.script.crypto._
import org.bitcoins.core.script.flag.{ ScriptFlag, ScriptFlagUtil }
import org.bitcoins.core.script.result.ScriptErrorWitnessPubKeyType
import org.bitcoins.core.util.{ BitcoinSLogger, BitcoinSUtil, BitcoinScriptUtil }
import scodec.bits.ByteVector
import scala.annotation.tailrec
@ -52,7 +53,7 @@ trait TransactionSignatureChecker extends BitcoinSLogger {
} else {
val sigsRemovedScript = BitcoinScriptUtil.calculateScriptForChecking(txSignatureComponent, signature, script)
val hashTypeByte = if (signature.bytes.nonEmpty) signature.bytes.last else 0x00.toByte
val hashType = HashType(Seq(0.toByte, 0.toByte, 0.toByte, hashTypeByte))
val hashType = HashType(ByteVector(0.toByte, 0.toByte, 0.toByte, hashTypeByte))
val spk = ScriptPubKey.fromAsm(sigsRemovedScript)
val hashForSignature = txSignatureComponent match {
case b: BaseTxSigComponent =>

View file

@ -2,6 +2,7 @@ package org.bitcoins.core.crypto
import org.bitcoins.core.script.crypto.HashType
import org.bitcoins.core.util.BitcoinSLogger
import scodec.bits.ByteVector
import scala.concurrent.{ ExecutionContext, Future }
@ -19,36 +20,36 @@ sealed abstract class TransactionSignatureCreator {
* @return
*/
def createSig(txSignatureComponent: TxSigComponent, privateKey: ECPrivateKey, hashType: HashType): ECDigitalSignature = {
val sign: Seq[Byte] => ECDigitalSignature = privateKey.sign(_: Seq[Byte])
val sign: scodec.bits.ByteVector => ECDigitalSignature = privateKey.sign(_: scodec.bits.ByteVector)
createSig(txSignatureComponent, sign, hashType)
}
/**
* This is intended to be a low level hardware wallet API.
* At a fundamental level, a hardware wallet expects a Seq[Byte] as input, and returns an [[ECDigitalSignature]]
* if it is able to sign the Seq[Byte]'s correctly.
* At a fundamental level, a hardware wallet expects a scodec.bits.ByteVector as input, and returns an [[ECDigitalSignature]]
* if it is able to sign the scodec.bits.ByteVector's correctly.
* @param component - the information needed to sign the transaction
* @param sign - the implementation of the hardware wallet protocol to sign the Seq[Byte] w/ the given public key
* @param sign - the implementation of the hardware wallet protocol to sign the scodec.bits.ByteVector w/ the given public key
* @param hashType - the hash type to be appended on the digital signature when the hardware wallet is done being signed
* @return the digital signature returned by the hardware wallet
*/
def createSig(component: TxSigComponent, sign: Seq[Byte] => ECDigitalSignature, hashType: HashType): ECDigitalSignature = {
def createSig(component: TxSigComponent, sign: scodec.bits.ByteVector => ECDigitalSignature, hashType: HashType): ECDigitalSignature = {
val hash = TransactionSignatureSerializer.hashForSignature(component, hashType)
val signature = sign(hash.bytes)
//append 1 byte hash type onto the end
val sig = ECDigitalSignature(signature.bytes ++ Seq(hashType.byte))
val sig = ECDigitalSignature(signature.bytes ++ ByteVector.fromByte(hashType.byte))
require(sig.isStrictEncoded, "We did not create a signature that is strictly encoded, got: " + sig)
require(DERSignatureUtil.isLowS(sig), "Sig does not have a low s value")
sig
}
/** This is the same as createSig above, except the 'sign' function returns a Future[ECDigitalSignature] */
def createSig(component: TxSigComponent, sign: Seq[Byte] => Future[ECDigitalSignature],
def createSig(component: TxSigComponent, sign: scodec.bits.ByteVector => Future[ECDigitalSignature],
hashType: HashType)(implicit ec: ExecutionContext): Future[ECDigitalSignature] = {
val hash = TransactionSignatureSerializer.hashForSignature(component, hashType)
val signature = sign(hash.bytes)
//append 1 byte hash type onto the end
val sig = signature.map(s => ECDigitalSignature(s.bytes ++ Seq(hashType.byte)))
val sig = signature.map(s => ECDigitalSignature(s.bytes ++ ByteVector.fromByte(hashType.byte)))
sig.map { s =>
require(s.isStrictEncoded, "We did not create a signature that is strictly encoded, got: " + sig)
require(DERSignatureUtil.isLowS(s), "Sig does not have a low s value")
@ -57,4 +58,4 @@ sealed abstract class TransactionSignatureCreator {
}
}
object TransactionSignatureCreator extends TransactionSignatureCreator
object TransactionSignatureCreator extends TransactionSignatureCreator

View file

@ -33,7 +33,7 @@ sealed abstract class TransactionSignatureSerializer {
* [[https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki]]
* [[https://github.com/bitcoin/bitcoin/blob/f8528134fc188abc5c7175a19680206964a8fade/src/script/interpreter.cpp#L1113]]
*/
def serializeForSignature(txSigComponent: TxSigComponent, hashType: HashType): Seq[Byte] = {
def serializeForSignature(txSigComponent: TxSigComponent, hashType: HashType): scodec.bits.ByteVector = {
val spendingTransaction = txSigComponent.transaction
val inputIndex = txSigComponent.inputIndex
val output = txSigComponent.output
@ -141,18 +141,21 @@ sealed abstract class TransactionSignatureSerializer {
val inputIndexInt = inputIndex.toInt
val emptyHash = CryptoUtil.emptyDoubleSha256Hash
val outPointHash: Seq[Byte] = if (isNotAnyoneCanPay) {
val bytes: Seq[Byte] = spendingTransaction.inputs.flatMap(_.previousOutput.bytes)
val outPointHash: scodec.bits.ByteVector = if (isNotAnyoneCanPay) {
val prevOuts = spendingTransaction.inputs.map(_.previousOutput)
val bytes: scodec.bits.ByteVector = BitcoinSUtil.toByteVector(prevOuts)
CryptoUtil.doubleSHA256(bytes).bytes
} else emptyHash.bytes
val sequenceHash: Seq[Byte] = if (isNotAnyoneCanPay && isNotSigHashNone && isNotSigHashSingle) {
val bytes = spendingTransaction.inputs.flatMap(_.sequence.bytes)
val sequenceHash: scodec.bits.ByteVector = if (isNotAnyoneCanPay && isNotSigHashNone && isNotSigHashSingle) {
val sequences = spendingTransaction.inputs.map(_.sequence)
val bytes = BitcoinSUtil.toByteVector(sequences)
CryptoUtil.doubleSHA256(bytes).bytes
} else emptyHash.bytes
val outputHash: Seq[Byte] = if (isNotSigHashSingle && isNotSigHashNone) {
val bytes = spendingTransaction.outputs.flatMap(o => o.bytes)
val outputHash: scodec.bits.ByteVector = if (isNotSigHashSingle && isNotSigHashNone) {
val outputs = spendingTransaction.outputs
val bytes = BitcoinSUtil.toByteVector(outputs)
CryptoUtil.doubleSHA256(bytes).bytes
} else if (HashType.isSigHashSingle(hashType.num) &&
inputIndex < UInt32(spendingTransaction.outputs.size)) {
@ -161,10 +164,10 @@ sealed abstract class TransactionSignatureSerializer {
bytes
} else emptyHash.bytes
val scriptBytes = script.flatMap(_.bytes)
val scriptBytes = BitcoinSUtil.toByteVector(script)
val i = spendingTransaction.inputs(inputIndexInt)
val serializationForSig: Seq[Byte] = spendingTransaction.version.bytes.reverse ++ outPointHash ++ sequenceHash ++
val serializationForSig: scodec.bits.ByteVector = spendingTransaction.version.bytes.reverse ++ outPointHash ++ sequenceHash ++
i.previousOutput.bytes ++ CompactSizeUInt.calc(scriptBytes).bytes ++
scriptBytes ++ amount.bytes ++ i.sequence.bytes.reverse ++
outputHash ++ spendingTransaction.lockTime.bytes.reverse ++ hashType.num.bytes.reverse
@ -227,7 +230,6 @@ sealed abstract class TransactionSignatureSerializer {
(output, index) <- spendingTransaction.outputs.zipWithIndex
} yield {
if (UInt32(index) < inputIndex) {
logger.info("Updating tx output to null in bitcoin core")
Some(EmptyTransactionOutput)
} else if (UInt32(index) == inputIndex) Some(output)
else None

View file

@ -77,7 +77,7 @@ object Satoshis extends Factory[Satoshis] with BaseNumbers[Satoshis] {
val zero = Satoshis(Int64.zero)
val one = Satoshis(Int64.one)
override def fromBytes(bytes: Seq[Byte]): Satoshis = RawSatoshisSerializer.read(bytes)
override def fromBytes(bytes: scodec.bits.ByteVector): Satoshis = RawSatoshisSerializer.read(bytes)
def apply(int64: Int64): Satoshis = SatoshisImpl(int64)

View file

@ -2,6 +2,7 @@ package org.bitcoins.core.number
import org.bitcoins.core.protocol.NetworkElement
import org.bitcoins.core.util.{ BitcoinSUtil, Factory, NumberUtil }
import scodec.bits.ByteVector
import scala.util.{ Failure, Success, Try }
@ -183,21 +184,25 @@ object UInt8 extends Factory[UInt8] with BaseNumbers[UInt8] {
def isValid(bigInt: BigInt): Boolean = bigInt >= 0 && bigInt < 256
override def fromBytes(bytes: Seq[Byte]): UInt8 = {
override def fromBytes(bytes: scodec.bits.ByteVector): UInt8 = {
require(bytes.size == 1, "Can only create a uint8 from a byte array of size one, got: " + bytes)
val res = NumberUtil.toUnsignedInt(bytes)
checkBounds(res)
}
def toUInt8(byte: Byte): UInt8 = {
fromBytes(Seq(byte))
fromBytes(ByteVector.fromByte(byte))
}
def toByte(uInt8: UInt8): Byte = uInt8.underlying.toByte
def toBytes(us: Seq[UInt8]): Seq[Byte] = us.map(toByte(_))
def toBytes(us: Seq[UInt8]): scodec.bits.ByteVector = {
ByteVector(us.map(toByte(_)))
}
def toUInt8s(bytes: Seq[Byte]): Seq[UInt8] = bytes.map(toUInt8(_))
def toUInt8s(bytes: scodec.bits.ByteVector): Seq[UInt8] = {
bytes.toSeq.map { b: Byte => toUInt8(b) }
}
def checkBounds(res: BigInt): UInt8 = {
if (res > max.underlying || res < min.underlying) {
@ -218,7 +223,7 @@ object UInt32 extends Factory[UInt32] with BaseNumbers[UInt32] {
lazy val min = zero
lazy val max = UInt32(4294967295L)
override def fromBytes(bytes: Seq[Byte]): UInt32 = {
override def fromBytes(bytes: scodec.bits.ByteVector): UInt32 = {
require(bytes.size <= 4, "UInt32 byte array was too large, got: " + BitcoinSUtil.encodeHex(bytes))
val res = NumberUtil.toUnsignedInt(bytes)
checkBounds(res)
@ -248,7 +253,7 @@ object UInt64 extends Factory[UInt64] with BaseNumbers[UInt64] {
lazy val min = zero
lazy val max = UInt64(BigInt("18446744073709551615"))
override def fromBytes(bytes: Seq[Byte]): UInt64 = {
override def fromBytes(bytes: scodec.bits.ByteVector): UInt64 = {
require(bytes.size <= 8)
val res: BigInt = NumberUtil.toUnsignedInt(bytes)
if (res > max.underlying || res < min.underlying) {
@ -272,7 +277,7 @@ object Int32 extends Factory[Int32] with BaseNumbers[Int32] {
lazy val min = Int32(-2147483648)
lazy val max = Int32(2147483647)
override def fromBytes(bytes: Seq[Byte]): Int32 = {
override def fromBytes(bytes: scodec.bits.ByteVector): Int32 = {
require(bytes.size <= 4, "We cannot have an Int32 be larger than 4 bytes")
Int32(BigInt(bytes.toArray).toInt)
}
@ -294,7 +299,7 @@ object Int64 extends Factory[Int64] with BaseNumbers[Int64] {
lazy val min = Int64(-9223372036854775808L)
lazy val max = Int64(9223372036854775807L)
override def fromBytes(bytes: Seq[Byte]): Int64 = {
override def fromBytes(bytes: scodec.bits.ByteVector): Int64 = {
require(bytes.size <= 8, "We cannot have an Int64 be larger than 8 bytes")
Int64(BigInt(bytes.toArray).toLong)
}
@ -302,4 +307,4 @@ object Int64 extends Factory[Int64] with BaseNumbers[Int64] {
def apply(long: Long): Int64 = Int64(BigInt(long))
def apply(bigInt: BigInt): Int64 = Int64Impl(bigInt)
}
}

View file

@ -8,6 +8,7 @@ import org.bitcoins.core.protocol.script._
import org.bitcoins.core.script.constant.ScriptConstant
import org.bitcoins.core.serializers.script.ScriptParser
import org.bitcoins.core.util._
import scodec.bits.ByteVector
import scala.annotation.tailrec
import scala.util.{ Failure, Success, Try }
@ -84,7 +85,10 @@ sealed abstract class Bech32Address extends BitcoinAddress {
Bech32Address.fromStringToWitSPK(value).get
}
override def hash: Sha256Digest = Sha256Digest(scriptPubKey.witnessProgram.flatMap(_.bytes))
override def hash: Sha256Digest = {
val byteVector = BitcoinSUtil.toByteVector(scriptPubKey.witnessProgram)
Sha256Digest(byteVector)
}
override def toString = "Bech32Address(" + value + ")"
@ -134,12 +138,12 @@ object Bech32Address extends AddressFactory[Bech32Address] {
}
def hrpExpand(hrp: HumanReadablePart): Seq[UInt8] = {
val x: Seq[Byte] = hrp.bytes.map { b: Byte =>
val x: scodec.bits.ByteVector = hrp.bytes.map { b: Byte =>
(b >> 5).toByte
}
val withZero: Seq[Byte] = x ++ Seq(0.toByte)
val withZero: scodec.bits.ByteVector = x ++ scodec.bits.ByteVector.low(1)
val y: Seq[Byte] = hrp.bytes.map { char =>
val y: scodec.bits.ByteVector = hrp.bytes.map { char =>
(char & 0x1f).toByte
}
val result = UInt8.toUInt8s(withZero ++ y)
@ -167,7 +171,7 @@ object Bech32Address extends AddressFactory[Bech32Address] {
chk
}
def verifyChecksum(hrp: HumanReadablePart, data: Seq[Byte]): Boolean = {
def verifyChecksum(hrp: HumanReadablePart, data: scodec.bits.ByteVector): Boolean = {
val u8s = UInt8.toUInt8s(data)
verifyCheckSum(hrp, u8s)
}
@ -231,15 +235,15 @@ object Bech32Address extends AddressFactory[Bech32Address] {
} else {
val hrpValid = checkHrpValidity(hrp)
val dataValid = checkDataValidity(data)
val isChecksumValid: Try[Seq[Byte]] = hrpValid.flatMap { h =>
val isChecksumValid: Try[scodec.bits.ByteVector] = hrpValid.flatMap { h =>
dataValid.flatMap { d =>
if (verifyChecksum(h, d)) {
if (d.size < 6) Success(Nil)
if (d.size < 6) Success(ByteVector.empty)
else Success(d.take(d.size - 6))
} else Failure(new IllegalArgumentException("Checksum was invalid on the bech32 address"))
}
}
isChecksumValid.flatMap { d: Seq[Byte] =>
isChecksumValid.flatMap { d: scodec.bits.ByteVector =>
val u8s = UInt8.toUInt8s(d)
hrpValid.map(h => Bech32Address(h, u8s))
}
@ -286,9 +290,9 @@ object Bech32Address extends AddressFactory[Bech32Address] {
* Takes in the data portion of a bech32 address and decodes it to a byte array
* It also checks the validity of the data portion according to BIP173
*/
def checkDataValidity(data: String): Try[Seq[Byte]] = {
def checkDataValidity(data: String): Try[scodec.bits.ByteVector] = {
@tailrec
def loop(remaining: List[Char], accum: Seq[Byte], hasUpper: Boolean, hasLower: Boolean): Try[Seq[Byte]] = remaining match {
def loop(remaining: List[Char], accum: scodec.bits.ByteVector, hasUpper: Boolean, hasLower: Boolean): Try[scodec.bits.ByteVector] = remaining match {
case Nil => Success(accum.reverse)
case h :: t =>
if (!charset.contains(h.toLower)) {
@ -303,7 +307,8 @@ object Bech32Address extends AddressFactory[Bech32Address] {
}
}
}
val payload: Try[Seq[Byte]] = loop(data.toCharArray.toList, Nil, false, false)
val payload: Try[scodec.bits.ByteVector] = loop(data.toCharArray.toList, ByteVector.empty,
false, false)
payload
}
@ -331,9 +336,9 @@ object P2PKHAddress extends AddressFactory[P2PKHAddress] {
}
override def fromString(address: String): Try[P2PKHAddress] = {
val decodeCheckP2PKH: Try[Seq[Byte]] = Base58.decodeCheck(address)
val decodeCheckP2PKH: Try[scodec.bits.ByteVector] = Base58.decodeCheck(address)
decodeCheckP2PKH.flatMap { bytes =>
val networkBytes: Option[(NetworkParameters, Seq[Byte])] = Networks.knownNetworks.map(n => (n, n.p2pkhNetworkByte))
val networkBytes: Option[(NetworkParameters, scodec.bits.ByteVector)] = Networks.knownNetworks.map(n => (n, n.p2pkhNetworkByte))
.find {
case (_, bs) =>
bytes.startsWith(bs)
@ -382,9 +387,9 @@ object P2SHAddress extends AddressFactory[P2SHAddress] {
def apply(hash: Sha256Hash160Digest, network: NetworkParameters): P2SHAddress = P2SHAddressImpl(hash, network)
override def fromString(address: String): Try[P2SHAddress] = {
val decodeCheckP2SH: Try[Seq[Byte]] = Base58.decodeCheck(address)
val decodeCheckP2SH: Try[scodec.bits.ByteVector] = Base58.decodeCheck(address)
decodeCheckP2SH.flatMap { bytes =>
val networkBytes: Option[(NetworkParameters, Seq[Byte])] = Networks.knownNetworks.map(n => (n, n.p2shNetworkByte))
val networkBytes: Option[(NetworkParameters, scodec.bits.ByteVector)] = Networks.knownNetworks.map(n => (n, n.p2shNetworkByte))
.find {
case (_, bs) =>
bytes.startsWith(bs)
@ -452,14 +457,14 @@ object BitcoinAddress extends AddressFactory[BitcoinAddress] {
object Address extends AddressFactory[Address] {
def fromBytes(bytes: Seq[Byte]): Try[Address] = {
def fromBytes(bytes: scodec.bits.ByteVector): Try[Address] = {
val encoded = Base58.encode(bytes)
BitcoinAddress.fromString(encoded)
}
def fromHex(hex: String): Try[Address] = fromBytes(BitcoinSUtil.decodeHex(hex))
def apply(bytes: Seq[Byte]): Try[Address] = fromBytes(bytes)
def apply(bytes: scodec.bits.ByteVector): Try[Address] = fromBytes(bytes)
def apply(str: String): Try[Address] = fromString(str)
@ -472,4 +477,4 @@ object Address extends AddressFactory[Address] {
def apply(spk: ScriptPubKey, networkParameters: NetworkParameters): Try[Address] = {
fromScriptPubKey(spk, networkParameters)
}
}
}

View file

@ -4,6 +4,7 @@ import org.bitcoins.core.number.{ UInt32, UInt64 }
import org.bitcoins.core.protocol.script.{ ScriptPubKey, ScriptSignature }
import org.bitcoins.core.script.constant.ScriptNumberUtil
import org.bitcoins.core.util.{ BitcoinSUtil, Factory }
import scodec.bits.ByteVector
/**
* Created by chris on 7/14/15.
@ -25,7 +26,7 @@ sealed abstract class CompactSizeUInt extends NetworkElement {
case _ => "ff" + BitcoinSUtil.flipEndianness(num.hex)
}
def bytes: Seq[Byte] = BitcoinSUtil.decodeHex(hex)
def bytes: scodec.bits.ByteVector = BitcoinSUtil.decodeHex(hex)
def toLong: Long = num.toLong
@ -37,9 +38,9 @@ sealed abstract class CompactSizeUInt extends NetworkElement {
}
object CompactSizeUInt extends Factory[CompactSizeUInt] {
private case class CompactSizeUIntImpl(num: UInt64, override val size: Int) extends CompactSizeUInt
private case class CompactSizeUIntImpl(num: UInt64, override val size: Long) extends CompactSizeUInt
override def fromBytes(bytes: Seq[Byte]): CompactSizeUInt = {
override def fromBytes(bytes: scodec.bits.ByteVector): CompactSizeUInt = {
parseCompactSizeUInt(bytes)
}
@ -65,7 +66,7 @@ object CompactSizeUInt extends Factory[CompactSizeUInt] {
* sequence of bytes
* https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers.
*/
def calculateCompactSizeUInt(bytes: Seq[Byte]): CompactSizeUInt = {
def calculateCompactSizeUInt(bytes: scodec.bits.ByteVector): CompactSizeUInt = {
//means we can represent the number with a single byte
if (bytes.size <= 252) CompactSizeUInt(UInt64(bytes.size), 1)
// can be represented with two bytes
@ -75,7 +76,7 @@ object CompactSizeUInt extends Factory[CompactSizeUInt] {
else CompactSizeUInt(UInt64(bytes.size), 9)
}
def calc(bytes: Seq[Byte]): CompactSizeUInt = calculateCompactSizeUInt(bytes)
def calc(bytes: scodec.bits.ByteVector): CompactSizeUInt = calculateCompactSizeUInt(bytes)
/** Responsible for calculating what the [[CompactSizeUInt]] is for this hex string. */
def calculateCompactSizeUInt(hex: String): CompactSizeUInt = calculateCompactSizeUInt(BitcoinSUtil.decodeHex(hex))
@ -90,20 +91,21 @@ object CompactSizeUInt extends Factory[CompactSizeUInt] {
* Parses a [[CompactSizeUInt]] from a sequence of bytes
* [[https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers]]
*/
def parseCompactSizeUInt(bytes: Seq[Byte]): CompactSizeUInt = {
def parseCompactSizeUInt(bytes: scodec.bits.ByteVector): CompactSizeUInt = {
require(bytes.nonEmpty, "Cannot parse a VarInt if the byte array is size 0")
val firstByte = UInt64(ByteVector(bytes.head))
//8 bit number
if (UInt64(Seq(bytes.head)).toBigInt < 253)
CompactSizeUInt(UInt64(Seq(bytes.head)), 1)
if (firstByte.toInt < 253)
CompactSizeUInt(firstByte, 1)
//16 bit number
else if (UInt64(Seq(bytes.head)).toInt == 253) CompactSizeUInt(UInt64(bytes.slice(1, 3).reverse), 3)
else if (firstByte.toInt == 253) CompactSizeUInt(UInt64(bytes.slice(1, 3).reverse), 3)
//32 bit number
else if (UInt64(Seq(bytes.head)).toInt == 254) CompactSizeUInt(UInt64(bytes.slice(1, 5).reverse), 5)
else if (firstByte.toInt == 254) CompactSizeUInt(UInt64(bytes.slice(1, 5).reverse), 5)
//64 bit number
else CompactSizeUInt(UInt64(bytes.slice(1, 9).reverse), 9)
}
def parse(bytes: Seq[Byte]): CompactSizeUInt = parseCompactSizeUInt(bytes)
def parse(bytes: scodec.bits.ByteVector): CompactSizeUInt = parseCompactSizeUInt(bytes)
/**
* Returns the size of a VarInt in the number of bytes
@ -136,8 +138,8 @@ object CompactSizeUInt extends Factory[CompactSizeUInt] {
private def parseLong(hex: String): Long = java.lang.Long.parseLong(hex, 16)
private def parseLong(bytes: List[Byte]): Long = parseLong(BitcoinSUtil.encodeHex(bytes))
private def parseLong(bytes: scodec.bits.ByteVector): Long = parseLong(BitcoinSUtil.encodeHex(bytes))
private def parseLong(byte: Byte): Long = parseLong(List(byte))
private def parseLong(byte: Byte): Long = parseLong(ByteVector.fromByte(byte))
}

View file

@ -10,13 +10,13 @@ import org.bitcoins.core.util.{ BitcoinSLogger, BitcoinSUtil }
abstract class NetworkElement {
/** The size of the NetworkElement in bytes. */
def size: Int = bytes.size
def size: Long = bytes.size
/** The hexadecimal representation of the NetworkElement */
def hex: String = BitcoinSUtil.encodeHex(bytes)
/** The byte representation of the NetworkElement */
def bytes: Seq[Byte]
def bytes: scodec.bits.ByteVector
lazy val logger = BitcoinSLogger.logger
}

View file

@ -63,6 +63,6 @@ object Block extends Factory[Block] {
Block(blockHeader, txCount, transactions)
}
def fromBytes(bytes: Seq[Byte]): Block = RawBlockSerializer.read(bytes)
def fromBytes(bytes: scodec.bits.ByteVector): Block = RawBlockSerializer.read(bytes)
}
}

View file

@ -108,7 +108,7 @@ sealed trait BlockHeader extends NetworkElement {
*/
def hashBE: DoubleSha256Digest = hash.flip
override def bytes: Seq[Byte] = RawBlockHeaderSerializer.write(this)
override def bytes: scodec.bits.ByteVector = RawBlockHeaderSerializer.write(this)
}
@ -125,6 +125,6 @@ object BlockHeader extends Factory[BlockHeader] {
BlockHeaderImpl(version, previousBlockHash, merkleRootHash, time, nBits, nonce)
}
def fromBytes(bytes: Seq[Byte]): BlockHeader = RawBlockHeaderSerializer.read(bytes)
def fromBytes(bytes: scodec.bits.ByteVector): BlockHeader = RawBlockHeaderSerializer.read(bytes)
}
}

View file

@ -11,6 +11,7 @@ import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.script.constant.{ BytesToPushOntoStack, ScriptConstant, ScriptNumber }
import org.bitcoins.core.script.crypto.OP_CHECKSIG
import org.bitcoins.core.util.{ BitcoinSUtil, BitcoinScriptUtil }
import scodec.bits.ByteVector
/**
* Created by chris on 5/22/16.
@ -37,14 +38,14 @@ sealed abstract class ChainParams {
def requireStandardTransaction: Boolean = true
/** Takes in a [[Base58Type]] and returns its base58 prefix. */
def base58Prefix(base58: Base58Type): Seq[Byte] = base58Prefixes(base58)
def base58Prefix(base58: Base58Type): scodec.bits.ByteVector = base58Prefixes(base58)
/**
* The mapping from a [[Base58Type]]to a String.
* Base58 prefixes for various keys/hashes on the network.
* See: [[https://en.bitcoin.it/wiki/List_of_address_prefixes]].
*/
def base58Prefixes: Map[Base58Type, Seq[Byte]]
def base58Prefixes: Map[Base58Type, scodec.bits.ByteVector]
/**
* Creates the Genesis [[Block]] for this blockchain.
@ -76,7 +77,7 @@ sealed abstract class ChainParams {
*/
def createGenesisBlock(timestamp: String, scriptPubKey: ScriptPubKey, time: UInt32, nonce: UInt32, nBits: UInt32,
version: Int32, amount: CurrencyUnit): Block = {
val timestampBytes = timestamp.getBytes(StandardCharsets.UTF_8)
val timestampBytes = ByteVector(timestamp.getBytes(StandardCharsets.UTF_8))
//see https://bitcoin.stackexchange.com/questions/13122/scriptsig-coinbase-structure-of-the-genesis-block
//for a full breakdown of the genesis block & its script signature
val const = ScriptConstant(timestampBytes)
@ -101,13 +102,13 @@ object MainNetChainParams extends BitcoinChainParams {
override def genesisBlock: Block = createGenesisBlock(UInt32(1231006505), UInt32(2083236893), UInt32(0x1d00ffff), Int32.one, Satoshis(Int64(5000000000L)))
override def base58Prefixes: Map[Base58Type, Seq[Byte]] = Map(
override def base58Prefixes: Map[Base58Type, scodec.bits.ByteVector] = Map(
Base58Type.PubKeyAddress -> BitcoinSUtil.decodeHex("00"),
Base58Type.ScriptAddress -> BitcoinSUtil.decodeHex("05"),
Base58Type.SecretKey -> BitcoinSUtil.decodeHex("80"),
Base58Type.ExtPublicKey -> Seq(BitcoinSUtil.hexToByte("04"), BitcoinSUtil.hexToByte("88"),
Base58Type.ExtPublicKey -> ByteVector(BitcoinSUtil.hexToByte("04"), BitcoinSUtil.hexToByte("88"),
BitcoinSUtil.hexToByte("b2"), BitcoinSUtil.hexToByte("1e")),
Base58Type.ExtSecretKey -> Seq(BitcoinSUtil.hexToByte("04"), BitcoinSUtil.hexToByte("88"),
Base58Type.ExtSecretKey -> ByteVector(BitcoinSUtil.hexToByte("04"), BitcoinSUtil.hexToByte("88"),
BitcoinSUtil.hexToByte("ad"), BitcoinSUtil.hexToByte("e4")))
}
@ -117,20 +118,20 @@ object TestNetChainParams extends BitcoinChainParams {
override def genesisBlock: Block = createGenesisBlock(UInt32(1296688602), UInt32(414098458), UInt32(0x1d00ffff), Int32.one, Satoshis(Int64(5000000000L)))
override def base58Prefixes: Map[Base58Type, Seq[Byte]] = Map(
override def base58Prefixes: Map[Base58Type, scodec.bits.ByteVector] = Map(
Base58Type.PubKeyAddress -> BitcoinSUtil.decodeHex("6f"),
Base58Type.ScriptAddress -> BitcoinSUtil.decodeHex("c4"),
Base58Type.SecretKey -> BitcoinSUtil.decodeHex("ef"),
Base58Type.ExtPublicKey -> Seq(BitcoinSUtil.hexToByte("04"), BitcoinSUtil.hexToByte("35"),
Base58Type.ExtPublicKey -> ByteVector(BitcoinSUtil.hexToByte("04"), BitcoinSUtil.hexToByte("35"),
BitcoinSUtil.hexToByte("87"), BitcoinSUtil.hexToByte("cf")),
Base58Type.ExtSecretKey -> Seq(BitcoinSUtil.hexToByte("04"), BitcoinSUtil.hexToByte("35"),
Base58Type.ExtSecretKey -> ByteVector(BitcoinSUtil.hexToByte("04"), BitcoinSUtil.hexToByte("35"),
BitcoinSUtil.hexToByte("83"), BitcoinSUtil.hexToByte("94")))
}
object RegTestNetChainParams extends BitcoinChainParams {
override def networkId = "regtest"
override def genesisBlock: Block = createGenesisBlock(UInt32(1296688602), UInt32(2), UInt32(0x207fffff), Int32.one, Satoshis(Int64(5000000000L)))
override def base58Prefixes: Map[Base58Type, Seq[Byte]] = TestNetChainParams.base58Prefixes
override def base58Prefixes: Map[Base58Type, scodec.bits.ByteVector] = TestNetChainParams.base58Prefixes
}
sealed abstract class Base58Type
@ -140,4 +141,4 @@ object Base58Type {
case object SecretKey extends Base58Type
case object ExtPublicKey extends Base58Type
case object ExtSecretKey extends Base58Type
}
}

View file

@ -89,10 +89,10 @@ object MerkleBlock extends Factory[MerkleBlock] {
MerkleBlockImpl(blockHeader, txCount, partialMerkleTree)
}
def apply(blockHeader: BlockHeader, txCount: UInt32, hashes: Seq[DoubleSha256Digest], bits: Seq[Boolean]): MerkleBlock = {
def apply(blockHeader: BlockHeader, txCount: UInt32, hashes: Seq[DoubleSha256Digest], bits: scodec.bits.BitVector): MerkleBlock = {
val partialMerkleTree = PartialMerkleTree(txCount, hashes, bits)
MerkleBlock(blockHeader, txCount, partialMerkleTree)
}
def fromBytes(bytes: Seq[Byte]): MerkleBlock = RawMerkleBlockSerializer.read(bytes)
def fromBytes(bytes: scodec.bits.ByteVector): MerkleBlock = RawMerkleBlockSerializer.read(bytes)
}

View file

@ -3,6 +3,7 @@ package org.bitcoins.core.protocol.blockchain
import org.bitcoins.core.crypto.DoubleSha256Digest
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.util._
import scodec.bits.{ BitVector, ByteVector }
import scala.annotation.tailrec
import scala.math._
@ -46,7 +47,7 @@ sealed trait PartialMerkleTree extends BitcoinSLogger {
def tree: BinaryTree[DoubleSha256Digest]
/** A sequence representing if this node is the parent of another node that matched a txid */
def bits: Seq[Boolean]
def bits: scodec.bits.BitVector
/** The hashes used to create the binary tree */
def hashes: Seq[DoubleSha256Digest]
@ -56,7 +57,7 @@ sealed trait PartialMerkleTree extends BitcoinSLogger {
//TODO: This is some really ugly that isn't tail recursive, try to clean this up eventually
def loop(
subTree: BinaryTree[DoubleSha256Digest],
remainingBits: Seq[Boolean], height: Int, pos: Int, accumMatches: Seq[DoubleSha256Digest]): (Seq[DoubleSha256Digest], Seq[Boolean]) = {
remainingBits: scodec.bits.BitVector, height: Int, pos: Int, accumMatches: Seq[DoubleSha256Digest]): (Seq[DoubleSha256Digest], scodec.bits.BitVector) = {
if (height == maxHeight) extractLeafMatch(accumMatches, remainingBits, subTree)
else {
//means we have a nontxid node
@ -86,8 +87,8 @@ sealed trait PartialMerkleTree extends BitcoinSLogger {
}
/** Handles a leaf match when we are extracting matches from the partial merkle tree */
private def extractLeafMatch(accumMatches: Seq[DoubleSha256Digest], remainingBits: Seq[Boolean],
subTree: BinaryTree[DoubleSha256Digest]): (Seq[DoubleSha256Digest], Seq[Boolean]) = {
private def extractLeafMatch(accumMatches: Seq[DoubleSha256Digest], remainingBits: scodec.bits.BitVector,
subTree: BinaryTree[DoubleSha256Digest]): (Seq[DoubleSha256Digest], scodec.bits.BitVector) = {
if (remainingBits.head) {
//means we have a txid node that matched the filter
subTree match {
@ -108,7 +109,9 @@ object PartialMerkleTree {
private val logger = BitcoinSLogger.logger
private case class PartialMerkleTreeImpl(tree: BinaryTree[DoubleSha256Digest], transactionCount: UInt32,
bits: Seq[Boolean], hashes: Seq[DoubleSha256Digest]) extends PartialMerkleTree
bits: scodec.bits.BitVector, hashes: Seq[DoubleSha256Digest]) extends PartialMerkleTree {
require(bits.size % 8 == 0, "As per BIP37, bits must be padded to the nearest byte")
}
def apply(txMatches: Seq[(Boolean, DoubleSha256Digest)]): PartialMerkleTree = {
val txIds = txMatches.map(_._2)
@ -123,7 +126,7 @@ object PartialMerkleTree {
* @return the binary tree that represents the partial merkle tree, the bits needed to reconstruct this partial merkle tree, and the hashes needed to be inserted
* according to the flags inside of bits
*/
private def build(txMatches: Seq[(Boolean, DoubleSha256Digest)]): (Seq[Boolean], Seq[DoubleSha256Digest]) = {
private def build(txMatches: Seq[(Boolean, DoubleSha256Digest)]): (scodec.bits.BitVector, Seq[DoubleSha256Digest]) = {
val maxHeight = calcMaxHeight(txMatches.size)
/**
@ -135,7 +138,7 @@ object PartialMerkleTree {
* @return the binary tree that represents the partial merkle tree, the bits needed to reconstruct this partial merkle tree, and the hashes needed to be inserted
* according to the flags inside of bits
*/
def loop(bits: Seq[Boolean], hashes: Seq[DoubleSha256Digest], height: Int, pos: Int): (Seq[Boolean], Seq[DoubleSha256Digest]) = {
def loop(bits: scodec.bits.BitVector, hashes: Seq[DoubleSha256Digest], height: Int, pos: Int): (scodec.bits.BitVector, Seq[DoubleSha256Digest]) = {
val parentOfMatch = matchesTx(maxHeight, maxHeight - height, pos, txMatches)
val newBits = parentOfMatch +: bits
if (height == 0 || !parentOfMatch) {
@ -153,11 +156,11 @@ object PartialMerkleTree {
} else (leftBits, leftHashes)
}
}
val (bits, hashes) = loop(Nil, Nil, maxHeight, 0)
val (bits, hashes) = loop(BitVector.empty, Nil, maxHeight, 0)
//pad the bit array to the nearest byte as required by BIP37
val bitsNeeded = if ((bits.size % 8) == 0) 0 else 8 - (bits.size % 8)
val paddingBits = for { _ <- 0 until bitsNeeded } yield false
(bits.reverse ++ paddingBits, hashes.reverse)
val bitsNeeded = if (bits.size % 8 == 0) 0 else (8 - (bits.size % 8)) + bits.size
val paddedBits = if (bitsNeeded == 0) bits else bits.padLeft(bitsNeeded)
(paddedBits.reverse, hashes.reverse)
}
/** Checks if a node at given the given height and position matches a transaction in the sequence */
@ -201,7 +204,7 @@ object PartialMerkleTree {
* @param bits the bits used indicate the structure of the partial merkle tree
* @return
*/
def apply(transactionCount: UInt32, hashes: Seq[DoubleSha256Digest], bits: Seq[Boolean]): PartialMerkleTree = {
def apply(transactionCount: UInt32, hashes: Seq[DoubleSha256Digest], bits: scodec.bits.BitVector): PartialMerkleTree = {
val tree = reconstruct(transactionCount.toInt, hashes, bits)
PartialMerkleTree(tree, transactionCount, bits, hashes)
}
@ -215,7 +218,7 @@ object PartialMerkleTree {
* @param bits the path to the matches in the partial merkle tree
* @param hashes the hashes used to reconstruct the binary tree according to [[bits]]
*/
def apply(tree: BinaryTree[DoubleSha256Digest], transactionCount: UInt32, bits: Seq[Boolean], hashes: Seq[DoubleSha256Digest]): PartialMerkleTree = {
def apply(tree: BinaryTree[DoubleSha256Digest], transactionCount: UInt32, bits: scodec.bits.BitVector, hashes: Seq[DoubleSha256Digest]): PartialMerkleTree = {
PartialMerkleTreeImpl(tree, transactionCount, bits, hashes)
}
@ -224,10 +227,10 @@ object PartialMerkleTree {
* [[https://bitcoin.org/en/developer-reference#parsing-a-merkleblock-message]]
* [[https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L96]]
*/
private def reconstruct(numTransaction: Int, hashes: Seq[DoubleSha256Digest], bits: Seq[Boolean]): BinaryTree[DoubleSha256Digest] = {
private def reconstruct(numTransaction: Int, hashes: Seq[DoubleSha256Digest], bits: scodec.bits.BitVector): BinaryTree[DoubleSha256Digest] = {
val maxHeight = calcMaxHeight(numTransaction)
//TODO: Optimize to tailrec function
def loop(remainingHashes: Seq[DoubleSha256Digest], remainingMatches: Seq[Boolean], height: Int, pos: Int): (BinaryTree[DoubleSha256Digest], Seq[DoubleSha256Digest], Seq[Boolean]) = {
def loop(remainingHashes: Seq[DoubleSha256Digest], remainingMatches: BitVector, height: Int, pos: Int): (BinaryTree[DoubleSha256Digest], Seq[DoubleSha256Digest], scodec.bits.BitVector) = {
if (height == maxHeight) {
//means we have a txid node
(
@ -241,7 +244,7 @@ object PartialMerkleTree {
val leftNodePos = pos * 2
val rightNodePos = (pos * 2) + 1
val (leftNode, leftRemainingHashes, leftRemainingBits) = loop(remainingHashes, remainingMatches.tail, nextHeight, leftNodePos)
val (rightNode, rightRemainingHashes, rightRemainingBits) =
val (rightNode, rightRemainingHashes, rightRemainingBits) = {
if (existsRightSubTree(pos, numTransaction, maxHeight, height)) {
val (rightNode, rightRemainingHashes, rightRemainingBits) =
loop(leftRemainingHashes, leftRemainingBits, nextHeight, rightNodePos)
@ -254,13 +257,18 @@ object PartialMerkleTree {
}
(rightNode, rightRemainingHashes, rightRemainingBits)
} else (leftNode, leftRemainingHashes, leftRemainingBits)
}
val nodeHash = CryptoUtil.doubleSHA256(leftNode.value.get.bytes ++ rightNode.value.get.bytes)
val node = Node(nodeHash, leftNode, rightNode)
(node, rightRemainingHashes, rightRemainingBits)
} else (Leaf(remainingHashes.head), remainingHashes.tail, remainingMatches.tail)
} else {
(Leaf(remainingHashes.head), remainingHashes.tail, remainingMatches.tail)
}
}
}
val (tree, remainingHashes, remainingBits) = loop(hashes, bits, 0, 0)
//require(remainingBits.isEmpty, s"Remainging bits should be empty, got ${remainingBits}")
//we must have used all the hashes provided to us to reconstruct the partial merkle tree as per BIP37
require(remainingHashes.size == 0, "We should not have any left over hashes after building our partial merkle tree, got: " + remainingHashes)
//we must not have any matches remaining, unless the remaining bits were use to pad our byte vector to 8 bits
@ -294,7 +302,7 @@ object PartialMerkleTree {
* in a byte array when reconstruction a partial merkle tree
* [[https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L174-L175]]
*/
private def usedAllBits(bits: Seq[Boolean], remainingBits: Seq[Boolean]): Boolean = {
private def usedAllBits(bits: scodec.bits.BitVector, remainingBits: scodec.bits.BitVector): Boolean = {
val bitsUsed = bits.size - remainingBits.size
((bitsUsed + 7) / 8) == ((bits.size + 7) / 8)
}

View file

@ -11,10 +11,10 @@ import org.bitcoins.core.util.{ BitcoinSUtil, Factory }
trait ScriptFactory[T] extends Factory[T] {
/** Builds a script from the given asm with the given constructor if the invariant holds true, else throws an error */
def buildScript(asm: Seq[ScriptToken], constructor: Seq[Byte] => T,
def buildScript(asm: Seq[ScriptToken], constructor: scodec.bits.ByteVector => T,
invariant: Seq[ScriptToken] => Boolean, errorMsg: String): T = {
if (invariant(asm)) {
val asmBytes = asm.flatMap(_.bytes)
val asmBytes = BitcoinSUtil.toByteVector(asm)
val compactSizeUInt = CompactSizeUInt.calc(asmBytes)
constructor(compactSizeUInt.bytes ++ asmBytes)
} else throw new IllegalArgumentException(errorMsg)
@ -23,7 +23,7 @@ trait ScriptFactory[T] extends Factory[T] {
/** Creates a T from the given [[ScriptToken]]s */
def fromAsm(asm: Seq[ScriptToken]): T
def fromBytes(bytes: Seq[Byte]): T = {
def fromBytes(bytes: scodec.bits.ByteVector): T = {
val cpmct = CompactSizeUInt.parseCompactSizeUInt(bytes)
val (_, noCmpctUInt) = bytes.splitAt(cpmct.bytes.size)
val asm = ScriptParser.fromBytes(noCmpctUInt)
@ -37,7 +37,7 @@ trait ScriptFactory[T] extends Factory[T] {
* @param bytes
* @return
*/
def fromAsmBytes(bytes: Seq[Byte]): T = {
def fromAsmBytes(bytes: scodec.bits.ByteVector): T = {
val cmpct = CompactSizeUInt.calc(bytes)
val fullBytes = cmpct.bytes ++ bytes
fromBytes(fullBytes)

View file

@ -38,7 +38,7 @@ sealed trait ScriptPubKey extends NetworkElement {
* The byte representation of [[asm]], this does NOT have the bytes
* for the [[org.bitcoins.core.protocol.CompactSizeUInt]] in the [[org.bitcoins.core.protocol.script.ScriptPubKey]]
*/
lazy val asmBytes: Seq[Byte] = asm.flatMap(_.bytes)
lazy val asmBytes: scodec.bits.ByteVector = BitcoinSUtil.toByteVector(asm)
}
@ -52,7 +52,7 @@ sealed trait P2PKHScriptPubKey extends ScriptPubKey {
}
object P2PKHScriptPubKey extends ScriptFactory[P2PKHScriptPubKey] {
private case class P2PKHScriptPubKeyImpl(bytes: Seq[Byte]) extends P2PKHScriptPubKey {
private case class P2PKHScriptPubKeyImpl(bytes: scodec.bits.ByteVector) extends P2PKHScriptPubKey {
override def toString = "P2PKHScriptPubKeyImpl(" + hex + ")"
}
@ -131,7 +131,7 @@ sealed trait MultiSignatureScriptPubKey extends ScriptPubKey {
object MultiSignatureScriptPubKey extends ScriptFactory[MultiSignatureScriptPubKey] {
private case class MultiSignatureScriptPubKeyImpl(bytes: Seq[Byte]) extends MultiSignatureScriptPubKey {
private case class MultiSignatureScriptPubKeyImpl(bytes: scodec.bits.ByteVector) extends MultiSignatureScriptPubKey {
override def toString = "MultiSignatureScriptPubKeyImpl(" + hex + ")"
}
@ -228,7 +228,7 @@ sealed trait P2SHScriptPubKey extends ScriptPubKey {
}
object P2SHScriptPubKey extends ScriptFactory[P2SHScriptPubKey] {
private case class P2SHScriptPubKeyImpl(bytes: Seq[Byte]) extends P2SHScriptPubKey {
private case class P2SHScriptPubKeyImpl(bytes: scodec.bits.ByteVector) extends P2SHScriptPubKey {
override def toString = "P2SHScriptPubKeyImpl(" + hex + ")"
}
@ -267,7 +267,7 @@ sealed trait P2PKScriptPubKey extends ScriptPubKey {
object P2PKScriptPubKey extends ScriptFactory[P2PKScriptPubKey] {
private case class P2PKScriptPubKeyImpl(bytes: Seq[Byte]) extends P2PKScriptPubKey {
private case class P2PKScriptPubKeyImpl(bytes: scodec.bits.ByteVector) extends P2PKScriptPubKey {
override def toString = "P2PKScriptPubKeyImpl(" + hex + ")"
}
@ -335,7 +335,7 @@ object LockTimeScriptPubKey extends ScriptFactory[LockTimeScriptPubKey] {
sealed trait CLTVScriptPubKey extends LockTimeScriptPubKey
object CLTVScriptPubKey extends ScriptFactory[CLTVScriptPubKey] {
private case class CLTVScriptPubKeyImpl(bytes: Seq[Byte]) extends CLTVScriptPubKey {
private case class CLTVScriptPubKeyImpl(bytes: scodec.bits.ByteVector) extends CLTVScriptPubKey {
override def toString = "CLTVScriptPubKeyImpl(" + hex + ")"
}
@ -405,7 +405,7 @@ object CLTVScriptPubKey extends ScriptFactory[CLTVScriptPubKey] {
sealed trait CSVScriptPubKey extends LockTimeScriptPubKey
object CSVScriptPubKey extends ScriptFactory[CSVScriptPubKey] {
private case class CSVScriptPubKeyImpl(bytes: Seq[Byte]) extends CSVScriptPubKey {
private case class CSVScriptPubKeyImpl(bytes: scodec.bits.ByteVector) extends CSVScriptPubKey {
override def toString = "CSVScriptPubKeyImpl(" + hex + ")"
}
@ -456,7 +456,7 @@ object CSVScriptPubKey extends ScriptFactory[CSVScriptPubKey] {
sealed trait NonStandardScriptPubKey extends ScriptPubKey
object NonStandardScriptPubKey extends ScriptFactory[NonStandardScriptPubKey] {
private case class NonStandardScriptPubKeyImpl(bytes: Seq[Byte]) extends NonStandardScriptPubKey {
private case class NonStandardScriptPubKeyImpl(bytes: scodec.bits.ByteVector) extends NonStandardScriptPubKey {
override def toString = "NonStandardScriptPubKeyImpl(" + hex + ")"
}
@ -470,7 +470,7 @@ object NonStandardScriptPubKey extends ScriptFactory[NonStandardScriptPubKey] {
/** Represents the empty ScriptPubKey */
case object EmptyScriptPubKey extends ScriptPubKey {
override def bytes = Seq(0.toByte)
override def bytes = scodec.bits.ByteVector.low(1)
}
/** Factory companion object used to create ScriptPubKey objects */
@ -524,7 +524,7 @@ object WitnessScriptPubKey {
* [[https://github.com/bitcoin/bitcoin/blob/14d01309bed59afb08651f2b701ff90371b15b20/src/script/script.cpp#L223-L237]]
*/
def isWitnessScriptPubKey(asm: Seq[ScriptToken]): Boolean = {
val bytes = asm.flatMap(_.bytes)
val bytes = BitcoinSUtil.toByteVector(asm)
val firstOp = asm.headOption
if (bytes.size < 4 || bytes.size > 42) false
else if (!validWitVersions.contains(firstOp.getOrElse(OP_1NEGATE))) false
@ -562,15 +562,16 @@ sealed abstract class P2WPKHWitnessSPKV0 extends WitnessScriptPubKeyV0 {
}
object P2WPKHWitnessSPKV0 extends ScriptFactory[P2WPKHWitnessSPKV0] {
private case class P2WPKHWitnessSPKV0Impl(bytes: Seq[Byte]) extends P2WPKHWitnessSPKV0
private case class P2WPKHWitnessSPKV0Impl(bytes: scodec.bits.ByteVector) extends P2WPKHWitnessSPKV0
override def fromAsm(asm: Seq[ScriptToken]): P2WPKHWitnessSPKV0 = {
buildScript(asm, P2WPKHWitnessSPKV0Impl(_), isValid(_), s"Given asm was not a P2WPKHWitnessSPKV0, got $asm")
}
def isValid(asm: Seq[ScriptToken]): Boolean = {
val asmBytes = BitcoinSUtil.toByteVector(asm)
WitnessScriptPubKeyV0.isValid(asm) &&
asm.flatMap(_.bytes).size == 22
asmBytes.size == 22
}
/** Creates a P2WPKH witness script pubkey */
@ -593,15 +594,16 @@ sealed abstract class P2WSHWitnessSPKV0 extends WitnessScriptPubKeyV0 {
}
object P2WSHWitnessSPKV0 extends ScriptFactory[P2WSHWitnessSPKV0] {
private case class P2WSHWitnessSPKV0Impl(bytes: Seq[Byte]) extends P2WSHWitnessSPKV0
private case class P2WSHWitnessSPKV0Impl(bytes: scodec.bits.ByteVector) extends P2WSHWitnessSPKV0
override def fromAsm(asm: Seq[ScriptToken]): P2WSHWitnessSPKV0 = {
buildScript(asm, P2WSHWitnessSPKV0Impl(_), isValid(_), s"Given asm was not a P2WSHWitnessSPKV0, got $asm")
}
def isValid(asm: Seq[ScriptToken]): Boolean = {
val asmBytes = BitcoinSUtil.toByteVector(asm)
WitnessScriptPubKeyV0.isValid(asm) &&
asm.flatMap(_.bytes).size == 34
asmBytes.size == 34
}
def apply(spk: ScriptPubKey): P2WSHWitnessSPKV0 = {
@ -618,7 +620,7 @@ sealed trait UnassignedWitnessScriptPubKey extends WitnessScriptPubKey {
}
object UnassignedWitnessScriptPubKey extends ScriptFactory[UnassignedWitnessScriptPubKey] {
private case class UnassignedWitnessScriptPubKeyImpl(bytes: Seq[Byte]) extends UnassignedWitnessScriptPubKey {
private case class UnassignedWitnessScriptPubKeyImpl(bytes: scodec.bits.ByteVector) extends UnassignedWitnessScriptPubKey {
override def toString = "UnassignedWitnessScriptPubKeyImpl(" + hex + ")"
}
@ -642,7 +644,7 @@ sealed trait WitnessCommitment extends ScriptPubKey {
}
object WitnessCommitment extends ScriptFactory[WitnessCommitment] {
private case class WitnessCommitmentImpl(bytes: Seq[Byte]) extends WitnessCommitment {
private case class WitnessCommitmentImpl(bytes: scodec.bits.ByteVector) extends WitnessCommitment {
override def toString = "WitnessCommitmentImpl(" + hex + ")"
}
@ -666,9 +668,10 @@ object WitnessCommitment extends ScriptFactory[WitnessCommitment] {
if (asm.size < 3) false
else {
val minCommitmentSize = 38
val asmBytes = BitcoinSUtil.toByteVector(asm)
val Seq(opReturn, pushOp, constant) = asm.take(3)
opReturn == OP_RETURN && pushOp == BytesToPushOntoStack(36) &&
constant.hex.take(8) == commitmentHeader && asm.flatMap(_.bytes).size >= minCommitmentSize
constant.hex.take(8) == commitmentHeader && asmBytes.size >= minCommitmentSize
}
}
}
@ -700,7 +703,7 @@ sealed trait EscrowTimeoutScriptPubKey extends ScriptPubKey {
}
object EscrowTimeoutScriptPubKey extends ScriptFactory[EscrowTimeoutScriptPubKey] {
private case class EscrowTimeoutScriptPubKeyImpl(bytes: Seq[Byte]) extends EscrowTimeoutScriptPubKey {
private case class EscrowTimeoutScriptPubKeyImpl(bytes: scodec.bits.ByteVector) extends EscrowTimeoutScriptPubKey {
override def toString = "EscrowTimeoutScriptPubKeyImpl(" + hex + ")"
}

View file

@ -8,5 +8,5 @@ import org.bitcoins.core.script.constant._
sealed trait ScriptPubKeyUpdateIndicator
case class UpdateScriptPubKeyAsm(asm: Seq[ScriptToken]) extends ScriptPubKeyUpdateIndicator
case class UpdateScriptPubKeyBytes(bytes: Seq[Byte]) extends ScriptPubKeyUpdateIndicator
case class UpdateScriptPubKeyBytes(bytes: scodec.bits.ByteVector) extends ScriptPubKeyUpdateIndicator

View file

@ -5,6 +5,7 @@ import org.bitcoins.core.protocol.{ CompactSizeUInt, NetworkElement }
import org.bitcoins.core.script.constant._
import org.bitcoins.core.serializers.script.{ RawScriptSignatureParser, ScriptParser }
import org.bitcoins.core.util._
import scodec.bits.ByteVector
import scala.util.{ Failure, Success, Try }
@ -27,7 +28,7 @@ sealed abstract class ScriptSignature extends NetworkElement {
lazy val asm: Seq[ScriptToken] = ScriptParser.fromBytes(bytes.splitAt(compactSizeUInt.size.toInt)._2)
/** Byte vector for script program WITHOUT the [[CompactSizeUInt]], this is the raw byte vector that can be run */
lazy val asmBytes = asm.flatMap(_.bytes)
lazy val asmBytes: ByteVector = BitcoinSUtil.toByteVector(asm)
/**
* The digital signatures contained inside of the script signature
@ -46,7 +47,7 @@ sealed trait NonStandardScriptSignature extends ScriptSignature {
}
object NonStandardScriptSignature extends ScriptFactory[NonStandardScriptSignature] {
private case class NonStandardScriptSignatureImpl(bytes: Seq[Byte]) extends NonStandardScriptSignature {
private case class NonStandardScriptSignatureImpl(bytes: scodec.bits.ByteVector) extends NonStandardScriptSignature {
}
@ -78,7 +79,7 @@ sealed trait P2PKHScriptSignature extends ScriptSignature {
}
object P2PKHScriptSignature extends ScriptFactory[P2PKHScriptSignature] {
private case class P2PKHScriptSignatureImpl(bytes: Seq[Byte]) extends P2PKHScriptSignature
private case class P2PKHScriptSignatureImpl(bytes: scodec.bits.ByteVector) extends P2PKHScriptSignature
def fromAsm(asm: Seq[ScriptToken]): P2PKHScriptSignature = {
buildScript(asm, P2PKHScriptSignatureImpl(_), isP2PKHScriptSig(_), "Given asm was not a P2PKHScriptSignature, got: " + asm)
@ -167,7 +168,7 @@ sealed trait P2SHScriptSignature extends ScriptSignature {
}
object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] {
private case class P2SHScriptSignatureImpl(bytes: Seq[Byte]) extends P2SHScriptSignature
private case class P2SHScriptSignatureImpl(bytes: scodec.bits.ByteVector) extends P2SHScriptSignature
def apply(scriptSig: ScriptSignature, redeemScript: ScriptPubKey): P2SHScriptSignature = {
//we need to calculate the size of the redeemScript and add the corresponding push op
@ -242,7 +243,7 @@ sealed trait MultiSignatureScriptSignature extends ScriptSignature {
object MultiSignatureScriptSignature extends ScriptFactory[MultiSignatureScriptSignature] {
private case class MultiSignatureScriptSignatureImpl(bytes: Seq[Byte]) extends MultiSignatureScriptSignature
private case class MultiSignatureScriptSignatureImpl(bytes: scodec.bits.ByteVector) extends MultiSignatureScriptSignature
def apply(signatures: Seq[ECDigitalSignature]): MultiSignatureScriptSignature = {
val sigsPushOpsPairs: Seq[Seq[ScriptToken]] = for {
@ -298,7 +299,7 @@ sealed trait P2PKScriptSignature extends ScriptSignature {
}
object P2PKScriptSignature extends ScriptFactory[P2PKScriptSignature] {
private case class P2PKScriptSignatureImpl(bytes: Seq[Byte]) extends P2PKScriptSignature
private case class P2PKScriptSignatureImpl(bytes: scodec.bits.ByteVector) extends P2PKScriptSignature
def apply(signature: ECDigitalSignature): P2PKScriptSignature = {
val pushOps = BitcoinScriptUtil.calculatePushOp(signature.bytes)
@ -331,9 +332,9 @@ sealed trait CLTVScriptSignature extends LockTimeScriptSignature {
}
object CLTVScriptSignature extends Factory[CLTVScriptSignature] {
private case class CLTVScriptSignatureImpl(bytes: Seq[Byte]) extends CLTVScriptSignature
private case class CLTVScriptSignatureImpl(bytes: scodec.bits.ByteVector) extends CLTVScriptSignature
override def fromBytes(bytes: Seq[Byte]): CLTVScriptSignature = {
override def fromBytes(bytes: scodec.bits.ByteVector): CLTVScriptSignature = {
CLTVScriptSignatureImpl(bytes)
}
@ -351,9 +352,9 @@ sealed trait CSVScriptSignature extends LockTimeScriptSignature {
}
object CSVScriptSignature extends Factory[CSVScriptSignature] {
private case class CSVScriptSignatureImpl(bytes: Seq[Byte]) extends CSVScriptSignature
private case class CSVScriptSignatureImpl(bytes: scodec.bits.ByteVector) extends CSVScriptSignature
override def fromBytes(bytes: Seq[Byte]): CSVScriptSignature = {
override def fromBytes(bytes: scodec.bits.ByteVector): CSVScriptSignature = {
CSVScriptSignatureImpl(bytes)
}
@ -369,7 +370,7 @@ object CSVScriptSignature extends Factory[CSVScriptSignature] {
/** Represents the empty script signature */
case object EmptyScriptSignature extends ScriptSignature {
def signatures = Nil
def bytes = Seq(0.toByte)
def bytes = scodec.bits.ByteVector.low(1)
}
object ScriptSignature extends ScriptFactory[ScriptSignature] {
@ -443,9 +444,9 @@ sealed trait EscrowTimeoutScriptSignature extends ScriptSignature {
}
object EscrowTimeoutScriptSignature extends Factory[EscrowTimeoutScriptSignature] {
private case class EscrowTimeoutScriptSignatureImpl(bytes: Seq[Byte]) extends EscrowTimeoutScriptSignature
private case class EscrowTimeoutScriptSignatureImpl(bytes: scodec.bits.ByteVector) extends EscrowTimeoutScriptSignature
override def fromBytes(bytes: Seq[Byte]): EscrowTimeoutScriptSignature = {
override def fromBytes(bytes: scodec.bits.ByteVector): EscrowTimeoutScriptSignature = {
//TODO: Come back and look at this, there is no invariant check here to see if the EscrowTiemoutScriptSig is valid
EscrowTimeoutScriptSignatureImpl(bytes)
}

View file

@ -4,6 +4,7 @@ import org.bitcoins.core.crypto.{ ECDigitalSignature, ECPublicKey, EmptyDigitalS
import org.bitcoins.core.protocol.{ CompactSizeUInt, NetworkElement }
import org.bitcoins.core.serializers.script.RawScriptWitnessParser
import org.bitcoins.core.util.{ BitcoinSLogger, BitcoinSUtil, BitcoinScriptUtil }
import scodec.bits.ByteVector
/**
* Created by chris on 11/10/16.
@ -13,7 +14,7 @@ import org.bitcoins.core.util.{ BitcoinSLogger, BitcoinSUtil, BitcoinScriptUtil
sealed abstract class ScriptWitness extends NetworkElement {
/** The byte vectors that are placed on to the stack when evaluating a witness program */
def stack: Seq[Seq[Byte]]
def stack: Seq[scodec.bits.ByteVector]
override def bytes = RawScriptWitnessParser.write(this)
}
@ -21,7 +22,7 @@ sealed abstract class ScriptWitness extends NetworkElement {
case object EmptyScriptWitness extends ScriptWitness {
override def stack = Nil
override def bytes = Seq(0.toByte)
override def bytes = scodec.bits.ByteVector.low(1)
}
sealed abstract class ScriptWitnessV0 extends ScriptWitness
@ -36,17 +37,17 @@ sealed abstract class P2WPKHWitnessV0 extends ScriptWitness {
def pubKey: ECPublicKey = ECPublicKey(stack.head)
def signature: ECDigitalSignature = stack(1) match {
case Nil => EmptyDigitalSignature
case bytes: Seq[Byte] => ECDigitalSignature(bytes)
case ByteVector.empty => EmptyDigitalSignature
case bytes: scodec.bits.ByteVector => ECDigitalSignature(bytes)
}
override def toString = "P2WPKHWitnessV0(" + stack.map(BitcoinSUtil.encodeHex(_)).toString + ")"
}
object P2WPKHWitnessV0 {
private case class P2WPKHWitnessV0Impl(stack: Seq[Seq[Byte]]) extends P2WPKHWitnessV0
private case class P2WPKHWitnessV0Impl(stack: Seq[scodec.bits.ByteVector]) extends P2WPKHWitnessV0
private def apply(stack: Seq[Seq[Byte]]): P2WPKHWitnessV0 = P2WPKHWitnessV0Impl(stack)
private def apply(stack: Seq[scodec.bits.ByteVector]): P2WPKHWitnessV0 = P2WPKHWitnessV0Impl(stack)
def apply(pubKey: ECPublicKey): P2WPKHWitnessV0 = {
P2WPKHWitnessV0(pubKey, EmptyDigitalSignature)
@ -72,7 +73,7 @@ sealed abstract class P2WSHWitnessV0 extends ScriptWitness {
}
object P2WSHWitnessV0 {
private case class P2WSHWitnessV0Impl(stack: Seq[Seq[Byte]]) extends P2WSHWitnessV0
private case class P2WSHWitnessV0Impl(stack: Seq[scodec.bits.ByteVector]) extends P2WSHWitnessV0
def apply(spk: ScriptPubKey): P2WSHWitnessV0 = {
P2WSHWitnessV0(spk, EmptyScriptSignature)
@ -84,26 +85,31 @@ object P2WSHWitnessV0 {
val minimalIf = BitcoinScriptUtil.minimalIfOp(scriptSig.asm)
val noPushOps = BitcoinScriptUtil.filterPushOps(minimalIf)
val minimalDummy = BitcoinScriptUtil.minimalDummy(noPushOps).reverse
val stack: Seq[Seq[Byte]] = spk.asmBytes +: minimalDummy.map(_.bytes)
val stack: Seq[scodec.bits.ByteVector] = spk.asmBytes +: minimalDummy.map(_.bytes)
P2WSHWitnessV0(stack)
}
private def apply(stack: Seq[Seq[Byte]]): P2WSHWitnessV0 = {
private def apply(stack: Seq[scodec.bits.ByteVector]): P2WSHWitnessV0 = {
P2WSHWitnessV0Impl(stack)
}
def apply(spk: ScriptPubKey, stack: Seq[Seq[Byte]]): P2WSHWitnessV0 = {
val fullStack: Seq[Seq[Byte]] = spk.asmBytes +: stack
def apply(spk: ScriptPubKey, stack: Seq[scodec.bits.ByteVector]): P2WSHWitnessV0 = {
val fullStack: Seq[scodec.bits.ByteVector] = spk.asmBytes +: stack
P2WSHWitnessV0(fullStack)
}
}
object ScriptWitness {
private val logger = BitcoinSLogger.logger
def apply(stack: Seq[Seq[Byte]]): ScriptWitness = {
def apply(stack: Seq[scodec.bits.ByteVector]): ScriptWitness = {
//TODO: eventually only compressed public keys will be allowed in v0 scripts
//https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#restrictions-on-public-key-type
val isPubKey = stack.headOption.isDefined && ECPublicKey.isFullyValid(stack.head) && (stack.head.size == 33 || stack.head.size == 65)
val isPubKey = {
stack.headOption.isDefined &&
ECPublicKey.isFullyValid(stack.head) &&
(stack.head.size == 33
|| stack.head.size == 65)
}
if (stack.isEmpty) {
EmptyScriptWitness
} else if (isPubKey && stack.size == 2) {
@ -126,4 +132,4 @@ object ScriptWitness {
}
}
}
}
}

View file

@ -28,7 +28,7 @@ case object WitnessVersion0 extends WitnessVersion {
/** Rebuilds a witness version 0 program, see BIP141 */
override def rebuild(scriptWitness: ScriptWitness, witnessProgram: Seq[ScriptToken]): Either[(Seq[ScriptToken], ScriptPubKey), ScriptError] = {
val programBytes = witnessProgram.flatMap(_.bytes)
val programBytes = BitcoinSUtil.toByteVector(witnessProgram)
programBytes.size match {
case 20 =>
//p2wpkh

View file

@ -128,7 +128,7 @@ sealed abstract class WitnessTransaction extends Transaction {
object Transaction extends Factory[Transaction] {
def fromBytes(bytes: Seq[Byte]): Transaction = {
def fromBytes(bytes: scodec.bits.ByteVector): Transaction = {
val wtxTry = Try(RawWitnessTransactionParser.read(bytes))
wtxTry match {
case Success(wtx) =>
@ -144,7 +144,7 @@ object BaseTransaction extends Factory[BaseTransaction] {
private case class BaseTransactionImpl(version: Int32, inputs: Seq[TransactionInput],
outputs: Seq[TransactionOutput], lockTime: UInt32) extends BaseTransaction
override def fromBytes(bytes: Seq[Byte]): BaseTransaction = RawBaseTransactionParser.read(bytes)
override def fromBytes(bytes: scodec.bits.ByteVector): BaseTransaction = RawBaseTransactionParser.read(bytes)
def apply(version: Int32, inputs: Seq[TransactionInput],
outputs: Seq[TransactionOutput], lockTime: UInt32): BaseTransaction = BaseTransactionImpl(version, inputs, outputs, lockTime)
@ -159,6 +159,6 @@ object WitnessTransaction extends Factory[WitnessTransaction] {
lockTime: UInt32, witness: TransactionWitness): WitnessTransaction =
WitnessTransactionImpl(version, inputs, outputs, lockTime, witness)
override def fromBytes(bytes: Seq[Byte]): WitnessTransaction = RawWitnessTransactionParser.read(bytes)
override def fromBytes(bytes: scodec.bits.ByteVector): WitnessTransaction = RawWitnessTransactionParser.read(bytes)
}
}

View file

@ -39,7 +39,7 @@ object TransactionInput extends Factory[TransactionInput] {
scriptSignature: ScriptSignature, sequence: UInt32) extends TransactionInput
def empty: TransactionInput = EmptyTransactionInput
def fromBytes(bytes: Seq[Byte]): TransactionInput = RawTransactionInputParser.read(bytes)
def fromBytes(bytes: scodec.bits.ByteVector): TransactionInput = RawTransactionInputParser.read(bytes)
def apply(outPoint: TransactionOutPoint, scriptSignature: ScriptSignature,
sequenceNumber: UInt32): TransactionInput = outPoint match {
@ -60,4 +60,4 @@ object CoinbaseInput {
def apply(scriptSignature: ScriptSignature, sequence: UInt32): CoinbaseInput = {
CoinbaseInputImpl(scriptSignature, sequence)
}
}
}

View file

@ -35,7 +35,7 @@ object TransactionOutPoint extends Factory[TransactionOutPoint] {
private case class TransactionOutPointImpl(txId: DoubleSha256Digest, vout: UInt32) extends TransactionOutPoint
def fromBytes(bytes: Seq[Byte]): TransactionOutPoint = RawTransactionOutPointParser.read(bytes)
def fromBytes(bytes: scodec.bits.ByteVector): TransactionOutPoint = RawTransactionOutPointParser.read(bytes)
def apply(txId: DoubleSha256Digest, index: UInt32): TransactionOutPoint = {
if (txId == EmptyTransactionOutPoint.txId && index == EmptyTransactionOutPoint.vout) {

View file

@ -28,9 +28,9 @@ case object EmptyTransactionOutput extends TransactionOutput {
object TransactionOutput extends Factory[TransactionOutput] {
private case class TransactionOutputImpl(value: CurrencyUnit, scriptPubKey: ScriptPubKey) extends TransactionOutput
def fromBytes(bytes: Seq[Byte]): TransactionOutput = RawTransactionOutputParser.read(bytes)
def fromBytes(bytes: scodec.bits.ByteVector): TransactionOutput = RawTransactionOutputParser.read(bytes)
def apply(currencyUnit: CurrencyUnit, scriptPubKey: ScriptPubKey): TransactionOutput = {
TransactionOutputImpl(currencyUnit, scriptPubKey)
}
}
}

View file

@ -18,7 +18,7 @@ sealed abstract class TransactionWitness extends NetworkElement {
/** Used to represent a transaction witness pre segwit, see BIP141 for details */
case object EmptyWitness extends TransactionWitness {
override def bytes = Seq(0.toByte)
override def bytes = scodec.bits.ByteVector.low(1)
override def witnesses = Nil
}
@ -46,9 +46,9 @@ object TransactionWitness {
}
TransactionWitness(replaced)
}
def fromBytes(bytes: Seq[Byte], numInputs: Int): TransactionWitness = RawTransactionWitnessParser.read(bytes, numInputs)
def fromBytes(bytes: scodec.bits.ByteVector, numInputs: Int): TransactionWitness = RawTransactionWitnessParser.read(bytes, numInputs)
def apply(bytes: Seq[Byte], numInputs: Int): TransactionWitness = fromBytes(bytes, numInputs)
def apply(bytes: scodec.bits.ByteVector, numInputs: Int): TransactionWitness = fromBytes(bytes, numInputs)
def apply(hex: String, numInputs: Int): TransactionWitness = fromBytes(BitcoinSUtil.decodeHex(hex), numInputs)
}
}

View file

@ -25,7 +25,7 @@ object BytesToPushOntoStack extends ScriptOperationFactory[BytesToPushOntoStack]
override def operations: Seq[BytesToPushOntoStack] =
(for { i <- 0 to 75 } yield BytesToPushOntoStackImpl(i))
def fromNumber(num: Int): BytesToPushOntoStack = {
def fromNumber(num: Long): BytesToPushOntoStack = {
if (num > 75) throw new IllegalArgumentException("We cannot have a BytesToPushOntoStack for greater than 75 bytes")
else {
val bytesToPushOntoStackOpt = operations.find(_.opCode == num)
@ -36,5 +36,5 @@ object BytesToPushOntoStack extends ScriptOperationFactory[BytesToPushOntoStack]
}
}
def apply(num: Int): BytesToPushOntoStack = fromNumber(num)
def apply(num: Long): BytesToPushOntoStack = fromNumber(num)
}

View file

@ -4,6 +4,7 @@ import org.bitcoins.core.script.ScriptProgram
import org.bitcoins.core.script.flag.ScriptFlagUtil
import org.bitcoins.core.script.result._
import org.bitcoins.core.util.{ BitcoinSLogger, BitcoinSUtil, BitcoinScriptUtil }
import scodec.bits.ByteVector
import scala.annotation.tailrec
@ -62,7 +63,7 @@ sealed abstract class ConstantInterpreter {
logger.debug("new script: " + newScript)
logger.debug("Bytes to push onto stack: " + bytesToPushOntoStack)
val constant: ScriptToken = if (bytesToPushOntoStack.size == 1) bytesToPushOntoStack.head
else ScriptConstant(BitcoinSUtil.flipEndianness(bytesToPushOntoStack.flatMap(_.bytes)))
else ScriptConstant(BitcoinSUtil.flipEndianness(BitcoinSUtil.toByteVector(bytesToPushOntoStack)))
logger.debug("Constant to be pushed onto stack: " + constant)
//check to see if we have the exact amount of bytes needed to be pushed onto the stack
@ -93,10 +94,13 @@ sealed abstract class ConstantInterpreter {
//for the case when we have the minimal data flag and the bytes to push onto stack is represented by the
//constant telling OP_PUSHDATA how many bytes need to go onto the stack
//for instance OP_PUSHDATA1 OP_0
val scriptNumOp = program.script(1).bytes match {
case h :: t => ScriptNumberOperation.fromNumber(h.toInt)
case Nil => None
val scriptNumOp = if (program.script(1).bytes.nonEmpty) {
val h = program.script(1).bytes.head
ScriptNumberOperation.fromNumber(h.toInt)
} else {
None
}
if (ScriptFlagUtil.requireMinimalData(program.flags) && program.script(1).bytes.size == 1 &&
scriptNumOp.isDefined) {
logger.error("We cannot use an OP_PUSHDATA operation for pushing " +

View file

@ -1,8 +1,10 @@
package org.bitcoins.core.script.constant
import org.bitcoins.core.number.Int64
import org.bitcoins.core.protocol.NetworkElement
import org.bitcoins.core.script.ScriptOperationFactory
import org.bitcoins.core.util.{ BitcoinSUtil, BitcoinScriptUtil, Factory }
import scodec.bits.ByteVector
import scala.util.{ Failure, Success, Try }
@ -14,12 +16,9 @@ import scala.util.{ Failure, Success, Try }
* This is the root class of Script. Every element in the Script language is a
* ScriptToken - think of this the same way you think about Object in Java.
*/
sealed trait ScriptToken {
/** The hexadecimal representation of this [[ScriptToken]]. */
def hex: String
sealed trait ScriptToken extends NetworkElement {
/** The byte representation of this [[ScriptToken]]. */
def bytes: Seq[Byte] = BitcoinSUtil.decodeHex(hex)
def bytes: scodec.bits.ByteVector
/** The conversion from the byte representation of a [[ScriptToken]] to a number. */
def toLong = ScriptNumberUtil.toLong(hex)
@ -32,7 +31,7 @@ sealed trait ScriptToken {
trait ScriptOperation extends ScriptToken {
def opCode: Int
override def hex: String = BitcoinSUtil.encodeHex(opCode.toByte)
def bytes: ByteVector = ByteVector.fromByte(opCode.toByte)
}
/** A constant in the Script language for instance as String or a number. */
@ -95,7 +94,7 @@ sealed abstract class ScriptNumber extends ScriptConstant {
object ScriptNumber extends Factory[ScriptNumber] {
/** Represents the number zero inside of bitcoin's script language. */
lazy val zero: ScriptNumber = ScriptNumberImpl(0, "")
lazy val zero: ScriptNumber = ScriptNumberImpl(0, ByteVector.empty)
/** Represents the number one inside of bitcoin's script language. */
lazy val one: ScriptNumber = ScriptNumberImpl(1)
/** Represents the number negative one inside of bitcoin's script language. */
@ -103,16 +102,16 @@ object ScriptNumber extends Factory[ScriptNumber] {
/** Bitcoin has a numbering system which has a negative zero. */
lazy val negativeZero: ScriptNumber = fromHex("80")
def fromBytes(bytes: Seq[Byte]) = {
def fromBytes(bytes: scodec.bits.ByteVector) = {
if (bytes.isEmpty) zero
else ScriptNumberImpl(ScriptNumberUtil.toLong(bytes), BitcoinSUtil.encodeHex(bytes))
else ScriptNumberImpl(ScriptNumberUtil.toLong(bytes), bytes)
}
def apply(underlying: Long): ScriptNumber = {
if (underlying == 0) zero else apply(ScriptNumberUtil.longToHex(underlying))
}
def apply(bytes: Seq[Byte], requireMinimal: Boolean): Try[ScriptNumber] = apply(BitcoinSUtil.encodeHex(bytes), requireMinimal)
def apply(bytes: scodec.bits.ByteVector, requireMinimal: Boolean): Try[ScriptNumber] = apply(BitcoinSUtil.encodeHex(bytes), requireMinimal)
def apply(hex: String, requireMinimal: Boolean): Try[ScriptNumber] = {
if (requireMinimal && !BitcoinScriptUtil.isShortestEncoding(hex)) {
@ -123,25 +122,22 @@ object ScriptNumber extends Factory[ScriptNumber] {
}
}
/**
* This represents a [[ScriptNumber]] inside of bitcoin
*
* @param underlying the number being represented
* @param hex the hex representation of the number - this can be different than the obvious value for
* the number. For instance we could have padded the number with another word of zeros
*/
private case class ScriptNumberImpl(underlying: Long, override val hex: String) extends ScriptNumber
private case class ScriptNumberImpl(underlying: Long, bytes: ByteVector) extends ScriptNumber
/**
* Companion object for [[ScriptNumberImpl]] that gives us access to more constructor types for the
* [[ScriptNumberImpl]] case class.
*/
private object ScriptNumberImpl {
def apply(hex: String): ScriptNumber = ScriptNumberImpl(ScriptNumberUtil.toLong(hex), hex)
def apply(hex: String): ScriptNumber = ScriptNumberImpl(ScriptNumberUtil.toLong(hex), BitcoinSUtil.decodeHex(hex))
def apply(bytes: Seq[Byte]): ScriptNumber = ScriptNumberImpl(ScriptNumberUtil.toLong(bytes))
def apply(bytes: scodec.bits.ByteVector): ScriptNumber = ScriptNumberImpl(ScriptNumberUtil.toLong(bytes))
def apply(underlying: Long): ScriptNumber = ScriptNumberImpl(underlying, ScriptNumberUtil.longToHex(underlying))
def apply(underlying: Long): ScriptNumber = {
ScriptNumberImpl(
underlying,
BitcoinSUtil.decodeHex(ScriptNumberUtil.longToHex(underlying)))
}
def apply(int64: Int64): ScriptNumber = ScriptNumberImpl(int64.toLong)
}
@ -342,11 +338,9 @@ object ScriptConstant extends Factory[ScriptConstant] {
lazy val negativeOne = ScriptConstant("81")
/** Creates a [[ScriptConstant]] from a sequence of bytes. */
def fromBytes(bytes: Seq[Byte]): ScriptConstant = ScriptConstantImpl(BitcoinSUtil.encodeHex(bytes))
def fromBytes(bytes: scodec.bits.ByteVector): ScriptConstant = ScriptConstantImpl(bytes)
/** Represent a public key or hash of a public key on our stack. */
private case class ScriptConstantImpl(hex: String) extends ScriptConstant {
def this(bytes: List[Byte]) = this(BitcoinSUtil.encodeHex(bytes))
}
private case class ScriptConstantImpl(bytes: ByteVector) extends ScriptConstant
}

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.script.constant
import org.bitcoins.core.util.BitcoinSUtil
import scodec.bits.ByteVector
/**
* Created by chris on 6/5/16.
@ -40,7 +41,7 @@ trait ScriptNumberUtil {
* @param bytes
* @return
*/
def toInt(bytes: Seq[Byte]): Int = {
def toInt(bytes: scodec.bits.ByteVector): Int = {
require(bytes.size <= 4, "We cannot have an integer with more than 4 bytes (32 bits)")
toLong(bytes).toInt
}
@ -54,18 +55,18 @@ trait ScriptNumberUtil {
* @param bytes
* @return
*/
def toLong(bytes: Seq[Byte]): Long = {
def toLong(bytes: scodec.bits.ByteVector): Long = {
val reversedBytes = bytes.reverse
if (bytes.size == 1 && bytes.head == -128) {
//the case for negative zero
0
} else if (isPositive(bytes)) {
if (firstByteAllZeros(reversedBytes.toList) && reversedBytes.size > 1) {
if (firstByteAllZeros(reversedBytes) && reversedBytes.size > 1) {
parseLong(reversedBytes.slice(1, reversedBytes.size))
} else parseLong(reversedBytes)
} else {
//remove the sign bit
val removedSignBit = changeSignBitToPositive(reversedBytes.toList)
val removedSignBit = changeSignBitToPositive(reversedBytes)
if (firstByteAllZeros(removedSignBit)) -parseLong(removedSignBit.slice(1, removedSignBit.size))
else -parseLong(removedSignBit)
}
@ -77,7 +78,7 @@ trait ScriptNumberUtil {
* @param bytes
* @return
*/
def isPositive(bytes: Seq[Byte]): Boolean = {
def isPositive(bytes: scodec.bits.ByteVector): Boolean = {
if (bytes.isEmpty) false
else {
val result: Int = bytes(bytes.size - 1) & 0x80
@ -92,19 +93,17 @@ trait ScriptNumberUtil {
* @param bytes
* @return
*/
def changeSignBitToPositive(bytes: Seq[Byte]): Seq[Byte] = {
def changeSignBitToPositive(bytes: scodec.bits.ByteVector): scodec.bits.ByteVector = {
val newByte: Byte = (bytes.head & 0x7F).toByte
(newByte :: bytes.tail.toList)
(newByte +: bytes.tail)
}
def firstByteAllZeros(bytes: Seq[Byte]): Boolean = {
def firstByteAllZeros(bytes: scodec.bits.ByteVector): Boolean = {
val lastByte = bytes.head
(lastByte & 0xFF) == 0
}
private def parseLong(bytes: Seq[Byte]): Long = parseLong(bytes.toList)
private def parseLong(bytes: List[Byte]): Long = parseLong(BitcoinSUtil.encodeHex(bytes))
private def parseLong(bytes: scodec.bits.ByteVector): Long = parseLong(BitcoinSUtil.encodeHex(bytes))
private def parseLong(hex: String): Long = java.lang.Long.parseLong(hex, 16)
@ -116,10 +115,10 @@ trait ScriptNumberUtil {
*/
def longToHex(long: Long): String = {
if (long > -1) {
val bytes = toByteSeq(long)
val bytes = toByteVec(long)
BitcoinSUtil.flipEndianness(BitcoinSUtil.encodeHex(bytes))
} else {
val bytes = toByteSeq(long.abs)
val bytes = toByteVec(long.abs)
//add sign bit
val negativeNumberBytes = changeSignBitToNegative(bytes)
val hex = BitcoinSUtil.encodeHex(negativeNumberBytes.reverse)
@ -127,7 +126,9 @@ trait ScriptNumberUtil {
}
}
def toByteSeq(long: Long): Seq[Byte] = BigInt(long).toByteArray
def toByteVec(long: Long): scodec.bits.ByteVector = {
ByteVector(BigInt(long).toByteArray)
}
/**
* Determines if a given hex string is a positive number
@ -139,22 +140,22 @@ trait ScriptNumberUtil {
def isNegative(hex: String): Boolean = isNegative(BitcoinSUtil.decodeHex(hex))
def isNegative(bytes: Seq[Byte]): Boolean = {
def isNegative(bytes: scodec.bits.ByteVector): Boolean = {
if (bytes.isEmpty) false else !isPositive(bytes)
}
def changeSignBitToPositive(hex: String): Seq[Byte] = changeSignBitToPositive(BitcoinSUtil.decodeHex(hex))
def changeSignBitToPositive(hex: String): scodec.bits.ByteVector = changeSignBitToPositive(BitcoinSUtil.decodeHex(hex))
def changeSignBitToNegative(hex: String): Seq[Byte] = changeSignBitToNegative(BitcoinSUtil.decodeHex(hex))
def changeSignBitToNegative(hex: String): scodec.bits.ByteVector = changeSignBitToNegative(BitcoinSUtil.decodeHex(hex))
def changeSignBitToNegative(bytes: Seq[Byte]): Seq[Byte] = {
def changeSignBitToNegative(bytes: scodec.bits.ByteVector): scodec.bits.ByteVector = {
val newByte = (bytes.head | 0x80).toByte
(newByte :: bytes.tail.toList)
(newByte +: bytes.tail)
}
def firstByteAllZeros(hex: String): Boolean = firstByteAllZeros(BitcoinSUtil.decodeHex(hex))
private def parseLong(byte: Byte): Long = parseLong(List(byte))
private def parseLong(byte: Byte): Long = parseLong(ByteVector.fromByte(byte))
}

View file

@ -21,31 +21,31 @@ sealed abstract class CryptoInterpreter {
/** The input is hashed twice: first with SHA-256 and then with RIPEMD-160. */
def opHash160(program: ScriptProgram): ScriptProgram = {
require(program.script.headOption.contains(OP_HASH160), "Script operation must be OP_HASH160")
executeHashFunction(program, CryptoUtil.sha256Hash160(_: Seq[Byte]))
executeHashFunction(program, CryptoUtil.sha256Hash160(_: scodec.bits.ByteVector))
}
/** The input is hashed using RIPEMD-160. */
def opRipeMd160(program: ScriptProgram): ScriptProgram = {
require(program.script.headOption.contains(OP_RIPEMD160), "Script operation must be OP_RIPEMD160")
executeHashFunction(program, CryptoUtil.ripeMd160(_: Seq[Byte]))
executeHashFunction(program, CryptoUtil.ripeMd160(_: scodec.bits.ByteVector))
}
/** The input is hashed using SHA-256. */
def opSha256(program: ScriptProgram): ScriptProgram = {
require(program.script.headOption.contains(OP_SHA256), "Script operation must be OP_SHA256")
executeHashFunction(program, CryptoUtil.sha256(_: Seq[Byte]))
executeHashFunction(program, CryptoUtil.sha256(_: scodec.bits.ByteVector))
}
/** The input is hashed two times with SHA-256. */
def opHash256(program: ScriptProgram): ScriptProgram = {
require(program.script.headOption.contains(OP_HASH256), "Script operation must be OP_HASH256")
executeHashFunction(program, CryptoUtil.doubleSHA256(_: Seq[Byte]))
executeHashFunction(program, CryptoUtil.doubleSHA256(_: scodec.bits.ByteVector))
}
/** The input is hashed using SHA-1. */
def opSha1(program: ScriptProgram): ScriptProgram = {
require(program.script.headOption.contains(OP_SHA1), "Script top must be OP_SHA1")
executeHashFunction(program, CryptoUtil.sha1(_: Seq[Byte]))
executeHashFunction(program, CryptoUtil.sha1(_: scodec.bits.ByteVector))
}
/**
@ -249,7 +249,7 @@ sealed abstract class CryptoInterpreter {
* @param hashFunction the hash function which needs to be used on the stack top (sha256,ripemd160,etc..)
* @return
*/
private def executeHashFunction(program: ScriptProgram, hashFunction: Seq[Byte] => HashDigest): ScriptProgram = {
private def executeHashFunction(program: ScriptProgram, hashFunction: scodec.bits.ByteVector => HashDigest): ScriptProgram = {
if (program.stack.nonEmpty) {
val stackTop = program.stack.head
val hash = ScriptConstant(hashFunction(stackTop.bytes).bytes)
@ -293,4 +293,4 @@ sealed abstract class CryptoInterpreter {
}
}
object CryptoInterpreter extends CryptoInterpreter
object CryptoInterpreter extends CryptoInterpreter

View file

@ -3,6 +3,7 @@ package org.bitcoins.core.script.crypto
import org.bitcoins.core.crypto.ECDigitalSignature
import org.bitcoins.core.number.Int32
import org.bitcoins.core.util.Factory
import scodec.bits.ByteVector
/**
* Created by chris on 1/18/16.
@ -13,12 +14,12 @@ sealed trait HashType {
}
object HashType extends Factory[HashType] {
def fromBytes(bytes: Seq[Byte]): HashType = {
def fromBytes(bytes: scodec.bits.ByteVector): HashType = {
val num = Int32(bytes)
fromNumber(num)
}
def fromByte(byte: Byte): HashType = fromBytes(Seq(byte))
def fromByte(byte: Byte): HashType = fromBytes(ByteVector.fromByte(byte))
def fromNumber(num: Int32): HashType = {
if (isSigHashNone(num)) {
@ -95,7 +96,7 @@ object HashType extends Factory[HashType] {
lazy val hashTypes = Seq(sigHashAll, sigHashNone, sigHashSingle, sigHashAnyoneCanPay,
sigHashNoneAnyoneCanPay, sigHashAllAnyoneCanPay, sigHashSingleAnyoneCanPay)
lazy val hashTypeBytes: Seq[Byte] = Seq(sigHashAllByte, sigHashSingleByte, sigHashNoneByte, sigHashAnyoneCanPayByte,
lazy val hashTypeBytes: Vector[Byte] = Vector(sigHashAllByte, sigHashSingleByte, sigHashNoneByte, sigHashAnyoneCanPayByte,
sigHashNoneAnyoneCanPayByte, sigHashSingleAnyoneCanPayByte, sigHashAllAnyoneCanPayByte)
def apply(num: Int32): HashType = fromNumber(num)

View file

@ -171,7 +171,7 @@ sealed abstract class ScriptInterpreter {
redeemScript match {
case w: WitnessScriptPubKey =>
val pushOp = BitcoinScriptUtil.calculatePushOp(redeemScriptBytes)
val expectedScriptBytes = pushOp.flatMap(_.bytes) ++ redeemScriptBytes
val expectedScriptBytes = BitcoinSUtil.toByteVector(pushOp) ++ redeemScriptBytes
val flags = scriptPubKeyExecutedProgram.flags
val segwitEnabled = ScriptFlagUtil.segWitEnabled(flags)
if (segwitEnabled && (scriptSig.asmBytes == expectedScriptBytes)) {
@ -301,11 +301,12 @@ sealed abstract class ScriptInterpreter {
private def loop(program: ScriptProgram, opCount: Int): ExecutedScriptProgram = {
logger.trace("Stack: " + program.stack)
logger.trace("Script: " + program.script)
val scriptByteVector = BitcoinSUtil.toByteVector(program.script)
if (opCount > maxScriptOps && !program.isInstanceOf[ExecutedScriptProgram]) {
logger.error("We have reached the maximum amount of script operations allowed")
logger.error("Here are the remaining operations in the script: " + program.script)
loop(ScriptProgram(program, ScriptErrorOpCount), opCount)
} else if (program.script.flatMap(_.bytes).size > 10000 && !program.isInstanceOf[ExecutedScriptProgram]) {
} else if (scriptByteVector.length > 10000 && !program.isInstanceOf[ExecutedScriptProgram]) {
logger.error("We cannot run a script that is larger than 10,000 bytes")
program match {
case p: PreExecutionScriptProgram =>

View file

@ -13,11 +13,8 @@ abstract class RawBitcoinSerializer[T] {
def read(hex: String): T = read(BitcoinSUtil.decodeHex(hex))
/** Reads in bytes and transforms it into the appropriate scala type T. */
def read(bytes: List[Byte]): T
/** Reads in bytes and transforms it into the appropriate scala type T. */
def read(bytes: Seq[Byte]): T = read(bytes.toList)
def read(bytes: scodec.bits.ByteVector): T
/** Takes a type T and writes it into the appropriate hexadecimal serialization for type T. */
def write(t: T): Seq[Byte]
def write(t: T): scodec.bits.ByteVector
}

View file

@ -3,6 +3,7 @@ package org.bitcoins.core.serializers
import org.bitcoins.core.number.UInt64
import org.bitcoins.core.protocol.{ CompactSizeUInt, NetworkElement }
import org.bitcoins.core.util.BitcoinSLogger
import scodec.bits.ByteVector
/**
* Created by chris on 2/18/16.
@ -14,10 +15,10 @@ sealed abstract class RawSerializerHelper {
* Used parse a byte sequence to a Seq[TransactionInput], Seq[TransactionOutput], etc
* Makes sure that we parse the correct amount of elements
*/
def parseCmpctSizeUIntSeq[T <: NetworkElement](bytes: Seq[Byte], constructor: Seq[Byte] => T): (Seq[T], Seq[Byte]) = {
def parseCmpctSizeUIntSeq[T <: NetworkElement](bytes: scodec.bits.ByteVector, constructor: scodec.bits.ByteVector => T): (Seq[T], scodec.bits.ByteVector) = {
val count = CompactSizeUInt.parse(bytes)
val payload = bytes.splitAt(count.size.toInt)._2
def loop(accum: Seq[T], remaining: Seq[Byte]): (Seq[T], Seq[Byte]) = {
def loop(accum: Seq[T], remaining: scodec.bits.ByteVector): (Seq[T], scodec.bits.ByteVector) = {
if (accum.size == count.num.toInt) {
(accum.reverse, remaining)
} else {
@ -32,12 +33,13 @@ sealed abstract class RawSerializerHelper {
(parsed, remaining)
}
/** Writes a Seq[TransactionInput]/Seq[TransactionOutput]/Seq[Transaction] -> Seq[Byte] */
def writeCmpctSizeUInt[T](ts: Seq[T], serializer: T => Seq[Byte]): Seq[Byte] = {
val serialized = ts.flatMap(serializer(_))
/** Writes a Seq[TransactionInput]/Seq[TransactionOutput]/Seq[Transaction] -> scodec.bits.ByteVector */
def writeCmpctSizeUInt[T](ts: Seq[T], serializer: T => scodec.bits.ByteVector): scodec.bits.ByteVector = {
val serializedSeq: Seq[ByteVector] = ts.map(serializer(_))
val serialized = serializedSeq.foldLeft(ByteVector.empty)(_ ++ _)
val cmpct = CompactSizeUInt(UInt64(ts.size))
cmpct.bytes ++ serialized
}
}
object RawSerializerHelper extends RawSerializerHelper
object RawSerializerHelper extends RawSerializerHelper

View file

@ -8,9 +8,9 @@ import org.bitcoins.core.number.Int64
*/
trait RawSatoshisSerializer extends RawBitcoinSerializer[Satoshis] {
def read(bytes: List[Byte]): Satoshis = Satoshis(Int64(bytes.reverse))
def read(bytes: scodec.bits.ByteVector): Satoshis = Satoshis(Int64(bytes.reverse))
def write(satoshis: Satoshis): Seq[Byte] = {
def write(satoshis: Satoshis): scodec.bits.ByteVector = {
Int64(satoshis.toLong).bytes.reverse
}

View file

@ -13,7 +13,7 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer
sealed abstract class RawBlockHeaderSerializer extends RawBitcoinSerializer[BlockHeader] {
/** Converts a list of bytes into a block header */
def read(bytes: List[Byte]): BlockHeader = {
def read(bytes: scodec.bits.ByteVector): BlockHeader = {
//version first 4 bytes
val version = Int32(bytes.take(4).reverse)
//previous header hash next 32 bytes
@ -35,7 +35,7 @@ sealed abstract class RawBlockHeaderSerializer extends RawBitcoinSerializer[Bloc
}
/** Serializes the BlockHeader to a byte array */
def write(blockHeader: BlockHeader): Seq[Byte] = {
def write(blockHeader: BlockHeader): scodec.bits.ByteVector = {
val version = blockHeader.version.bytes.reverse
val prevHash = blockHeader.previousBlockHash.bytes
@ -50,4 +50,4 @@ sealed abstract class RawBlockHeaderSerializer extends RawBitcoinSerializer[Bloc
}
object RawBlockHeaderSerializer extends RawBlockHeaderSerializer
object RawBlockHeaderSerializer extends RawBlockHeaderSerializer

View file

@ -12,15 +12,15 @@ import org.bitcoins.core.serializers.{ RawBitcoinSerializer, RawSerializerHelper
sealed abstract class RawBlockSerializer extends RawBitcoinSerializer[Block] {
/** Takes a list of bytes and converts it into a Block */
def read(bytes: List[Byte]): Block = {
def read(bytes: scodec.bits.ByteVector): Block = {
val blockHeader: BlockHeader = BlockHeader(bytes.take(80))
val txBytes: Seq[Byte] = bytes.splitAt(80)._2
val (transactions, _) = RawSerializerHelper.parseCmpctSizeUIntSeq[Transaction](txBytes, Transaction(_: Seq[Byte]))
val txBytes: scodec.bits.ByteVector = bytes.splitAt(80)._2
val (transactions, _) = RawSerializerHelper.parseCmpctSizeUIntSeq[Transaction](txBytes, Transaction(_: scodec.bits.ByteVector))
Block(blockHeader, transactions)
}
/** Takes in a block and converts it to a byte array */
def write(block: Block): Seq[Byte] = {
def write(block: Block): scodec.bits.ByteVector = {
val writtenHeader = block.blockHeader.bytes
val txBytes = RawSerializerHelper.writeCmpctSizeUInt(block.transactions, { tx: Transaction => tx.bytes })
writtenHeader ++ txBytes
@ -28,4 +28,4 @@ sealed abstract class RawBlockSerializer extends RawBitcoinSerializer[Block] {
}
object RawBlockSerializer extends RawBlockSerializer
object RawBlockSerializer extends RawBlockSerializer

View file

@ -6,6 +6,8 @@ import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.blockchain.MerkleBlock
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.util.BitcoinSUtil
import org.slf4j.LoggerFactory
import scodec.bits.{ BitVector, ByteVector }
import scala.annotation.tailrec
@ -15,7 +17,9 @@ import scala.annotation.tailrec
*/
sealed abstract class RawMerkleBlockSerializer extends RawBitcoinSerializer[MerkleBlock] {
def read(bytes: List[Byte]): MerkleBlock = {
private val logger = LoggerFactory.getLogger(this.getClass.getSimpleName)
def read(bytes: scodec.bits.ByteVector): MerkleBlock = {
val blockHeader = RawBlockHeaderSerializer.read(bytes.take(80))
val bytesAfterBlockHeaderParsing = bytes.slice(blockHeader.bytes.size, bytes.size)
val transactionCount = UInt32(bytesAfterBlockHeaderParsing.slice(0, 4).reverse)
@ -27,19 +31,26 @@ sealed abstract class RawMerkleBlockSerializer extends RawBitcoinSerializer[Merk
val (hashes, bytesAfterTxHashParsing) = parseTransactionHashes(bytesAfterHashCountParsing, hashCount)
val flagCount = CompactSizeUInt.parseCompactSizeUInt(bytesAfterTxHashParsing)
val flags = bytesAfterTxHashParsing.slice(flagCount.size.toInt, bytesAfterTxHashParsing.size)
val matches = BitcoinSUtil.bytesToBitVectors(flags).flatMap(_.reverse)
val matches = flags.toArray
.map(BitVector(_).reverse)
.foldLeft(BitVector.empty)(_ ++ _)
MerkleBlock(blockHeader, transactionCount, hashes, matches)
}
def write(merkleBlock: MerkleBlock): Seq[Byte] = {
def write(merkleBlock: MerkleBlock): scodec.bits.ByteVector = {
val partialMerkleTree = merkleBlock.partialMerkleTree
val bitVectors = parseToBytes(partialMerkleTree.bits)
val byteVectors: Seq[Byte] = BitcoinSUtil.bitVectorsToBytes(bitVectors)
val bitVectors = partialMerkleTree.bits
val byteVectors: scodec.bits.ByteVector = {
bitVectors.toByteArray
.map(BitVector(_).reverse)
.foldLeft(ByteVector.empty)(_ ++ _.bytes)
}
val flagCount = CompactSizeUInt(UInt64(Math.ceil(partialMerkleTree.bits.size.toDouble / 8).toInt))
val hashes: ByteVector = BitcoinSUtil.toByteVector(merkleBlock.hashes)
merkleBlock.blockHeader.bytes ++
merkleBlock.transactionCount.bytes.reverse ++
CompactSizeUInt(UInt64(merkleBlock.hashes.size)).bytes ++
merkleBlock.hashes.flatMap(_.bytes) ++ flagCount.bytes ++ byteVectors
hashes ++ flagCount.bytes ++ byteVectors
}
/**
@ -48,33 +59,15 @@ sealed abstract class RawMerkleBlockSerializer extends RawBitcoinSerializer[Merk
* @param hashCount the amount of tx hashes we need to parse from bytes
* @return the sequence of tx hashes and the remaining bytes to be parsed into a MerkleBlockMessage
*/
private def parseTransactionHashes(bytes: Seq[Byte], hashCount: CompactSizeUInt): (Seq[DoubleSha256Digest], Seq[Byte]) = {
private def parseTransactionHashes(bytes: scodec.bits.ByteVector, hashCount: CompactSizeUInt): (Seq[DoubleSha256Digest], scodec.bits.ByteVector) = {
@tailrec
def loop(remainingHashes: Long, remainingBytes: Seq[Byte],
accum: List[DoubleSha256Digest]): (Seq[DoubleSha256Digest], Seq[Byte]) = {
def loop(remainingHashes: Long, remainingBytes: scodec.bits.ByteVector,
accum: List[DoubleSha256Digest]): (Seq[DoubleSha256Digest], scodec.bits.ByteVector) = {
if (remainingHashes <= 0) (accum.reverse, remainingBytes)
else loop(remainingHashes - 1, remainingBytes.slice(32, remainingBytes.size), DoubleSha256Digest(remainingBytes.take(32)) :: accum)
}
loop(hashCount.num.toInt, bytes, Nil)
}
/** Parses a sequence of bits to a sequence of bit vectors grouped into bytes */
private def parseToBytes(bits: Seq[Boolean]): Seq[Seq[Boolean]] = {
@tailrec
def loop(remainingBits: Seq[Boolean], accum: Seq[Seq[Boolean]]): Seq[Seq[Boolean]] = remainingBits match {
case Nil => accum.reverse
case h :: t => accum.headOption match {
case None => loop(remainingBits, Nil +: accum)
case Some(bits) if bits.size == 8 =>
//if we have 8 bits in this sequence we need to create a new byte and prepend it to the accum
loop(remainingBits, Nil +: accum)
case Some(bits) =>
val newBits = h +: bits
loop(t, newBits +: accum.tail)
}
}
loop(bits, Seq(Nil))
}
}
object RawMerkleBlockSerializer extends RawMerkleBlockSerializer

View file

@ -4,6 +4,7 @@ import org.bitcoins.core.bloom.{ BloomFilter, BloomFlag }
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.RawBitcoinSerializer
import scodec.bits.ByteVector
/**
* Created by chris on 8/4/16.
@ -11,7 +12,7 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer
*/
sealed abstract class RawBloomFilterSerializer extends RawBitcoinSerializer[BloomFilter] {
override def read(bytes: List[Byte]): BloomFilter = {
override def read(bytes: scodec.bits.ByteVector): BloomFilter = {
val filterSize = CompactSizeUInt.parseCompactSizeUInt(bytes)
val filter = bytes.slice(filterSize.size.toInt, filterSize.size.toInt + filterSize.num.toInt)
val hashFuncsIndex = (filterSize.size + filterSize.num.toInt).toInt
@ -23,11 +24,11 @@ sealed abstract class RawBloomFilterSerializer extends RawBitcoinSerializer[Bloo
}
override def write(bloomFilter: BloomFilter): Seq[Byte] = {
override def write(bloomFilter: BloomFilter): scodec.bits.ByteVector = {
bloomFilter.filterSize.bytes ++ bloomFilter.data ++
bloomFilter.hashFuncs.bytes.reverse ++ bloomFilter.tweak.bytes.reverse ++
Seq(bloomFilter.flags.byte)
ByteVector.fromByte(bloomFilter.flags.byte)
}
}
object RawBloomFilterSerializer extends RawBloomFilterSerializer
object RawBloomFilterSerializer extends RawBloomFilterSerializer

View file

@ -12,7 +12,7 @@ import scala.util.Try
*/
trait RawScriptPubKeyParser extends RawBitcoinSerializer[ScriptPubKey] {
override def read(bytes: List[Byte]): ScriptPubKey = {
override def read(bytes: scodec.bits.ByteVector): ScriptPubKey = {
if (bytes.isEmpty) EmptyScriptPubKey
else {
val compactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(bytes)
@ -25,7 +25,7 @@ trait RawScriptPubKeyParser extends RawBitcoinSerializer[ScriptPubKey] {
}
}
override def write(scriptPubKey: ScriptPubKey): Seq[Byte] = scriptPubKey.bytes
override def write(scriptPubKey: ScriptPubKey): scodec.bits.ByteVector = scriptPubKey.bytes
}
object RawScriptPubKeyParser extends RawScriptPubKeyParser

View file

@ -13,7 +13,7 @@ import scala.util.Try
*/
sealed abstract class RawScriptSignatureParser extends RawBitcoinSerializer[ScriptSignature] {
def read(bytes: List[Byte]): ScriptSignature = {
def read(bytes: scodec.bits.ByteVector): ScriptSignature = {
if (bytes.isEmpty) EmptyScriptSignature
else {
val compactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(bytes)
@ -26,7 +26,7 @@ sealed abstract class RawScriptSignatureParser extends RawBitcoinSerializer[Scri
}
}
def write(scriptSig: ScriptSignature): Seq[Byte] = scriptSig.bytes
def write(scriptSig: ScriptSignature): scodec.bits.ByteVector = scriptSig.bytes
}
object RawScriptSignatureParser extends RawScriptSignatureParser

View file

@ -5,6 +5,8 @@ import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.script.ScriptWitness
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.util.BitcoinSUtil
import org.slf4j.LoggerFactory
import scodec.bits.ByteVector
import scala.annotation.tailrec
@ -13,12 +15,14 @@ import scala.annotation.tailrec
*/
sealed abstract class RawScriptWitnessParser extends RawBitcoinSerializer[ScriptWitness] {
def read(bytes: List[Byte]): ScriptWitness = {
private val logger = LoggerFactory.getLogger(this.getClass.getSimpleName)
def read(bytes: scodec.bits.ByteVector): ScriptWitness = {
//first byte is the number of stack items
val stackSize = CompactSizeUInt.parseCompactSizeUInt(bytes)
val (_, stackBytes) = bytes.splitAt(stackSize.size.toInt)
@tailrec
def loop(remainingBytes: Seq[Byte], accum: Seq[Seq[Byte]], remainingStackItems: UInt64): Seq[Seq[Byte]] = {
def loop(remainingBytes: scodec.bits.ByteVector, accum: Seq[scodec.bits.ByteVector], remainingStackItems: UInt64): Seq[scodec.bits.ByteVector] = {
if (remainingStackItems <= UInt64.zero) accum
else {
val elementSize = CompactSizeUInt.parseCompactSizeUInt(remainingBytes)
@ -34,19 +38,19 @@ sealed abstract class RawScriptWitnessParser extends RawBitcoinSerializer[Script
witness
}
def write(scriptWitness: ScriptWitness): Seq[Byte] = {
def write(scriptWitness: ScriptWitness): scodec.bits.ByteVector = {
@tailrec
def loop(remainingStack: Seq[Seq[Byte]], accum: Seq[Seq[Byte]]): Seq[Seq[Byte]] = {
def loop(remainingStack: Seq[scodec.bits.ByteVector], accum: Vector[scodec.bits.ByteVector]): Vector[scodec.bits.ByteVector] = {
if (remainingStack.isEmpty) accum.reverse
else {
val compactSizeUInt: CompactSizeUInt = CompactSizeUInt.calc(remainingStack.head)
val serialization: Seq[Byte] = compactSizeUInt.bytes ++ remainingStack.head
val serialization: scodec.bits.ByteVector = compactSizeUInt.bytes ++ remainingStack.head
loop(remainingStack.tail, serialization +: accum)
}
}
val stackItems: Seq[Seq[Byte]] = loop(scriptWitness.stack.reverse, Nil)
val stackItems: Vector[scodec.bits.ByteVector] = loop(scriptWitness.stack.reverse, Vector.empty)
val size = CompactSizeUInt(UInt64(stackItems.size))
(size.bytes +: stackItems).flatten
(size.bytes +: stackItems).fold(ByteVector.empty)(_ ++ _)
}
}

View file

@ -4,6 +4,7 @@ import org.bitcoins.core.number.UInt32
import org.bitcoins.core.script._
import org.bitcoins.core.script.constant._
import org.bitcoins.core.util.{ BitcoinSLogger, BitcoinSUtil, Factory }
import scodec.bits.ByteVector
import scala.annotation.tailrec
import scala.util.Try
@ -14,7 +15,7 @@ import scala.util.Try
sealed abstract class ScriptParser extends Factory[List[ScriptToken]] {
/** Parses a list of bytes into a list of script tokens */
def fromBytes(bytes: Seq[Byte]): List[ScriptToken] = {
def fromBytes(bytes: scodec.bits.ByteVector): List[ScriptToken] = {
val scriptTokens: List[ScriptToken] = parse(bytes)
scriptTokens
}
@ -43,18 +44,21 @@ sealed abstract class ScriptParser extends Factory[List[ScriptToken]] {
*/
private def parse(str: String): List[ScriptToken] = {
@tailrec
def loop(operations: List[String], accum: List[Byte]): List[Byte] = {
def loop(operations: List[String], accum: scodec.bits.ByteVector): scodec.bits.ByteVector = {
/* logger.debug("Attempting to parse: " + operations.headOption)
logger.debug("Accum: " + accum)*/
operations match {
//for parsing strings like 'Az', need to remove single quotes
//example: [[https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_valid.json#L24]]
case h :: t if (h.size > 0 && h.head == ''' && h.last == ''') =>
case h +: t if (h.size > 0 && h.head == ''' && h.last == ''') =>
val strippedQuotes = h.replace("'", "")
if (strippedQuotes.size == 0) {
loop(t, OP_0.bytes.toList ++ accum)
loop(t, OP_0.bytes ++ accum)
} else {
val bytes: Seq[Byte] = BitcoinSUtil.decodeHex(BitcoinSUtil.flipEndianness(strippedQuotes.getBytes.toList))
val bytes: scodec.bits.ByteVector = {
val b = ByteVector.apply(strippedQuotes.getBytes)
BitcoinSUtil.decodeHex(BitcoinSUtil.flipEndianness(b))
}
val bytesToPushOntoStack: List[ScriptToken] = (bytes.size > 75) match {
case true =>
@ -67,31 +71,33 @@ sealed abstract class ScriptParser extends Factory[List[ScriptToken]] {
case size if size < Int.MaxValue =>
List(scriptNumber, OP_PUSHDATA4)
}
case false => List(BytesToPushOntoStack(bytes.size))
case false => List(BytesToPushOntoStack(bytes.size.toInt))
}
loop(t, bytes.toList ++ bytesToPushOntoStack.flatMap(_.bytes) ++ accum)
val pushOpBytes: ByteVector = bytesToPushOntoStack.foldLeft(ByteVector.empty)(_ ++ _.bytes)
val aggregation: ByteVector = bytes ++ pushOpBytes ++ accum
loop(t, aggregation)
}
//if we see a byte constant in the form of "0x09adb"
case h :: t if (h.size > 1 && h.substring(0, 2) == "0x") =>
loop(t, BitcoinSUtil.decodeHex(h.substring(2, h.size).toLowerCase).toList.reverse ++ accum)
case h +: t if (h.size > 1 && h.substring(0, 2) == "0x") =>
loop(t, BitcoinSUtil.decodeHex(h.substring(2, h.size).toLowerCase).reverse ++ accum)
//skip the empty string
case h :: t if (h == "") => loop(t, accum)
case h :: t if (h == "0") => loop(t, OP_0.bytes.toList ++ accum)
case h +: t if (h == "") => loop(t, accum)
case h +: t if (h == "0") => loop(t, OP_0.bytes ++ accum)
case h :: t if (ScriptOperation.fromString(h).isDefined) =>
case h +: t if (ScriptOperation.fromString(h).isDefined) =>
val op = ScriptOperation.fromString(h).get
loop(t, op.bytes.toList ++ accum)
case h :: t if (tryParsingLong(h)) =>
loop(t, op.bytes ++ accum)
case h +: t if (tryParsingLong(h)) =>
val hexLong = BitcoinSUtil.flipEndianness(ScriptNumberUtil.longToHex(h.toLong))
val bytesToPushOntoStack = BytesToPushOntoStack(hexLong.size / 2)
//convert the string to int, then convert to hex
loop(t, BitcoinSUtil.decodeHex(hexLong).toList ++ bytesToPushOntoStack.bytes.toList ++ accum)
loop(t, BitcoinSUtil.decodeHex(hexLong) ++ bytesToPushOntoStack.bytes ++ accum)
//means that it must be a BytesToPushOntoStack followed by a script constant
case h :: t =>
case h +: t =>
//find the size of the string in bytes
val bytesToPushOntoStack = BytesToPushOntoStack(h.size / 2)
loop(t, BitcoinSUtil.decodeHex(BitcoinSUtil.flipEndianness(h)).toList ++ bytesToPushOntoStack.bytes.toList ++ accum)
loop(t, BitcoinSUtil.decodeHex(BitcoinSUtil.flipEndianness(h)) ++ bytesToPushOntoStack.bytes ++ accum)
case Nil => accum
}
}
@ -111,7 +117,7 @@ sealed abstract class ScriptParser extends Factory[List[ScriptToken]] {
//take a look at https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/core_read.cpp#L53-L88
//for the offical parsing algorithm, for examples of weird formats look inside of
//[[https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_valid.json]]
val parsedBytesFromString = loop(str.split(" ").toList, List()).reverse
val parsedBytesFromString = loop(str.split(" ").toList, ByteVector.empty).reverse
parse(parsedBytesFromString)
}
}
@ -120,24 +126,22 @@ sealed abstract class ScriptParser extends Factory[List[ScriptToken]] {
* Parses a byte array into a the asm operations for a script
* will throw an exception if it fails to parse a op code
*/
private def parse(bytes: List[Byte]): List[ScriptToken] = {
private def parse(bytes: scodec.bits.ByteVector): List[ScriptToken] = {
@tailrec
def loop(bytes: List[Byte], accum: List[ScriptToken]): List[ScriptToken] = {
def loop(bytes: scodec.bits.ByteVector, accum: List[ScriptToken]): List[ScriptToken] = {
//logger.debug("Byte to be parsed: " + bytes.headOption)
bytes match {
case h :: t =>
val op = ScriptOperation(h).get
val parsingHelper: ParsingHelper[Byte] = parseOperationByte(op, accum, t)
loop(parsingHelper.tail, parsingHelper.accum)
case Nil => accum
if (bytes.nonEmpty) {
val op = ScriptOperation(bytes.head).get
val parsingHelper: ParsingHelper = parseOperationByte(op, accum, bytes.tail)
loop(parsingHelper.tail, parsingHelper.accum)
} else {
accum
}
}
loop(bytes, List()).reverse
loop(bytes, Nil).reverse
}
private def parse(bytes: Seq[Byte]): List[ScriptToken] = parse(bytes.toList)
/** Parses a redeem script from the given script token */
def parseRedeemScript(scriptToken: ScriptToken): Try[List[ScriptToken]] = {
val redeemScript: Try[List[ScriptToken]] = Try(parse(scriptToken.bytes))
@ -148,7 +152,7 @@ sealed abstract class ScriptParser extends Factory[List[ScriptToken]] {
* Slices the amount of bytes specified in the bytesToPushOntoStack parameter and then creates a script constant
* from those bytes. Returns the script constant and the byte array without the script constant
*/
private def sliceConstant[T](bytesToPushOntoStack: BytesToPushOntoStack, data: List[T]): (List[T], List[T]) = {
private def sliceConstant(bytesToPushOntoStack: BytesToPushOntoStack, data: ByteVector): (ByteVector, ByteVector) = {
val finalIndex = bytesToPushOntoStack.opCode
val dataConstant = data.slice(0, finalIndex)
(dataConstant, data.slice(finalIndex, data.size))
@ -162,7 +166,7 @@ sealed abstract class ScriptParser extends Factory[List[ScriptToken]] {
*/
def parseBytesFromString(s: String): List[ScriptConstant] = {
//logger.debug("Parsing bytes from string " + s)
val scriptConstants: List[ScriptConstant] = (raw"\b0x([0-9a-f]+)\b".r
val scriptConstants = (raw"\b0x([0-9a-f]+)\b".r
.findAllMatchIn(s.toLowerCase)
.map(g =>
// 1 hex = 4 bits therefore 16 hex characters * 4 bits = 64
@ -173,33 +177,33 @@ sealed abstract class ScriptParser extends Factory[List[ScriptToken]] {
ScriptNumber(g.group(1))
} else {
ScriptConstant(g.group(1))
}).toList)
scriptConstants
}))
scriptConstants.toList
}
private sealed case class ParsingHelper[T](tail: List[T], accum: List[ScriptToken])
private sealed case class ParsingHelper(tail: ByteVector, accum: List[ScriptToken])
/**
* Parses an operation if the tail is a List[Byte]
* Parses an operation if the tail is a scodec.bits.ByteVector
* If the operation is a bytesToPushOntoStack, it pushes the number of bytes onto the stack
* specified by the bytesToPushOntoStack
* i.e. If the operation was BytesToPushOntoStackImpl(5), it would slice 5 bytes off of the tail and
* places them into a ScriptConstant and add them to the accumulator.
*/
private def parseOperationByte(op: ScriptOperation, accum: List[ScriptToken], tail: List[Byte]): ParsingHelper[Byte] = {
private def parseOperationByte(op: ScriptOperation, accum: List[ScriptToken], tail: scodec.bits.ByteVector): ParsingHelper = {
op match {
case bytesToPushOntoStack: BytesToPushOntoStack =>
//logger.debug("Parsing operation byte: " +bytesToPushOntoStack )
//means that we need to push x amount of bytes on to the stack
val (constant, newTail) = sliceConstant(bytesToPushOntoStack, tail)
val scriptConstant = ScriptConstant(constant)
ParsingHelper(newTail, scriptConstant :: bytesToPushOntoStack :: accum)
ParsingHelper(newTail, scriptConstant +: bytesToPushOntoStack +: accum)
case OP_PUSHDATA1 => parseOpPushData(op, accum, tail)
case OP_PUSHDATA2 => parseOpPushData(op, accum, tail)
case OP_PUSHDATA4 => parseOpPushData(op, accum, tail)
case _ =>
//means that we need to push the operation onto the stack
ParsingHelper(tail, op :: accum)
ParsingHelper(tail, op +: accum)
}
}
@ -211,15 +215,15 @@ sealed abstract class ScriptParser extends Factory[List[ScriptToken]] {
* @param tail the bytes to be parsed still
* @return
*/
private def parseOpPushData(op: ScriptOperation, accum: List[ScriptToken], tail: List[Byte]): ParsingHelper[Byte] = {
private def parseOpPushData(op: ScriptOperation, accum: List[ScriptToken], tail: scodec.bits.ByteVector): ParsingHelper = {
def parseOpPushDataHelper(numBytes: Int): ParsingHelper[Byte] = {
def parseOpPushDataHelper(numBytes: Int): ParsingHelper = {
//next numBytes is the size of the script constant
val scriptConstantHex = tail.slice(0, numBytes)
val uInt32Push = UInt32(BitcoinSUtil.flipEndianness(scriptConstantHex))
//need this for the case where we have an OP_PUSHDATA4 with a number larger than a int32 can hold
//TODO: Review this more, see this transaction's scriptSig as an example: b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc
val bytesForPushOp = Try(uInt32Push.toInt).getOrElse(tail.size)
val bytesForPushOp: Long = Try(uInt32Push.toLong).getOrElse(tail.length)
val bytesToPushOntoStack = ScriptConstant(scriptConstantHex)
val endIndex = {
val idx = bytesForPushOp + numBytes
@ -252,15 +256,15 @@ sealed abstract class ScriptParser extends Factory[List[ScriptToken]] {
* @return
*/
private def buildParsingHelper(op: ScriptOperation, bytesToPushOntoStack: ScriptConstant,
scriptConstant: ScriptConstant, restOfBytes: List[Byte], accum: List[ScriptToken]): ParsingHelper[Byte] = {
scriptConstant: ScriptConstant, restOfBytes: scodec.bits.ByteVector, accum: List[ScriptToken]): ParsingHelper = {
if (bytesToPushOntoStack.hex == "00") {
//if we need to push 0 bytes onto the stack we do not add the script constant
ParsingHelper[Byte](
ParsingHelper(
restOfBytes,
bytesToPushOntoStack :: op :: accum)
} else ParsingHelper[Byte](
bytesToPushOntoStack +: op +: accum)
} else ParsingHelper(
restOfBytes,
scriptConstant :: bytesToPushOntoStack :: op :: accum)
scriptConstant +: bytesToPushOntoStack +: op +: accum)
}
/** Checks if a string can be cast to an int */

View file

@ -13,7 +13,7 @@ import org.bitcoins.core.util.BitcoinSUtil
*/
sealed abstract class RawTransactionInputParser extends RawBitcoinSerializer[TransactionInput] {
override def read(bytes: List[Byte]): TransactionInput = {
override def read(bytes: scodec.bits.ByteVector): TransactionInput = {
val outPoint = TransactionOutPoint(bytes.take(36))
val scriptSigBytes = bytes.slice(36, bytes.size)
val scriptSig: ScriptSignature = RawScriptSignatureParser.read(scriptSigBytes)
@ -26,7 +26,7 @@ sealed abstract class RawTransactionInputParser extends RawBitcoinSerializer[Tra
}
/** Writes a single transaction input */
def write(input: TransactionInput): Seq[Byte] = {
def write(input: TransactionInput): scodec.bits.ByteVector = {
input.previousOutput.bytes ++ input.scriptSignature.bytes ++ input.sequence.bytes.reverse
}
}

View file

@ -11,14 +11,14 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer
*/
sealed abstract class RawTransactionOutPointParser extends RawBitcoinSerializer[TransactionOutPoint] {
override def read(bytes: List[Byte]): TransactionOutPoint = {
val txId: List[Byte] = bytes.take(32)
override def read(bytes: scodec.bits.ByteVector): TransactionOutPoint = {
val txId: scodec.bits.ByteVector = bytes.take(32)
val indexBytes = bytes.slice(32, 36)
val index = UInt32(indexBytes.reverse)
TransactionOutPoint(DoubleSha256Digest(txId), index)
}
def write(outPoint: TransactionOutPoint): Seq[Byte] = {
def write(outPoint: TransactionOutPoint): scodec.bits.ByteVector = {
//UInt32s cannot hold negative numbers, but sometimes the Bitcoin Protocol requires the vout to be -1, which is serialized
//as "0xFFFFFFFF".
//https://github.com/bitcoin/bitcoin/blob/d612837814020ae832499d18e6ee5eb919a87907/src/primitives/transaction.h

View file

@ -13,7 +13,7 @@ import org.bitcoins.core.serializers.{ RawBitcoinSerializer, RawSatoshisSerializ
sealed abstract class RawTransactionOutputParser extends RawBitcoinSerializer[TransactionOutput] {
/** Writes a single transaction output */
override def write(output: TransactionOutput): Seq[Byte] = {
override def write(output: TransactionOutput): scodec.bits.ByteVector = {
val satoshis: Satoshis = CurrencyUnits.toSatoshis(output.value)
satoshis.bytes ++ output.scriptPubKey.bytes
}
@ -22,7 +22,7 @@ sealed abstract class RawTransactionOutputParser extends RawBitcoinSerializer[Tr
* Reads a single output from the given bytes, note this is different than [[org.bitcoins.core.serializers.transaction.RawTransactionOutputParser.read]]
* because it does NOT expect a [[CompactSizeUInt]] to be the first element in the byte array indicating how many outputs we have
*/
override def read(bytes: List[Byte]): TransactionOutput = {
override def read(bytes: scodec.bits.ByteVector): TransactionOutput = {
val satoshisBytes = bytes.take(8)
val satoshis = RawSatoshisSerializer.read(satoshisBytes)
//it doesn't include itself towards the size, thats why it is incremented by one
@ -34,4 +34,4 @@ sealed abstract class RawTransactionOutputParser extends RawBitcoinSerializer[Tr
}
object RawTransactionOutputParser extends RawTransactionOutputParser
object RawTransactionOutputParser extends RawTransactionOutputParser

View file

@ -3,6 +3,8 @@ package org.bitcoins.core.serializers.transaction
import org.bitcoins.core.protocol.script.ScriptWitness
import org.bitcoins.core.protocol.transaction.TransactionWitness
import org.bitcoins.core.serializers.script.RawScriptWitnessParser
import org.slf4j.LoggerFactory
import scodec.bits.ByteVector
import scala.annotation.tailrec
@ -13,14 +15,14 @@ import scala.annotation.tailrec
* [[https://github.com/bitcoin/bitcoin/blob/b4e4ba475a5679e09f279aaf2a83dcf93c632bdb/src/primitives/transaction.h#L232-L268]]
*/
sealed abstract class RawTransactionWitnessParser {
private val logger = LoggerFactory.getLogger(this.getClass.getSimpleName)
/**
* We can only tell how many [[ScriptWitness]]
* we have if we have the number of inputs the transaction creates
*/
def read(bytes: Seq[Byte], numInputs: Int): TransactionWitness = {
def read(bytes: scodec.bits.ByteVector, numInputs: Int): TransactionWitness = {
@tailrec
def loop(remainingBytes: Seq[Byte], remainingInputs: Int, accum: Seq[ScriptWitness]): Seq[ScriptWitness] = {
def loop(remainingBytes: scodec.bits.ByteVector, remainingInputs: Int, accum: Seq[ScriptWitness]): Seq[ScriptWitness] = {
if (remainingInputs != 0) {
val w = RawScriptWitnessParser.read(remainingBytes)
val (_, newRemainingBytes) = remainingBytes.splitAt(w.bytes.size)
@ -32,7 +34,9 @@ sealed abstract class RawTransactionWitnessParser {
TransactionWitness(witnesses)
}
def write(witness: TransactionWitness): Seq[Byte] = witness.witnesses.flatMap(_.bytes)
def write(witness: TransactionWitness): scodec.bits.ByteVector = {
witness.witnesses.foldLeft(ByteVector.empty)(_ ++ _.bytes)
}
}
object RawTransactionWitnessParser extends RawTransactionWitnessParser
object RawTransactionWitnessParser extends RawTransactionWitnessParser

View file

@ -2,6 +2,7 @@ package org.bitcoins.core.util
import org.bitcoins.core.crypto.ECPrivateKey
import org.bitcoins.core.protocol.blockchain._
import scodec.bits.ByteVector
import scala.annotation.tailrec
import scala.util.{ Failure, Success, Try }
@ -16,15 +17,15 @@ sealed abstract class Base58 {
val base58Pairs = base58Characters.zipWithIndex.toMap
private val logger = BitcoinSLogger.logger
/** Verifies a given [[Base58Type]] string against its checksum (last 4 decoded bytes). */
def decodeCheck(input: String): Try[Seq[Byte]] = {
val decodedTry: Try[Seq[Byte]] = Try(decode(input))
def decodeCheck(input: String): Try[scodec.bits.ByteVector] = {
val decodedTry: Try[scodec.bits.ByteVector] = Try(decode(input))
decodedTry.flatMap { decoded =>
if (decoded.length < 4) Failure(new IllegalArgumentException("Invalid input"))
else {
val splitSeqs = decoded.splitAt(decoded.length - 4)
val data: Seq[Byte] = splitSeqs._1
val checksum: Seq[Byte] = splitSeqs._2
val actualChecksum: Seq[Byte] = CryptoUtil.doubleSHA256(data).bytes.take(4)
val data: scodec.bits.ByteVector = splitSeqs._1
val checksum: scodec.bits.ByteVector = splitSeqs._2
val actualChecksum: scodec.bits.ByteVector = CryptoUtil.doubleSHA256(data).bytes.take(4)
if (checksum == actualChecksum) Success(data)
else Failure(new IllegalArgumentException("checksums don't validate"))
}
@ -32,8 +33,8 @@ sealed abstract class Base58 {
}
/** Encodes a sequence of bytes to a [[Base58Type]] string. */
def encode(bytes: Seq[Byte]): String = {
val ones: String = bytes.takeWhile(_ == 0).map(_ => '1').mkString
def encode(bytes: scodec.bits.ByteVector): String = {
val ones: String = bytes.toSeq.takeWhile(_ == 0).map(_ => '1').mkString
@tailrec
def loop(current: BigInt, str: String): String = current match {
case a if current == BigInt(0) =>
@ -59,18 +60,18 @@ sealed abstract class Base58 {
}
/** Encodes a [[Byte]] to its [[Base58Type]] representation. */
def encode(byte: Byte): String = encode(Seq(byte))
def encode(byte: Byte): String = encode(ByteVector.fromByte(byte))
/**
* Takes in [[Base58Type]] string and returns sequence of [[Byte]]s
* https://github.com/ACINQ/bitcoin-lib/blob/master/src/main/scala/fr/acinq/bitcoin/Base58.scala.
*/
def decode(input: String): Seq[Byte] = {
val zeroes = input.takeWhile(_ == '1').map(_ => 0: Byte).toArray
def decode(input: String): scodec.bits.ByteVector = {
val zeroes = ByteVector(input.takeWhile(_ == '1').map(_ => 0: Byte))
val trim = input.dropWhile(_ == '1').toList
val decoded = trim.foldLeft(BigInt(0))((a, b) =>
a.*(BigInt(58L)).+(BigInt(base58Pairs(b))))
if (trim.isEmpty) zeroes else zeroes ++ decoded.toByteArray.dropWhile(_ == 0)
if (trim.isEmpty) zeroes else zeroes ++ ByteVector(decoded.toByteArray.dropWhile(_ == 0))
}
/** Determines if a string is a valid [[Base58Type]] string. */
@ -94,10 +95,10 @@ sealed abstract class Base58 {
* ('1', '3', 'm', 'n', '2')
*/
private def isValidAddressPreFixByte(byte: Byte): Boolean = {
val validAddressPreFixBytes: Seq[Byte] =
val validAddressPreFixBytes: scodec.bits.ByteVector =
MainNetChainParams.base58Prefixes(PubKeyAddress) ++ MainNetChainParams.base58Prefixes(ScriptAddress) ++
TestNetChainParams.base58Prefixes(PubKeyAddress) ++ TestNetChainParams.base58Prefixes(ScriptAddress)
validAddressPreFixBytes.contains(byte)
validAddressPreFixBytes.toSeq.contains(byte)
}
/**
@ -105,9 +106,9 @@ sealed abstract class Base58 {
* ('5', '9', 'c')
*/
private def isValidSecretKeyPreFixByte(byte: Byte): Boolean = {
val validSecretKeyPreFixBytes: Seq[Byte] =
val validSecretKeyPreFixBytes: scodec.bits.ByteVector =
MainNetChainParams.base58Prefixes(SecretKey) ++ TestNetChainParams.base58Prefixes(SecretKey)
validSecretKeyPreFixBytes.contains(byte)
validSecretKeyPreFixBytes.toSeq.contains(byte)
}
/**
@ -130,4 +131,4 @@ sealed abstract class Base58 {
}
}
object Base58 extends Base58
object Base58 extends Base58

View file

@ -1,19 +1,22 @@
package org.bitcoins.core.util
import org.bitcoins.core.protocol.NetworkElement
import scodec.bits.{ BitVector, ByteVector }
import scala.math.BigInt
/**
* Created by chris on 2/26/16.
*/
trait BitcoinSUtil {
def decodeHex(hex: String): Seq[Byte] = {
hex.replaceAll("[^0-9A-Fa-f]", "").sliding(2, 2).toArray.map(Integer.parseInt(_, 16).toByte).toList
private val logger = BitcoinSLogger.logger
def decodeHex(hex: String): scodec.bits.ByteVector = {
if (hex.isEmpty) ByteVector.empty else scodec.bits.ByteVector.fromHex(hex).get
}
def encodeHex(bytes: Seq[Byte]): String = bytes.map("%02x".format(_)).mkString
def encodeHex(bytes: scodec.bits.ByteVector): String = bytes.toHex
def encodeHex(byte: Byte): String = encodeHex(Seq(byte))
def encodeHex(byte: Byte): String = encodeHex(scodec.bits.ByteVector(byte))
/**
* Encodes a long number to a hex string, pads it with an extra '0' char
@ -43,7 +46,7 @@ trait BitcoinSUtil {
addPadding(4, hex)
}
def encodeHex(bigInt: BigInt): String = BitcoinSUtil.encodeHex(bigInt.toByteArray)
def encodeHex(bigInt: BigInt): String = BitcoinSUtil.encodeHex(ByteVector(bigInt.toByteArray))
/** Tests if a given string is a hexadecimal string. */
def isHex(str: String): Boolean = {
@ -61,8 +64,9 @@ trait BitcoinSUtil {
def flipEndianness(hex: String): String = flipEndianness(decodeHex(hex))
/** Flips the endianness of the given sequence of bytes. */
def flipEndianness(bytes: Seq[Byte]): String = encodeHex(bytes.reverse)
def flipEndianness(bytes: scodec.bits.ByteVector): String = encodeHex(bytes.reverse)
def flipEndiannessBytes(bytes: ByteVector): ByteVector = bytes.reverse
/**
* Adds the amount padding bytes needed to fix the size of the hex string
* for instance, ints are required to be 4 bytes. If the number is just 1
@ -77,29 +81,26 @@ trait BitcoinSUtil {
}
/** Converts a sequence of bytes to a sequence of bit vectors */
def bytesToBitVectors(bytes: Seq[Byte]): Seq[Seq[Boolean]] = bytes.map(byteToBitVector)
def bytesToBitVectors(bytes: scodec.bits.ByteVector): scodec.bits.BitVector = {
bytes.toBitVector
}
/** Converts a byte to a bit vector representing that byte */
def byteToBitVector(byte: Byte): Seq[Boolean] = {
(0 to 7).map(index => isBitSet(byte, 7 - index))
def byteToBitVector(byte: Byte): scodec.bits.BitVector = {
BitVector.fromByte(byte)
}
/** Checks if the bit at the given index is set */
def isBitSet(byte: Byte, index: Int): Boolean = ((byte >> index) & 1) == 1
/** Converts a bit vector to a single byte -- the resulting byte is big endian */
def bitVectorToByte(bits: Seq[Boolean]): Byte = {
require(bits.size <= 8, "Cannot convert a bit vector to a byte when the size of the bit vector is larger than 8, got: " + bits)
val b = bits.reverse
val result: Seq[Int] = b.zipWithIndex.map {
case (b, index) =>
if (b) NumberUtil.pow2(index).toInt else 0
}
result.sum.toByte
/** Converts a sequence of bit vectors to a sequence of bytes */
def bitVectorToBytes(bits: scodec.bits.BitVector): scodec.bits.ByteVector = {
bits.bytes
}
/** Converts a sequence of bit vectors to a sequence of bytes */
def bitVectorsToBytes(bits: Seq[Seq[Boolean]]): Seq[Byte] = bits.map(bitVectorToByte)
def toByteVector[T <: NetworkElement](h: Seq[T]): ByteVector = {
h.foldLeft(ByteVector.empty)(_ ++ _.bytes)
}
}

View file

@ -9,6 +9,7 @@ import org.bitcoins.core.script.crypto.{ OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIF
import org.bitcoins.core.script.flag.{ ScriptFlag, ScriptFlagUtil }
import org.bitcoins.core.script.result.{ ScriptError, ScriptErrorPubKeyType, ScriptErrorWitnessPubKeyType }
import org.bitcoins.core.script.{ ExecutionInProgressScriptProgram, ScriptProgram }
import scodec.bits.BitVector
import scala.annotation.tailrec
@ -24,7 +25,7 @@ trait BitcoinScriptUtil extends BitcoinSLogger {
}
/** Converts a sequence of script tokens to them to their byte values */
def asmToBytes(asm: Seq[ScriptToken]): Seq[Byte] = BitcoinSUtil.decodeHex(asmToHex(asm))
def asmToBytes(asm: Seq[ScriptToken]): scodec.bits.ByteVector = BitcoinSUtil.decodeHex(asmToHex(asm))
/**
* Filters out push operations in our sequence of script tokens
@ -113,14 +114,20 @@ trait BitcoinScriptUtil extends BitcoinSLogger {
*/
def isPushOnly(script: Seq[ScriptToken]): Boolean = {
@tailrec
def loop(tokens: Seq[ScriptToken], accum: List[Boolean]): Seq[Boolean] = tokens match {
def loop(tokens: Seq[ScriptToken]): Boolean = tokens match {
case h :: t => h match {
case scriptOp: ScriptOperation => loop(t, (scriptOp.opCode < OP_16.opCode) :: accum)
case _: ScriptToken => loop(t, true :: accum)
case scriptOp: ScriptOperation =>
if (scriptOp.opCode < OP_16.opCode) {
loop(t)
} else {
false
}
case _: ScriptToken => loop(t)
}
case Nil => accum
case Nil => true
}
!loop(script, List()).exists(_ == false)
loop(script)
}
/**
@ -175,7 +182,7 @@ trait BitcoinScriptUtil extends BitcoinSLogger {
} else throw new IllegalArgumentException("ScriptToken is to large for pushops, size: " + scriptTokenSize)
}
def calculatePushOp(bytes: Seq[Byte]): Seq[ScriptToken] = calculatePushOp(ScriptConstant(bytes))
def calculatePushOp(bytes: scodec.bits.ByteVector): Seq[ScriptToken] = calculatePushOp(ScriptConstant(bytes))
/**
* Whenever a [[ScriptConstant]] is interpreted to a number BIP62 could enforce that number to be encoded
@ -184,7 +191,7 @@ trait BitcoinScriptUtil extends BitcoinSLogger {
*/
def isShortestEncoding(constant: ScriptConstant): Boolean = isShortestEncoding(constant.bytes)
def isShortestEncoding(bytes: Seq[Byte]): Boolean = {
def isShortestEncoding(bytes: scodec.bits.ByteVector): Boolean = {
// If the most-significant-byte - excluding the sign bit - is zero
// then we're not minimal. Note how this test also rejects the
// negative-zero encoding, 0x80.
@ -366,7 +373,7 @@ trait BitcoinScriptUtil extends BitcoinSLogger {
* All bytes in the byte vector must be zero, unless it is the last byte, which can be 0 or 0x80 (negative zero)
*/
def castToBool(token: ScriptToken): Boolean = {
token.bytes.zipWithIndex.exists {
token.bytes.toArray.zipWithIndex.exists {
case (b, index) =>
val byteNotZero = b.toByte != 0
val lastByteNotNegativeZero = !(index == token.bytes.size - 1 && b.toByte == 0x80.toByte)

View file

@ -6,6 +6,7 @@ import org.bitcoins.core.crypto._
import org.bouncycastle.crypto.digests.{ RIPEMD160Digest, SHA512Digest }
import org.bouncycastle.crypto.macs.HMac
import org.bouncycastle.crypto.params.KeyParameter
import scodec.bits.ByteVector
/**
* Created by chris on 1/14/16.
@ -16,8 +17,8 @@ trait CryptoUtil {
/** Does the following computation: RIPEMD160(SHA256(hex)).*/
def sha256Hash160(hex: String): Sha256Hash160Digest = sha256Hash160(BitcoinSUtil.decodeHex(hex))
def sha256Hash160(bytes: Seq[Byte]): Sha256Hash160Digest = {
val hash = ripeMd160(sha256(bytes.toArray).bytes).bytes
def sha256Hash160(bytes: scodec.bits.ByteVector): Sha256Hash160Digest = {
val hash = ripeMd160(sha256(bytes).bytes).bytes
Sha256Hash160Digest(hash)
}
@ -25,8 +26,8 @@ trait CryptoUtil {
def doubleSHA256(hex: String): DoubleSha256Digest = doubleSHA256(BitcoinSUtil.decodeHex(hex))
/** Performs sha256(sha256(bytes)). */
def doubleSHA256(bytes: Seq[Byte]): DoubleSha256Digest = {
val hash: Seq[Byte] = sha256(sha256(bytes).bytes).bytes
def doubleSHA256(bytes: scodec.bits.ByteVector): DoubleSha256Digest = {
val hash: scodec.bits.ByteVector = sha256(sha256(bytes).bytes).bytes
DoubleSha256Digest(hash)
}
@ -34,15 +35,15 @@ trait CryptoUtil {
def sha256(hex: String): Sha256Digest = sha256(BitcoinSUtil.decodeHex(hex))
/** Takes sha256(bytes). */
def sha256(bytes: Seq[Byte]): Sha256Digest = {
val hash = MessageDigest.getInstance("SHA-256").digest(bytes.toArray).toList
Sha256Digest(hash)
def sha256(bytes: scodec.bits.ByteVector): Sha256Digest = {
val hash = MessageDigest.getInstance("SHA-256").digest(bytes.toArray)
Sha256Digest(ByteVector(hash))
}
/** Performs SHA1(bytes). */
def sha1(bytes: Seq[Byte]): Sha1Digest = {
def sha1(bytes: scodec.bits.ByteVector): Sha1Digest = {
val hash = MessageDigest.getInstance("SHA-1").digest(bytes.toArray).toList
Sha1Digest(hash)
Sha1Digest(ByteVector(hash))
}
/** Performs SHA1(hex). */
@ -52,25 +53,25 @@ trait CryptoUtil {
def ripeMd160(hex: String): RipeMd160Digest = ripeMd160(BitcoinSUtil.decodeHex(hex))
/** Performs RIPEMD160(bytes). */
def ripeMd160(bytes: Seq[Byte]): RipeMd160Digest = {
def ripeMd160(bytes: scodec.bits.ByteVector): RipeMd160Digest = {
//from this tutorial http://rosettacode.org/wiki/RIPEMD-160#Scala
val messageDigest = new RIPEMD160Digest
val raw = bytes.toArray
messageDigest.update(raw, 0, raw.length)
val out = Array.fill[Byte](messageDigest.getDigestSize())(0)
messageDigest.doFinal(out, 0)
RipeMd160Digest(out.toList)
RipeMd160Digest(ByteVector(out))
}
val emptyDoubleSha256Hash = DoubleSha256Digest("0000000000000000000000000000000000000000000000000000000000000000")
def hmac512(key: Seq[Byte], data: Seq[Byte]): Seq[Byte] = {
def hmac512(key: scodec.bits.ByteVector, data: scodec.bits.ByteVector): scodec.bits.ByteVector = {
val hmac512 = new HMac(new SHA512Digest())
hmac512.init(new KeyParameter(key.toArray))
hmac512.update(data.toArray, 0, data.size)
hmac512.update(data.toArray, 0, data.intSize.get)
val output = new Array[Byte](64)
hmac512.doFinal(output, 0)
output
ByteVector(output)
}
}

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