mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-25 07:17:32 +01:00
Moving CompactUIntImpl into factory, adding NetworkElement trait to Block/BlockHeader to allow for easy access to hex/byte representations
This commit is contained in:
parent
ec5e2b85c3
commit
59c1968271
9 changed files with 130 additions and 27 deletions
|
@ -11,13 +11,11 @@ trait CompactSizeUInt {
|
|||
|
||||
/**
|
||||
* The number parsed from VarInt
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
def num : Long
|
||||
/**
|
||||
* The length of the VarInt in bytes
|
||||
*
|
||||
* The length of the VarInt in bytes
|
||||
* @return
|
||||
*/
|
||||
def size : Long
|
||||
|
@ -33,7 +31,14 @@ trait CompactSizeUInt {
|
|||
|
||||
}
|
||||
|
||||
case class CompactSizeUIntImpl(num : Long, size : Long) extends CompactSizeUInt
|
||||
object CompactSizeUInt {
|
||||
private sealed case class CompactSizeUIntImpl(num : Long, size : Long) extends CompactSizeUInt
|
||||
def apply(num : Long, size : Long) : CompactSizeUInt = {
|
||||
CompactSizeUIntImpl(num,size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package org.bitcoins.core.protocol.blockchain
|
||||
|
||||
import org.bitcoins.core.protocol.CompactSizeUInt
|
||||
import org.bitcoins.core.protocol.{CompactSizeUInt, NetworkElement}
|
||||
import org.bitcoins.core.protocol.transaction.Transaction
|
||||
import org.bitcoins.core.serializers.blockchain.RawBlockSerializer
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, CryptoUtil, Factory}
|
||||
|
||||
/**
|
||||
* Created by chris on 5/19/16.
|
||||
|
@ -11,7 +13,7 @@ import org.bitcoins.core.protocol.transaction.Transaction
|
|||
* Bitcoin Developer Reference link:
|
||||
* https://bitcoin.org/en/developer-reference#serialized-blocks
|
||||
*/
|
||||
trait Block {
|
||||
sealed trait Block extends NetworkElement with BitcoinSLogger {
|
||||
|
||||
/**
|
||||
* The block header for this block
|
||||
|
@ -32,13 +34,22 @@ trait Block {
|
|||
*/
|
||||
def transactions : Seq[Transaction]
|
||||
|
||||
/**
|
||||
* Returns the block's hash
|
||||
* @return
|
||||
*/
|
||||
def hash : Seq[Byte] = CryptoUtil.doubleSHA256(bytes)
|
||||
|
||||
|
||||
def hex = RawBlockSerializer.write(this)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Companion object for creating Blocks
|
||||
*/
|
||||
object Block {
|
||||
object Block extends Factory[Block] {
|
||||
|
||||
private sealed case class BlockImpl(blockHeader : BlockHeader,
|
||||
txCount : CompactSizeUInt, transactions : Seq[Transaction]) extends Block
|
||||
|
@ -46,4 +57,8 @@ object Block {
|
|||
def apply(blockHeader : BlockHeader, txCount : CompactSizeUInt, transactions : Seq[Transaction]) : Block = {
|
||||
BlockImpl(blockHeader, txCount, transactions)
|
||||
}
|
||||
|
||||
def fromBytes(bytes : Seq[Byte]) : Block = RawBlockSerializer.read(bytes)
|
||||
|
||||
def apply(bytes : Seq[Byte]) : Block = fromBytes(bytes)
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
package org.bitcoins.core.protocol.blockchain
|
||||
|
||||
import org.bitcoins.core.protocol.NetworkElement
|
||||
import org.bitcoins.core.util.BitcoinSLogger
|
||||
|
||||
/**
|
||||
* Created by chris on 5/19/16.
|
||||
* Nodes collect new transactions into a block, hash them into a hash tree,
|
||||
|
@ -13,13 +16,14 @@ package org.bitcoins.core.protocol.blockchain
|
|||
* Bitcoin Core implementation:
|
||||
* https://github.com/bitcoin/bitcoin/blob/master/src/primitives/block.h#L20
|
||||
*/
|
||||
trait BlockHeader {
|
||||
sealed trait BlockHeader extends NetworkElement with BitcoinSLogger {
|
||||
|
||||
/**
|
||||
* The block version number indicates which set of block validation rules to follow.
|
||||
* See the list of block versions below.
|
||||
* See BIP9 for more information on what version number signify
|
||||
* https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki
|
||||
*
|
||||
* @return the version number for this block
|
||||
*/
|
||||
def version : Long
|
||||
|
@ -28,6 +32,7 @@ trait BlockHeader {
|
|||
/**
|
||||
* A SHA256(SHA256()) hash in internal byte order of the previous block’s header.
|
||||
* This ensures no previous block can be changed without also changing this block’s header.
|
||||
*
|
||||
* @return the previous block's hash
|
||||
*/
|
||||
def previousBlockHash : String
|
||||
|
@ -37,6 +42,7 @@ trait BlockHeader {
|
|||
* The merkle root is derived from the hashes of all transactions included in this block,
|
||||
* ensuring that none of those transactions can be modified without modifying the header.
|
||||
* https://bitcoin.org/en/developer-reference#merkle-trees
|
||||
*
|
||||
* @return the merkle root of the merkle tree
|
||||
*/
|
||||
def merkleRootHash : String
|
||||
|
@ -46,6 +52,7 @@ trait BlockHeader {
|
|||
* The block time is a Unix epoch time when the miner started hashing the header (according to the miner).
|
||||
* Must be greater than or equal to the median time of the previous 11 blocks.
|
||||
* Full nodes will not accept blocks with headers more than two hours in the future according to their clock.
|
||||
*
|
||||
* @return the time when the miner started solving the block
|
||||
*/
|
||||
def time : Long
|
||||
|
@ -54,6 +61,7 @@ trait BlockHeader {
|
|||
* An encoded version of the target threshold this block’s header hash must be less than or equal to.
|
||||
* See the nBits format described below.
|
||||
* https://bitcoin.org/en/developer-reference#target-nbits
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
def nBits : Long
|
||||
|
@ -62,6 +70,7 @@ trait BlockHeader {
|
|||
* An arbitrary number miners change to modify the header hash in order to produce a hash below the target threshold.
|
||||
* If all 32-bit values are tested, the time can be updated or the coinbase
|
||||
* transaction can be changed and the merkle root updated.
|
||||
*
|
||||
* @return the nonce used to try and solve a block
|
||||
*/
|
||||
def nonce : Long
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
package org.bitcoins.core.protocol.blockchain
|
||||
|
||||
import org.bitcoins.core.currency.CurrencyUnit
|
||||
import org.bitcoins.core.protocol.{CompactSizeUInt}
|
||||
import org.bitcoins.core.protocol.script.{ScriptPubKey, ScriptSignature}
|
||||
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionConstants, TransactionInput, TransactionOutput}
|
||||
import org.bitcoins.core.script.constant.{BytesToPushOntoStack, ScriptConstant, ScriptNumber}
|
||||
import org.bitcoins.core.script.crypto.OP_CHECKSIG
|
||||
import org.bitcoins.core.util.BitcoinSUtil
|
||||
|
||||
/**
|
||||
|
@ -56,6 +62,52 @@ sealed trait ChainParams {
|
|||
* @return
|
||||
*/
|
||||
def dnsSeeds : Seq[String]
|
||||
|
||||
|
||||
/**
|
||||
* Creates the genesis block for this blockchain
|
||||
* Mimics this function in bitcoin core
|
||||
* https://github.com/bitcoin/bitcoin/blob/master/src/chainparams.cpp#L51
|
||||
* @param time the time when the miner started hashing the block header
|
||||
* @param nonce the nonce to mine the block
|
||||
* @param nBits An encoded version of the target threshold this block’s header hash must be less than or equal to.
|
||||
* @param version the block version
|
||||
* @param amount the block reward for the gensis block (50 BTC in Bitcoin)
|
||||
* @return the newly minted genesis block
|
||||
*/
|
||||
def createGenesisBlock(time : Long, nonce : Long, nBits : Long, version : Int, amount : CurrencyUnit) : Block = {
|
||||
val timestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"
|
||||
val genesisOutputScript = ScriptPubKey.fromAsm(
|
||||
Seq(ScriptConstant("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51e" +
|
||||
"c112de5c384df7ba0b8d578a4c702b6bf11d5f"), OP_CHECKSIG))
|
||||
createGenesisBlock(timestamp,genesisOutputScript,time,nonce,nBits,version,amount)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timestamp a piece of data to signify when this block was first created - satoshi used an article headline
|
||||
* @param scriptPubKey the scriptPubKey that needs to be satisfied in able to spend the genesis block reward
|
||||
* @param time the time when the miner started hashing the block header
|
||||
* @param nonce the nonce used to mine the block
|
||||
* @param nBits An encoded version of the target threshold this block's header hash must be less than or equal to
|
||||
* @param version the block version
|
||||
* @param amount the block reward for the genesis block (50 BTC in Bitcoin)
|
||||
* @return the newly minted genesis block
|
||||
*/
|
||||
def createGenesisBlock(timestamp : String, scriptPubKey : ScriptPubKey, time : Long, nonce : Long, nBits : Long,
|
||||
version : Int, amount : CurrencyUnit) : Block = {
|
||||
val timestampHex = BitcoinSUtil.flipEndianess(timestamp.map(_.toByte))
|
||||
val scriptSignature = ScriptSignature.fromAsm(Seq(ScriptNumber(486604799), BytesToPushOntoStack(4),
|
||||
ScriptConstant(timestampHex)))
|
||||
val input = TransactionInput(scriptSignature)
|
||||
val output = TransactionOutput(amount,scriptPubKey)
|
||||
val tx = Transaction(TransactionConstants.version,Seq(input), Seq(output), TransactionConstants.lockTime)
|
||||
val prevBlockHash = "00000000000000"
|
||||
//TODO: Replace this with a merkle root hash computed algorithmically
|
||||
val merkleRootHash = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
||||
val genesisBlockHeader = BlockHeader(version,prevBlockHash,merkleRootHash,time,nBits,nonce)
|
||||
val genesisBlock = Block(genesisBlockHeader,CompactSizeUInt(1,1),Seq(tx))
|
||||
genesisBlock
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ case object EmptyTransactionInput extends TransactionInput {
|
|||
*/
|
||||
sealed trait CoinbaseInput extends TransactionInput {
|
||||
override def previousOutput = EmptyTransactionOutPoint
|
||||
override def sequence = TransactionConstants.sequence
|
||||
}
|
||||
|
||||
|
||||
|
@ -50,7 +51,7 @@ object TransactionInput extends Factory[TransactionInput] {
|
|||
scriptSignature : ScriptSignature, sequence : Long) extends TransactionInput
|
||||
|
||||
private sealed case class CoinbaseInputImpl(
|
||||
scriptSignature : ScriptSignature, sequence : Long) extends CoinbaseInput
|
||||
scriptSignature : ScriptSignature) extends CoinbaseInput
|
||||
|
||||
private def factory(oldInput : TransactionInput, scriptPubKey: ScriptPubKey) : TransactionInput = {
|
||||
val scriptSig = ScriptSignature(scriptPubKey.hex)
|
||||
|
@ -63,7 +64,6 @@ object TransactionInput extends Factory[TransactionInput] {
|
|||
|
||||
/**
|
||||
* Creates a transaction input from a given output and the output's transaction
|
||||
*
|
||||
* @param oldInput
|
||||
* @param output
|
||||
* @param outputsTransaction
|
||||
|
@ -81,7 +81,7 @@ object TransactionInput extends Factory[TransactionInput] {
|
|||
|
||||
private def factory(outPoint : TransactionOutPoint, scriptSignature : ScriptSignature, sequenceNumber : Long) : TransactionInput = {
|
||||
outPoint match {
|
||||
case EmptyTransactionOutPoint => CoinbaseInputImpl(scriptSignature,sequenceNumber)
|
||||
case EmptyTransactionOutPoint => CoinbaseInputImpl(scriptSignature)
|
||||
case _ : TransactionOutPoint => TransactionInputImpl(outPoint, scriptSignature, sequenceNumber)
|
||||
}
|
||||
}
|
||||
|
@ -113,4 +113,13 @@ object TransactionInput extends Factory[TransactionInput] {
|
|||
def apply(outPoint : TransactionOutPoint, scriptSignature : ScriptSignature, sequenceNumber : Long) : TransactionInput = factory(outPoint,scriptSignature,sequenceNumber)
|
||||
|
||||
def apply(bytes : Seq[Byte]) : TransactionInput = fromBytes(bytes)
|
||||
|
||||
/**
|
||||
* Creates a coinbase input - coinbase inputs always have an empty outpoint
|
||||
* @param scriptSignature this can contain anything, miners use this to signify support for various protocol BIPs
|
||||
* @return the coinbase input
|
||||
*/
|
||||
def apply(scriptSignature: ScriptSignature) : CoinbaseInput = {
|
||||
CoinbaseInputImpl(scriptSignature)
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ trait RawBlockSerializer extends RawBitcoinSerializer[Block] {
|
|||
def read(bytes : List[Byte]) : Block = ???
|
||||
|
||||
/**
|
||||
* Takes in a block and converts it a hexadecimal string
|
||||
* Takes in a block and converts it to a hexadecimal string
|
||||
* @param block the block that needs to be converted to a hexadecimal string
|
||||
* @return the hexadecimal string representing a block
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.bitcoins.core.util
|
||||
|
||||
import org.bitcoins.core.protocol.script.{ScriptPubKey, ScriptSignature}
|
||||
import org.bitcoins.core.protocol.{CompactSizeUInt, CompactSizeUIntImpl}
|
||||
import org.bitcoins.core.protocol.{CompactSizeUInt}
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
/**
|
||||
|
@ -142,13 +142,13 @@ trait NumberUtil extends BitcoinSLogger {
|
|||
def parseCompactSizeUInt(bytes : Seq[Byte]) : CompactSizeUInt = {
|
||||
require(bytes.size > 0, "Cannot parse a VarInt if the byte array is size 0")
|
||||
//8 bit number
|
||||
if (parseLong(bytes.head) < 253) CompactSizeUIntImpl(parseLong(bytes.head),1)
|
||||
if (parseLong(bytes.head) < 253) CompactSizeUInt(parseLong(bytes.head),1)
|
||||
//16 bit number
|
||||
else if (parseLong(bytes.head) == 253) CompactSizeUIntImpl(parseLong(bytes.slice(1,3).reverse),3)
|
||||
else if (parseLong(bytes.head) == 253) CompactSizeUInt(parseLong(bytes.slice(1,3).reverse),3)
|
||||
//32 bit number
|
||||
else if (parseLong(bytes.head) == 254) CompactSizeUIntImpl(parseLong(bytes.slice(1,5).reverse),5)
|
||||
else if (parseLong(bytes.head) == 254) CompactSizeUInt(parseLong(bytes.slice(1,5).reverse),5)
|
||||
//64 bit number
|
||||
else CompactSizeUIntImpl(parseLong(bytes.slice(1,9).reverse),9)
|
||||
else CompactSizeUInt(parseLong(bytes.slice(1,9).reverse),9)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,13 +179,13 @@ trait NumberUtil extends BitcoinSLogger {
|
|||
*/
|
||||
def parseCompactSizeUInt(script : ScriptSignature) : CompactSizeUInt = {
|
||||
if (script.bytes.size <=252 ) {
|
||||
CompactSizeUIntImpl(script.bytes.size,1)
|
||||
CompactSizeUInt(script.bytes.size,1)
|
||||
} else if (script.bytes.size <= 0xffff) {
|
||||
CompactSizeUIntImpl(script.bytes.size,3)
|
||||
CompactSizeUInt(script.bytes.size,3)
|
||||
} else if (script.bytes.size <= 0xffffffff) {
|
||||
CompactSizeUIntImpl(script.bytes.size,5)
|
||||
CompactSizeUInt(script.bytes.size,5)
|
||||
}
|
||||
else CompactSizeUIntImpl(script.bytes.size,9)
|
||||
else CompactSizeUInt(script.bytes.size,9)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -197,13 +197,12 @@ trait NumberUtil extends BitcoinSLogger {
|
|||
*/
|
||||
def parseCompactSizeUInt(scriptPubKey : ScriptPubKey) : CompactSizeUInt = {
|
||||
if (scriptPubKey.bytes.size <=252 ) {
|
||||
CompactSizeUIntImpl(scriptPubKey.bytes.size,1)
|
||||
CompactSizeUInt(scriptPubKey.bytes.size,1)
|
||||
} else if (scriptPubKey.bytes.size <= 0xffff) {
|
||||
CompactSizeUIntImpl(scriptPubKey.bytes.size,3)
|
||||
CompactSizeUInt(scriptPubKey.bytes.size,3)
|
||||
} else if (scriptPubKey.bytes.size <= 0xffffffff) {
|
||||
CompactSizeUIntImpl(scriptPubKey.bytes.size,5)
|
||||
}
|
||||
else CompactSizeUIntImpl(scriptPubKey.bytes.size,9)
|
||||
CompactSizeUInt(scriptPubKey.bytes.size,5)
|
||||
} else CompactSizeUInt(scriptPubKey.bytes.size,9)
|
||||
}
|
||||
|
||||
private def parseLong(hex : String) : Long = java.lang.Long.parseLong(hex,16)
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package org.bitcoins.core.protocol.blockchain
|
||||
|
||||
import org.bitcoins.core.currency.Bitcoins
|
||||
import org.scalatest.{FlatSpec, MustMatchers}
|
||||
|
||||
/**
|
||||
* Created by chris on 5/24/16.
|
||||
*/
|
||||
class ChainParamsTest extends FlatSpec with MustMatchers {
|
||||
|
||||
"ChainParams" must "create the bitcoin genesis block" in {
|
||||
val genesisBlock = MainNetChainParams.createGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, Bitcoins(50))
|
||||
genesisBlock.hash must be ("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import org.bitcoinj.core.DumpedPrivateKey
|
|||
import org.bitcoins.core.config.TestNet3
|
||||
import org.bitcoins.core.crypto.{ECFactory, ECPublicKey}
|
||||
import org.bitcoins.core.currency.CurrencyUnits
|
||||
import org.bitcoins.core.protocol.{CompactSizeUIntImpl}
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.transaction._
|
||||
import org.slf4j.LoggerFactory
|
||||
|
|
Loading…
Add table
Reference in a new issue