From c7167068b8434fd8fb4b4db1ed289904508c7dca Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Dec 2015 21:15:22 +0000 Subject: [PATCH 1/6] Removed need for mutation in State. --- src/account.rs | 4 +- src/lib.rs | 2 + src/state.rs | 140 ++++++++++++++++++++++--------------------------- 3 files changed, 67 insertions(+), 79 deletions(-) diff --git a/src/account.rs b/src/account.rs index 4641c5bf1..7b5bd1908 100644 --- a/src/account.rs +++ b/src/account.rs @@ -41,10 +41,10 @@ impl Account { } /// Create a new account with the given balance. - pub fn new_basic(balance: U256) -> Account { + pub fn new_basic(balance: U256, nonce: U256) -> Account { Account { balance: balance, - nonce: U256::from(0u8), + nonce: nonce, storage_root: SHA3_NULL_RLP, storage_overlay: RefCell::new(HashMap::new()), code_hash: Some(SHA3_EMPTY), diff --git a/src/lib.rs b/src/lib.rs index d7f354423..776deb3dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(cell_extras)] + //! Ethcore's ethereum implementation //! //! ### Rust version diff --git a/src/state.rs b/src/state.rs index 936a41baf..d4bdf6485 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,13 +1,15 @@ +use std::cell::*; +use std::ops::*; use std::collections::HashMap; use util::hash::*; use util::hashdb::*; use util::overlaydb::*; use util::trie::*; +use util::bytes::*; use util::rlp::*; use util::uint::*; -//use std::cell::*; -//use std::ops::*; use account::Account; + /* enum ValueOrRef<'self, 'db: 'self> { Value(OverlayDB), @@ -34,9 +36,9 @@ impl<'self, 'db> ValueOrRef<'self, 'db: 'self> { pub struct State { db: OverlayDB, root: H256, - cache: HashMap>, + cache: RefCell>>, - _account_start_nonce: U256, + account_start_nonce: U256, } impl State { @@ -51,8 +53,8 @@ impl State { State { db: db, root: root, - cache: HashMap::new(), - _account_start_nonce: account_start_nonce, + cache: RefCell::new(HashMap::new()), + account_start_nonce: account_start_nonce, } } @@ -66,8 +68,8 @@ impl State { State { db: db, root: root, - cache: HashMap::new(), - _account_start_nonce: account_start_nonce, + cache: RefCell::new(HashMap::new()), + account_start_nonce: account_start_nonce, } } @@ -76,27 +78,41 @@ impl State { Self::new(OverlayDB::new_temp(), U256::from(0u8)) } - /// Return reference to root - pub fn root(&self) -> &H256 { - &self.root - } - /// Destroy the current object and return root and database. pub fn drop(self) -> (H256, OverlayDB) { (self.root, self.db) } + /// Return reference to root + pub fn root(&self) -> &H256 { + &self.root + } + /// Expose the underlying database; good to use for calling `state.db().commit()`. pub fn db(&mut self) -> &mut OverlayDB { &mut self.db } /// Get the balance of account `a`. - // TODO: make immutable - pub fn balance(&mut self, a: &Address) -> U256 { + pub fn balance(&self, a: &Address) -> U256 { self.get(a, false).as_ref().map(|account| account.balance().clone()).unwrap_or(U256::from(0u8)) } + /// Get the nonce of account `a`. + pub fn nonce(&self, a: &Address) -> U256 { + self.get(a, false).as_ref().map(|account| account.nonce().clone()).unwrap_or(U256::from(0u8)) + } + + /// Mutate storage of account `a` so that it is `value` for `key`. + pub fn storage_at(&self, a: &Address, key: &H256) -> H256 { + self.get(a, false).as_ref().map(|a|a.storage_at(&self.db, key)).unwrap_or(H256::new()) + } + + /// Mutate storage of account `a` so that it is `value` for `key`. + pub fn code(&self, a: &Address) -> Option> { + self.get(a, true).as_ref().map(|a|a.code().map(|x|x.to_vec())).unwrap_or(None) + } + /// Add `incr` to the balance of account `a`. pub fn add_balance(&mut self, a: &Address, incr: &U256) { self.require(a, false).add_balance(incr) @@ -107,34 +123,21 @@ impl State { self.require(a, false).sub_balance(decr) } - /// Get the nonce of account `a`. - // TODO: make immutable - pub fn nonce(&mut self, a: &Address) -> U256 { - self.get(a, false).as_ref().map(|account| account.nonce().clone()).unwrap_or(U256::from(0u8)) - } - /// Increment the nonce of account `a` by 1. pub fn inc_nonce(&mut self, a: &Address) { self.require(a, false).inc_nonce() } - /// Mutate storage of account `a` so that it is `value` for `key`. - pub fn storage_at(&mut self, a: &Address, key: &H256) -> H256 { - self.ensure_cached(a, false); - self.try_get(a).map(|a|a.storage_at(&self.db, key)).unwrap_or(H256::new()) - } - - /// Mutate storage of account `a` so that it is `value` for `key`. - pub fn code(&mut self, a: &Address) -> Option<&[u8]> { - self.ensure_cached(a, true); - self.try_get(a).map(|a|a.code()).unwrap_or(None) - } - /// Mutate storage of account `a` so that it is `value` for `key`. pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) { self.require(a, false).set_storage(key, value); } + /// Mutate storage of account `a` so that it is `value` for `key`. + pub fn set_code(&mut self, a: &Address, code: Bytes) { + self.require_or_from(a, true, || Account::new_contract(U256::from(0u8))).set_code(code); + } + /// Commit accounts to TrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. /// `accounts` is mutable because we may need to commit the code or storage and record that. pub fn commit_into(db: &mut HashDB, mut root: H256, accounts: &mut HashMap>) -> H256 { @@ -165,69 +168,51 @@ impl State { /// Commits our cached account changes into the trie. pub fn commit(&mut self) { let r = self.root.clone(); // would prefer not to do this, really. - self.root = Self::commit_into(&mut self.db, r, &mut self.cache); + self.root = Self::commit_into(&mut self.db, r, self.cache.borrow_mut().deref_mut()); } /// Pull account `a` in our cache from the trie DB and return it. /// `require_code` requires that the code be cached, too. // TODO: make immutable through returning an Option> - fn get(&mut self, a: &Address, require_code: bool) -> Option<&Account> { - self.ensure_cached(a, require_code); - self.try_get(a) - } - - /// Return account `a` from our cache, or None if it doesn't exist in the cache or - /// the account is empty. - /// Call `ensure_cached` before if you want to avoid the "it doesn't exist in the cache" - /// possibility. - fn try_get(&self, a: &Address) -> Option<&Account> { - self.cache.get(a).map(|x| x.as_ref()).unwrap_or(None) - } - - /// Ensure account `a` exists in our cache. - /// `require_code` requires that the code be cached, too. - fn ensure_cached(&mut self, a: &Address, require_code: bool) { - if self.cache.get(a).is_none() { + fn get(&self, a: &Address, require_code: bool) -> Ref> { + if self.cache.borrow().get(a).is_none() { // load from trie. - let act = TrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp)); - println!("Loaded {:?} from trie: {:?}", a, act); - self.cache.insert(a.clone(), act); + self.cache.borrow_mut().insert(a.clone(), TrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp))); } - let db = &self.db; if require_code { - if let Some(ref mut account) = self.cache.get_mut(a).unwrap().as_mut() { - println!("Caching code"); - account.cache_code(db); - println!("Now: {:?}", account); + if let Some(ref mut account) = self.cache.borrow_mut().get_mut(a).unwrap().as_mut() { + account.cache_code(&self.db); } } + Ref::map(self.cache.borrow(), |m| m.get(a).unwrap()) } /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. /// `force_create` creates a new, empty basic account if there is not currently an active account. - fn require(&mut self, a: &Address, require_code: bool) -> &mut Account { - self.require_or_from(a, require_code, || Account::new_basic(U256::from(0u8))) + fn require(&self, a: &Address, require_code: bool) -> RefMut { + self.require_or_from(a, require_code, || Account::new_basic(U256::from(0u8), self.account_start_nonce)) } /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. /// `force_create` creates a new, empty basic account if there is not currently an active account. - fn require_or_from Account>(&mut self, a: &Address, require_code: bool, default: F) -> &mut Account { - if self.cache.get(a).is_none() { + fn require_or_from Account>(&self, a: &Address, require_code: bool, default: F) -> RefMut { + // TODO: use entry + if self.cache.borrow().get(a).is_none() { // load from trie. - self.cache.insert(a.clone(), TrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp))); + self.cache.borrow_mut().insert(a.clone(), TrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp))); } - if self.cache.get(a).unwrap().is_none() { - self.cache.insert(a.clone(), Some(default())); + if self.cache.borrow().get(a).unwrap().is_none() { + self.cache.borrow_mut().insert(a.clone(), Some(default())); } - let db = &self.db; - self.cache.get_mut(a).unwrap().as_mut().map(|account| { + let b = self.cache.borrow_mut(); + RefMut::map(b, |m| m.get_mut(a).unwrap().as_mut().map(|account| { if require_code { - account.cache_code(db); + account.cache_code(&self.db); } account - }).unwrap() + }).unwrap()) } } @@ -247,15 +232,16 @@ fn code_from_database() { let a = Address::from_str("0000000000000000000000000000000000000000").unwrap(); let (r, db) = { let mut s = State::new_temp(); - s.require_or_from(&a, false, ||Account::new_contract(U256::from(42u32))).set_code(vec![1, 2, 3]); - assert_eq!(s.code(&a), Some(&[1u8, 2, 3][..])); + s.require_or_from(&a, false, ||Account::new_contract(U256::from(42u32))); + s.set_code(&a, vec![1, 2, 3]); + assert_eq!(s.code(&a), Some([1u8, 2, 3].to_vec())); s.commit(); - assert_eq!(s.code(&a), Some(&[1u8, 2, 3][..])); + assert_eq!(s.code(&a), Some([1u8, 2, 3].to_vec())); s.drop() }; - let mut s = State::new_existing(db, r, U256::from(0u8)); - assert_eq!(s.code(&a), Some(&[1u8, 2, 3][..])); + let s = State::new_existing(db, r, U256::from(0u8)); + assert_eq!(s.code(&a), Some([1u8, 2, 3].to_vec())); } #[test] @@ -268,7 +254,7 @@ fn storage_at_from_database() { s.drop() }; - let mut s = State::new_existing(db, r, U256::from(0u8)); + let s = State::new_existing(db, r, U256::from(0u8)); assert_eq!(s.storage_at(&a, &H256::from(&U256::from(01u64))), H256::from(&U256::from(69u64))); } @@ -284,7 +270,7 @@ fn get_from_database() { s.drop() }; - let mut s = State::new_existing(db, r, U256::from(0u8)); + let s = State::new_existing(db, r, U256::from(0u8)); assert_eq!(s.balance(&a), U256::from(69u64)); assert_eq!(s.nonce(&a), U256::from(1u64)); } From 6b61ab6322574ea2f970d12b88df5085e16827c2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Dec 2015 21:22:19 +0000 Subject: [PATCH 2/6] More succient code in State require/get. --- src/state.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/state.rs b/src/state.rs index d4bdf6485..5f5efabaf 100644 --- a/src/state.rs +++ b/src/state.rs @@ -173,12 +173,9 @@ impl State { /// Pull account `a` in our cache from the trie DB and return it. /// `require_code` requires that the code be cached, too. - // TODO: make immutable through returning an Option> fn get(&self, a: &Address, require_code: bool) -> Ref> { - if self.cache.borrow().get(a).is_none() { - // load from trie. - self.cache.borrow_mut().insert(a.clone(), TrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp))); - } + self.cache.borrow_mut().entry(a.clone()).or_insert_with(|| + TrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp))); if require_code { if let Some(ref mut account) = self.cache.borrow_mut().get_mut(a).unwrap().as_mut() { account.cache_code(&self.db); @@ -196,12 +193,8 @@ impl State { /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. /// `force_create` creates a new, empty basic account if there is not currently an active account. fn require_or_from Account>(&self, a: &Address, require_code: bool, default: F) -> RefMut { - // TODO: use entry - if self.cache.borrow().get(a).is_none() { - // load from trie. - self.cache.borrow_mut().insert(a.clone(), TrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp))); - } - + self.cache.borrow_mut().entry(a.clone()).or_insert_with(|| + TrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp))); if self.cache.borrow().get(a).unwrap().is_none() { self.cache.borrow_mut().insert(a.clone(), Some(default())); } From 9d70f6bdff9a395a45c94aca4e42feb117f6e7d2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Dec 2015 21:38:25 +0000 Subject: [PATCH 3/6] State::transfer_balance and a couple of placeholders. --- src/state.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/state.rs b/src/state.rs index 5f5efabaf..a2b7c16e9 100644 --- a/src/state.rs +++ b/src/state.rs @@ -123,6 +123,12 @@ impl State { self.require(a, false).sub_balance(decr) } + /// Subtracts `by` from the balance of `from` and adds it to that of `to`. + pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256) { + self.sub_balance(from, by); + self.add_balance(to, by); + } + /// Increment the nonce of account `a` by 1. pub fn inc_nonce(&mut self, a: &Address) { self.require(a, false).inc_nonce() @@ -138,6 +144,17 @@ impl State { self.require_or_from(a, true, || Account::new_contract(U256::from(0u8))).set_code(code); } + /// Execute a given transaction. + /// This will change the state accordingly. +/* pub fn execute(_env_info: EnvInfo, _seal_engine: SealEngine, _t: Transaction, _p: Permanence) -> (ExecutionResult, TransactionReceipt) { + unimplemented!(); + }*/ + + /// Convert into a JSON representation. + pub fn as_json(&self) -> String { + unimplemented!(); + } + /// Commit accounts to TrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. /// `accounts` is mutable because we may need to commit the code or storage and record that. pub fn commit_into(db: &mut HashDB, mut root: H256, accounts: &mut HashMap>) -> H256 { @@ -171,6 +188,11 @@ impl State { self.root = Self::commit_into(&mut self.db, r, self.cache.borrow_mut().deref_mut()); } + /// Populate the state from `accounts`. Just uses `commit_into`. + pub fn populate_from(&mut self, _accounts: &mut HashMap>) { + unimplemented!(); + } + /// Pull account `a` in our cache from the trie DB and return it. /// `require_code` requires that the code be cached, too. fn get(&self, a: &Address, require_code: bool) -> Ref> { @@ -272,6 +294,7 @@ fn get_from_database() { fn alter_balance() { let mut s = State::new_temp(); let a = Address::from_str("0000000000000000000000000000000000000000").unwrap(); + let b = Address::from_str("0000000000000000000000000000000000000001").unwrap(); s.add_balance(&a, &U256::from(69u64)); assert_eq!(s.balance(&a), U256::from(69u64)); s.commit(); @@ -280,6 +303,12 @@ fn alter_balance() { assert_eq!(s.balance(&a), U256::from(27u64)); s.commit(); assert_eq!(s.balance(&a), U256::from(27u64)); + s.transfer_balance(&a, &b, &U256::from(18u64)); + assert_eq!(s.balance(&a), U256::from(9u64)); + assert_eq!(s.balance(&b), U256::from(18u64)); + s.commit(); + assert_eq!(s.balance(&a), U256::from(9u64)); + assert_eq!(s.balance(&b), U256::from(18u64)); } #[test] From 435911b9f04819afb0719d0e66bcb3cc5d82a271 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Dec 2015 12:16:12 +0000 Subject: [PATCH 4/6] Repot & introduce various additional components for rest of consensus algorithm. --- src/engine.rs | 129 ++++++++++++++++++++++++++++++ src/env_info.rs | 24 ++++++ src/{blockheader.rs => header.rs} | 0 src/lib.rs | 5 +- src/receipt.rs | 6 ++ src/state.rs | 31 ++----- src/transaction.rs | 15 ++-- 7 files changed, 180 insertions(+), 30 deletions(-) create mode 100644 src/engine.rs create mode 100644 src/env_info.rs rename src/{blockheader.rs => header.rs} (100%) create mode 100644 src/receipt.rs diff --git a/src/engine.rs b/src/engine.rs new file mode 100644 index 000000000..9b1a62980 --- /dev/null +++ b/src/engine.rs @@ -0,0 +1,129 @@ +use util::uint::*; +use util::hash::*; +use util::bytes::*; +use header::Header; +use std::collections::hash_map::*; +use util::error::*; + +/// Definition of the cost schedule and other parameterisations for the EVM. +pub struct EvmSchedule { + pub exceptional_failed_code_deposit: bool, + pub have_delegate_call: bool, + pub stack_limit: U256, + pub tier_step_gas: [U256; 8], + pub exp_gas: U256, + pub exp_byte_gas: U256, + pub sha3_gas: U256, + pub sha3_word_gas: U256, + pub sload_gas: U256, + pub sstore_set_gas: U256, + pub sstore_reset_gas: U256, + pub sstore_refund_gas: U256, + pub jumpdest_gas: U256, + pub log_gas: U256, + pub log_data_gas: U256, + pub log_topic_gas: U256, + pub create_gas: U256, + pub call_gas: U256, + pub call_stipend: U256, + pub call_value_transfer_gas: U256, + pub call_new_account_gas: U256, + pub suicide_refund_gas: U256, + pub memory_gas: U256, + pub quad_coeff_div: U256, + pub create_data_gas: U256, + pub tx_gas: U256, + pub tx_create_gas: U256, + pub tx_data_zero_gas: U256, + pub tx_data_non_zero_gas: U256, + pub copy_gas: U256, +} + +/// Definition of a contract whose implementation is built-in. +pub struct Builtin { + /// The gas cost of running this built-in for the given size of input data. + pub cost: Box U256>, // TODO: U256 should be bignum. + /// Run this built-in function with the input being the first argument and the output + /// being placed into the second. + pub execute: Box, +} + +/// Parameters for a block chain; includes both those intrinsic to the design of the +/// chain and those to be interpreted by the active chain engine. +pub struct Params { + /* + TODO: std::unordered_map precompiled; + */ + pub block_reward: U256, + pub maximum_extra_data_size: U256, + pub account_start_nonce: U256, + pub evm_schedule: EvmSchedule, + pub builtins: HashMap, + pub misc: HashMap, +} + +// TODO: move to ethcore-util +/// A version value with strict meaning. +pub struct SemanticVersion { + /// Major version - API/feature removals & breaking changes. + pub major: u8, + /// Minor version - API/feature additions. + pub minor: u8, + /// Tiny version - bug fixes. + pub tiny: u8, +} + +impl SemanticVersion { + /// Create a new object. + pub fn new(major: u8, minor: u8, tiny: u8) -> SemanticVersion { SemanticVersion{major: major, minor: minor, tiny: tiny} } + + /// Convert to a `u32` representation. + pub fn as_u32(&self) -> u32 { ((self.major as u32) << 16u32) + ((self.minor as u32) << 8u32) + self.tiny as u32 } +} + +// TODO: implement PartialOrdered for SemanticVersion. + +/// A consensus mechanism for the chain. Generally either proof-of-work or proof-of-stake-based. +/// Provides hooks into each of the major parts of block import. +pub trait Engine { + /// The name of this engine. + fn name(&self) -> &str; + /// The version of this engine. Should be of the form + fn version(&self) -> SemanticVersion { SemanticVersion::new(0, 0 ,0) } + + /// The number of additional header fields required for this engine. + fn seal_fields(&self) -> u32 { 0 } + /// Default values of the additional fields RLP-encoded in a raw (non-list) harness. + fn seal_rlp(&self) -> Bytes { vec![] } + + /// Additional engine-specific information for the user/developer concerning `header`. + fn extra_info(&self, _header: &Header) -> HashMap { HashMap::new() } + + /// Verify that `header` is valid. + /// `parent` (the parent header) and `block` (the header's full block) may be provided for additional + /// checks. Returns either a null `Ok` or a general error detailing the problem with import. + fn verify(&self, _header: &Header, _parent: Option<&Header>, _block: Option<&[u8]>) -> Result<(), EthcoreError> { Ok(()) } +/* + virtual void verify(Strictness _s, BlockHeader const& _bi, BlockHeader const& _parent = BlockHeader(), bytesConstRef _block = bytesConstRef()) const; + /// Additional verification for transactions in blocks. + virtual void verifyTransaction(ImportRequirements::value _ir, TransactionBase const& _t, BlockHeader const& _bi) const; + /// Don't forget to call Super::populateFromParent when subclassing & overriding. + virtual void populateFromParent(BlockHeader& _bi, BlockHeader const& _parent) const; +*/ + + /// Get the general parameters of the chain. + fn params(&self) -> &Params; + /// Set the general parameters of the chain. + fn set_params(&mut self, p: Params); +} + +/// An engine which does not provide any consensus mechanism. +pub struct NullEngine { + params: Params, +} + +impl Engine for NullEngine { + fn name(&self) -> &str { "NullEngine" } + fn params(&self) -> &Params { &self.params } + fn set_params(&mut self, params: Params) { self.params = params; } +} \ No newline at end of file diff --git a/src/env_info.rs b/src/env_info.rs new file mode 100644 index 000000000..dec8069ac --- /dev/null +++ b/src/env_info.rs @@ -0,0 +1,24 @@ +use util::uint::*; +use util::hash::*; + +/// Simple vector of hashes, should be at most 256 items large, can be smaller if being used +/// for a block whose number is less than 257. +pub type LastHashes = Vec; + +/// Information concerning the execution environment for a message-call/contract-creation. +pub struct EnvInfo { + /// The block number. + pub number: U256, + /// The block author. + pub author: Address, + /// The block timestamp. + pub timestamp: U256, + /// The block difficulty. + pub difficulty: U256, + /// The block gas limit. + pub gas_limit: U256, + /// The last 256 block hashes. + pub last_hashes: LastHashes, + /// The gas used. + pub gas_used: U256, +} \ No newline at end of file diff --git a/src/blockheader.rs b/src/header.rs similarity index 100% rename from src/blockheader.rs rename to src/header.rs diff --git a/src/lib.rs b/src/lib.rs index 776deb3dc..071c3bf06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,10 +84,13 @@ pub use util::hash::*; pub use util::uint::*; pub use util::bytes::*; +pub mod env_info; +pub mod engine; pub mod state; pub mod account; -pub mod blockheader; +pub mod header; pub mod transaction; +pub mod receipt; pub mod networkparams; pub mod denominations; diff --git a/src/receipt.rs b/src/receipt.rs new file mode 100644 index 000000000..e860970ac --- /dev/null +++ b/src/receipt.rs @@ -0,0 +1,6 @@ +use util::hash::*; + +pub struct Receipt { + // TODO + pub state_root: H256, +} diff --git a/src/state.rs b/src/state.rs index a2b7c16e9..dbe349d77 100644 --- a/src/state.rs +++ b/src/state.rs @@ -9,28 +9,13 @@ use util::bytes::*; use util::rlp::*; use util::uint::*; use account::Account; +use transaction::Transaction; +use receipt::Receipt; +use env_info::EnvInfo; +use engine::Engine; -/* -enum ValueOrRef<'self, 'db: 'self> { - Value(OverlayDB), - Ref(&'db mut OverlayDB) -} - -impl<'self, 'db> ValueOrRef<'self, 'db: 'self> { - pub fn get_mut(&mut self) -> &mut OverlayDB { - match self { - Value(ref mut x) => x, - Ref(x) => x, - } - } - pub fn get(&self) -> &OverlayDB { - match self { - Value(ref x) => x, - Ref(x) => x, - } - } -} -*/ +/// Information concerning the result of the `State::apply` operation. +pub struct ApplyResult; // TODO /// Representation of the entire state of all accounts in the system. pub struct State { @@ -146,9 +131,9 @@ impl State { /// Execute a given transaction. /// This will change the state accordingly. -/* pub fn execute(_env_info: EnvInfo, _seal_engine: SealEngine, _t: Transaction, _p: Permanence) -> (ExecutionResult, TransactionReceipt) { + pub fn apply(_env_info: &EnvInfo, _engine: &Engine, _t: &Transaction, _is_permanent: bool) -> (ApplyResult, Receipt) { unimplemented!(); - }*/ + } /// Convert into a JSON representation. pub fn as_json(&self) -> String { diff --git a/src/transaction.rs b/src/transaction.rs index 4fbd9588b..82fa9ccb6 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -3,20 +3,23 @@ use util::bytes::*; use util::uint::*; use util::rlp::*; +/// A set of information describing an externally-originating message call +/// or contract creation operation. pub struct Transaction { nonce: U256, gas_price: U256, gas: U256, - receive_address: Option
, + to: Option
, value: U256, data: Bytes, } impl Transaction { + /// Is this transaction meant to create a contract? pub fn is_contract_creation(&self) -> bool { - self.receive_address.is_none() + self.to.is_none() } - + /// Is this transaction meant to send a message? pub fn is_message_call(&self) -> bool { !self.is_contract_creation() } @@ -28,7 +31,7 @@ impl Encodable for Transaction { self.nonce.encode(e); self.gas_price.encode(e); self.gas.encode(e); - self.receive_address.encode(e); + self.to.encode(e); self.value.encode(e); self.data.encode(e); }) @@ -36,14 +39,14 @@ impl Encodable for Transaction { } impl Decodable for Transaction { - fn decode(decoder: &D) -> Result where D: Decoder { + fn decode(decoder: &D) -> Result where D: Decoder { let d = try!(decoder.as_list()); let transaction = Transaction { nonce: try!(Decodable::decode(&d[0])), gas_price: try!(Decodable::decode(&d[1])), gas: try!(Decodable::decode(&d[2])), - receive_address: try!(Decodable::decode(&d[3])), + to: try!(Decodable::decode(&d[3])), value: try!(Decodable::decode(&d[4])), data: try!(Decodable::decode(&d[5])), }; From c718a5c62798e4d43930cf904cad6711506cfe20 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Dec 2015 12:22:54 +0000 Subject: [PATCH 5/6] Additional doc/tests. --- src/engine.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 9b1a62980..1fe89d8e9 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -63,7 +63,16 @@ pub struct Params { } // TODO: move to ethcore-util -/// A version value with strict meaning. +/// A version value with strict meaning. Use `to_u32` to convert to a simple integer. +/// +/// # Example +/// ``` +/// extern crate ethcore; +/// use ethcore::engine::*; +/// fn main() { +/// assert_eq!(SemanticVersion::new(1, 2, 3).as_u32(), 0x010203); +/// } +/// ``` pub struct SemanticVersion { /// Major version - API/feature removals & breaking changes. pub major: u8, @@ -78,7 +87,7 @@ impl SemanticVersion { pub fn new(major: u8, minor: u8, tiny: u8) -> SemanticVersion { SemanticVersion{major: major, minor: minor, tiny: tiny} } /// Convert to a `u32` representation. - pub fn as_u32(&self) -> u32 { ((self.major as u32) << 16u32) + ((self.minor as u32) << 8u32) + self.tiny as u32 } + pub fn as_u32(&self) -> u32 { ((self.major as u32) << 16) + ((self.minor as u32) << 8) + self.tiny as u32 } } // TODO: implement PartialOrdered for SemanticVersion. From feee9a26cb937cfa7929c0dbde022dc8eacc7f79 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Dec 2015 12:29:06 +0000 Subject: [PATCH 6/6] Remove SemanticVersion to ethcore-util. --- src/engine.rs | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 1fe89d8e9..509c0d6db 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1,6 +1,7 @@ use util::uint::*; use util::hash::*; use util::bytes::*; +use util::semantic_version::*; use header::Header; use std::collections::hash_map::*; use util::error::*; @@ -62,36 +63,6 @@ pub struct Params { pub misc: HashMap, } -// TODO: move to ethcore-util -/// A version value with strict meaning. Use `to_u32` to convert to a simple integer. -/// -/// # Example -/// ``` -/// extern crate ethcore; -/// use ethcore::engine::*; -/// fn main() { -/// assert_eq!(SemanticVersion::new(1, 2, 3).as_u32(), 0x010203); -/// } -/// ``` -pub struct SemanticVersion { - /// Major version - API/feature removals & breaking changes. - pub major: u8, - /// Minor version - API/feature additions. - pub minor: u8, - /// Tiny version - bug fixes. - pub tiny: u8, -} - -impl SemanticVersion { - /// Create a new object. - pub fn new(major: u8, minor: u8, tiny: u8) -> SemanticVersion { SemanticVersion{major: major, minor: minor, tiny: tiny} } - - /// Convert to a `u32` representation. - pub fn as_u32(&self) -> u32 { ((self.major as u32) << 16) + ((self.minor as u32) << 8) + self.tiny as u32 } -} - -// TODO: implement PartialOrdered for SemanticVersion. - /// A consensus mechanism for the chain. Generally either proof-of-work or proof-of-stake-based. /// Provides hooks into each of the major parts of block import. pub trait Engine {