From db23ee765a112042c399ad2a87155cec1750a56e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 6 Jan 2016 15:57:17 +0100 Subject: [PATCH] Fixes and a test! Now correctly builds Morden's genesis block. --- src/header.rs | 23 +++++++++++---- src/spec.rs | 77 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 27 deletions(-) diff --git a/src/header.rs b/src/header.rs index 28e568e8e..6f9cd8f14 100644 --- a/src/header.rs +++ b/src/header.rs @@ -3,12 +3,22 @@ use util::bytes::*; use util::uint::*; use util::rlp::*; -pub static ZERO_ADDRESS: Address = Address([0x00; 20]); -pub static ZERO_H256: H256 = H256([0x00; 32]); -pub static ZERO_LOGBLOOM: LogBloom = H2048([0x00; 256]); - +/// Type for a 2048-bit log-bloom, as used by our blocks. pub type LogBloom = H2048; +/// Constant address for point 0. Often used as a default. +pub static ZERO_ADDRESS: Address = Address([0x00; 20]); +/// Constant 256-bit datum for 0. Often used as a default. +pub static ZERO_H256: H256 = H256([0x00; 32]); +/// Constant 2048-bit datum for 0. Often used as a default. +pub static ZERO_LOGBLOOM: LogBloom = H2048([0x00; 256]); + +/// A block header. +/// +/// Reflects the specific RLP fields of a block in the chain with additional room for the seal +/// which is non-specific. +/// +/// Doesn't do all that much on its own. #[derive(Debug)] pub struct Header { pub parent_hash: H256, @@ -31,6 +41,7 @@ pub struct Header { } impl Header { + /// Create a new, default-valued, header. pub fn new() -> Header { Header { parent_hash: ZERO_H256.clone(), @@ -76,7 +87,7 @@ impl Decodable for Header { }; for i in 13..d.len() { - blockheader.seal.push(try!(Decodable::decode(&d[i]))); + blockheader.seal.push(d[i].as_raw().to_vec()); } Ok(blockheader) @@ -101,7 +112,7 @@ impl Encodable for Header { self.extra_data.encode(e); for b in self.seal.iter() { - b.encode(e); + e.emit_raw(&b); } }) } diff --git a/src/spec.rs b/src/spec.rs index 872c41541..b0cffc901 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -34,7 +34,7 @@ pub fn base_to_json(source: &[u8]) -> Json { /// Convert JSON value to equivlaent RLP representation. // TODO: handle container types. -pub fn json_to_rlp(json: &Json) -> Bytes { +fn json_to_rlp(json: &Json) -> Bytes { match json { &Json::I64(o) => encode(&(o as u64)), &Json::U64(o) => encode(&o), @@ -49,7 +49,7 @@ pub fn json_to_rlp(json: &Json) -> Bytes { } /// Convert JSON to a string->RLP map. -pub fn json_to_rlp_map(json: &Json) -> HashMap { +fn json_to_rlp_map(json: &Json) -> HashMap { json.as_object().unwrap().iter().map(|(k, v)| (k, json_to_rlp(v))).fold(HashMap::new(), |mut acc, kv| { acc.insert(kv.0.clone(), kv.1); acc @@ -98,25 +98,22 @@ impl Spec { /// Return the state root for the genesis state, memoising accordingly. pub fn state_root(&self) -> Ref { if self.state_root_memo.borrow().is_none() { - *self.state_root_memo.borrow_mut() = Some(trie_root(self.genesis_state.iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect())); + *self.state_root_memo.borrow_mut() = Some(sec_trie_root(self.genesis_state.iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect())); } Ref::map(self.state_root_memo.borrow(), |x|x.as_ref().unwrap()) } - /// Compose the genesis block for this chain. - pub fn genesis_block(&self) -> Bytes { - let empty_list = RlpStream::new_list(0).out(); - let empty_list_sha3 = empty_list.sha3(); - let header = Header { + fn genesis_header(&self) -> Header { + Header { parent_hash: self.parent_hash.clone(), timestamp: self.timestamp.clone(), number: U256::from(0u8), author: self.author.clone(), - transactions_root: SHA3_EMPTY.clone(), - uncles_hash: empty_list_sha3.clone(), + transactions_root: SHA3_NULL_RLP.clone(), + uncles_hash: RlpStream::new_list(0).out().sha3(), extra_data: self.extra_data.clone(), state_root: self.state_root().clone(), - receipts_root: SHA3_EMPTY.clone(), + receipts_root: SHA3_NULL_RLP.clone(), log_bloom: H2048::new().clone(), gas_used: self.gas_used.clone(), gas_limit: self.gas_limit.clone(), @@ -130,7 +127,13 @@ impl Spec { let r = Rlp::new(&seal); (0..self.seal_fields).map(|i| r.at(i).raw().to_vec()).collect() }, - }; + } + } + + /// Compose the genesis block for this chain. + pub fn genesis_block(&self) -> Bytes { + let empty_list = RlpStream::new_list(0).out(); + let header = self.genesis_header(); let mut ret = RlpStream::new_list(3); ret.append(&header); ret.append_raw(&empty_list, 1); @@ -235,7 +238,7 @@ impl Spec { acc }), seal_fields: 2, - seal_rlp: { let mut r = RlpStream::new_list(2); r.append(&0x2au64); r.append(&H256::new()); r.out() }, // TODO: make correct + seal_rlp: { let mut r = RlpStream::new_list(2); r.append(&H256::new()); r.append(&0x2au64); r.out() }, // TODO: make correct state_root_memo: RefCell::new(None), } } @@ -273,12 +276,12 @@ impl Spec { acc }), seal_fields: 2, - seal_rlp: { let mut r = RlpStream::new_list(2); r.append(&0x42u64); r.append(&H256::new()); r.out() }, + seal_rlp: { let mut r = RlpStream::new_list(2); r.append(&H256::new()); r.append(&0x42u64); r.out() }, state_root_memo: RefCell::new(None), } } - /// Creates the Morden network chain spec. + /// Creates the actual Morden network chain spec. pub fn new_morden() -> Spec { Spec { engine_name: "Ethash".to_string(), @@ -299,21 +302,53 @@ impl Spec { builtins: Self::standard_builtins(), parent_hash: H256::new(), author: Address::new(), - difficulty: U256::from(131_072u64), - gas_limit: U256::from(0u64), + difficulty: U256::from(0x20000u64), + gas_limit: U256::from(0x2fefd8u64), gas_used: U256::from(0u64), timestamp: U256::from(0u64), extra_data: vec![], - genesis_state: vec![ - (Address::from_str("102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c").unwrap(), Account::new_basic(U256::from(1) << 200, U256::from(0))) - ].into_iter().fold(HashMap::new(), | mut acc, vec | { + genesis_state: { + let n = U256::from(1) << 20; + vec![ + (Address::from_str("0000000000000000000000000000000000000001").unwrap(), Account::new_basic(U256::from(1), n)), + (Address::from_str("0000000000000000000000000000000000000002").unwrap(), Account::new_basic(U256::from(1), n)), + (Address::from_str("0000000000000000000000000000000000000003").unwrap(), Account::new_basic(U256::from(1), n)), + (Address::from_str("0000000000000000000000000000000000000004").unwrap(), Account::new_basic(U256::from(1), n)), + (Address::from_str("102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c").unwrap(), Account::new_basic(U256::from(1) << 200, n)) + ]}.into_iter().fold(HashMap::new(), | mut acc, vec | { acc.insert(vec.0, vec.1); acc }), seal_fields: 2, - seal_rlp: { let mut r = RlpStream::new_list(2); r.append(&0x00006d6f7264656eu64); r.append(&H256::from_str("00000000000000000000000000000000000000647572616c65787365646c6578").unwrap()); r.out() }, // TODO: make correct + seal_rlp: { + let mut r = RlpStream::new(); + r.append(&H256::from_str("00000000000000000000000000000000000000647572616c65787365646c6578").unwrap()); + r.append(&FromHex::from_hex("00006d6f7264656e").unwrap()); + r.out() + }, state_root_memo: RefCell::new(None), } } } +mod tests { + use std::str::FromStr; + use util::uint::*; + use util::hash::*; + use util::bytes::*; + use util::trie::*; + use util::sha3::*; + use views::*; + use util::memorydb::*; + use super::*; + + #[test] + fn all() { + let morden = Spec::new_morden(); + // let engine = morden.to_engine(); // Ethash doesn't exist as an engine yet, so would fail. + + assert_eq!(*morden.state_root(), H256::from_str("f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9").unwrap()); + let genesis = morden.genesis_block(); + assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap()); + } +} \ No newline at end of file