Merge branch 'master' of github.com:gavofyork/ethcore into client

This commit is contained in:
arkpar 2016-01-15 13:18:18 +01:00
commit d80fe310a3
4 changed files with 45 additions and 54 deletions

View File

@ -20,16 +20,19 @@ pub struct OutOfBounds<T: fmt::Debug> {
/// Result of executing the transaction. /// Result of executing the transaction.
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub enum ExecutionError { pub enum ExecutionError {
/// Returned when there gas paid for transaction execution is
/// lower than base gas required.
NotEnoughBaseGas { required: U256, got: U256 },
/// Returned when block (gas_used + gas) > gas_limit. /// Returned when block (gas_used + gas) > gas_limit.
/// ///
/// If gas =< gas_limit, upstream may try to execute the transaction /// If gas =< gas_limit, upstream may try to execute the transaction
/// in next block. /// in next block.
BlockGasLimitReached { gas_limit: U256, gas_used: U256, gas: U256 }, BlockGasLimitReached { gas_limit: U256, gas_used: U256, gas: U256 },
/// Returned when transaction nonce does not match state nonce. /// Returned when transaction nonce does not match state nonce.
InvalidNonce { expected: U256, is: U256 }, InvalidNonce { expected: U256, got: U256 },
/// Returned when cost of transaction (value + gas_price * gas) exceeds /// Returned when cost of transaction (value + gas_price * gas) exceeds
/// current sender balance. /// current sender balance.
NotEnoughCash { required: U512, is: U512 }, NotEnoughCash { required: U512, got: U512 },
/// Returned when internal evm error occurs. /// Returned when internal evm error occurs.
Internal Internal
} }

View File

@ -21,8 +21,6 @@ pub struct Substate {
logs: Vec<LogEntry>, logs: Vec<LogEntry>,
/// Refund counter of SSTORE nonzero->zero. /// Refund counter of SSTORE nonzero->zero.
refunds_count: U256, refunds_count: U256,
/// True if transaction, or one of its subcalls runs out of gas.
excepted: bool,
/// Created contracts. /// Created contracts.
contracts_created: Vec<Address> contracts_created: Vec<Address>
} }
@ -34,7 +32,6 @@ impl Substate {
suicides: HashSet::new(), suicides: HashSet::new(),
logs: vec![], logs: vec![],
refunds_count: U256::zero(), refunds_count: U256::zero(),
excepted: false,
contracts_created: vec![] contracts_created: vec![]
} }
} }
@ -43,11 +40,8 @@ impl Substate {
self.suicides.extend(s.suicides.into_iter()); self.suicides.extend(s.suicides.into_iter());
self.logs.extend(s.logs.into_iter()); self.logs.extend(s.logs.into_iter());
self.refunds_count = self.refunds_count + s.refunds_count; self.refunds_count = self.refunds_count + s.refunds_count;
self.excepted |= s.excepted;
self.contracts_created.extend(s.contracts_created.into_iter()); self.contracts_created.extend(s.contracts_created.into_iter());
} }
pub fn excepted(&self) -> bool { self.excepted }
} }
/// Transaction execution receipt. /// Transaction execution receipt.
@ -68,8 +62,6 @@ pub struct Executed {
pub cumulative_gas_used: U256, pub cumulative_gas_used: U256,
/// Vector of logs generated by transaction. /// Vector of logs generated by transaction.
pub logs: Vec<LogEntry>, pub logs: Vec<LogEntry>,
/// Execution ended running out of gas.
pub excepted: bool,
/// Addresses of contracts created during execution of transaction. /// Addresses of contracts created during execution of transaction.
/// Ordered from earliest creation. /// Ordered from earliest creation.
/// ///
@ -117,11 +109,18 @@ impl<'a> Executive<'a> {
let sender = try!(t.sender()); let sender = try!(t.sender());
let nonce = self.state.nonce(&sender); let nonce = self.state.nonce(&sender);
// TODO: error on base gas required let schedule = self.engine.schedule(self.info);
let base_gas_required = U256::from(t.gas_required(&schedule));
if t.gas < base_gas_required {
return Err(From::from(ExecutionError::NotEnoughBaseGas { required: base_gas_required, got: t.gas }));
}
let init_gas = t.gas - base_gas_required;
// validate transaction nonce // validate transaction nonce
if t.nonce != nonce { if t.nonce != nonce {
return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, is: t.nonce })); return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce }));
} }
// validate if transaction fits into given block // validate if transaction fits into given block
@ -140,7 +139,7 @@ impl<'a> Executive<'a> {
// avoid unaffordable transactions // avoid unaffordable transactions
if U512::from(balance) < total_cost { if U512::from(balance) < total_cost {
return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, is: U512::from(balance) })); return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, got: U512::from(balance) }));
} }
// NOTE: there can be no invalid transactions from this point. // NOTE: there can be no invalid transactions from this point.
@ -149,9 +148,6 @@ impl<'a> Executive<'a> {
let mut substate = Substate::new(); let mut substate = Substate::new();
let schedule = self.engine.schedule(self.info);
let init_gas = t.gas - U256::from(t.gas_required(&schedule));
let res = match t.action() { let res = match t.action() {
&Action::Create => { &Action::Create => {
let params = ActionParams { let params = ActionParams {
@ -207,7 +203,10 @@ impl<'a> Executive<'a> {
Ok(params.gas - cost) Ok(params.gas - cost)
}, },
// just drain the whole gas // just drain the whole gas
false => Ok(U256::zero()) false => {
self.state.revert(backup);
Err(evm::Error::OutOfGas)
}
} }
} else if params.code.len() > 0 { } else if params.code.len() > 0 {
// if destination is a contract, do normal message call // if destination is a contract, do normal message call
@ -293,7 +292,6 @@ impl<'a> Executive<'a> {
refunded: refund, refunded: refund,
cumulative_gas_used: self.info.gas_used + gas_used, cumulative_gas_used: self.info.gas_used + gas_used,
logs: substate.logs, logs: substate.logs,
excepted: substate.excepted,
contracts_created: substate.contracts_created contracts_created: substate.contracts_created
}) })
}, },
@ -304,7 +302,6 @@ impl<'a> Executive<'a> {
refunded: U256::zero(), refunded: U256::zero(),
cumulative_gas_used: self.info.gas_used + t.gas, cumulative_gas_used: self.info.gas_used + t.gas,
logs: vec![], logs: vec![],
excepted: true,
contracts_created: vec![] contracts_created: vec![]
}) })
} }
@ -315,7 +312,6 @@ impl<'a> Executive<'a> {
// TODO: handle other evm::Errors same as OutOfGas once they are implemented // TODO: handle other evm::Errors same as OutOfGas once they are implemented
match result { match result {
&Err(evm::Error::OutOfGas) => { &Err(evm::Error::OutOfGas) => {
substate.excepted = true;
self.state.revert(backup); self.state.revert(backup);
}, },
&Ok(_) | &Err(evm::Error::Internal) => substate.accrue(un_substate) &Ok(_) | &Err(evm::Error::Internal) => substate.accrue(un_substate)
@ -461,7 +457,7 @@ impl<'a> Ext for Externalities<'a> {
let gas = *gas - gas_cost; let gas = *gas - gas_cost;
// if balance is insufficient or we are to deep, return // if balance is insufficient or we are too deep, return
if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth { if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth {
return Ok((gas + call_gas, true)); return Ok((gas + call_gas, true));
} }
@ -899,7 +895,6 @@ mod tests {
assert_eq!(executed.refunded, U256::from(58_699)); assert_eq!(executed.refunded, U256::from(58_699));
assert_eq!(executed.cumulative_gas_used, U256::from(41_301)); assert_eq!(executed.cumulative_gas_used, U256::from(41_301));
assert_eq!(executed.logs.len(), 0); assert_eq!(executed.logs.len(), 0);
assert_eq!(executed.excepted, false);
assert_eq!(executed.contracts_created.len(), 0); assert_eq!(executed.contracts_created.len(), 0);
assert_eq!(state.balance(&sender), U256::from(1)); assert_eq!(state.balance(&sender), U256::from(1));
assert_eq!(state.balance(&contract), U256::from(17)); assert_eq!(state.balance(&contract), U256::from(17));
@ -946,8 +941,8 @@ mod tests {
}; };
match res { match res {
Err(Error::Execution(ExecutionError::InvalidNonce { expected, is })) Err(Error::Execution(ExecutionError::InvalidNonce { expected, got }))
if expected == U256::zero() && is == U256::one() => (), if expected == U256::zero() && got == U256::one() => (),
_ => assert!(false, "Expected invalid nonce error.") _ => assert!(false, "Expected invalid nonce error.")
} }
} }
@ -997,8 +992,8 @@ mod tests {
}; };
match res { match res {
Err(Error::Execution(ExecutionError::NotEnoughCash { required , is })) Err(Error::Execution(ExecutionError::NotEnoughCash { required , got }))
if required == U512::from(100_018) && is == U512::from(100_017) => (), if required == U512::from(100_018) && got == U512::from(100_017) => (),
_ => assert!(false, "Expected not enough cash error. {:?}", res) _ => assert!(false, "Expected not enough cash error. {:?}", res)
} }
} }

