Merge branch 'master' into evm

Conflicts:
	src/evm/tests.rs
	src/executive.rs
This commit is contained in:
Tomusdrw 2016-01-16 11:33:41 +01:00
commit a1a4c5a068
15 changed files with 115 additions and 52 deletions

View File

@ -205,7 +205,6 @@ impl Account {
match (self.code_hash.is_none(), self.code_cache.is_empty()) {
(true, true) => self.code_hash = Some(SHA3_EMPTY),
(true, false) => {
println!("Writing into DB {:?}", self.code_cache);
self.code_hash = Some(db.insert(&self.code_cache));
},
(false, _) => {},

View File

@ -126,6 +126,15 @@ impl<'x, 'y> OpenBlock<'x, 'y> {
/// Alter the timestamp of the block.
pub fn set_timestamp(&mut self, timestamp: u64) { self.block.header.set_timestamp(timestamp); }
/// Alter the difficulty for the block.
pub fn set_difficulty(&mut self, a: U256) { self.block.header.set_difficulty(a); }
/// Alter the gas limit for the block.
pub fn set_gas_limit(&mut self, a: U256) { self.block.header.set_gas_limit(a); }
/// Alter the gas limit for the block.
pub fn set_gas_used(&mut self, a: U256) { self.block.header.set_gas_used(a); }
/// Alter the extra_data for the block.
pub fn set_extra_data(&mut self, extra_data: Bytes) -> Result<(), BlockError> {
if extra_data.len() > self.engine.maximum_extra_data_size() {
@ -158,7 +167,7 @@ impl<'x, 'y> OpenBlock<'x, 'y> {
author: self.block.header.author.clone(),
timestamp: self.block.header.timestamp,
difficulty: self.block.header.difficulty.clone(),
last_hashes: self.last_hashes.clone(),
last_hashes: self.last_hashes.clone(), // TODO: should be a reference.
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(),
}
@ -169,6 +178,7 @@ impl<'x, 'y> OpenBlock<'x, 'y> {
/// If valid, it will be executed, and archived together with the receipt.
pub fn push_transaction(&mut self, t: Transaction, h: Option<H256>) -> Result<&Receipt, Error> {
let env_info = self.env_info();
// info!("env_info says gas_used={}", env_info.gas_used);
match self.block.state.apply(&env_info, self.engine, &t) {
Ok(receipt) => {
self.block.archive_set.insert(h.unwrap_or_else(||t.hash()));
@ -255,10 +265,19 @@ impl IsBlock for SealedBlock {
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
pub fn enact<'x, 'y>(block_bytes: &[u8], engine: &'x Engine, db: OverlayDB, parent: &Header, last_hashes: &'y LastHashes) -> Result<ClosedBlock<'x, 'y>, Error> {
{
let header = BlockView::new(block_bytes).header_view();
let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce());
trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
}
let block = BlockView::new(block_bytes);
let header = block.header_view();
let mut b = OpenBlock::new(engine, db, parent, last_hashes, header.author(), header.extra_data());
b.set_difficulty(header.difficulty());
b.set_gas_limit(header.gas_limit());
b.set_timestamp(header.timestamp());
// info!("enact: Enacting #{}. env_info={:?}", header.number(), b.env_info());
for t in block.transactions().into_iter() { try!(b.push_transaction(t, None)); }
for u in block.uncles().into_iter() { try!(b.push_uncle(u)); }
Ok(b.close())

View File

@ -142,14 +142,13 @@ impl Client {
},
};
// build last hashes
let mut last = self.chain.read().unwrap().best_block_hash();
let mut last_hashes = LastHashes::new();
last_hashes.resize(256, H256::new());
last_hashes[0] = header.parent_hash.clone();
for i in 0..255 {
match self.chain.read().unwrap().block_details(&last) {
match self.chain.read().unwrap().block_details(&last_hashes[i]) {
Some(details) => {
last_hashes[i + 1] = details.parent.clone();
last = details.parent.clone();
},
None => break,
}

View File

@ -53,6 +53,8 @@ impl Engine for Ethash {
max(gas_floor_target, gas_limit - gas_limit / bound_divisor + x!(1) + (header.gas_used * x!(6) / x!(5)) / bound_divisor)
}
};
// info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number, header.difficulty, header.gas_limit);
}
/// Apply the block reward on finalisation of the block.

View File

@ -7,10 +7,10 @@ use env_info::*;
pub trait Ext {
/// Returns a value for given key.
fn sload(&self, key: &H256) -> H256;
fn storage_at(&self, key: &H256) -> H256;
/// Stores a value for given key.
fn sstore(&mut self, key: H256, value: H256);
fn set_storage_at(&mut self, key: H256, value: H256);
/// Returns address balance.
fn balance(&self, address: &Address) -> U256;

View File

@ -301,7 +301,7 @@ impl Interpreter {
instructions::SSTORE => {
let address = H256::from(stack.peek(0));
let newval = stack.peek(1);
let val = U256::from(ext.sload(&address).as_slice());
let val = U256::from(ext.storage_at(&address).as_slice());
let gas = if self.is_zero(&val) && !self.is_zero(newval) {
schedule.sstore_set_gas
@ -618,13 +618,13 @@ impl Interpreter {
},
instructions::SLOAD => {
let key = H256::from(&stack.pop_back());
let word = U256::from(ext.sload(&key).as_slice());
let word = U256::from(ext.storage_at(&key).as_slice());
stack.push(word);
},
instructions::SSTORE => {
let key = H256::from(&stack.pop_back());
let word = H256::from(&stack.pop_back());
ext.sstore(key, word);
ext.set_storage_at(key, word);
},
instructions::PC => {
stack.push(U256::from(code.position - 1));

View File

@ -175,14 +175,14 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
fn sload(&self, index: *const evmjit::I256, out_value: *mut evmjit::I256) {
unsafe {
let i = H256::from_jit(&*index);
let o = self.ext.sload(&i);
let o = self.ext.storage_at(&i);
*out_value = o.into_jit();
}
}
fn sstore(&mut self, index: *const evmjit::I256, value: *const evmjit::I256) {
unsafe {
self.ext.sstore(H256::from_jit(&*index), H256::from_jit(&*value));
self.ext.set_storage_at(H256::from_jit(&*index), H256::from_jit(&*value));
}
}

View File

@ -35,11 +35,11 @@ impl Default for Schedule {
}
impl Ext for FakeExt {
fn sload(&self, key: &H256) -> H256 {
fn storage_at(&self, key: &H256) -> H256 {
self.store.get(key).unwrap_or(&H256::new()).clone()
}
fn sstore(&mut self, key: H256, value: H256) {
fn set_storage_at(&mut self, key: H256, value: H256) {
self.store.insert(key, value);
}

View File

@ -171,6 +171,7 @@ impl<'a> Executive<'a> {
// at first, transfer value to destination
self.state.transfer_balance(&params.sender, &params.address, &params.value);
debug!("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
@ -200,7 +201,11 @@ impl<'a> Executive<'a> {
let mut ext = self.to_externalities(params, &mut unconfirmed_substate, OutputPolicy::Return(output));
self.engine.vm_factory().create().exec(&params, &mut ext)
};
trace!("exec: sstore-clears={}\n", unconfirmed_substate.refunds_count);
trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
self.enact_result(&res, substate, unconfirmed_substate, backup);
trace!("exec: new substate={:?}\n", substate);
res
} else {
// otherwise, nothing
@ -240,20 +245,24 @@ impl<'a> Executive<'a> {
let sstore_refunds = U256::from(schedule.sstore_refund_gas) * substate.refunds_count;
// refunds from contract suicides
let suicide_refunds = U256::from(schedule.suicide_refund_gas) * U256::from(substate.suicides.len());
let refunds_bound = sstore_refunds + suicide_refunds;
// real ammount to refund
let gas_left = match &result { &Ok(x) => x, _ => x!(0) };
let refund = cmp::min(sstore_refunds + suicide_refunds, (t.gas - gas_left) / U256::from(2)) + gas_left;
let refund_value = refund * t.gas_price;
trace!("Refunding sender: sstore0s: {}, suicides: {}, gas_left: {}, refund: {}, refund_value: {}, sender: {}", sstore_refunds, suicide_refunds, gas_left, refund, refund_value, t.sender().unwrap());
self.state.add_balance(&t.sender().unwrap(), &refund_value);
let gas_left_prerefund = match &result { &Ok(x) => x, _ => x!(0) };
let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) / U256::from(2));
let gas_left = gas_left_prerefund + refunded;
// fees earned by author
let fees = t.gas - refund;
let fees_value = fees * t.gas_price;
let author = &self.info.author;
self.state.add_balance(author, &fees_value);
trace!("Compensating author: fees: {}, fees_value: {}, author: {}", fees, fees_value, author);
let gas_used = t.gas - gas_left;
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",
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());
self.state.add_balance(&t.sender().unwrap(), &refund_value);
trace!("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.iter() {
@ -261,8 +270,6 @@ impl<'a> Executive<'a> {
self.state.kill_account(address);
}
let gas_used = t.gas - gas_left;
match result {
Err(evm::Error::Internal) => Err(ExecutionError::Internal),
// TODO [ToDr] BadJumpDestination @debris - how to handle that?
@ -280,16 +287,16 @@ impl<'a> Executive<'a> {
contracts_created: vec![]
})
},
Ok(_) => {
_ => {
Ok(Executed {
gas: t.gas,
gas_used: gas_used,
refunded: refund,
refunded: refunded,
cumulative_gas_used: self.info.gas_used + gas_used,
logs: substate.logs,
contracts_created: substate.contracts_created
contracts_created: substate.contracts_created,
})
}
},
}
}

View File

@ -60,15 +60,19 @@ impl<'a> Externalities<'a> {
}
impl<'a> Ext for Externalities<'a> {
fn sload(&self, key: &H256) -> H256 {
fn storage_at(&self, key: &H256) -> H256 {
trace!("ext: storage_at({}, {}) == {}\n", self.params.address, key, U256::from(self.state.storage_at(&self.params.address, key).as_slice()));
self.state.storage_at(&self.params.address, key)
}
fn sstore(&mut self, key: H256, value: H256) {
fn set_storage_at(&mut self, key: H256, value: H256) {
let old = self.state.storage_at(&self.params.address, &key);
// if SSTORE nonzero -> zero, increment refund count
if value == H256::new() && self.state.storage_at(&self.params.address, &key) != H256::new() {
if value.is_zero() && !old.is_zero() {
trace!("ext: additional refund. {} -> {}\n", self.substate.refunds_count, self.substate.refunds_count + x!(1));
self.substate.refunds_count = self.substate.refunds_count + U256::one();
}
trace!("ext: set_storage_at({}, {}): {} -> {}\n", self.params.address, key, U256::from(old.as_slice()), U256::from(value.as_slice()));
self.state.set_storage(&self.params.address, key, value)
}
@ -80,9 +84,14 @@ impl<'a> Ext for Externalities<'a> {
match *number < U256::from(self.info.number) && number.low_u64() >= cmp::max(256, self.info.number) - 256 {
true => {
let index = self.info.number - number.low_u64() - 1;
self.info.last_hashes[index as usize].clone()
let r = self.info.last_hashes[index as usize].clone();
trace!("ext: blockhash({}) -> {} self.info.number={}\n", number, r, self.info.number);
r
},
false => {
trace!("ext: blockhash({}) -> null self.info.number={}\n", number, self.info.number);
H256::from(&U256::zero())
},
false => H256::from(&U256::zero()),
}
}
@ -124,6 +133,7 @@ impl<'a> Ext for Externalities<'a> {
data: &[u8],
code_address: &Address,
output: &mut [u8]) -> Result<(U256, bool), evm::Error> {
let mut gas_cost = *call_gas;
let mut call_gas = *call_gas;
@ -138,7 +148,10 @@ impl<'a> Ext for Externalities<'a> {
call_gas = call_gas + U256::from(self.schedule.call_stipend);
}
debug!("Externalities::call(gas={}, call_gas={}, recv={}, value={}, data={}, code={})\n", gas, call_gas, receive_address, value, data.pretty(), code_address);
if gas_cost > *gas {
debug!("Externalities::call: OutOfGas gas_cost={}, gas={}", gas_cost, gas);
return Err(evm::Error::OutOfGas);
}
@ -146,7 +159,8 @@ impl<'a> Ext for Externalities<'a> {
// if balance is insufficient or we are too deep, return
if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth {
return Ok((gas + call_gas, true));
debug!("Externalities::call: OutOfCash bal({})={}, value={}", self.params.address, self.state.balance(&self.params.address), value);
return Ok((gas + call_gas, false));
}
let params = ActionParams {
@ -161,8 +175,13 @@ impl<'a> Ext for Externalities<'a> {
data: Some(data.to_vec()),
};
let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth);
match ex.call(&params, self.substate, BytesRef::Fixed(output)) {
trace!("Externalities::call: BEFORE: bal({})={}, bal({})={}\n", params.sender, self.state.balance(&params.sender), params.address, self.state.balance(&params.address));
trace!("Externalities::call: CALLING: params={:?}\n", params);
let r = Executive::from_parent(self.state, self.info, self.engine, self.depth).call(&params, self.substate, BytesRef::Fixed(output));
trace!("Externalities::call: AFTER: bal({})={}, bal({})={}\n", params.sender, self.state.balance(&params.sender), params.address, self.state.balance(&params.address));
match r {
Ok(gas_left) => Ok((gas + gas_left, true)),
_ => Ok((gas, false))
}

View File

@ -67,7 +67,9 @@ impl Header {
pub fn state_root(&self) -> &H256 { &self.state_root }
pub fn receipts_root(&self) -> &H256 { &self.receipts_root }
pub fn gas_limit(&self) -> &U256 { &self.gas_limit }
pub fn difficulty(&self) -> &U256 { &self.difficulty }
pub fn seal(&self) -> &Vec<Bytes> { &self.seal }
// TODO: seal_at, set_seal_at &c.
@ -79,6 +81,10 @@ impl Header {
pub fn set_extra_data(&mut self, a: Bytes) { if a != self.extra_data { self.extra_data = a; self.note_dirty(); } }
pub fn set_gas_used(&mut self, a: U256) { self.gas_used = a; self.note_dirty(); }
pub fn set_gas_limit(&mut self, a: U256) { self.gas_limit = a; self.note_dirty(); }
pub fn set_difficulty(&mut self, a: U256) { self.difficulty = a; self.note_dirty(); }
pub fn set_seal(&mut self, a: Vec<Bytes>) { self.seal = a; self.note_dirty(); }
/// Get the hash of this header (sha3 of the RLP).

View File

@ -3,6 +3,7 @@ use engine::Engine;
use executive::Executive;
use pod_account::*;
use pod_state::*;
use state_diff::*;
pub type ApplyResult = Result<Receipt, Error>;
@ -106,12 +107,16 @@ impl State {
/// 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)
let old = self.balance(a);
self.require(a, false).add_balance(incr);
trace!("state: add_balance({}, {}): {} -> {}\n", a, incr, old, self.balance(a));
}
/// Subtract `decr` from the balance of account `a`.
pub fn sub_balance(&mut self, a: &Address, decr: &U256) {
self.require(a, false).sub_balance(decr)
let old = self.balance(a);
self.require(a, false).sub_balance(decr);
trace!("state: sub_balance({}, {}): {} -> {}\n", a, decr, old, self.balance(a));
}
/// Subtracts `by` from the balance of `from` and adds it to that of `to`.
@ -139,8 +144,13 @@ impl State {
/// Execute a given transaction.
/// This will change the state accordingly.
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult {
let old = self.to_pod();
let e = try!(Executive::new(self, env_info, engine).transact(t));
//println!("Executed: {:?}", e);
debug!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod()));
self.commit();
let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs);
debug!("Transaction receipt: {:?}", receipt);
@ -219,8 +229,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.
fn get(&self, a: &Address, require_code: bool) -> Ref<Option<Account>> {
self.cache.borrow_mut().entry(a.clone()).or_insert_with(||
SecTrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp)));
self.cache.borrow_mut().entry(a.clone()).or_insert_with(|| {
SecTrieDB::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);

View File

@ -2,6 +2,7 @@ use common::*;
/// State changes which should be applied in finalize,
/// after transaction is fully executed.
#[derive(Debug)]
pub struct Substate {
/// Any accounts that have suicided.
pub suicides: HashSet<Address>,

View File

@ -60,12 +60,12 @@ impl<'a> TestExt<'a> {
}
impl<'a> Ext for TestExt<'a> {
fn sload(&self, key: &H256) -> H256 {
self.ext.sload(key)
fn storage_at(&self, key: &H256) -> H256 {
self.ext.storage_at(key)
}
fn sstore(&mut self, key: H256, value: H256) {
self.ext.sstore(key, value)
fn set_storage_at(&mut self, key: H256, value: H256) {
self.ext.set_storage_at(key, value)
}
fn balance(&self, address: &Address) -> U256 {

View File

@ -115,18 +115,18 @@ pub fn verify_block_family<BC>(header: &Header, bytes: &[u8], engine: &Engine, b
/// Phase 4 verification. Check block information against transaction enactment results,
pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error> {
if expected.state_root != got.state_root {
return Err(From::from(BlockError::InvalidStateRoot(Mismatch { expected: expected.state_root.clone(), found: got.state_root.clone() })))
if expected.gas_used != got.gas_used {
return Err(From::from(BlockError::InvalidGasUsed(Mismatch { expected: expected.gas_used, found: got.gas_used })))
}
if expected.receipts_root != got.receipts_root {
return Err(From::from(BlockError::InvalidReceiptsStateRoot(Mismatch { expected: expected.receipts_root.clone(), found: got.receipts_root.clone() })))
}
if expected.state_root != got.state_root {
return Err(From::from(BlockError::InvalidStateRoot(Mismatch { expected: expected.state_root.clone(), found: got.state_root.clone() })))
}
if expected.log_bloom != got.log_bloom {
return Err(From::from(BlockError::InvalidLogBloom(Mismatch { expected: expected.log_bloom.clone(), found: got.log_bloom.clone() })))
}
if expected.gas_used != got.gas_used {
return Err(From::from(BlockError::InvalidGasUsed(Mismatch { expected: expected.gas_used, found: got.gas_used })))
}
Ok(())
}