From 71670e6277c192fe0b1426e0a64586a9957bcdb0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 Jan 2016 18:26:35 +0100 Subject: [PATCH 1/5] Fix test warnings. --- src/block.rs | 5 ++--- src/ethereum/ethash.rs | 8 +------- src/ethereum/mod.rs | 4 ++-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/block.rs b/src/block.rs index 3c42e4e27..6ed97f6a7 100644 --- a/src/block.rs +++ b/src/block.rs @@ -123,7 +123,7 @@ impl<'engine> OpenBlock<'engine> { } } - /// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure ou the uncles. + /// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles. pub fn close(self, _uncles: Vec
) -> ClosedBlock<'engine> { unimplemented!(); } } @@ -155,11 +155,10 @@ impl IsBlock for SealedBlock { #[test] fn open_block() { - use super::*; use spec::*; let engine = Spec::new_test().to_engine().unwrap(); let genesis_header = engine.spec().genesis_header(); let mut db = OverlayDB::new_temp(); engine.spec().ensure_db_good(&mut db); - let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()]); + let _ = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()]); } \ No newline at end of file diff --git a/src/ethereum/ethash.rs b/src/ethereum/ethash.rs index 13b1f6a46..a238330ea 100644 --- a/src/ethereum/ethash.rs +++ b/src/ethereum/ethash.rs @@ -31,16 +31,10 @@ impl Engine for Ethash { #[test] fn playpen() { use super::*; - use state::*; let engine = new_morden().to_engine().unwrap(); let genesis_header = engine.spec().genesis_header(); let mut db = OverlayDB::new_temp(); engine.spec().ensure_db_good(&mut db); - assert!(SecTrieDB::new(&db, &genesis_header.state_root).contains(&address_from_hex("102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c"))); - { - let s = State::from_existing(db.clone(), genesis_header.state_root.clone(), engine.account_start_nonce()); - assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64)); - } - let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()]); + let _ = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()]); // let c = b.close(); } \ No newline at end of file diff --git a/src/ethereum/mod.rs b/src/ethereum/mod.rs index e743c6d09..ed1950d64 100644 --- a/src/ethereum/mod.rs +++ b/src/ethereum/mod.rs @@ -56,7 +56,7 @@ mod tests { let genesis = morden.genesis_block(); assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap()); - morden.to_engine(); + let _ = morden.to_engine(); } #[test] @@ -67,6 +67,6 @@ mod tests { let genesis = frontier.genesis_block(); assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap()); - frontier.to_engine(); + let _ = frontier.to_engine(); } } \ No newline at end of file From 8b5b493f7de742f32c949e1f6e1a38307474b8c1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 Jan 2016 18:58:04 +0100 Subject: [PATCH 2/5] Sketch of how OpenBlock::close() might look. --- src/block.rs | 32 ++++++++++++++++++++++++++++--- src/header.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/block.rs b/src/block.rs index 6ed97f6a7..15546f665 100644 --- a/src/block.rs +++ b/src/block.rs @@ -71,7 +71,7 @@ pub struct OpenBlock<'engine> { /// There is no function available to push a transaction. If you want that you'll need to `reopen()` it. pub struct ClosedBlock<'engine> { open_block: OpenBlock<'engine>, - _uncles: Vec
, + uncles: Bytes, } /// A block that has a valid seal. @@ -105,7 +105,7 @@ impl<'engine> OpenBlock<'engine> { timestamp: self.block.header.timestamp.clone(), difficulty: self.block.header.difficulty.clone(), last_hashes: self.last_hashes.clone(), - gas_used: if let Some(ref t) = self.block.archive.last() {t.receipt.gas_used} else {U256::from(0)}, + gas_used: self.block.archive.last().map(|t| t.receipt.gas_used).unwrap_or(U256::from(0)), gas_limit: self.block.header.gas_limit.clone(), } } @@ -124,7 +124,26 @@ impl<'engine> OpenBlock<'engine> { } /// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles. - pub fn close(self, _uncles: Vec
) -> ClosedBlock<'engine> { unimplemented!(); } + pub fn close(self, uncles: Vec
, author: Address, extra_data: Bytes) -> ClosedBlock<'engine> { + // TODO: populate rest of header. + self.engine.on_close_block(...); + self.header.author = author; + //self.header.transactions_root = ...; + let s = RlpStream::new_list(uncles.len()); + for u in uncles.iter() { + s.append(u.rlp()) + } + let uncle_bytes = u.out(); + self.header.uncles_hash = uncle_bytes.sha3(); + self.header.extra_data = extra_data; + self.header.state_root = self.state.root().clone(); + //self.header.receipts_root = ...; + //self.header.log_bloom = ...; // will need to amalgamate. + self.header.gas_used = self.block.archive.last().map(|t| t.receipt.gas_used).unwrap_or(U256::from(0)); + self.header.note_dirty(); + + ClosedBlock::new(self, uncle_bytes) + } } impl<'engine> IsBlock for OpenBlock<'engine> { @@ -132,6 +151,13 @@ impl<'engine> IsBlock for OpenBlock<'engine> { } impl<'engine> ClosedBlock<'engine> { + fn new(open_block: OpenBlock, uncles: Bytes) -> Self { + Self { + open_block: open_block, + uncles: uncles, + } + } + /// Get the hash of the header without seal arguments. pub fn preseal_hash(&self) -> H256 { unimplemented!(); } diff --git a/src/header.rs b/src/header.rs index 80d91eb20..85655d6e0 100644 --- a/src/header.rs +++ b/src/header.rs @@ -39,6 +39,13 @@ pub struct Header { pub hash: RefCell>, //TODO: make this private } +enum SealInclusion { + WithSeal, + WithoutSeal, +} + +pub use SealInclusion::*; + impl Header { /// Create a new, default-valued, header. pub fn new() -> Header { @@ -64,19 +71,55 @@ impl Header { } } + /// Get the hash of this header (sha3 of the RLP). pub fn hash(&self) -> H256 { let mut hash = self.hash.borrow_mut(); match &mut *hash { &mut Some(ref h) => h.clone(), hash @ &mut None => { - let mut stream = RlpStream::new(); - stream.append(self); - let h = stream.as_raw().sha3(); - *hash = Some(h.clone()); - h.clone() + *hash = Some(self.hash(WithSeal)); + hash.unwrap().clone() } } } + + /// Note that some fields have changed. Resets the memoised hash. + pub fn note_dirty(&self) { + *self.hash.borrow_mut() = None; + } + + // TODO: get hash without seal. + + // TODO: make these functions traity + pub fn stream_rlp(&self, s: &mut RlpStream, with_seal: SealInclusion) { + s.append_list(13 + if with_seal == WithSeal {self.seal.len()} else {0}) + s.append(&self.parent_hash); + s.append(&self.uncles_hash); + s.append(&self.author); + s.append(&self.state_root); + s.append(&self.transactions_root); + s.append(&self.receipts_root); + s.append(&self.log_bloom); + s.append(&self.difficulty); + s.append(&self.number); + s.append(&self.gas_limit); + s.append(&self.gas_used); + s.append(&self.timestamp); + s.append(&self.extra_data); + if with_seal == WithSeal { + for b in self.seal.iter() { + e.append_raw(&b); + } + } + } + + pub rlp(&self, with_seal: SealInclusion) -> Bytes { + let s = RlpStream::new(); + self.stream_rlp(&mut s, with_seal); + s.out() + } + + pub hash(&self, with_seal: SealInclusion) -> H256 { self.rlp().sha3() } } impl Decodable for Header { From 249c6157522631bf73da328707ca3f71994ed45c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 Jan 2016 22:13:13 +0100 Subject: [PATCH 3/5] Minor refactoring, OpenBlock::close closer to working. --- src/basic_types.rs | 7 +++++++ src/block.rs | 40 ++++++++++++++++------------------------ src/common.rs | 2 ++ src/header.rs | 40 ++++++++++++++-------------------------- src/lib.rs | 3 ++- src/receipt.rs | 2 ++ 6 files changed, 43 insertions(+), 51 deletions(-) create mode 100644 src/basic_types.rs diff --git a/src/basic_types.rs b/src/basic_types.rs new file mode 100644 index 000000000..2c18c59d2 --- /dev/null +++ b/src/basic_types.rs @@ -0,0 +1,7 @@ +use util::*; + +/// Type for a 2048-bit log-bloom, as used by our blocks. +pub type LogBloom = H2048; + +/// Constant 2048-bit datum for 0. Often used as a default. +pub static ZERO_LOGBLOOM: LogBloom = H2048([0x00; 256]); diff --git a/src/block.rs b/src/block.rs index 15546f665..79bcd5505 100644 --- a/src/block.rs +++ b/src/block.rs @@ -1,9 +1,5 @@ -use util::*; -use transaction::*; -use receipt::*; +use common::*; use engine::*; -use header::*; -use env_info::*; use state::*; /// A transaction/receipt execution entry. @@ -124,23 +120,19 @@ impl<'engine> OpenBlock<'engine> { } /// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles. - pub fn close(self, uncles: Vec
, author: Address, extra_data: Bytes) -> ClosedBlock<'engine> { - // TODO: populate rest of header. - self.engine.on_close_block(...); - self.header.author = author; - //self.header.transactions_root = ...; - let s = RlpStream::new_list(uncles.len()); - for u in uncles.iter() { - s.append(u.rlp()) - } - let uncle_bytes = u.out(); - self.header.uncles_hash = uncle_bytes.sha3(); - self.header.extra_data = extra_data; - self.header.state_root = self.state.root().clone(); - //self.header.receipts_root = ...; - //self.header.log_bloom = ...; // will need to amalgamate. - self.header.gas_used = self.block.archive.last().map(|t| t.receipt.gas_used).unwrap_or(U256::from(0)); - self.header.note_dirty(); + pub fn close(mut self, uncles: Vec
, author: Address, extra_data: Bytes) -> ClosedBlock<'engine> { + // populate rest of header. +// self.engine.on_close_block(...); + self.block.header.author = author; +// self.header.transactions_root = ...; + let uncle_bytes = uncles.iter().fold(RlpStream::new_list(uncles.len()), |mut s, u| {s.append(&u.rlp(Seal::With)); s} ).out(); + self.block.header.uncles_hash = uncle_bytes.sha3(); + self.block.header.extra_data = extra_data; + self.block.header.state_root = self.block.state.root().clone(); +// self.header.receipts_root = ...; + self.block.header.log_bloom = self.block.archive.iter().fold(LogBloom::zero(), |mut b, e| {b |= &e.receipt.log_bloom; b}); + self.block.header.gas_used = self.block.archive.last().map(|t| t.receipt.gas_used).unwrap_or(U256::from(0)); + self.block.header.note_dirty(); ClosedBlock::new(self, uncle_bytes) } @@ -151,8 +143,8 @@ impl<'engine> IsBlock for OpenBlock<'engine> { } impl<'engine> ClosedBlock<'engine> { - fn new(open_block: OpenBlock, uncles: Bytes) -> Self { - Self { + fn new<'a>(open_block: OpenBlock<'a>, uncles: Bytes) -> ClosedBlock<'a> { + ClosedBlock { open_block: open_block, uncles: uncles, } diff --git a/src/common.rs b/src/common.rs index ec4eb14cd..106a7a3b9 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,4 +1,5 @@ pub use util::*; +pub use basic_types::*; pub use env_info::*; pub use evm_schedule::*; pub use views::*; @@ -6,3 +7,4 @@ pub use builtin::*; pub use header::*; pub use account::*; pub use transaction::*; +pub use receipt::*; diff --git a/src/header.rs b/src/header.rs index 85655d6e0..56f03460e 100644 --- a/src/header.rs +++ b/src/header.rs @@ -1,14 +1,5 @@ use util::*; - -/// 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]); +use basic_types::*; /// A block header. /// @@ -39,13 +30,11 @@ pub struct Header { pub hash: RefCell>, //TODO: make this private } -enum SealInclusion { - WithSeal, - WithoutSeal, +pub enum Seal { + With, + Without, } -pub use SealInclusion::*; - impl Header { /// Create a new, default-valued, header. pub fn new() -> Header { @@ -77,8 +66,8 @@ impl Header { match &mut *hash { &mut Some(ref h) => h.clone(), hash @ &mut None => { - *hash = Some(self.hash(WithSeal)); - hash.unwrap().clone() + *hash = Some(self.rlp_sha3(Seal::With)); + hash.as_ref().unwrap().clone() } } } @@ -91,8 +80,8 @@ impl Header { // TODO: get hash without seal. // TODO: make these functions traity - pub fn stream_rlp(&self, s: &mut RlpStream, with_seal: SealInclusion) { - s.append_list(13 + if with_seal == WithSeal {self.seal.len()} else {0}) + pub fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) { + s.append_list(13 + match with_seal { Seal::With => self.seal.len(), _ => 0 }); s.append(&self.parent_hash); s.append(&self.uncles_hash); s.append(&self.author); @@ -106,20 +95,19 @@ impl Header { s.append(&self.gas_used); s.append(&self.timestamp); s.append(&self.extra_data); - if with_seal == WithSeal { - for b in self.seal.iter() { - e.append_raw(&b); - } + match with_seal { + Seal::With => for b in self.seal.iter() { s.append_raw(&b, 1); }, + _ => {} } } - pub rlp(&self, with_seal: SealInclusion) -> Bytes { - let s = RlpStream::new(); + pub fn rlp(&self, with_seal: Seal) -> Bytes { + let mut s = RlpStream::new(); self.stream_rlp(&mut s, with_seal); s.out() } - pub hash(&self, with_seal: SealInclusion) -> H256 { self.rlp().sha3() } + pub fn rlp_sha3(&self, with_seal: Seal) -> H256 { self.rlp(with_seal).sha3() } } impl Decodable for Header { diff --git a/src/lib.rs b/src/lib.rs index 698801d8e..f4621feeb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ #![feature(cell_extras)] - +#![feature(augmented_assignments)] //! Ethcore's ethereum implementation //! //! ### Rust version @@ -85,6 +85,7 @@ extern crate evmjit; extern crate ethcore_util as util; pub mod common; +pub mod basic_types; pub mod env_info; pub mod engine; pub mod state; diff --git a/src/receipt.rs b/src/receipt.rs index fb72e2e18..6f91c14dc 100644 --- a/src/receipt.rs +++ b/src/receipt.rs @@ -1,8 +1,10 @@ use util::*; +use basic_types::LogBloom; /// Information describing execution of a transaction. pub struct Receipt { // TODO pub state_root: H256, pub gas_used: U256, + pub log_bloom: LogBloom, } From cf8ef01c6de2ad37102f4414a3983852e732ef5f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 Jan 2016 22:28:31 +0100 Subject: [PATCH 4/5] State::kill_account added with tests & docs. --- src/state.rs | 56 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/state.rs b/src/state.rs index f0e10fa2d..3afa1d308 100644 --- a/src/state.rs +++ b/src/state.rs @@ -79,6 +79,11 @@ impl State { self.require_or_from(contract, false, || Account::new_contract(U256::from(0u8)), |r| r.reset_code()); } + /// Remove an existing account. + pub fn kill_account(&mut self, account: &Address) { + self.cache.borrow_mut().insert(account.clone(), None); + } + /// Get the balance of account `a`. pub fn balance(&self, a: &Address) -> U256 { self.get(a, false).as_ref().map(|account| account.balance().clone()).unwrap_or(U256::from(0u8)) @@ -228,12 +233,11 @@ use util::hash::*; use util::trie::*; use util::rlp::*; use util::uint::*; -use std::str::FromStr; use account::*; #[test] fn code_from_database() { - let a = Address::from_str("0000000000000000000000000000000000000000").unwrap(); + let a = Address::zero(); let (r, db) = { let mut s = State::new_temp(); s.require_or_from(&a, false, ||Account::new_contract(U256::from(42u32)), |_|{}); @@ -250,7 +254,7 @@ fn code_from_database() { #[test] fn storage_at_from_database() { - let a = Address::from_str("0000000000000000000000000000000000000000").unwrap(); + let a = Address::zero(); let (r, db) = { let mut s = State::new_temp(); s.set_storage(&a, H256::from(&U256::from(01u64)), H256::from(&U256::from(69u64))); @@ -264,7 +268,7 @@ fn storage_at_from_database() { #[test] fn get_from_database() { - let a = Address::from_str("0000000000000000000000000000000000000000").unwrap(); + let a = Address::zero(); let (r, db) = { let mut s = State::new_temp(); s.inc_nonce(&a); @@ -279,11 +283,45 @@ fn get_from_database() { assert_eq!(s.nonce(&a), U256::from(1u64)); } +#[test] +fn remove() { + let a = Address::zero(); + let mut s = State::new_temp(); + s.inc_nonce(&a); + assert_eq!(s.nonce(&a), U256::from(1u64)); + s.kill_account(&a); + assert_eq!(s.nonce(&a), U256::from(0u64)); +} + +#[test] +fn remove_from_database() { + let a = Address::zero(); + let (r, db) = { + let mut s = State::new_temp(); + s.inc_nonce(&a); + s.commit(); + assert_eq!(s.nonce(&a), U256::from(1u64)); + s.drop() + }; + + let (r, db) = { + let mut s = State::from_existing(db, r, U256::from(0u8)); + assert_eq!(s.nonce(&a), U256::from(1u64)); + s.kill_account(&a); + s.commit(); + assert_eq!(s.nonce(&a), U256::from(0u64)); + s.drop() + }; + + let s = State::from_existing(db, r, U256::from(0u8)); + assert_eq!(s.nonce(&a), U256::from(0u64)); +} + #[test] fn alter_balance() { let mut s = State::new_temp(); - let a = Address::from_str("0000000000000000000000000000000000000000").unwrap(); - let b = Address::from_str("0000000000000000000000000000000000000001").unwrap(); + let a = Address::zero(); + let b = address_from_u64(1u64); s.add_balance(&a, &U256::from(69u64)); assert_eq!(s.balance(&a), U256::from(69u64)); s.commit(); @@ -303,7 +341,7 @@ fn alter_balance() { #[test] fn alter_nonce() { let mut s = State::new_temp(); - let a = Address::from_str("0000000000000000000000000000000000000000").unwrap(); + let a = Address::zero(); s.inc_nonce(&a); assert_eq!(s.nonce(&a), U256::from(1u64)); s.inc_nonce(&a); @@ -319,7 +357,7 @@ fn alter_nonce() { #[test] fn balance_nonce() { let mut s = State::new_temp(); - let a = Address::from_str("0000000000000000000000000000000000000000").unwrap(); + let a = Address::zero(); assert_eq!(s.balance(&a), U256::from(0u64)); assert_eq!(s.nonce(&a), U256::from(0u64)); s.commit(); @@ -330,7 +368,7 @@ fn balance_nonce() { #[test] fn ensure_cached() { let mut s = State::new_temp(); - let a = Address::from_str("0000000000000000000000000000000000000000").unwrap(); + let a = Address::zero(); s.require(&a, false); s.commit(); assert_eq!(s.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785"); From 9a79a9032d74c06d97440c1c44987539bf27fe5e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 Jan 2016 22:45:27 +0100 Subject: [PATCH 5/5] on_close_block fixed and tested. --- src/block.rs | 32 ++++++++++++++++++-------------- src/ethereum/ethash.rs | 10 +++++----- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/block.rs b/src/block.rs index 79bcd5505..aefa1da2f 100644 --- a/src/block.rs +++ b/src/block.rs @@ -120,21 +120,22 @@ impl<'engine> OpenBlock<'engine> { } /// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles. - pub fn close(mut self, uncles: Vec
, author: Address, extra_data: Bytes) -> ClosedBlock<'engine> { + pub fn close(self, uncles: Vec
, author: Address, extra_data: Bytes) -> ClosedBlock<'engine> { + let mut s = self; // populate rest of header. -// self.engine.on_close_block(...); - self.block.header.author = author; -// self.header.transactions_root = ...; + s.engine.on_close_block(&mut s.block); + s.block.header.author = author; +// s.header.transactions_root = ...; let uncle_bytes = uncles.iter().fold(RlpStream::new_list(uncles.len()), |mut s, u| {s.append(&u.rlp(Seal::With)); s} ).out(); - self.block.header.uncles_hash = uncle_bytes.sha3(); - self.block.header.extra_data = extra_data; - self.block.header.state_root = self.block.state.root().clone(); -// self.header.receipts_root = ...; - self.block.header.log_bloom = self.block.archive.iter().fold(LogBloom::zero(), |mut b, e| {b |= &e.receipt.log_bloom; b}); - self.block.header.gas_used = self.block.archive.last().map(|t| t.receipt.gas_used).unwrap_or(U256::from(0)); - self.block.header.note_dirty(); + s.block.header.uncles_hash = uncle_bytes.sha3(); + s.block.header.extra_data = extra_data; + s.block.header.state_root = s.block.state.root().clone(); +// s.header.receipts_root = ...; + s.block.header.log_bloom = s.block.archive.iter().fold(LogBloom::zero(), |mut b, e| {b |= &e.receipt.log_bloom; b}); + s.block.header.gas_used = s.block.archive.last().map(|t| t.receipt.gas_used).unwrap_or(U256::from(0)); + s.block.header.note_dirty(); - ClosedBlock::new(self, uncle_bytes) + ClosedBlock::new(s, uncle_bytes) } } @@ -174,9 +175,12 @@ impl IsBlock for SealedBlock { #[test] fn open_block() { use spec::*; - let engine = Spec::new_test().to_engine().unwrap(); + use ethereum::*; + let engine = new_morden().to_engine().unwrap(); let genesis_header = engine.spec().genesis_header(); let mut db = OverlayDB::new_temp(); engine.spec().ensure_db_good(&mut db); - let _ = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()]); + let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()]); + let b = b.close(vec![], Address::zero(), vec![]); + assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244F40000").unwrap()); } \ No newline at end of file diff --git a/src/ethereum/ethash.rs b/src/ethereum/ethash.rs index a238330ea..02a21a233 100644 --- a/src/ethereum/ethash.rs +++ b/src/ethereum/ethash.rs @@ -23,18 +23,18 @@ impl Engine for Ethash { /// Apply the block reward on finalisation of the block. fn on_close_block(&self, block: &mut Block) { let a = block.header().author.clone(); - block.state_mut().add_balance(&a, &decode(&self.spec().engine_params.get("block_reward").unwrap())); + block.state_mut().add_balance(&a, &decode(&self.spec().engine_params.get("blockReward").unwrap())); } } -// TODO: test for on_close_block. #[test] -fn playpen() { +fn on_close_block() { use super::*; let engine = new_morden().to_engine().unwrap(); let genesis_header = engine.spec().genesis_header(); let mut db = OverlayDB::new_temp(); engine.spec().ensure_db_good(&mut db); - let _ = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()]); -// let c = b.close(); + let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()]); + let b = b.close(vec![], Address::zero(), vec![]); + assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244F40000").unwrap()); } \ No newline at end of file