View File

@ -31,8 +31,7 @@ impl PodAccount {
let mut stream = RlpStream::new_list(4); let mut stream = RlpStream::new_list(4);
stream.append(&self.nonce); stream.append(&self.nonce);
stream.append(&self.balance); stream.append(&self.balance);
// TODO. stream.append(&sec_trie_root(self.storage.iter().map(|(k, v)| (k.to_vec(), encode(&U256::from(v.as_slice())))).collect()));
stream.append(&SHA3_NULL_RLP);
stream.append(&self.code.sha3()); stream.append(&self.code.sha3());
stream.out() stream.out()
} }

View File

@ -4,11 +4,6 @@ use pod_state::*;
use state_diff::*; use state_diff::*;
use ethereum; use ethereum;
fn flush(s: String) {
::std::io::stdout().write(s.as_bytes()).unwrap();
::std::io::stdout().flush().unwrap();
}
fn do_json_test(json_data: &[u8]) -> Vec<String> { fn do_json_test(json_data: &[u8]) -> Vec<String> {
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid"); let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
let mut failed = Vec::new(); let mut failed = Vec::new();
@ -39,32 +34,31 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
//println!("Transaction: {:?}", t); //println!("Transaction: {:?}", t);
//println!("Env: {:?}", env); //println!("Env: {:?}", env);
let calc_post = sec_trie_root(post.get().iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect());
{ if fail_unless(post_state_root == calc_post) {
println!("!!! {}: Trie root mismatch (got: {}, expect: {}):", name, calc_post, post_state_root);
println!("!!! Post:\n{}", post);
} else {
let mut s = State::new_temp(); let mut s = State::new_temp();
s.populate_from(post.clone()); s.populate_from(pre);
s.commit(); s.commit();
assert_eq!(&post_state_root, s.root()); let res = s.apply(&env, engine.deref(), &t);
}
let mut s = State::new_temp(); if fail_unless(s.root() == &post_state_root) {
s.populate_from(pre); println!("!!! {}: State mismatch (got: {}, expect: {}):", name, s.root(), post_state_root);
s.commit(); let our_post = s.to_pod();
let res = s.apply(&env, engine.deref(), &t); println!("Got:\n{}", our_post);
println!("Expect:\n{}", post);
println!("Diff ---expect -> +++got:\n{}", StateDiff::diff_pod(&post, &our_post));
}
if fail_unless(s.root() == &post_state_root) { if let Ok(r) = res {
println!("!!! {}: State mismatch (got: {}, expect: {}):", name, s.root(), post_state_root); if fail_unless(logs == r.logs) {
let our_post = s.to_pod(); println!("!!! {}: Logs mismatch:", name);
println!("Got:\n{}", our_post); println!("Got:\n{:?}", r.logs);
println!("Expect:\n{}", post); println!("Expect:\n{:?}", logs);
println!("Diff ---expect -> +++got:\n{}", StateDiff::diff_pod(&post, &our_post)); }
}
if let Ok(r) = res {
if fail_unless(logs == r.logs) {
println!("!!! {}: Logs mismatch:", name);
println!("Got:\n{:?}", r.logs);
println!("Expect:\n{:?}", logs);
} }
} }
} }