From 387e3ec3fd38df75a23997b2190cf138ccb0ad84 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 26 Jan 2016 15:00:22 +0100 Subject: [PATCH] Ensure Spec::ensure_db_good() places DB entries for code & storage. --- src/account.rs | 6 +++++- src/blockchain.rs | 5 +++++ src/client.rs | 17 ++++++++++++++++- src/evm/interpreter.rs | 3 +++ src/executive.rs | 11 +++++------ src/externalities.rs | 1 + src/pod_account.rs | 14 +++++++++++++- src/spec.rs | 5 +++-- src/state.rs | 1 + src/tests/chain.rs | 5 +++-- util/src/trie/sectriedbmut.rs | 6 ++++++ util/src/trie/triedbmut.rs | 5 +++++ 12 files changed, 66 insertions(+), 13 deletions(-) diff --git a/src/account.rs b/src/account.rs index b0fbf3f85..409637d6f 100644 --- a/src/account.rs +++ b/src/account.rs @@ -149,11 +149,15 @@ impl Account { /// Provide a database to lookup `code_hash`. Should not be called if it is a contract without code. pub fn cache_code(&mut self, db: &HashDB) -> bool { // TODO: fill out self.code_cache; + trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty()); self.is_cached() || match self.code_hash { Some(ref h) => match db.lookup(h) { Some(x) => { self.code_cache = x.to_vec(); true }, - _ => false, + _ => { + warn!("Failed reverse lookup of {}", h); + false + }, }, _ => false, } diff --git a/src/blockchain.rs b/src/blockchain.rs index 3bd31688a..da9ee04c2 100644 --- a/src/blockchain.rs +++ b/src/blockchain.rs @@ -107,6 +107,11 @@ pub trait BlockProvider { fn genesis_hash(&self) -> H256 { self.block_hash(0).expect("Genesis hash should always exist") } + + /// Returns the header of the genesis block. + fn genesis_header(&self) -> Header { + self.block_header(&self.genesis_hash()).unwrap() + } } #[derive(Debug, Hash, Eq, PartialEq, Clone)] diff --git a/src/client.rs b/src/client.rs index 2cc6c150d..91ccf4b95 100644 --- a/src/client.rs +++ b/src/client.rs @@ -4,8 +4,10 @@ use blockchain::{BlockChain, BlockProvider, CacheSize}; use views::BlockView; use error::*; use header::BlockNumber; +use state::State; use spec::Spec; use engine::Engine; +use views::HeaderView; use block_queue::{BlockQueue, BlockQueueInfo}; use service::NetSyncMessage; use env_info::LastHashes; @@ -98,6 +100,11 @@ pub trait BlockChainClient : Sync + Send { /// Get blockchain information. fn chain_info(&self) -> BlockChainInfo; + + /// Get the best block header. + fn best_block_header(&self) -> Bytes { + self.block_header(&self.chain_info().best_block_hash).unwrap() + } } #[derive(Default, Clone, Debug, Eq, PartialEq)] @@ -137,7 +144,9 @@ const HISTORY: u64 = 1000; impl Client { /// Create a new client with given spec and DB path. pub fn new(spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, Error> { - let chain = Arc::new(RwLock::new(BlockChain::new(&spec.genesis_block(), path))); + let gb = spec.genesis_block(); + flushln!("Spec says genesis block is {}", gb.pretty()); + let chain = Arc::new(RwLock::new(BlockChain::new(&gb, path))); let mut opts = Options::new(); opts.set_max_open_files(256); opts.create_if_missing(true); @@ -168,6 +177,7 @@ impl Client { if engine.spec().ensure_db_good(&mut state_db) { state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); } + flushln!("Client::new: commiting. Best root now: {}. contains: {}", chain.read().unwrap().genesis_header().state_root, state_db.contains(&chain.read().unwrap().genesis_header().state_root)); Ok(Arc::new(Client { chain: chain, engine: engine.clone(), @@ -261,6 +271,11 @@ impl Client { self.uncommited_states.write().unwrap().remove(hash); } + /// Get a copy of the best block's state. + pub fn state(&self) -> State { + State::from_existing(self.state_db.clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce()) + } + /// Get info on the cache. pub fn cache_info(&self) -> CacheSize { self.chain.read().unwrap().cache_size() diff --git a/src/evm/interpreter.rs b/src/evm/interpreter.rs index 7657b1bbe..2f43b5199 100644 --- a/src/evm/interpreter.rs +++ b/src/evm/interpreter.rs @@ -275,6 +275,8 @@ impl evm::Evm for Interpreter { code: &code }; + flushln!("Executing: {:?}", params); + while reader.position < code.len() { let instruction = code[reader.position]; reader.position += 1; @@ -640,6 +642,7 @@ impl Interpreter { return Ok(InstructionResult::StopExecution); }, instructions::SUICIDE => { + flushln!("SUICIDE!"); let address = stack.pop_back(); ext.suicide(&u256_to_address(&address)); return Ok(InstructionResult::StopExecution); diff --git a/src/executive.rs b/src/executive.rs index f5952e530..9c3a669cf 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -166,7 +166,6 @@ impl<'a> Executive<'a> { /// Modifies the substate and the output. /// Returns either gas_left or `evm::Error`. pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result { - println!("Calling executive. Sender: {}", params.sender); // backup used in case of running out of gas let backup = self.state.clone(); @@ -174,7 +173,7 @@ impl<'a> Executive<'a> { if let ActionValue::Transfer(val) = params.value { self.state.transfer_balance(¶ms.sender, ¶ms.address, &val); } - trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info); + flushln!("Executive::call(params={:?}) self.env_info={:?}", params, self.info); if self.engine.is_builtin(¶ms.code_address) { // if destination is builtin, try to execute it @@ -261,17 +260,17 @@ impl<'a> Executive<'a> { let refund_value = gas_left * t.gas_price; let fees_value = gas_used * t.gas_price; - trace!("exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={}\n", + flushln!("exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={}\n", t.gas, sstore_refunds, suicide_refunds, refunds_bound, gas_left_prerefund, refunded, gas_left, gas_used, refund_value, fees_value); - trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, t.sender().unwrap()); + flushln!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, t.sender().unwrap()); self.state.add_balance(&t.sender().unwrap(), &refund_value); - trace!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author); + flushln!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author); self.state.add_balance(&self.info.author, &fees_value); // perform suicides for address in &substate.suicides { - trace!("Killing {}", address); + flushln!("Killing {}", address); self.state.kill_account(address); } diff --git a/src/externalities.rs b/src/externalities.rs index f9a79c3c0..e7a73d553 100644 --- a/src/externalities.rs +++ b/src/externalities.rs @@ -215,6 +215,7 @@ impl<'a> Ext for Externalities<'a> { fn suicide(&mut self, refund_address: &Address) { let address = self.origin_info.address.clone(); let balance = self.balance(&address); + flushln!("Suiciding {} -> {} (xfer: {})", address, refund_address, balance); self.state.transfer_balance(&address, refund_address, &balance); self.substate.suicides.insert(address); } diff --git a/src/pod_account.rs b/src/pod_account.rs index 81b8b1c44..979658202 100644 --- a/src/pod_account.rs +++ b/src/pod_account.rs @@ -31,7 +31,7 @@ impl PodAccount { } } - /// TODO [Gav Wood] Please document me + /// Returns the RLP for this account. pub fn rlp(&self) -> Bytes { let mut stream = RlpStream::new_list(4); stream.append(&self.nonce); @@ -40,6 +40,18 @@ impl PodAccount { stream.append(&self.code.sha3()); stream.out() } + + /// Place additional data into given hash DB. + pub fn insert_additional(&self, db: &mut HashDB) { + if !self.code.is_empty() { + db.insert(&self.code); + } + let mut r = H256::new(); + let mut t = SecTrieDBMut::new(db, &mut r); + for (k, v) in &self.storage { + t.insert(k, &encode(&U256::from(v.as_slice()))); + } + } } impl fmt::Display for PodAccount { diff --git a/src/spec.rs b/src/spec.rs index 326552524..f4166eab2 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -261,7 +261,6 @@ impl Spec { /// Ensure that the given state DB has the trie nodes in for the genesis state. pub fn ensure_db_good(&self, db: &mut HashDB) -> bool { if !db.contains(&self.state_root()) { - info!("Populating genesis state..."); let mut root = H256::new(); { let mut t = SecTrieDBMut::new(db, &mut root); @@ -269,8 +268,10 @@ impl Spec { t.insert(address.as_slice(), &account.rlp()); } } + for (_, account) in self.genesis_state.get().iter() { + account.insert_additional(db); + } assert!(db.contains(&self.state_root())); - info!("Genesis state is ready"); true } else { false } } diff --git a/src/state.rs b/src/state.rs index 7310f63a7..238638617 100644 --- a/src/state.rs +++ b/src/state.rs @@ -103,6 +103,7 @@ impl State { /// Mutate storage of account `a` so that it is `value` for `key`. pub fn code(&self, a: &Address) -> Option { + flushln!("Getting code at {}", a); self.get(a, true).as_ref().map_or(None, |a|a.code().map(|x|x.to_vec())) } diff --git a/src/tests/chain.rs b/src/tests/chain.rs index ba42ae935..046c16052 100644 --- a/src/tests/chain.rs +++ b/src/tests/chain.rs @@ -22,7 +22,8 @@ fn do_json_test(json_data: &[u8]) -> Vec { let blocks: Vec = test["blocks"].as_array().unwrap().iter().map(|e| xjson!(&e["rlp"])).collect(); let mut spec = ethereum::new_frontier_like_test(); - spec.set_genesis_state(PodState::from_json(test.find("pre").unwrap())); + let s = PodState::from_json(test.find("pre").unwrap()); + spec.set_genesis_state(s); spec.overwrite_genesis(test.find("genesisBlockHeader").unwrap()); assert!(spec.is_state_root_valid()); @@ -56,7 +57,7 @@ declare_test!{BlockchainTests_bcInvalidHeaderTest, "BlockchainTests/bcInvalidHea declare_test!{ignore => BlockchainTests_bcInvalidRLPTest, "BlockchainTests/bcInvalidRLPTest"} // FAILS declare_test!{ignore => BlockchainTests_bcMultiChainTest, "BlockchainTests/bcMultiChainTest"} // FAILS declare_test!{BlockchainTests_bcRPC_API_Test, "BlockchainTests/bcRPC_API_Test"} -declare_test!{ignore => BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} // FAILS (Suicides, GasUsed) +declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} // FAILS (Suicides, GasUsed) declare_test!{BlockchainTests_bcTotalDifficultyTest, "BlockchainTests/bcTotalDifficultyTest"} declare_test!{ignore => BlockchainTests_bcUncleHeaderValiditiy, "BlockchainTests/bcUncleHeaderValiditiy"} // FAILS declare_test!{ignore => BlockchainTests_bcUncleTest, "BlockchainTests/bcUncleTest"} // FAILS diff --git a/util/src/trie/sectriedbmut.rs b/util/src/trie/sectriedbmut.rs index 99c2e2bb1..7f8e292f0 100644 --- a/util/src/trie/sectriedbmut.rs +++ b/util/src/trie/sectriedbmut.rs @@ -25,6 +25,12 @@ impl<'db> SecTrieDBMut<'db> { pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self { SecTrieDBMut { raw: TrieDBMut::from_existing(db, root) } } + + /// Get the backing database. + pub fn db(&'db self) -> &'db HashDB { self.raw.db() } + + /// Get the backing database. + pub fn db_mut(&'db mut self) -> &'db mut HashDB { self.raw.db_mut() } } impl<'db> Trie for SecTrieDBMut<'db> { diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index 48749bf0d..17d3f5866 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -87,6 +87,11 @@ impl<'db> TrieDBMut<'db> { self.db } + /// Get the backing database. + pub fn db_mut(&'db mut self) -> &'db mut HashDB { + self.db + } + /// Determine all the keys in the backing database that belong to the trie. pub fn keys(&self) -> Vec { let mut ret: Vec = Vec::new();