Ensure Spec::ensure_db_good() places DB entries for code & storage.

This commit is contained in:
Gav Wood 2016-01-26 15:00:22 +01:00
parent 7065c477a4
commit 387e3ec3fd
12 changed files with 66 additions and 13 deletions

View File

@ -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,
}

View File

@ -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)]

View File

@ -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<NetSyncMessage> ) -> Result<Arc<Client>, 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()

View File

@ -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);

View File

@ -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(&params.sender, &params.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(&params.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);
}

View File

@ -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);
}

View File

@ -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 {

View File

@ -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 }
}

View File

@ -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<Bytes> {
flushln!("Getting code at {}", a);
self.get(a, true).as_ref().map_or(None, |a|a.code().map(|x|x.to_vec()))
}

View File

@ -22,7 +22,8 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
let blocks: Vec<Bytes> = 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

View File

@ -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> {

View File

@ -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<H256> {
let mut ret: Vec<H256> = Vec::new();