commit
acd9467147
|
@ -385,34 +385,9 @@ mod tests {
|
|||
|
||||
use super::{Storage, Store};
|
||||
use devtools::RandomTempPath;
|
||||
use chain::{
|
||||
Block, BlockHeader, Transaction, RepresentH256, TransactionOutput,
|
||||
TransactionInput, OutPoint,
|
||||
};
|
||||
use chain::{Block, RepresentH256};
|
||||
use super::super::BlockRef;
|
||||
use test_data;
|
||||
use primitives::hash::H256;
|
||||
use primitives::bytes::Bytes;
|
||||
|
||||
fn dummy_coinbase_tx() -> Transaction {
|
||||
Transaction {
|
||||
version: 0,
|
||||
inputs: vec![
|
||||
TransactionInput {
|
||||
previous_output: OutPoint { hash: H256::from(0), index: 0xffffffff },
|
||||
script_sig: Bytes::new_with_len(0),
|
||||
sequence: 0
|
||||
}
|
||||
],
|
||||
outputs: vec![
|
||||
TransactionOutput {
|
||||
value: 0,
|
||||
script_pubkey: Bytes::new_with_len(0),
|
||||
}
|
||||
],
|
||||
lock_time: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn open_store() {
|
||||
|
@ -505,36 +480,15 @@ mod tests {
|
|||
let genesis_meta = store.transaction_meta(&genesis_coinbase).unwrap();
|
||||
assert!(!genesis_meta.is_spent(0));
|
||||
|
||||
let forged_block = Block::new(
|
||||
BlockHeader {
|
||||
version: 0,
|
||||
previous_header_hash: genesis.hash(),
|
||||
merkle_root_hash: H256::from(0),
|
||||
nbits: 0,
|
||||
time: 0,
|
||||
nonce: 0,
|
||||
},
|
||||
vec![
|
||||
dummy_coinbase_tx(),
|
||||
Transaction {
|
||||
version: 0,
|
||||
inputs: vec![
|
||||
TransactionInput {
|
||||
previous_output: OutPoint { hash: genesis_coinbase.clone(), index: 0 },
|
||||
script_sig: Bytes::new_with_len(0),
|
||||
sequence: 0
|
||||
}
|
||||
],
|
||||
outputs: vec![
|
||||
TransactionOutput {
|
||||
value: 0,
|
||||
script_pubkey: Bytes::new_with_len(0),
|
||||
}
|
||||
],
|
||||
lock_time: 0,
|
||||
},
|
||||
]
|
||||
);
|
||||
let forged_block = test_data::block_builder()
|
||||
.header().parent(genesis.hash()).build()
|
||||
.transaction().coinbase().build()
|
||||
.transaction()
|
||||
.input().hash(genesis_coinbase.clone()).build()
|
||||
.output().build()
|
||||
.build()
|
||||
.build();
|
||||
|
||||
store.insert_block(&forged_block).unwrap();
|
||||
|
||||
let genesis_meta = store.transaction_meta(&genesis_coinbase).unwrap();
|
||||
|
|
|
@ -0,0 +1,350 @@
|
|||
//! Block builder
|
||||
|
||||
use chain;
|
||||
use primitives::hash::H256;
|
||||
use primitives::bytes::Bytes;
|
||||
use invoke::{Invoke, Identity};
|
||||
|
||||
pub struct BlockBuilder<F=Identity> {
|
||||
callback: F,
|
||||
header: Option<chain::BlockHeader>,
|
||||
transactions: Vec<chain::Transaction>,
|
||||
}
|
||||
|
||||
impl BlockBuilder {
|
||||
pub fn new() -> Self {
|
||||
BlockBuilder::with_callback(Identity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> BlockBuilder<F> where F: Invoke<chain::Block> {
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
BlockBuilder {
|
||||
callback: callback,
|
||||
header: None,
|
||||
transactions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_header(mut self, header: chain::BlockHeader) -> Self {
|
||||
self.header = Some(header);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_transaction(mut self, transaction: chain::Transaction) -> Self {
|
||||
self.transactions.push(transaction);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_transactions<I>(mut self, txs: I) -> Self
|
||||
where I: IntoIterator<Item=chain::Transaction>
|
||||
{
|
||||
self.transactions.extend(txs);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_raw(mut self, raw: &'static str) -> Self {
|
||||
let raw_block: chain::Block = raw.into();
|
||||
self.transactions = raw_block.transactions.to_vec();
|
||||
self.header = Some(raw_block.header().clone());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn header(self) -> BlockHeaderBuilder<Self> {
|
||||
BlockHeaderBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
pub fn transaction(self) -> TransactionBuilder<Self> {
|
||||
TransactionBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(
|
||||
chain::Block::new(
|
||||
self.header.unwrap(),
|
||||
self.transactions,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Invoke<chain::BlockHeader> for BlockBuilder<F>
|
||||
where F: Invoke<chain::Block>
|
||||
{
|
||||
type Result = Self;
|
||||
|
||||
fn invoke(self, header: chain::BlockHeader) -> Self {
|
||||
self.with_header(header)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Invoke<chain::Transaction> for BlockBuilder<F>
|
||||
where F: Invoke<chain::Block>
|
||||
{
|
||||
type Result = Self;
|
||||
|
||||
fn invoke(self, tx: chain::Transaction) -> Self {
|
||||
self.with_transaction(tx)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BlockHeaderBuilder<F=Identity> {
|
||||
callback: F,
|
||||
time: u32,
|
||||
parent: H256,
|
||||
nonce: u32,
|
||||
nbits: u32,
|
||||
version: u32,
|
||||
merkle_root: H256,
|
||||
}
|
||||
|
||||
impl<F> BlockHeaderBuilder<F> where F: Invoke<chain::BlockHeader> {
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
BlockHeaderBuilder {
|
||||
callback: callback,
|
||||
time: 0,
|
||||
nonce: 0,
|
||||
merkle_root: H256::from(0),
|
||||
parent: H256::from(0),
|
||||
nbits: 0,
|
||||
version: 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent(mut self, parent: H256) -> Self {
|
||||
self.parent = parent;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn time(mut self, time: u32) -> Self {
|
||||
self.time = time;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn merkle_root(mut self, merkle_root: H256) -> Self {
|
||||
self.merkle_root = merkle_root;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn nbits(mut self, nbits: u32) -> Self {
|
||||
self.nbits = nbits;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn nonce(mut self, nonce: u32) -> Self {
|
||||
self.nonce = nonce;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(
|
||||
chain::BlockHeader {
|
||||
time: self.time,
|
||||
previous_header_hash: self.parent,
|
||||
nbits: self.nbits,
|
||||
nonce: self.nonce,
|
||||
merkle_root_hash: self.merkle_root,
|
||||
version: self.version,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TransactionBuilder<F=Identity> {
|
||||
callback: F,
|
||||
version: i32,
|
||||
lock_time: u32,
|
||||
inputs: Vec<chain::TransactionInput>,
|
||||
outputs: Vec<chain::TransactionOutput>,
|
||||
}
|
||||
|
||||
impl<F> TransactionBuilder<F> where F: Invoke<chain::Transaction> {
|
||||
fn with_callback(callback: F) -> Self {
|
||||
TransactionBuilder {
|
||||
callback: callback,
|
||||
version: 1,
|
||||
lock_time: 0,
|
||||
inputs: Vec::new(),
|
||||
outputs: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn with_input(mut self, input: chain::TransactionInput) -> Self {
|
||||
self.inputs.push(input);
|
||||
self
|
||||
}
|
||||
|
||||
fn with_output(mut self, input: chain::TransactionOutput) -> Self {
|
||||
self.outputs.push(input);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn lock_time(mut self, time: u32) -> Self {
|
||||
self.lock_time = time;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn input(self) -> TransactionInputBuilder<Self> {
|
||||
TransactionInputBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
pub fn coinbase(self) -> Self {
|
||||
self.input().coinbase().build()
|
||||
}
|
||||
|
||||
pub fn output(self) -> TransactionOutputBuilder<Self> {
|
||||
TransactionOutputBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(
|
||||
chain::Transaction {
|
||||
lock_time: self.lock_time,
|
||||
version: self.version,
|
||||
inputs: self.inputs,
|
||||
outputs: self.outputs,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<F> Invoke<chain::TransactionInput> for TransactionBuilder<F>
|
||||
where F: Invoke<chain::Transaction>
|
||||
{
|
||||
type Result = Self;
|
||||
|
||||
fn invoke(self, tx: chain::TransactionInput) -> Self {
|
||||
self.with_input(tx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Invoke<chain::TransactionOutput> for TransactionBuilder<F>
|
||||
where F: Invoke<chain::Transaction>
|
||||
{
|
||||
type Result = Self;
|
||||
|
||||
fn invoke(self, tx: chain::TransactionOutput) -> Self {
|
||||
self.with_output(tx)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TransactionInputBuilder<F=Identity> {
|
||||
callback: F,
|
||||
output: Option<chain::OutPoint>,
|
||||
signature: Bytes,
|
||||
sequence: u32,
|
||||
}
|
||||
|
||||
impl<F> TransactionInputBuilder<F> where F: Invoke<chain::TransactionInput> {
|
||||
fn with_callback(callback: F) -> Self {
|
||||
TransactionInputBuilder {
|
||||
callback: callback,
|
||||
output: None,
|
||||
signature: Bytes::new_with_len(0),
|
||||
sequence: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hash(mut self, hash: H256) -> Self {
|
||||
let mut output = self.output.unwrap_or(chain::OutPoint { hash: hash.clone(), index: 0 });
|
||||
output.hash = hash;
|
||||
self.output = Some(output);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn index(mut self, index: u32) -> Self {
|
||||
let mut output = self.output.unwrap_or(chain::OutPoint { hash: H256::from(0), index: index });
|
||||
output.index = index;
|
||||
self.output = Some(output);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn coinbase(mut self) -> Self {
|
||||
self.output = Some(chain::OutPoint { hash: H256::from(0), index: 0xffffffff });
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(
|
||||
chain::TransactionInput {
|
||||
previous_output: self.output.unwrap_or_else(|| panic!("Building input without previous output")),
|
||||
script_sig: self.signature,
|
||||
sequence: self.sequence,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct TransactionOutputBuilder<F=Identity> {
|
||||
callback: F,
|
||||
value: u64,
|
||||
signature: Bytes,
|
||||
}
|
||||
|
||||
impl<F> TransactionOutputBuilder<F> where F: Invoke<chain::TransactionOutput> {
|
||||
fn with_callback(callback: F) -> Self {
|
||||
TransactionOutputBuilder {
|
||||
callback: callback,
|
||||
signature: Bytes::new_with_len(0),
|
||||
value: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value(mut self, value: u64) -> Self {
|
||||
self.value = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(
|
||||
chain::TransactionOutput {
|
||||
script_pubkey: self.signature,
|
||||
value: self.value,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block_builder() -> BlockBuilder { BlockBuilder::new() }
|
||||
|
||||
#[test]
|
||||
fn example1() {
|
||||
let block = BlockBuilder::new().header().time(1000).build().build();
|
||||
assert_eq!(block.header().time, 1000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example2() {
|
||||
let block = BlockBuilder::new()
|
||||
.header().build()
|
||||
.transaction().lock_time(100500).build()
|
||||
.build();
|
||||
|
||||
assert_eq!(block.transactions().len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example3() {
|
||||
let block = block_builder().header().build()
|
||||
.transaction().coinbase().build()
|
||||
.build();
|
||||
|
||||
assert!(block.transactions()[0].is_coinbase());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example4() {
|
||||
let block = block_builder().header().build()
|
||||
.transaction().coinbase()
|
||||
.output().value(10).build()
|
||||
.build()
|
||||
.transaction()
|
||||
.input().hash(H256::from(1)).index(1).build()
|
||||
.build()
|
||||
.build();
|
||||
|
||||
assert_eq!(block.transactions().len(), 2);
|
||||
assert_eq!(block.transactions()[1].inputs[0].previous_output.hash, H256::from(1));
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
//! invoke helper
|
||||
|
||||
pub trait Invoke<A> {
|
||||
type Result;
|
||||
|
||||
fn invoke(self, arg: A) -> Self::Result;
|
||||
}
|
||||
|
||||
pub struct Identity;
|
||||
|
||||
impl<A> Invoke<A> for Identity {
|
||||
type Result = A;
|
||||
|
||||
fn invoke(self, arg: A) -> A { arg }
|
||||
}
|
|
@ -7,8 +7,11 @@ extern crate serialization as ser;
|
|||
use chain::Block;
|
||||
|
||||
pub mod chain_builder;
|
||||
pub mod block;
|
||||
pub mod invoke;
|
||||
|
||||
pub use chain_builder::{ChainBuilder, TransactionBuilder};
|
||||
pub use block::block_builder;
|
||||
|
||||
pub fn block1() -> Block {
|
||||
let block: Block = "01000000ba8b9cda965dd8e536670f9ddec10e53aab14b20bacad27b9137190000000000190760b278fe7b8565fda3b968b918d5fd997f993b23674c0af3b6fde300b38f33a5914ce6ed5b1b01e32f570201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704e6ed5b1b014effffffff0100f2052a01000000434104b68a50eaa0287eff855189f949c1c6e5f58b37c88231373d8a59809cbae83059cc6469d65c665ccfd1cfeb75c6e8e19413bba7fbff9bc762419a76d87b16086eac000000000100000001a6b97044d03da79c005b20ea9c0e1a6d9dc12d9f7b91a5911c9030a439eed8f5000000004948304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501ffffffff0100f2052a010000001976a914404371705fa9bd789a2fcd52d2c580b65d35549d88ac00000000".into();
|
||||
|
|
Loading…
Reference in New Issue