Propagate trie errors upwards from State (#4655)
* state backend trait mirroring state_db API * minimal state backend trait make state module public * fix json tests * return errors on database corruption * fix tests, json tests * fix remainder of build * add Backend bound on state
This commit is contained in:
parent
eb9ee35d6c
commit
1bf2b27708
@ -540,7 +540,8 @@ pub fn enact(
|
|||||||
{
|
{
|
||||||
if ::log::max_log_level() >= ::log::LogLevel::Trace {
|
if ::log::max_log_level() >= ::log::LogLevel::Trace {
|
||||||
let s = State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(), factories.clone())?;
|
let s = State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(), factories.clone())?;
|
||||||
trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n", header.number(), s.root(), header.author(), s.balance(&header.author()));
|
trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n",
|
||||||
|
header.number(), s.root(), header.author(), s.balance(&header.author())?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -890,17 +890,20 @@ impl BlockChainClient for Client {
|
|||||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||||
|
|
||||||
let sender = t.sender();
|
let sender = t.sender();
|
||||||
let balance = state.balance(&sender);
|
let balance = state.balance(&sender).map_err(|_| CallError::StateCorrupt)?;
|
||||||
let needed_balance = t.value + t.gas * t.gas_price;
|
let needed_balance = t.value + t.gas * t.gas_price;
|
||||||
if balance < needed_balance {
|
if balance < needed_balance {
|
||||||
// give the sender a sufficient balance
|
// give the sender a sufficient balance
|
||||||
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty)
|
||||||
|
.map_err(|_| CallError::StateCorrupt)?;
|
||||||
}
|
}
|
||||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(t, options)?;
|
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(t, options)?;
|
||||||
|
|
||||||
// TODO gav move this into Executive.
|
// TODO gav move this into Executive.
|
||||||
ret.state_diff = original_state.map(|original| state.diff_from(original));
|
if let Some(original) = original_state {
|
||||||
|
ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
@ -921,7 +924,7 @@ impl BlockChainClient for Client {
|
|||||||
// that's just a copy of the state.
|
// that's just a copy of the state.
|
||||||
let original_state = self.state_at(block).ok_or(CallError::StatePruned)?;
|
let original_state = self.state_at(block).ok_or(CallError::StatePruned)?;
|
||||||
let sender = t.sender();
|
let sender = t.sender();
|
||||||
let balance = original_state.balance(&sender);
|
let balance = original_state.balance(&sender).map_err(ExecutionError::from)?;
|
||||||
let options = TransactOptions { tracing: true, vm_tracing: false, check_nonce: false };
|
let options = TransactOptions { tracing: true, vm_tracing: false, check_nonce: false };
|
||||||
|
|
||||||
let cond = |gas| {
|
let cond = |gas| {
|
||||||
@ -933,27 +936,29 @@ impl BlockChainClient for Client {
|
|||||||
let needed_balance = tx.value + tx.gas * tx.gas_price;
|
let needed_balance = tx.value + tx.gas * tx.gas_price;
|
||||||
if balance < needed_balance {
|
if balance < needed_balance {
|
||||||
// give the sender a sufficient balance
|
// give the sender a sufficient balance
|
||||||
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty)
|
||||||
|
.map_err(ExecutionError::from)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm)
|
Ok(Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm)
|
||||||
.transact(&tx, options.clone())
|
.transact(&tx, options.clone())
|
||||||
.map(|r| r.exception.is_none())
|
.map(|r| r.exception.is_none())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut upper = header.gas_limit();
|
let mut upper = header.gas_limit();
|
||||||
if !cond(upper) {
|
if !cond(upper)? {
|
||||||
// impossible at block gas limit - try `UPPER_CEILING` instead.
|
// impossible at block gas limit - try `UPPER_CEILING` instead.
|
||||||
// TODO: consider raising limit by powers of two.
|
// TODO: consider raising limit by powers of two.
|
||||||
upper = UPPER_CEILING.into();
|
upper = UPPER_CEILING.into();
|
||||||
if !cond(upper) {
|
if !cond(upper)? {
|
||||||
trace!(target: "estimate_gas", "estimate_gas failed with {}", upper);
|
trace!(target: "estimate_gas", "estimate_gas failed with {}", upper);
|
||||||
return Err(CallError::Execution(ExecutionError::Internal))
|
let err = ExecutionError::Internal(format!("Requires higher than upper limit of {}", upper));
|
||||||
|
return Err(err.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let lower = t.gas_required(&self.engine.schedule(&env_info)).into();
|
let lower = t.gas_required(&self.engine.schedule(&env_info)).into();
|
||||||
if cond(lower) {
|
if cond(lower)? {
|
||||||
trace!(target: "estimate_gas", "estimate_gas succeeded with {}", lower);
|
trace!(target: "estimate_gas", "estimate_gas succeeded with {}", lower);
|
||||||
return Ok(lower)
|
return Ok(lower)
|
||||||
}
|
}
|
||||||
@ -961,23 +966,25 @@ impl BlockChainClient for Client {
|
|||||||
/// Find transition point between `lower` and `upper` where `cond` changes from `false` to `true`.
|
/// Find transition point between `lower` and `upper` where `cond` changes from `false` to `true`.
|
||||||
/// Returns the lowest value between `lower` and `upper` for which `cond` returns true.
|
/// Returns the lowest value between `lower` and `upper` for which `cond` returns true.
|
||||||
/// We assert: `cond(lower) = false`, `cond(upper) = true`
|
/// We assert: `cond(lower) = false`, `cond(upper) = true`
|
||||||
fn binary_chop<F>(mut lower: U256, mut upper: U256, mut cond: F) -> U256 where F: FnMut(U256) -> bool {
|
fn binary_chop<F, E>(mut lower: U256, mut upper: U256, mut cond: F) -> Result<U256, E>
|
||||||
|
where F: FnMut(U256) -> Result<bool, E>
|
||||||
|
{
|
||||||
while upper - lower > 1.into() {
|
while upper - lower > 1.into() {
|
||||||
let mid = (lower + upper) / 2.into();
|
let mid = (lower + upper) / 2.into();
|
||||||
trace!(target: "estimate_gas", "{} .. {} .. {}", lower, mid, upper);
|
trace!(target: "estimate_gas", "{} .. {} .. {}", lower, mid, upper);
|
||||||
let c = cond(mid);
|
let c = cond(mid)?;
|
||||||
match c {
|
match c {
|
||||||
true => upper = mid,
|
true => upper = mid,
|
||||||
false => lower = mid,
|
false => lower = mid,
|
||||||
};
|
};
|
||||||
trace!(target: "estimate_gas", "{} => {} .. {}", c, lower, upper);
|
trace!(target: "estimate_gas", "{} => {} .. {}", c, lower, upper);
|
||||||
}
|
}
|
||||||
upper
|
Ok(upper)
|
||||||
}
|
}
|
||||||
|
|
||||||
// binary chop to non-excepting call with gas somewhere between 21000 and block gas limit
|
// binary chop to non-excepting call with gas somewhere between 21000 and block gas limit
|
||||||
trace!(target: "estimate_gas", "estimate_gas chopping {} .. {}", lower, upper);
|
trace!(target: "estimate_gas", "estimate_gas chopping {} .. {}", lower, upper);
|
||||||
Ok(binary_chop(lower, upper, cond))
|
binary_chop(lower, upper, cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replay(&self, id: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
fn replay(&self, id: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||||
@ -1006,17 +1013,16 @@ impl BlockChainClient for Client {
|
|||||||
let rest = txs.split_off(address.index);
|
let rest = txs.split_off(address.index);
|
||||||
for t in txs {
|
for t in txs {
|
||||||
let t = SignedTransaction::new(t).expect(PROOF);
|
let t = SignedTransaction::new(t).expect(PROOF);
|
||||||
match Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(&t, Default::default()) {
|
let x = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(&t, Default::default())?;
|
||||||
Ok(x) => { env_info.gas_used = env_info.gas_used + x.gas_used; }
|
env_info.gas_used = env_info.gas_used + x.gas_used;
|
||||||
Err(ee) => { return Err(CallError::Execution(ee)) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let first = rest.into_iter().next().expect("We split off < `address.index`; Length is checked earlier; qed");
|
let first = rest.into_iter().next().expect("We split off < `address.index`; Length is checked earlier; qed");
|
||||||
let t = SignedTransaction::new(first).expect(PROOF);
|
let t = SignedTransaction::new(first).expect(PROOF);
|
||||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(&t, options)?;
|
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(&t, options)?;
|
||||||
ret.state_diff = original_state.map(|original| state.diff_from(original));
|
if let Some(original) = original_state {
|
||||||
|
ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?)
|
||||||
|
}
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1108,11 +1114,11 @@ impl BlockChainClient for Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> {
|
fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> {
|
||||||
self.state_at(id).map(|s| s.nonce(address))
|
self.state_at(id).and_then(|s| s.nonce(address).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn storage_root(&self, address: &Address, id: BlockId) -> Option<H256> {
|
fn storage_root(&self, address: &Address, id: BlockId) -> Option<H256> {
|
||||||
self.state_at(id).and_then(|s| s.storage_root(address))
|
self.state_at(id).and_then(|s| s.storage_root(address).ok()).and_then(|x| x)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_hash(&self, id: BlockId) -> Option<H256> {
|
fn block_hash(&self, id: BlockId) -> Option<H256> {
|
||||||
@ -1121,15 +1127,15 @@ impl BlockChainClient for Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn code(&self, address: &Address, id: BlockId) -> Option<Option<Bytes>> {
|
fn code(&self, address: &Address, id: BlockId) -> Option<Option<Bytes>> {
|
||||||
self.state_at(id).map(|s| s.code(address).map(|c| (*c).clone()))
|
self.state_at(id).and_then(|s| s.code(address).ok()).map(|c| c.map(|c| (&*c).clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn balance(&self, address: &Address, id: BlockId) -> Option<U256> {
|
fn balance(&self, address: &Address, id: BlockId) -> Option<U256> {
|
||||||
self.state_at(id).map(|s| s.balance(address))
|
self.state_at(id).and_then(|s| s.balance(address).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn storage_at(&self, address: &Address, position: &H256, id: BlockId) -> Option<H256> {
|
fn storage_at(&self, address: &Address, position: &H256, id: BlockId) -> Option<H256> {
|
||||||
self.state_at(id).map(|s| s.storage_at(address, position))
|
self.state_at(id).and_then(|s| s.storage_at(address, position).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_accounts(&self, id: BlockId, after: Option<&Address>, count: u64) -> Option<Vec<Address>> {
|
fn list_accounts(&self, id: BlockId, after: Option<&Address>, count: u64) -> Option<Vec<Address>> {
|
||||||
@ -1182,7 +1188,7 @@ impl BlockChainClient for Client {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let root = match state.storage_root(account) {
|
let root = match state.storage_root(account) {
|
||||||
Some(root) => root,
|
Ok(Some(root)) => root,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -250,10 +250,12 @@ impl Engine for AuthorityRound {
|
|||||||
fn on_close_block(&self, block: &mut ExecutedBlock) {
|
fn on_close_block(&self, block: &mut ExecutedBlock) {
|
||||||
let fields = block.fields_mut();
|
let fields = block.fields_mut();
|
||||||
// Bestow block reward
|
// Bestow block reward
|
||||||
fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty);
|
let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty)
|
||||||
|
.map_err(::error::Error::from)
|
||||||
|
.and_then(|_| fields.state.commit());
|
||||||
// Commit state so that we can actually figure out the state root.
|
// Commit state so that we can actually figure out the state root.
|
||||||
if let Err(e) = fields.state.commit() {
|
if let Err(e) = res {
|
||||||
warn!("Encountered error on state commit: {}", e);
|
warn!("Encountered error on closing block: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,10 +467,12 @@ impl Engine for Tendermint {
|
|||||||
fn on_close_block(&self, block: &mut ExecutedBlock) {
|
fn on_close_block(&self, block: &mut ExecutedBlock) {
|
||||||
let fields = block.fields_mut();
|
let fields = block.fields_mut();
|
||||||
// Bestow block reward
|
// Bestow block reward
|
||||||
fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty);
|
let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty)
|
||||||
|
.map_err(::error::Error::from)
|
||||||
|
.and_then(|_| fields.state.commit());
|
||||||
// Commit state so that we can actually figure out the state root.
|
// Commit state so that we can actually figure out the state root.
|
||||||
if let Err(e) = fields.state.commit() {
|
if let Err(e) = res {
|
||||||
warn!("Encountered error on state commit: {}", e);
|
warn!("Encountered error on closing block: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,10 +229,16 @@ impl Engine for Ethash {
|
|||||||
if block.fields().header.number() == self.ethash_params.dao_hardfork_transition {
|
if block.fields().header.number() == self.ethash_params.dao_hardfork_transition {
|
||||||
// TODO: enable trigger function maybe?
|
// TODO: enable trigger function maybe?
|
||||||
// if block.fields().header.gas_limit() <= 4_000_000.into() {
|
// if block.fields().header.gas_limit() <= 4_000_000.into() {
|
||||||
let mut state = block.fields_mut().state;
|
let state = block.fields_mut().state;
|
||||||
for child in &self.ethash_params.dao_hardfork_accounts {
|
for child in &self.ethash_params.dao_hardfork_accounts {
|
||||||
let b = state.balance(child);
|
let beneficiary = &self.ethash_params.dao_hardfork_beneficiary;
|
||||||
state.transfer_balance(child, &self.ethash_params.dao_hardfork_beneficiary, &b, CleanupMode::NoEmpty);
|
let res = state.balance(child)
|
||||||
|
.and_then(|b| state.transfer_balance(child, beneficiary, &b, CleanupMode::NoEmpty));
|
||||||
|
|
||||||
|
if let Err(_) = res {
|
||||||
|
warn!("Unable to apply DAO hardfork due to database corruption.");
|
||||||
|
warn!("Your node is now likely out of consensus.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
@ -245,12 +251,28 @@ impl Engine for Ethash {
|
|||||||
let fields = block.fields_mut();
|
let fields = block.fields_mut();
|
||||||
|
|
||||||
// Bestow block reward
|
// Bestow block reward
|
||||||
fields.state.add_balance(fields.header.author(), &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())), CleanupMode::NoEmpty);
|
let res = fields.state.add_balance(
|
||||||
|
fields.header.author(),
|
||||||
|
&(reward + reward / U256::from(32) * U256::from(fields.uncles.len())),
|
||||||
|
CleanupMode::NoEmpty
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = res {
|
||||||
|
warn!("Failed to give block reward: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
// Bestow uncle rewards
|
// Bestow uncle rewards
|
||||||
let current_number = fields.header.number();
|
let current_number = fields.header.number();
|
||||||
for u in fields.uncles.iter() {
|
for u in fields.uncles.iter() {
|
||||||
fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)), CleanupMode::NoEmpty);
|
let res = fields.state.add_balance(
|
||||||
|
u.author(),
|
||||||
|
&(reward * U256::from(8 + u.number() - current_number) / U256::from(8)),
|
||||||
|
CleanupMode::NoEmpty
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = res {
|
||||||
|
warn!("Failed to give uncle reward: {}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit state so that we can actually figure out the state root.
|
// Commit state so that we can actually figure out the state root.
|
||||||
@ -491,7 +513,7 @@ mod tests {
|
|||||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let b = b.close();
|
let b = b.close();
|
||||||
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
|
assert_eq!(b.state().balance(&Address::zero()).unwrap(), U256::from_str("4563918244f40000").unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -509,8 +531,8 @@ mod tests {
|
|||||||
b.push_uncle(uncle).unwrap();
|
b.push_uncle(uncle).unwrap();
|
||||||
|
|
||||||
let b = b.close();
|
let b = b.close();
|
||||||
assert_eq!(b.state().balance(&Address::zero()), "478eae0e571ba000".into());
|
assert_eq!(b.state().balance(&Address::zero()).unwrap(), "478eae0e571ba000".into());
|
||||||
assert_eq!(b.state().balance(&uncle_author), "3cb71f51fc558000".into());
|
assert_eq!(b.state().balance(&uncle_author).unwrap(), "3cb71f51fc558000".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -91,12 +91,12 @@ mod tests {
|
|||||||
let mut db_result = get_temp_state_db();
|
let mut db_result = get_temp_state_db();
|
||||||
let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
|
let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
|
||||||
let s = State::from_existing(db, genesis_header.state_root().clone(), engine.account_start_nonce(), Default::default()).unwrap();
|
let s = State::from_existing(db, genesis_header.state_root().clone(), engine.account_start_nonce(), Default::default()).unwrap();
|
||||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000001".into()), 1u64.into());
|
assert_eq!(s.balance(&"0000000000000000000000000000000000000001".into()).unwrap(), 1u64.into());
|
||||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()), 1u64.into());
|
assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()).unwrap(), 1u64.into());
|
||||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000003".into()), 1u64.into());
|
assert_eq!(s.balance(&"0000000000000000000000000000000000000003".into()).unwrap(), 1u64.into());
|
||||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000004".into()), 1u64.into());
|
assert_eq!(s.balance(&"0000000000000000000000000000000000000004".into()).unwrap(), 1u64.into());
|
||||||
assert_eq!(s.balance(&"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c".into()), U256::from(1u64) << 200);
|
assert_eq!(s.balance(&"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c".into()).unwrap(), U256::from(1u64) << 200);
|
||||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000000".into()), 0u64.into());
|
assert_eq!(s.balance(&"0000000000000000000000000000000000000000".into()).unwrap(), 0u64.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
//! Evm interface.
|
//! Evm interface.
|
||||||
|
|
||||||
use std::{ops, cmp, fmt};
|
use std::{ops, cmp, fmt};
|
||||||
use util::{U128, U256, U512, Uint};
|
use util::{U128, U256, U512, Uint, trie};
|
||||||
use action_params::ActionParams;
|
use action_params::ActionParams;
|
||||||
use evm::Ext;
|
use evm::Ext;
|
||||||
|
|
||||||
/// Evm errors.
|
/// Evm errors.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
||||||
/// The state should be reverted to the state from before the
|
/// The state should be reverted to the state from before the
|
||||||
@ -61,8 +61,13 @@ pub enum Error {
|
|||||||
},
|
},
|
||||||
/// Returned on evm internal error. Should never be ignored during development.
|
/// Returned on evm internal error. Should never be ignored during development.
|
||||||
/// Likely to cause consensus issues.
|
/// Likely to cause consensus issues.
|
||||||
#[allow(dead_code)] // created only by jit
|
Internal(String),
|
||||||
Internal,
|
}
|
||||||
|
|
||||||
|
impl From<Box<trie::TrieError>> for Error {
|
||||||
|
fn from(err: Box<trie::TrieError>) -> Self {
|
||||||
|
Error::Internal(format!("Internal error: {}", err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
@ -74,7 +79,7 @@ impl fmt::Display for Error {
|
|||||||
BadInstruction { .. } => "Bad instruction",
|
BadInstruction { .. } => "Bad instruction",
|
||||||
StackUnderflow { .. } => "Stack underflow",
|
StackUnderflow { .. } => "Stack underflow",
|
||||||
OutOfStack { .. } => "Out of stack",
|
OutOfStack { .. } => "Out of stack",
|
||||||
Internal => "Internal error",
|
Internal(ref msg) => msg,
|
||||||
};
|
};
|
||||||
message.fmt(f)
|
message.fmt(f)
|
||||||
}
|
}
|
||||||
|
@ -42,24 +42,25 @@ pub enum MessageCallResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Externalities interface for EVMs
|
/// Externalities interface for EVMs
|
||||||
|
// TODO: [rob] associated error type instead of `trie::Result`. Not all EVMs are trie powered.
|
||||||
pub trait Ext {
|
pub trait Ext {
|
||||||
/// Returns a value for given key.
|
/// Returns a value for given key.
|
||||||
fn storage_at(&self, key: &H256) -> H256;
|
fn storage_at(&self, key: &H256) -> trie::Result<H256>;
|
||||||
|
|
||||||
/// Stores a value for given key.
|
/// Stores a value for given key.
|
||||||
fn set_storage(&mut self, key: H256, value: H256);
|
fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()>;
|
||||||
|
|
||||||
/// Determine whether an account exists.
|
/// Determine whether an account exists.
|
||||||
fn exists(&self, address: &Address) -> bool;
|
fn exists(&self, address: &Address) -> trie::Result<bool>;
|
||||||
|
|
||||||
/// Determine whether an account exists and is not null (zero balance/nonce, no code).
|
/// Determine whether an account exists and is not null (zero balance/nonce, no code).
|
||||||
fn exists_and_not_null(&self, address: &Address) -> bool;
|
fn exists_and_not_null(&self, address: &Address) -> trie::Result<bool>;
|
||||||
|
|
||||||
/// Balance of the origin account.
|
/// Balance of the origin account.
|
||||||
fn origin_balance(&self) -> U256;
|
fn origin_balance(&self) -> trie::Result<U256>;
|
||||||
|
|
||||||
/// Returns address balance.
|
/// Returns address balance.
|
||||||
fn balance(&self, address: &Address) -> U256;
|
fn balance(&self, address: &Address) -> trie::Result<U256>;
|
||||||
|
|
||||||
/// Returns the hash of one of the 256 most recent complete blocks.
|
/// Returns the hash of one of the 256 most recent complete blocks.
|
||||||
fn blockhash(&self, number: &U256) -> H256;
|
fn blockhash(&self, number: &U256) -> H256;
|
||||||
@ -87,10 +88,10 @@ pub trait Ext {
|
|||||||
) -> MessageCallResult;
|
) -> MessageCallResult;
|
||||||
|
|
||||||
/// Returns code at given address
|
/// Returns code at given address
|
||||||
fn extcode(&self, address: &Address) -> Arc<Bytes>;
|
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>>;
|
||||||
|
|
||||||
/// Returns code size at given address
|
/// Returns code size at given address
|
||||||
fn extcodesize(&self, address: &Address) -> usize;
|
fn extcodesize(&self, address: &Address) -> trie::Result<usize>;
|
||||||
|
|
||||||
/// Creates log entry with given topics and data
|
/// Creates log entry with given topics and data
|
||||||
fn log(&mut self, topics: Vec<H256>, data: &[u8]);
|
fn log(&mut self, topics: Vec<H256>, data: &[u8]);
|
||||||
@ -101,7 +102,7 @@ pub trait Ext {
|
|||||||
|
|
||||||
/// Should be called when contract commits suicide.
|
/// Should be called when contract commits suicide.
|
||||||
/// Address to which funds should be refunded.
|
/// Address to which funds should be refunded.
|
||||||
fn suicide(&mut self, refund_address: &Address);
|
fn suicide(&mut self, refund_address: &Address) -> trie::Result<()> ;
|
||||||
|
|
||||||
/// Returns schedule.
|
/// Returns schedule.
|
||||||
fn schedule(&self) -> &Schedule;
|
fn schedule(&self) -> &Schedule;
|
||||||
|
@ -123,7 +123,7 @@ impl<Gas: CostType> Gasometer<Gas> {
|
|||||||
instructions::SSTORE => {
|
instructions::SSTORE => {
|
||||||
let address = H256::from(stack.peek(0));
|
let address = H256::from(stack.peek(0));
|
||||||
let newval = stack.peek(1);
|
let newval = stack.peek(1);
|
||||||
let val = U256::from(&*ext.storage_at(&address));
|
let val = U256::from(&*ext.storage_at(&address)?);
|
||||||
|
|
||||||
let gas = if val.is_zero() && !newval.is_zero() {
|
let gas = if val.is_zero() && !newval.is_zero() {
|
||||||
schedule.sstore_set_gas
|
schedule.sstore_set_gas
|
||||||
@ -146,12 +146,12 @@ impl<Gas: CostType> Gasometer<Gas> {
|
|||||||
instructions::SUICIDE => {
|
instructions::SUICIDE => {
|
||||||
let mut gas = Gas::from(schedule.suicide_gas);
|
let mut gas = Gas::from(schedule.suicide_gas);
|
||||||
|
|
||||||
let is_value_transfer = !ext.origin_balance().is_zero();
|
let is_value_transfer = !ext.origin_balance()?.is_zero();
|
||||||
let address = u256_to_address(stack.peek(0));
|
let address = u256_to_address(stack.peek(0));
|
||||||
if (
|
if (
|
||||||
!schedule.no_empty && !ext.exists(&address)
|
!schedule.no_empty && !ext.exists(&address)?
|
||||||
) || (
|
) || (
|
||||||
schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address)
|
schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address)?
|
||||||
) {
|
) {
|
||||||
gas = overflowing!(gas.overflow_add(schedule.suicide_to_new_account_cost.into()));
|
gas = overflowing!(gas.overflow_add(schedule.suicide_to_new_account_cost.into()));
|
||||||
}
|
}
|
||||||
@ -198,9 +198,9 @@ impl<Gas: CostType> Gasometer<Gas> {
|
|||||||
let is_value_transfer = !stack.peek(2).is_zero();
|
let is_value_transfer = !stack.peek(2).is_zero();
|
||||||
|
|
||||||
if instruction == instructions::CALL && (
|
if instruction == instructions::CALL && (
|
||||||
(!schedule.no_empty && !ext.exists(&address))
|
(!schedule.no_empty && !ext.exists(&address)?)
|
||||||
||
|
||
|
||||||
(schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address))
|
(schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address)?)
|
||||||
) {
|
) {
|
||||||
gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into()));
|
gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into()));
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
let create_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is `CREATE`; qed");
|
let create_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is `CREATE`; qed");
|
||||||
|
|
||||||
let contract_code = self.mem.read_slice(init_off, init_size);
|
let contract_code = self.mem.read_slice(init_off, init_size);
|
||||||
let can_create = ext.balance(¶ms.address) >= endowment && ext.depth() < ext.schedule().max_depth;
|
let can_create = ext.balance(¶ms.address)? >= endowment && ext.depth() < ext.schedule().max_depth;
|
||||||
|
|
||||||
if !can_create {
|
if !can_create {
|
||||||
stack.push(U256::zero());
|
stack.push(U256::zero());
|
||||||
@ -319,11 +319,11 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
// Get sender & receive addresses, check if we have balance
|
// Get sender & receive addresses, check if we have balance
|
||||||
let (sender_address, receive_address, has_balance, call_type) = match instruction {
|
let (sender_address, receive_address, has_balance, call_type) = match instruction {
|
||||||
instructions::CALL => {
|
instructions::CALL => {
|
||||||
let has_balance = ext.balance(¶ms.address) >= value.expect("value set for all but delegate call; qed");
|
let has_balance = ext.balance(¶ms.address)? >= value.expect("value set for all but delegate call; qed");
|
||||||
(¶ms.address, &code_address, has_balance, CallType::Call)
|
(¶ms.address, &code_address, has_balance, CallType::Call)
|
||||||
},
|
},
|
||||||
instructions::CALLCODE => {
|
instructions::CALLCODE => {
|
||||||
let has_balance = ext.balance(¶ms.address) >= value.expect("value set for all but delegate call; qed");
|
let has_balance = ext.balance(¶ms.address)? >= value.expect("value set for all but delegate call; qed");
|
||||||
(¶ms.address, ¶ms.address, has_balance, CallType::CallCode)
|
(¶ms.address, ¶ms.address, has_balance, CallType::CallCode)
|
||||||
},
|
},
|
||||||
instructions::DELEGATECALL => (¶ms.sender, ¶ms.address, true, CallType::DelegateCall),
|
instructions::DELEGATECALL => (¶ms.sender, ¶ms.address, true, CallType::DelegateCall),
|
||||||
@ -366,7 +366,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
},
|
},
|
||||||
instructions::SUICIDE => {
|
instructions::SUICIDE => {
|
||||||
let address = stack.pop_back();
|
let address = stack.pop_back();
|
||||||
ext.suicide(&u256_to_address(&address));
|
ext.suicide(&u256_to_address(&address))?;
|
||||||
return Ok(InstructionResult::StopExecution);
|
return Ok(InstructionResult::StopExecution);
|
||||||
},
|
},
|
||||||
instructions::LOG0...instructions::LOG4 => {
|
instructions::LOG0...instructions::LOG4 => {
|
||||||
@ -410,19 +410,19 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
},
|
},
|
||||||
instructions::SLOAD => {
|
instructions::SLOAD => {
|
||||||
let key = H256::from(&stack.pop_back());
|
let key = H256::from(&stack.pop_back());
|
||||||
let word = U256::from(&*ext.storage_at(&key));
|
let word = U256::from(&*ext.storage_at(&key)?);
|
||||||
stack.push(word);
|
stack.push(word);
|
||||||
},
|
},
|
||||||
instructions::SSTORE => {
|
instructions::SSTORE => {
|
||||||
let address = H256::from(&stack.pop_back());
|
let address = H256::from(&stack.pop_back());
|
||||||
let val = stack.pop_back();
|
let val = stack.pop_back();
|
||||||
|
|
||||||
let current_val = U256::from(&*ext.storage_at(&address));
|
let current_val = U256::from(&*ext.storage_at(&address)?);
|
||||||
// Increase refund for clear
|
// Increase refund for clear
|
||||||
if !self.is_zero(¤t_val) && self.is_zero(&val) {
|
if !self.is_zero(¤t_val) && self.is_zero(&val) {
|
||||||
ext.inc_sstore_clears();
|
ext.inc_sstore_clears();
|
||||||
}
|
}
|
||||||
ext.set_storage(address, H256::from(&val));
|
ext.set_storage(address, H256::from(&val))?;
|
||||||
},
|
},
|
||||||
instructions::PC => {
|
instructions::PC => {
|
||||||
stack.push(U256::from(code.position - 1));
|
stack.push(U256::from(code.position - 1));
|
||||||
@ -438,7 +438,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
},
|
},
|
||||||
instructions::BALANCE => {
|
instructions::BALANCE => {
|
||||||
let address = u256_to_address(&stack.pop_back());
|
let address = u256_to_address(&stack.pop_back());
|
||||||
let balance = ext.balance(&address);
|
let balance = ext.balance(&address)?;
|
||||||
stack.push(balance);
|
stack.push(balance);
|
||||||
},
|
},
|
||||||
instructions::CALLER => {
|
instructions::CALLER => {
|
||||||
@ -474,7 +474,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
},
|
},
|
||||||
instructions::EXTCODESIZE => {
|
instructions::EXTCODESIZE => {
|
||||||
let address = u256_to_address(&stack.pop_back());
|
let address = u256_to_address(&stack.pop_back());
|
||||||
let len = ext.extcodesize(&address);
|
let len = ext.extcodesize(&address)?;
|
||||||
stack.push(U256::from(len));
|
stack.push(U256::from(len));
|
||||||
},
|
},
|
||||||
instructions::CALLDATACOPY => {
|
instructions::CALLDATACOPY => {
|
||||||
@ -485,7 +485,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
},
|
},
|
||||||
instructions::EXTCODECOPY => {
|
instructions::EXTCODECOPY => {
|
||||||
let address = u256_to_address(&stack.pop_back());
|
let address = u256_to_address(&stack.pop_back());
|
||||||
let code = ext.extcode(&address);
|
let code = ext.extcode(&address)?;
|
||||||
self.copy_data_to_memory(stack, &code);
|
self.copy_data_to_memory(stack, &code);
|
||||||
},
|
},
|
||||||
instructions::GASPRICE => {
|
instructions::GASPRICE => {
|
||||||
|
@ -82,28 +82,29 @@ impl Default for Schedule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ext for FakeExt {
|
impl Ext for FakeExt {
|
||||||
fn storage_at(&self, key: &H256) -> H256 {
|
fn storage_at(&self, key: &H256) -> trie::Result<H256> {
|
||||||
self.store.get(key).unwrap_or(&H256::new()).clone()
|
Ok(self.store.get(key).unwrap_or(&H256::new()).clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_storage(&mut self, key: H256, value: H256) {
|
fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()> {
|
||||||
self.store.insert(key, value);
|
self.store.insert(key, value);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists(&self, address: &Address) -> bool {
|
fn exists(&self, address: &Address) -> trie::Result<bool> {
|
||||||
self.balances.contains_key(address)
|
Ok(self.balances.contains_key(address))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists_and_not_null(&self, address: &Address) -> bool {
|
fn exists_and_not_null(&self, address: &Address) -> trie::Result<bool> {
|
||||||
self.balances.get(address).map_or(false, |b| !b.is_zero())
|
Ok(self.balances.get(address).map_or(false, |b| !b.is_zero()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn origin_balance(&self) -> U256 {
|
fn origin_balance(&self) -> trie::Result<U256> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn balance(&self, address: &Address) -> U256 {
|
fn balance(&self, address: &Address) -> trie::Result<U256> {
|
||||||
self.balances[address]
|
Ok(self.balances[address])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blockhash(&self, number: &U256) -> H256 {
|
fn blockhash(&self, number: &U256) -> H256 {
|
||||||
@ -146,12 +147,12 @@ impl Ext for FakeExt {
|
|||||||
MessageCallResult::Success(*gas)
|
MessageCallResult::Success(*gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcode(&self, address: &Address) -> Arc<Bytes> {
|
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>> {
|
||||||
self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone()
|
Ok(self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcodesize(&self, address: &Address) -> usize {
|
fn extcodesize(&self, address: &Address) -> trie::Result<usize> {
|
||||||
self.codes.get(address).map_or(0, |c| c.len())
|
Ok(self.codes.get(address).map_or(0, |c| c.len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
|
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
|
||||||
@ -165,7 +166,7 @@ impl Ext for FakeExt {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suicide(&mut self, _refund_address: &Address) {
|
fn suicide(&mut self, _refund_address: &Address) -> trie::Result<()> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
mut vm_tracer: V
|
mut vm_tracer: V
|
||||||
) -> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer {
|
) -> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer {
|
||||||
let sender = t.sender();
|
let sender = t.sender();
|
||||||
let nonce = self.state.nonce(&sender);
|
let nonce = self.state.nonce(&sender)?;
|
||||||
|
|
||||||
let schedule = self.engine.schedule(self.info);
|
let schedule = self.engine.schedule(self.info);
|
||||||
let base_gas_required = U256::from(t.gas_required(&schedule));
|
let base_gas_required = U256::from(t.gas_required(&schedule));
|
||||||
@ -149,7 +149,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we might need bigints here, or at least check overflows.
|
// TODO: we might need bigints here, or at least check overflows.
|
||||||
let balance = self.state.balance(&sender);
|
let balance = self.state.balance(&sender)?;
|
||||||
let gas_cost = t.gas.full_mul(t.gas_price);
|
let gas_cost = t.gas.full_mul(t.gas_price);
|
||||||
let total_cost = U512::from(t.value) + gas_cost;
|
let total_cost = U512::from(t.value) + gas_cost;
|
||||||
|
|
||||||
@ -160,8 +160,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: there can be no invalid transactions from this point.
|
// NOTE: there can be no invalid transactions from this point.
|
||||||
self.state.inc_nonce(&sender);
|
self.state.inc_nonce(&sender)?;
|
||||||
self.state.sub_balance(&sender, &U256::from(gas_cost));
|
self.state.sub_balance(&sender, &U256::from(gas_cost))?;
|
||||||
|
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
|
|
||||||
@ -192,8 +192,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
gas: init_gas,
|
gas: init_gas,
|
||||||
gas_price: t.gas_price,
|
gas_price: t.gas_price,
|
||||||
value: ActionValue::Transfer(t.value),
|
value: ActionValue::Transfer(t.value),
|
||||||
code: self.state.code(address),
|
code: self.state.code(address)?,
|
||||||
code_hash: self.state.code_hash(address),
|
code_hash: self.state.code_hash(address)?,
|
||||||
data: Some(t.data.clone()),
|
data: Some(t.data.clone()),
|
||||||
call_type: CallType::Call,
|
call_type: CallType::Call,
|
||||||
};
|
};
|
||||||
@ -257,7 +257,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
|
|
||||||
// at first, transfer value to destination
|
// at first, transfer value to destination
|
||||||
if let ActionValue::Transfer(val) = params.value {
|
if let ActionValue::Transfer(val) = params.value {
|
||||||
self.state.transfer_balance(¶ms.sender, ¶ms.address, &val, substate.to_cleanup_mode(&schedule));
|
self.state.transfer_balance(¶ms.sender, ¶ms.address, &val, substate.to_cleanup_mode(&schedule))?;
|
||||||
}
|
}
|
||||||
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
|
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
|
||||||
|
|
||||||
@ -322,13 +322,13 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
|
|
||||||
let traces = subtracer.traces();
|
let traces = subtracer.traces();
|
||||||
match res {
|
match res {
|
||||||
Ok(gas_left) => tracer.trace_call(
|
Ok(ref gas_left) => tracer.trace_call(
|
||||||
trace_info,
|
trace_info,
|
||||||
gas - gas_left,
|
gas - *gas_left,
|
||||||
trace_output,
|
trace_output,
|
||||||
traces
|
traces
|
||||||
),
|
),
|
||||||
Err(e) => tracer.trace_failed_call(trace_info, traces, e.into()),
|
Err(ref e) => tracer.trace_failed_call(trace_info, traces, e.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
||||||
@ -365,9 +365,9 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
// create contract and transfer value to it if necessary
|
// create contract and transfer value to it if necessary
|
||||||
let schedule = self.engine.schedule(self.info);
|
let schedule = self.engine.schedule(self.info);
|
||||||
let nonce_offset = if schedule.no_empty {1} else {0}.into();
|
let nonce_offset = if schedule.no_empty {1} else {0}.into();
|
||||||
let prev_bal = self.state.balance(¶ms.address);
|
let prev_bal = self.state.balance(¶ms.address)?;
|
||||||
if let ActionValue::Transfer(val) = params.value {
|
if let ActionValue::Transfer(val) = params.value {
|
||||||
self.state.sub_balance(¶ms.sender, &val);
|
self.state.sub_balance(¶ms.sender, &val)?;
|
||||||
self.state.new_contract(¶ms.address, val + prev_bal, nonce_offset);
|
self.state.new_contract(¶ms.address, val + prev_bal, nonce_offset);
|
||||||
} else {
|
} else {
|
||||||
self.state.new_contract(¶ms.address, prev_bal, nonce_offset);
|
self.state.new_contract(¶ms.address, prev_bal, nonce_offset);
|
||||||
@ -388,14 +388,14 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
vm_tracer.done_subtrace(subvmtracer);
|
vm_tracer.done_subtrace(subvmtracer);
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(gas_left) => tracer.trace_create(
|
Ok(ref gas_left) => tracer.trace_create(
|
||||||
trace_info,
|
trace_info,
|
||||||
gas - gas_left,
|
gas - *gas_left,
|
||||||
trace_output,
|
trace_output,
|
||||||
created,
|
created,
|
||||||
subtracer.traces()
|
subtracer.traces()
|
||||||
),
|
),
|
||||||
Err(e) => tracer.trace_failed_create(trace_info, subtracer.traces(), e.into())
|
Err(ref e) => tracer.trace_failed_create(trace_info, subtracer.traces(), e.into())
|
||||||
};
|
};
|
||||||
|
|
||||||
self.enact_result(&res, substate, unconfirmed_substate);
|
self.enact_result(&res, substate, unconfirmed_substate);
|
||||||
@ -435,9 +435,9 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
let sender = t.sender();
|
let sender = t.sender();
|
||||||
trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, sender);
|
trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, sender);
|
||||||
// Below: NoEmpty is safe since the sender must already be non-null to have sent this transaction
|
// Below: NoEmpty is safe since the sender must already be non-null to have sent this transaction
|
||||||
self.state.add_balance(&sender, &refund_value, CleanupMode::NoEmpty);
|
self.state.add_balance(&sender, &refund_value, CleanupMode::NoEmpty)?;
|
||||||
trace!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author);
|
trace!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author);
|
||||||
self.state.add_balance(&self.info.author, &fees_value, substate.to_cleanup_mode(&schedule));
|
self.state.add_balance(&self.info.author, &fees_value, substate.to_cleanup_mode(&schedule))?;
|
||||||
|
|
||||||
// perform suicides
|
// perform suicides
|
||||||
for address in &substate.suicides {
|
for address in &substate.suicides {
|
||||||
@ -446,13 +446,13 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
|
|
||||||
// perform garbage-collection
|
// perform garbage-collection
|
||||||
for address in &substate.garbage {
|
for address in &substate.garbage {
|
||||||
if self.state.exists(address) && !self.state.exists_and_not_null(address) {
|
if self.state.exists(address)? && !self.state.exists_and_not_null(address)? {
|
||||||
self.state.kill_account(address);
|
self.state.kill_account(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Err(evm::Error::Internal) => Err(ExecutionError::Internal),
|
Err(evm::Error::Internal(msg)) => Err(ExecutionError::Internal(msg)),
|
||||||
Err(exception) => {
|
Err(exception) => {
|
||||||
Ok(Executed {
|
Ok(Executed {
|
||||||
exception: Some(exception),
|
exception: Some(exception),
|
||||||
@ -495,7 +495,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
| Err(evm::Error::OutOfStack {..}) => {
|
| Err(evm::Error::OutOfStack {..}) => {
|
||||||
self.state.revert_to_checkpoint();
|
self.state.revert_to_checkpoint();
|
||||||
},
|
},
|
||||||
Ok(_) | Err(evm::Error::Internal) => {
|
Ok(_) | Err(evm::Error::Internal(_)) => {
|
||||||
self.state.discard_checkpoint();
|
self.state.discard_checkpoint();
|
||||||
substate.accrue(un_substate);
|
substate.accrue(un_substate);
|
||||||
}
|
}
|
||||||
@ -544,7 +544,7 @@ mod tests {
|
|||||||
params.value = ActionValue::Transfer(U256::from(0x7));
|
params.value = ActionValue::Transfer(U256::from(0x7));
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty).unwrap();
|
||||||
let info = EnvInfo::default();
|
let info = EnvInfo::default();
|
||||||
let engine = TestEngine::new(0);
|
let engine = TestEngine::new(0);
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
@ -555,9 +555,9 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(79_975));
|
assert_eq!(gas_left, U256::from(79_975));
|
||||||
assert_eq!(state.storage_at(&address, &H256::new()), H256::from(&U256::from(0xf9u64)));
|
assert_eq!(state.storage_at(&address, &H256::new()).unwrap(), H256::from(&U256::from(0xf9u64)));
|
||||||
assert_eq!(state.balance(&sender), U256::from(0xf9));
|
assert_eq!(state.balance(&sender).unwrap(), U256::from(0xf9));
|
||||||
assert_eq!(state.balance(&address), U256::from(0x7));
|
assert_eq!(state.balance(&address).unwrap(), U256::from(0x7));
|
||||||
// 0 cause contract hasn't returned
|
// 0 cause contract hasn't returned
|
||||||
assert_eq!(substate.contracts_created.len(), 0);
|
assert_eq!(substate.contracts_created.len(), 0);
|
||||||
|
|
||||||
@ -603,7 +603,7 @@ mod tests {
|
|||||||
params.value = ActionValue::Transfer(U256::from(100));
|
params.value = ActionValue::Transfer(U256::from(100));
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
|
||||||
let info = EnvInfo::default();
|
let info = EnvInfo::default();
|
||||||
let engine = TestEngine::new(0);
|
let engine = TestEngine::new(0);
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
@ -662,7 +662,7 @@ mod tests {
|
|||||||
params.call_type = CallType::Call;
|
params.call_type = CallType::Call;
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
|
||||||
let info = EnvInfo::default();
|
let info = EnvInfo::default();
|
||||||
let engine = TestEngine::new(5);
|
let engine = TestEngine::new(5);
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
@ -773,7 +773,7 @@ mod tests {
|
|||||||
params.value = ActionValue::Transfer(100.into());
|
params.value = ActionValue::Transfer(100.into());
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
|
||||||
let info = EnvInfo::default();
|
let info = EnvInfo::default();
|
||||||
let engine = TestEngine::new(5);
|
let engine = TestEngine::new(5);
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
@ -861,7 +861,7 @@ mod tests {
|
|||||||
params.value = ActionValue::Transfer(U256::from(100));
|
params.value = ActionValue::Transfer(U256::from(100));
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
|
||||||
let info = EnvInfo::default();
|
let info = EnvInfo::default();
|
||||||
let engine = TestEngine::new(0);
|
let engine = TestEngine::new(0);
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
@ -913,7 +913,7 @@ mod tests {
|
|||||||
params.value = ActionValue::Transfer(U256::from(100));
|
params.value = ActionValue::Transfer(U256::from(100));
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
|
||||||
let info = EnvInfo::default();
|
let info = EnvInfo::default();
|
||||||
let engine = TestEngine::new(1024);
|
let engine = TestEngine::new(1024);
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
@ -971,9 +971,9 @@ mod tests {
|
|||||||
|
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.init_code(&address_a, code_a.clone());
|
state.init_code(&address_a, code_a.clone()).unwrap();
|
||||||
state.init_code(&address_b, code_b.clone());
|
state.init_code(&address_b, code_b.clone()).unwrap();
|
||||||
state.add_balance(&sender, &U256::from(100_000), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from(100_000), CleanupMode::NoEmpty).unwrap();
|
||||||
|
|
||||||
let info = EnvInfo::default();
|
let info = EnvInfo::default();
|
||||||
let engine = TestEngine::new(0);
|
let engine = TestEngine::new(0);
|
||||||
@ -985,7 +985,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(73_237));
|
assert_eq!(gas_left, U256::from(73_237));
|
||||||
assert_eq!(state.storage_at(&address_a, &H256::from(&U256::from(0x23))), H256::from(&U256::from(1)));
|
assert_eq!(state.storage_at(&address_a, &H256::from(&U256::from(0x23))).unwrap(), H256::from(&U256::from(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// test is incorrect, mk
|
// test is incorrect, mk
|
||||||
@ -1019,7 +1019,7 @@ mod tests {
|
|||||||
params.code = Some(Arc::new(code.clone()));
|
params.code = Some(Arc::new(code.clone()));
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.init_code(&address, code);
|
state.init_code(&address, code).unwrap();
|
||||||
let info = EnvInfo::default();
|
let info = EnvInfo::default();
|
||||||
let engine = TestEngine::new(0);
|
let engine = TestEngine::new(0);
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
@ -1030,8 +1030,8 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(59_870));
|
assert_eq!(gas_left, U256::from(59_870));
|
||||||
assert_eq!(state.storage_at(&address, &H256::from(&U256::zero())), H256::from(&U256::from(1)));
|
assert_eq!(state.storage_at(&address, &H256::from(&U256::zero())).unwrap(), H256::from(&U256::from(1)));
|
||||||
assert_eq!(state.storage_at(&address, &H256::from(&U256::one())), H256::from(&U256::from(1)));
|
assert_eq!(state.storage_at(&address, &H256::from(&U256::one())).unwrap(), H256::from(&U256::from(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// test is incorrect, mk
|
// test is incorrect, mk
|
||||||
@ -1052,7 +1052,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.add_balance(&sender, &U256::from(18), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from(18), CleanupMode::NoEmpty).unwrap();
|
||||||
let mut info = EnvInfo::default();
|
let mut info = EnvInfo::default();
|
||||||
info.gas_limit = U256::from(100_000);
|
info.gas_limit = U256::from(100_000);
|
||||||
let engine = TestEngine::new(0);
|
let engine = TestEngine::new(0);
|
||||||
@ -1069,10 +1069,10 @@ mod tests {
|
|||||||
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.contracts_created.len(), 0);
|
assert_eq!(executed.contracts_created.len(), 0);
|
||||||
assert_eq!(state.balance(&sender), U256::from(1));
|
assert_eq!(state.balance(&sender).unwrap(), U256::from(1));
|
||||||
assert_eq!(state.balance(&contract), U256::from(17));
|
assert_eq!(state.balance(&contract).unwrap(), U256::from(17));
|
||||||
assert_eq!(state.nonce(&sender), U256::from(1));
|
assert_eq!(state.nonce(&sender).unwrap(), U256::from(1));
|
||||||
assert_eq!(state.storage_at(&contract, &H256::new()), H256::from(&U256::from(1)));
|
assert_eq!(state.storage_at(&contract, &H256::new()).unwrap(), H256::from(&U256::from(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
evm_test!{test_transact_invalid_nonce: test_transact_invalid_nonce_jit, test_transact_invalid_nonce_int}
|
evm_test!{test_transact_invalid_nonce: test_transact_invalid_nonce_jit, test_transact_invalid_nonce_int}
|
||||||
@ -1090,7 +1090,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty).unwrap();
|
||||||
let mut info = EnvInfo::default();
|
let mut info = EnvInfo::default();
|
||||||
info.gas_limit = U256::from(100_000);
|
info.gas_limit = U256::from(100_000);
|
||||||
let engine = TestEngine::new(0);
|
let engine = TestEngine::new(0);
|
||||||
@ -1123,7 +1123,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty).unwrap();
|
||||||
let mut info = EnvInfo::default();
|
let mut info = EnvInfo::default();
|
||||||
info.gas_used = U256::from(20_000);
|
info.gas_used = U256::from(20_000);
|
||||||
info.gas_limit = U256::from(100_000);
|
info.gas_limit = U256::from(100_000);
|
||||||
@ -1158,7 +1158,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.add_balance(&sender, &U256::from(100_017), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from(100_017), CleanupMode::NoEmpty).unwrap();
|
||||||
let mut info = EnvInfo::default();
|
let mut info = EnvInfo::default();
|
||||||
info.gas_limit = U256::from(100_000);
|
info.gas_limit = U256::from(100_000);
|
||||||
let engine = TestEngine::new(0);
|
let engine = TestEngine::new(0);
|
||||||
@ -1193,7 +1193,7 @@ mod tests {
|
|||||||
params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap());
|
params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap());
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty).unwrap();
|
||||||
let info = EnvInfo::default();
|
let info = EnvInfo::default();
|
||||||
let engine = TestEngine::new(0);
|
let engine = TestEngine::new(0);
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
|
@ -108,25 +108,25 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B>
|
|||||||
impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
||||||
where T: Tracer, V: VMTracer, B: StateBackend
|
where T: Tracer, V: VMTracer, B: StateBackend
|
||||||
{
|
{
|
||||||
fn storage_at(&self, key: &H256) -> H256 {
|
fn storage_at(&self, key: &H256) -> trie::Result<H256> {
|
||||||
self.state.storage_at(&self.origin_info.address, key)
|
self.state.storage_at(&self.origin_info.address, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_storage(&mut self, key: H256, value: H256) {
|
fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()> {
|
||||||
self.state.set_storage(&self.origin_info.address, key, value)
|
self.state.set_storage(&self.origin_info.address, key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists(&self, address: &Address) -> bool {
|
fn exists(&self, address: &Address) -> trie::Result<bool> {
|
||||||
self.state.exists(address)
|
self.state.exists(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists_and_not_null(&self, address: &Address) -> bool {
|
fn exists_and_not_null(&self, address: &Address) -> trie::Result<bool> {
|
||||||
self.state.exists_and_not_null(address)
|
self.state.exists_and_not_null(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn origin_balance(&self) -> U256 { self.balance(&self.origin_info.address) }
|
fn origin_balance(&self) -> trie::Result<U256> { self.balance(&self.origin_info.address) }
|
||||||
|
|
||||||
fn balance(&self, address: &Address) -> U256 {
|
fn balance(&self, address: &Address) -> trie::Result<U256> {
|
||||||
self.state.balance(address)
|
self.state.balance(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +149,13 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
|||||||
|
|
||||||
fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult {
|
fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult {
|
||||||
// create new contract address
|
// create new contract address
|
||||||
let address = contract_address(&self.origin_info.address, &self.state.nonce(&self.origin_info.address));
|
let address = match self.state.nonce(&self.origin_info.address) {
|
||||||
|
Ok(nonce) => contract_address(&self.origin_info.address, &nonce),
|
||||||
|
Err(e) => {
|
||||||
|
debug!(target: "ext", "Database corruption encountered: {:?}", e);
|
||||||
|
return ContractCreateResult::Failed
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// prepare the params
|
// prepare the params
|
||||||
let params = ActionParams {
|
let params = ActionParams {
|
||||||
@ -166,7 +172,10 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
|||||||
call_type: CallType::None,
|
call_type: CallType::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.state.inc_nonce(&self.origin_info.address);
|
if let Err(e) = self.state.inc_nonce(&self.origin_info.address) {
|
||||||
|
debug!(target: "ext", "Database corruption encountered: {:?}", e);
|
||||||
|
return ContractCreateResult::Failed
|
||||||
|
}
|
||||||
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.vm_factory, self.depth);
|
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.vm_factory, self.depth);
|
||||||
|
|
||||||
// TODO: handle internal error separately
|
// TODO: handle internal error separately
|
||||||
@ -191,6 +200,14 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
|||||||
) -> MessageCallResult {
|
) -> MessageCallResult {
|
||||||
trace!(target: "externalities", "call");
|
trace!(target: "externalities", "call");
|
||||||
|
|
||||||
|
let code_res = self.state.code(code_address)
|
||||||
|
.and_then(|code| self.state.code_hash(code_address).map(|hash| (code, hash)));
|
||||||
|
|
||||||
|
let (code, code_hash) = match code_res {
|
||||||
|
Ok((code, hash)) => (code, hash),
|
||||||
|
Err(_) => return MessageCallResult::Failed,
|
||||||
|
};
|
||||||
|
|
||||||
let mut params = ActionParams {
|
let mut params = ActionParams {
|
||||||
sender: sender_address.clone(),
|
sender: sender_address.clone(),
|
||||||
address: receive_address.clone(),
|
address: receive_address.clone(),
|
||||||
@ -199,8 +216,8 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
|||||||
origin: self.origin_info.origin.clone(),
|
origin: self.origin_info.origin.clone(),
|
||||||
gas: *gas,
|
gas: *gas,
|
||||||
gas_price: self.origin_info.gas_price,
|
gas_price: self.origin_info.gas_price,
|
||||||
code: self.state.code(code_address),
|
code: code,
|
||||||
code_hash: self.state.code_hash(code_address),
|
code_hash: code_hash,
|
||||||
data: Some(data.to_vec()),
|
data: Some(data.to_vec()),
|
||||||
call_type: call_type,
|
call_type: call_type,
|
||||||
};
|
};
|
||||||
@ -217,12 +234,12 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcode(&self, address: &Address) -> Arc<Bytes> {
|
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>> {
|
||||||
self.state.code(address).unwrap_or_else(|| Arc::new(vec![]))
|
Ok(self.state.code(address)?.unwrap_or_else(|| Arc::new(vec![])))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcodesize(&self, address: &Address) -> usize {
|
fn extcodesize(&self, address: &Address) -> trie::Result<usize> {
|
||||||
self.state.code_size(address).unwrap_or(0)
|
Ok(self.state.code_size(address)?.unwrap_or(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature="dev", allow(match_ref_pats))]
|
#[cfg_attr(feature="dev", allow(match_ref_pats))]
|
||||||
@ -257,10 +274,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
|||||||
|
|
||||||
handle_copy(copy);
|
handle_copy(copy);
|
||||||
|
|
||||||
let mut code = vec![];
|
self.state.init_code(&self.origin_info.address, data.to_vec())?;
|
||||||
code.extend_from_slice(data);
|
|
||||||
|
|
||||||
self.state.init_code(&self.origin_info.address, code);
|
|
||||||
Ok(*gas - return_cost)
|
Ok(*gas - return_cost)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,19 +291,26 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suicide(&mut self, refund_address: &Address) {
|
fn suicide(&mut self, refund_address: &Address) -> trie::Result<()> {
|
||||||
let address = self.origin_info.address.clone();
|
let address = self.origin_info.address.clone();
|
||||||
let balance = self.balance(&address);
|
let balance = self.balance(&address)?;
|
||||||
if &address == refund_address {
|
if &address == refund_address {
|
||||||
// TODO [todr] To be consistent with CPP client we set balance to 0 in that case.
|
// TODO [todr] To be consistent with CPP client we set balance to 0 in that case.
|
||||||
self.state.sub_balance(&address, &balance);
|
self.state.sub_balance(&address, &balance)?;
|
||||||
} else {
|
} else {
|
||||||
trace!(target: "ext", "Suiciding {} -> {} (xfer: {})", address, refund_address, balance);
|
trace!(target: "ext", "Suiciding {} -> {} (xfer: {})", address, refund_address, balance);
|
||||||
self.state.transfer_balance(&address, refund_address, &balance, self.substate.to_cleanup_mode(&self.schedule));
|
self.state.transfer_balance(
|
||||||
|
&address,
|
||||||
|
refund_address,
|
||||||
|
&balance,
|
||||||
|
self.substate.to_cleanup_mode(&self.schedule)
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tracer.trace_suicide(address, balance, refund_address.clone());
|
self.tracer.trace_suicide(address, balance, refund_address.clone());
|
||||||
self.substate.suicides.insert(address);
|
self.substate.suicides.insert(address);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schedule(&self) -> &Schedule {
|
fn schedule(&self) -> &Schedule {
|
||||||
@ -485,7 +506,7 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let vm_factory = Default::default();
|
let vm_factory = Default::default();
|
||||||
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||||
ext.suicide(refund_account);
|
ext.suicide(refund_account).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(setup.sub_state.suicides.len(), 1);
|
assert_eq!(setup.sub_state.suicides.len(), 1);
|
||||||
|
@ -74,39 +74,39 @@ impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B>
|
|||||||
address: Address,
|
address: Address,
|
||||||
tracer: &'a mut T,
|
tracer: &'a mut T,
|
||||||
vm_tracer: &'a mut V,
|
vm_tracer: &'a mut V,
|
||||||
) -> Self {
|
) -> trie::Result<Self> {
|
||||||
TestExt {
|
Ok(TestExt {
|
||||||
contract_address: contract_address(&address, &state.nonce(&address)),
|
contract_address: contract_address(&address, &state.nonce(&address)?),
|
||||||
ext: Externalities::new(state, info, engine, vm_factory, depth, origin_info, substate, output, tracer, vm_tracer),
|
ext: Externalities::new(state, info, engine, vm_factory, depth, origin_info, substate, output, tracer, vm_tracer),
|
||||||
callcreates: vec![]
|
callcreates: vec![]
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
|
impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
|
||||||
where T: Tracer, V: VMTracer, B: StateBackend
|
where T: Tracer, V: VMTracer, B: StateBackend
|
||||||
{
|
{
|
||||||
fn storage_at(&self, key: &H256) -> H256 {
|
fn storage_at(&self, key: &H256) -> trie::Result<H256> {
|
||||||
self.ext.storage_at(key)
|
self.ext.storage_at(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_storage(&mut self, key: H256, value: H256) {
|
fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()> {
|
||||||
self.ext.set_storage(key, value)
|
self.ext.set_storage(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists(&self, address: &Address) -> bool {
|
fn exists(&self, address: &Address) -> trie::Result<bool> {
|
||||||
self.ext.exists(address)
|
self.ext.exists(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists_and_not_null(&self, address: &Address) -> bool {
|
fn exists_and_not_null(&self, address: &Address) -> trie::Result<bool> {
|
||||||
self.ext.exists_and_not_null(address)
|
self.ext.exists_and_not_null(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn balance(&self, address: &Address) -> U256 {
|
fn balance(&self, address: &Address) -> trie::Result<U256> {
|
||||||
self.ext.balance(address)
|
self.ext.balance(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn origin_balance(&self) -> U256 {
|
fn origin_balance(&self) -> trie::Result<U256> {
|
||||||
self.ext.origin_balance()
|
self.ext.origin_balance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,11 +143,11 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
|
|||||||
MessageCallResult::Success(*gas)
|
MessageCallResult::Success(*gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcode(&self, address: &Address) -> Arc<Bytes> {
|
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>> {
|
||||||
self.ext.extcode(address)
|
self.ext.extcode(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcodesize(&self, address: &Address) -> usize {
|
fn extcodesize(&self, address: &Address) -> trie::Result<usize> {
|
||||||
self.ext.extcodesize(address)
|
self.ext.extcodesize(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
|
|||||||
self.ext.ret(gas, data)
|
self.ext.ret(gas, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suicide(&mut self, refund_address: &Address) {
|
fn suicide(&mut self, refund_address: &Address) -> trie::Result<()> {
|
||||||
self.ext.suicide(refund_address)
|
self.ext.suicide(refund_address)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,6 +201,19 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
|
|||||||
fail = true
|
fail = true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
macro_rules! try_fail {
|
||||||
|
($e: expr) => {
|
||||||
|
match $e {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
let msg = format!("Internal error: {}", e);
|
||||||
|
fail_unless(false, &msg);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let out_of_gas = vm.out_of_gas();
|
let out_of_gas = vm.out_of_gas();
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
@ -217,7 +230,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
|
|||||||
|
|
||||||
// execute
|
// execute
|
||||||
let (res, callcreates) = {
|
let (res, callcreates) = {
|
||||||
let mut ex = TestExt::new(
|
let mut ex = try_fail!(TestExt::new(
|
||||||
&mut state,
|
&mut state,
|
||||||
&info,
|
&info,
|
||||||
&engine,
|
&engine,
|
||||||
@ -229,7 +242,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
|
|||||||
params.address.clone(),
|
params.address.clone(),
|
||||||
&mut tracer,
|
&mut tracer,
|
||||||
&mut vm_tracer,
|
&mut vm_tracer,
|
||||||
);
|
));
|
||||||
let mut evm = vm_factory.create(params.gas);
|
let mut evm = vm_factory.create(params.gas);
|
||||||
let res = evm.exec(params, &mut ex);
|
let res = evm.exec(params, &mut ex);
|
||||||
// a return in finalize will not alter callcreates
|
// a return in finalize will not alter callcreates
|
||||||
@ -248,14 +261,19 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
|
|||||||
for (address, account) in vm.post_state.unwrap().into_iter() {
|
for (address, account) in vm.post_state.unwrap().into_iter() {
|
||||||
let address = address.into();
|
let address = address.into();
|
||||||
let code: Vec<u8> = account.code.into();
|
let code: Vec<u8> = account.code.into();
|
||||||
fail_unless(state.code(&address).as_ref().map_or_else(|| code.is_empty(), |c| &**c == &code), "code is incorrect");
|
let found_code = try_fail!(state.code(&address));
|
||||||
fail_unless(state.balance(&address) == account.balance.into(), "balance is incorrect");
|
let found_balance = try_fail!(state.balance(&address));
|
||||||
fail_unless(state.nonce(&address) == account.nonce.into(), "nonce is incorrect");
|
let found_nonce = try_fail!(state.nonce(&address));
|
||||||
account.storage.into_iter().foreach(|(k, v)| {
|
|
||||||
|
fail_unless(found_code.as_ref().map_or_else(|| code.is_empty(), |c| &**c == &code), "code is incorrect");
|
||||||
|
fail_unless(found_balance == account.balance.into(), "balance is incorrect");
|
||||||
|
fail_unless(found_nonce == account.nonce.into(), "nonce is incorrect");
|
||||||
|
for (k, v) in account.storage {
|
||||||
let key: U256 = k.into();
|
let key: U256 = k.into();
|
||||||
let value: U256 = v.into();
|
let value: U256 = v.into();
|
||||||
fail_unless(state.storage_at(&address, &From::from(key)) == From::from(value), "storage is incorrect");
|
let found_storage = try_fail!(state.storage_at(&address, &From::from(key)));
|
||||||
});
|
fail_unless(found_storage == From::from(value), "storage is incorrect");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let calls: Option<Vec<CallCreate>> = vm.calls.map(|c| c.into_iter().map(From::from).collect());
|
let calls: Option<Vec<CallCreate>> = vm.calls.map(|c| c.into_iter().map(From::from).collect());
|
||||||
|
@ -711,17 +711,20 @@ impl MinerService for Miner {
|
|||||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||||
|
|
||||||
let sender = t.sender();
|
let sender = t.sender();
|
||||||
let balance = state.balance(&sender);
|
let balance = state.balance(&sender).map_err(ExecutionError::from)?;
|
||||||
let needed_balance = t.value + t.gas * t.gas_price;
|
let needed_balance = t.value + t.gas * t.gas_price;
|
||||||
if balance < needed_balance {
|
if balance < needed_balance {
|
||||||
// give the sender a sufficient balance
|
// give the sender a sufficient balance
|
||||||
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty)
|
||||||
|
.map_err(ExecutionError::from)?;
|
||||||
}
|
}
|
||||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, client.vm_factory()).transact(t, options)?;
|
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, client.vm_factory()).transact(t, options)?;
|
||||||
|
|
||||||
// TODO gav move this into Executive.
|
// TODO gav move this into Executive.
|
||||||
ret.state_diff = original_state.map(|original| state.diff_from(original));
|
if let Some(original) = original_state {
|
||||||
|
ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
},
|
},
|
||||||
@ -729,35 +732,37 @@ impl MinerService for Miner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> U256 {
|
// TODO: The `chain.latest_x` actually aren't infallible, they just panic on corruption.
|
||||||
|
// TODO: return trie::Result<T> here, or other.
|
||||||
|
fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<U256> {
|
||||||
self.from_pending_block(
|
self.from_pending_block(
|
||||||
chain.chain_info().best_block_number,
|
chain.chain_info().best_block_number,
|
||||||
|| chain.latest_balance(address),
|
|| Some(chain.latest_balance(address)),
|
||||||
|b| b.block().fields().state.balance(address)
|
|b| b.block().fields().state.balance(address).ok(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256 {
|
fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> Option<H256> {
|
||||||
self.from_pending_block(
|
self.from_pending_block(
|
||||||
chain.chain_info().best_block_number,
|
chain.chain_info().best_block_number,
|
||||||
|| chain.latest_storage_at(address, position),
|
|| Some(chain.latest_storage_at(address, position)),
|
||||||
|b| b.block().fields().state.storage_at(address, position)
|
|b| b.block().fields().state.storage_at(address, position).ok(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> U256 {
|
fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<U256> {
|
||||||
self.from_pending_block(
|
self.from_pending_block(
|
||||||
chain.chain_info().best_block_number,
|
chain.chain_info().best_block_number,
|
||||||
|| chain.latest_nonce(address),
|
|| Some(chain.latest_nonce(address)),
|
||||||
|b| b.block().fields().state.nonce(address)
|
|b| b.block().fields().state.nonce(address).ok(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> {
|
fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<Option<Bytes>> {
|
||||||
self.from_pending_block(
|
self.from_pending_block(
|
||||||
chain.chain_info().best_block_number,
|
chain.chain_info().best_block_number,
|
||||||
|| chain.latest_code(address),
|
|| Some(chain.latest_code(address)),
|
||||||
|b| b.block().fields().state.code(address).map(|c| (*c).clone())
|
|b| b.block().fields().state.code(address).ok().map(|c| c.map(|c| (&*c).clone()))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,19 +181,19 @@ pub trait MinerService : Send + Sync {
|
|||||||
fn sensible_gas_limit(&self) -> U256 { 21000.into() }
|
fn sensible_gas_limit(&self) -> U256 { 21000.into() }
|
||||||
|
|
||||||
/// Latest account balance in pending state.
|
/// Latest account balance in pending state.
|
||||||
fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> U256;
|
fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<U256>;
|
||||||
|
|
||||||
/// Call into contract code using pending state.
|
/// Call into contract code using pending state.
|
||||||
fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
||||||
|
|
||||||
/// Get storage value in pending state.
|
/// Get storage value in pending state.
|
||||||
fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256;
|
fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> Option<H256>;
|
||||||
|
|
||||||
/// Get account nonce in pending state.
|
/// Get account nonce in pending state.
|
||||||
fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> U256;
|
fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<U256>;
|
||||||
|
|
||||||
/// Get contract code in pending state.
|
/// Get contract code in pending state.
|
||||||
fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes>;
|
fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option<Option<Bytes>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mining status
|
/// Mining status
|
||||||
|
@ -389,6 +389,6 @@ mod tests {
|
|||||||
let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
|
let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
|
||||||
let state = State::from_existing(db.boxed_clone(), spec.state_root(), spec.engine.account_start_nonce(), Default::default()).unwrap();
|
let state = State::from_existing(db.boxed_clone(), spec.state_root(), spec.engine.account_start_nonce(), Default::default()).unwrap();
|
||||||
let expected = H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
|
let expected = H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
|
||||||
assert_eq!(state.storage_at(&Address::from_str("0000000000000000000000000000000000000005").unwrap(), &H256::zero()), expected);
|
assert_eq!(state.storage_at(&Address::from_str("0000000000000000000000000000000000000005").unwrap(), &H256::zero()).unwrap(), expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,22 +169,16 @@ impl Account {
|
|||||||
|
|
||||||
/// Get (and cache) the contents of the trie's storage at `key`.
|
/// Get (and cache) the contents of the trie's storage at `key`.
|
||||||
/// Takes modifed storage into account.
|
/// Takes modifed storage into account.
|
||||||
pub fn storage_at(&self, db: &HashDB, key: &H256) -> H256 {
|
pub fn storage_at(&self, db: &HashDB, key: &H256) -> trie::Result<H256> {
|
||||||
if let Some(value) = self.cached_storage_at(key) {
|
if let Some(value) = self.cached_storage_at(key) {
|
||||||
return value;
|
return Ok(value);
|
||||||
}
|
}
|
||||||
let db = SecTrieDB::new(db, &self.storage_root)
|
let db = SecTrieDB::new(db, &self.storage_root)?;
|
||||||
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
|
|
||||||
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
|
|
||||||
using it will not fail.");
|
|
||||||
|
|
||||||
let item: U256 = match db.get_with(key, ::rlp::decode) {
|
let item: U256 = db.get_with(key, ::rlp::decode)?.unwrap_or_else(U256::zero);
|
||||||
Ok(x) => x.unwrap_or_else(U256::zero),
|
|
||||||
Err(e) => panic!("Encountered potential DB corruption: {}", e),
|
|
||||||
};
|
|
||||||
let value: H256 = item.into();
|
let value: H256 = item.into();
|
||||||
self.storage_cache.borrow_mut().insert(key.clone(), value.clone());
|
self.storage_cache.borrow_mut().insert(key.clone(), value.clone());
|
||||||
value
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get cached storage value if any. Returns `None` if the
|
/// Get cached storage value if any. Returns `None` if the
|
||||||
@ -345,24 +339,19 @@ impl Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Commit the `storage_changes` to the backing DB and update `storage_root`.
|
/// Commit the `storage_changes` to the backing DB and update `storage_root`.
|
||||||
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut HashDB) {
|
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut HashDB) -> trie::Result<()> {
|
||||||
let mut t = trie_factory.from_existing(db, &mut self.storage_root)
|
let mut t = trie_factory.from_existing(db, &mut self.storage_root)?;
|
||||||
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
|
|
||||||
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
|
|
||||||
using it will not fail.");
|
|
||||||
for (k, v) in self.storage_changes.drain() {
|
for (k, v) in self.storage_changes.drain() {
|
||||||
// cast key and value to trait type,
|
// cast key and value to trait type,
|
||||||
// so we can call overloaded `to_bytes` method
|
// so we can call overloaded `to_bytes` method
|
||||||
let res = match v.is_zero() {
|
match v.is_zero() {
|
||||||
true => t.remove(&k),
|
true => t.remove(&k)?,
|
||||||
false => t.insert(&k, &encode(&U256::from(&*v))),
|
false => t.insert(&k, &encode(&U256::from(&*v)))?,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = res {
|
|
||||||
warn!("Encountered potential DB corruption: {}", e);
|
|
||||||
}
|
|
||||||
self.storage_cache.borrow_mut().insert(k, v);
|
self.storage_cache.borrow_mut().insert(k, v);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
|
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
|
||||||
@ -494,7 +483,7 @@ mod tests {
|
|||||||
let rlp = {
|
let rlp = {
|
||||||
let mut a = Account::new_contract(69.into(), 0.into());
|
let mut a = Account::new_contract(69.into(), 0.into());
|
||||||
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
|
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
|
||||||
a.commit_storage(&Default::default(), &mut db);
|
a.commit_storage(&Default::default(), &mut db).unwrap();
|
||||||
a.init_code(vec![]);
|
a.init_code(vec![]);
|
||||||
a.commit_code(&mut db);
|
a.commit_code(&mut db);
|
||||||
a.rlp()
|
a.rlp()
|
||||||
@ -502,8 +491,8 @@ mod tests {
|
|||||||
|
|
||||||
let a = Account::from_rlp(&rlp);
|
let a = Account::from_rlp(&rlp);
|
||||||
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
|
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
|
||||||
assert_eq!(a.storage_at(&db.immutable(), &H256::from(&U256::from(0x00u64))), H256::from(&U256::from(0x1234u64)));
|
assert_eq!(a.storage_at(&db.immutable(), &H256::from(&U256::from(0x00u64))).unwrap(), H256::from(&U256::from(0x1234u64)));
|
||||||
assert_eq!(a.storage_at(&db.immutable(), &H256::from(&U256::from(0x01u64))), H256::new());
|
assert_eq!(a.storage_at(&db.immutable(), &H256::from(&U256::from(0x01u64))).unwrap(), H256::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -532,7 +521,7 @@ mod tests {
|
|||||||
let mut db = AccountDBMut::new(&mut db, &Address::new());
|
let mut db = AccountDBMut::new(&mut db, &Address::new());
|
||||||
a.set_storage(0.into(), 0x1234.into());
|
a.set_storage(0.into(), 0x1234.into());
|
||||||
assert_eq!(a.storage_root(), None);
|
assert_eq!(a.storage_root(), None);
|
||||||
a.commit_storage(&Default::default(), &mut db);
|
a.commit_storage(&Default::default(), &mut db).unwrap();
|
||||||
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
|
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,11 +531,11 @@ mod tests {
|
|||||||
let mut db = MemoryDB::new();
|
let mut db = MemoryDB::new();
|
||||||
let mut db = AccountDBMut::new(&mut db, &Address::new());
|
let mut db = AccountDBMut::new(&mut db, &Address::new());
|
||||||
a.set_storage(0.into(), 0x1234.into());
|
a.set_storage(0.into(), 0x1234.into());
|
||||||
a.commit_storage(&Default::default(), &mut db);
|
a.commit_storage(&Default::default(), &mut db).unwrap();
|
||||||
a.set_storage(1.into(), 0x1234.into());
|
a.set_storage(1.into(), 0x1234.into());
|
||||||
a.commit_storage(&Default::default(), &mut db);
|
a.commit_storage(&Default::default(), &mut db).unwrap();
|
||||||
a.set_storage(1.into(), 0.into());
|
a.set_storage(1.into(), 0.into());
|
||||||
a.commit_storage(&Default::default(), &mut db);
|
a.commit_storage(&Default::default(), &mut db).unwrap();
|
||||||
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
|
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ use state_db::StateDB;
|
|||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
|
|
||||||
|
use util::trie;
|
||||||
use util::trie::recorder::Recorder;
|
use util::trie::recorder::Recorder;
|
||||||
|
|
||||||
mod account;
|
mod account;
|
||||||
@ -362,37 +363,37 @@ impl<B: Backend> State<B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether an account exists.
|
/// Determine whether an account exists.
|
||||||
pub fn exists(&self, a: &Address) -> bool {
|
pub fn exists(&self, a: &Address) -> trie::Result<bool> {
|
||||||
// Bloom filter does not contain empty accounts, so it is important here to
|
// Bloom filter does not contain empty accounts, so it is important here to
|
||||||
// check if account exists in the database directly before EIP-161 is in effect.
|
// check if account exists in the database directly before EIP-161 is in effect.
|
||||||
self.ensure_cached(a, RequireCache::None, false, |a| a.is_some())
|
self.ensure_cached(a, RequireCache::None, false, |a| a.is_some())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether an account exists and if not empty.
|
/// Determine whether an account exists and if not empty.
|
||||||
pub fn exists_and_not_null(&self, a: &Address) -> bool {
|
pub fn exists_and_not_null(&self, a: &Address) -> trie::Result<bool> {
|
||||||
self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null()))
|
self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the balance of account `a`.
|
/// Get the balance of account `a`.
|
||||||
pub fn balance(&self, a: &Address) -> U256 {
|
pub fn balance(&self, a: &Address) -> trie::Result<U256> {
|
||||||
self.ensure_cached(a, RequireCache::None, true,
|
self.ensure_cached(a, RequireCache::None, true,
|
||||||
|a| a.as_ref().map_or(U256::zero(), |account| *account.balance()))
|
|a| a.as_ref().map_or(U256::zero(), |account| *account.balance()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the nonce of account `a`.
|
/// Get the nonce of account `a`.
|
||||||
pub fn nonce(&self, a: &Address) -> U256 {
|
pub fn nonce(&self, a: &Address) -> trie::Result<U256> {
|
||||||
self.ensure_cached(a, RequireCache::None, true,
|
self.ensure_cached(a, RequireCache::None, true,
|
||||||
|a| a.as_ref().map_or(self.account_start_nonce, |account| *account.nonce()))
|
|a| a.as_ref().map_or(self.account_start_nonce, |account| *account.nonce()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the storage root of account `a`.
|
/// Get the storage root of account `a`.
|
||||||
pub fn storage_root(&self, a: &Address) -> Option<H256> {
|
pub fn storage_root(&self, a: &Address) -> trie::Result<Option<H256>> {
|
||||||
self.ensure_cached(a, RequireCache::None, true,
|
self.ensure_cached(a, RequireCache::None, true,
|
||||||
|a| a.as_ref().and_then(|account| account.storage_root().cloned()))
|
|a| a.as_ref().and_then(|account| account.storage_root().cloned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutate storage of account `address` so that it is `value` for `key`.
|
/// Mutate storage of account `address` so that it is `value` for `key`.
|
||||||
pub fn storage_at(&self, address: &Address, key: &H256) -> H256 {
|
pub fn storage_at(&self, address: &Address, key: &H256) -> trie::Result<H256> {
|
||||||
// Storage key search and update works like this:
|
// Storage key search and update works like this:
|
||||||
// 1. If there's an entry for the account in the local cache check for the key and return it if found.
|
// 1. If there's an entry for the account in the local cache check for the key and return it if found.
|
||||||
// 2. If there's an entry for the account in the global cache check for the key or load it into that account.
|
// 2. If there's an entry for the account in the global cache check for the key or load it into that account.
|
||||||
@ -406,42 +407,46 @@ impl<B: Backend> State<B> {
|
|||||||
match maybe_acc.account {
|
match maybe_acc.account {
|
||||||
Some(ref account) => {
|
Some(ref account) => {
|
||||||
if let Some(value) = account.cached_storage_at(key) {
|
if let Some(value) = account.cached_storage_at(key) {
|
||||||
return value;
|
return Ok(value);
|
||||||
} else {
|
} else {
|
||||||
local_account = Some(maybe_acc);
|
local_account = Some(maybe_acc);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => return H256::new(),
|
_ => return Ok(H256::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check the global cache and and cache storage key there if found,
|
// check the global cache and and cache storage key there if found,
|
||||||
// otherwise cache the account localy and cache storage key there.
|
let trie_res = self.db.get_cached(address, |acc| match acc {
|
||||||
if let Some(result) = self.db.get_cached(address, |acc| acc.map_or(H256::new(), |a| {
|
None => Ok(H256::new()),
|
||||||
|
Some(a) => {
|
||||||
let account_db = self.factories.accountdb.readonly(self.db.as_hashdb(), a.address_hash(address));
|
let account_db = self.factories.accountdb.readonly(self.db.as_hashdb(), a.address_hash(address));
|
||||||
a.storage_at(account_db.as_hashdb(), key)
|
a.storage_at(account_db.as_hashdb(), key)
|
||||||
})) {
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
match trie_res {
|
||||||
|
None => {}
|
||||||
|
Some(res) => return res,
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise cache the account localy and cache storage key there.
|
||||||
if let Some(ref mut acc) = local_account {
|
if let Some(ref mut acc) = local_account {
|
||||||
if let Some(ref account) = acc.account {
|
if let Some(ref account) = acc.account {
|
||||||
let account_db = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(address));
|
let account_db = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(address));
|
||||||
return account.storage_at(account_db.as_hashdb(), key)
|
return account.storage_at(account_db.as_hashdb(), key)
|
||||||
} else {
|
} else {
|
||||||
return H256::new()
|
return Ok(H256::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the account could exist before any requests to trie
|
// check if the account could exist before any requests to trie
|
||||||
if self.db.is_known_null(address) { return H256::zero() }
|
if self.db.is_known_null(address) { return Ok(H256::zero()) }
|
||||||
|
|
||||||
// account is not found in the global cache, get from the DB and insert into local
|
// account is not found in the global cache, get from the DB and insert into local
|
||||||
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||||
let maybe_acc = match db.get_with(address, Account::from_rlp) {
|
let maybe_acc = db.get_with(address, Account::from_rlp)?;
|
||||||
Ok(acc) => acc,
|
let r = maybe_acc.as_ref().map_or(Ok(H256::new()), |a| {
|
||||||
Err(e) => panic!("Potential DB corruption encountered: {}", e),
|
|
||||||
};
|
|
||||||
let r = maybe_acc.as_ref().map_or(H256::new(), |a| {
|
|
||||||
let account_db = self.factories.accountdb.readonly(self.db.as_hashdb(), a.address_hash(address));
|
let account_db = self.factories.accountdb.readonly(self.db.as_hashdb(), a.address_hash(address));
|
||||||
a.storage_at(account_db.as_hashdb(), key)
|
a.storage_at(account_db.as_hashdb(), key)
|
||||||
});
|
});
|
||||||
@ -450,75 +455,84 @@ impl<B: Backend> State<B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get accounts' code.
|
/// Get accounts' code.
|
||||||
pub fn code(&self, a: &Address) -> Option<Arc<Bytes>> {
|
pub fn code(&self, a: &Address) -> trie::Result<Option<Arc<Bytes>>> {
|
||||||
self.ensure_cached(a, RequireCache::Code, true,
|
self.ensure_cached(a, RequireCache::Code, true,
|
||||||
|a| a.as_ref().map_or(None, |a| a.code().clone()))
|
|a| a.as_ref().map_or(None, |a| a.code().clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an account's code hash.
|
/// Get an account's code hash.
|
||||||
pub fn code_hash(&self, a: &Address) -> H256 {
|
pub fn code_hash(&self, a: &Address) -> trie::Result<H256> {
|
||||||
self.ensure_cached(a, RequireCache::None, true,
|
self.ensure_cached(a, RequireCache::None, true,
|
||||||
|a| a.as_ref().map_or(SHA3_EMPTY, |a| a.code_hash()))
|
|a| a.as_ref().map_or(SHA3_EMPTY, |a| a.code_hash()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get accounts' code size.
|
/// Get accounts' code size.
|
||||||
pub fn code_size(&self, a: &Address) -> Option<usize> {
|
pub fn code_size(&self, a: &Address) -> trie::Result<Option<usize>> {
|
||||||
self.ensure_cached(a, RequireCache::CodeSize, true,
|
self.ensure_cached(a, RequireCache::CodeSize, true,
|
||||||
|a| a.as_ref().and_then(|a| a.code_size()))
|
|a| a.as_ref().and_then(|a| a.code_size()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add `incr` to the balance of account `a`.
|
/// Add `incr` to the balance of account `a`.
|
||||||
#[cfg_attr(feature="dev", allow(single_match))]
|
#[cfg_attr(feature="dev", allow(single_match))]
|
||||||
pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) {
|
pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) -> trie::Result<()> {
|
||||||
trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a));
|
trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a)?);
|
||||||
let is_value_transfer = !incr.is_zero();
|
let is_value_transfer = !incr.is_zero();
|
||||||
if is_value_transfer || (cleanup_mode == CleanupMode::ForceCreate && !self.exists(a)) {
|
if is_value_transfer || (cleanup_mode == CleanupMode::ForceCreate && !self.exists(a)?) {
|
||||||
self.require(a, false).add_balance(incr);
|
self.require(a, false)?.add_balance(incr);
|
||||||
} else {
|
} else {
|
||||||
match cleanup_mode {
|
match cleanup_mode {
|
||||||
CleanupMode::KillEmpty(set) => if !is_value_transfer && self.exists(a) && !self.exists_and_not_null(a) {
|
CleanupMode::KillEmpty(set) => if !is_value_transfer && self.exists(a)? && !self.exists_and_not_null(a)? {
|
||||||
set.insert(a.clone());
|
set.insert(a.clone());
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Subtract `decr` from the balance of account `a`.
|
/// Subtract `decr` from the balance of account `a`.
|
||||||
pub fn sub_balance(&mut self, a: &Address, decr: &U256) {
|
pub fn sub_balance(&mut self, a: &Address, decr: &U256) -> trie::Result<()> {
|
||||||
trace!(target: "state", "sub_balance({}, {}): {}", a, decr, self.balance(a));
|
trace!(target: "state", "sub_balance({}, {}): {}", a, decr, self.balance(a)?);
|
||||||
if !decr.is_zero() || !self.exists(a) {
|
if !decr.is_zero() || !self.exists(a)? {
|
||||||
self.require(a, false).sub_balance(decr);
|
self.require(a, false)?.sub_balance(decr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Subtracts `by` from the balance of `from` and adds it to that of `to`.
|
/// 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, cleanup_mode: CleanupMode) {
|
pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256, cleanup_mode: CleanupMode) -> trie::Result<()> {
|
||||||
self.sub_balance(from, by);
|
self.sub_balance(from, by)?;
|
||||||
self.add_balance(to, by, cleanup_mode);
|
self.add_balance(to, by, cleanup_mode)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increment the nonce of account `a` by 1.
|
/// Increment the nonce of account `a` by 1.
|
||||||
pub fn inc_nonce(&mut self, a: &Address) {
|
pub fn inc_nonce(&mut self, a: &Address) -> trie::Result<()> {
|
||||||
self.require(a, false).inc_nonce()
|
self.require(a, false).map(|mut x| x.inc_nonce())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutate storage of account `a` so that it is `value` for `key`.
|
/// Mutate storage of account `a` so that it is `value` for `key`.
|
||||||
pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) {
|
pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) -> trie::Result<()> {
|
||||||
if self.storage_at(a, &key) != value {
|
if self.storage_at(a, &key)? != value {
|
||||||
self.require(a, false).set_storage(key, value)
|
self.require(a, false)?.set_storage(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialise the code of account `a` so that it is `code`.
|
/// Initialise the code of account `a` so that it is `code`.
|
||||||
/// NOTE: Account should have been created with `new_contract`.
|
/// NOTE: Account should have been created with `new_contract`.
|
||||||
pub fn init_code(&mut self, a: &Address, code: Bytes) {
|
pub fn init_code(&mut self, a: &Address, code: Bytes) -> trie::Result<()> {
|
||||||
self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{}).init_code(code);
|
self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{})?.init_code(code);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the code of account `a` so that it is `code`.
|
/// Reset the code of account `a` so that it is `code`.
|
||||||
pub fn reset_code(&mut self, a: &Address, code: Bytes) {
|
pub fn reset_code(&mut self, a: &Address, code: Bytes) -> trie::Result<()> {
|
||||||
self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{}).reset_code(code);
|
self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{})?.reset_code(code);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a given transaction.
|
/// Execute a given transaction.
|
||||||
@ -559,7 +573,7 @@ impl<B: Backend> State<B> {
|
|||||||
let addr_hash = account.address_hash(address);
|
let addr_hash = account.address_hash(address);
|
||||||
{
|
{
|
||||||
let mut account_db = factories.accountdb.create(db.as_hashdb_mut(), addr_hash);
|
let mut account_db = factories.accountdb.create(db.as_hashdb_mut(), addr_hash);
|
||||||
account.commit_storage(&factories.trie, account_db.as_hashdb_mut());
|
account.commit_storage(&factories.trie, account_db.as_hashdb_mut())?;
|
||||||
account.commit_code(account_db.as_hashdb_mut());
|
account.commit_code(account_db.as_hashdb_mut());
|
||||||
}
|
}
|
||||||
if !account.is_empty() {
|
if !account.is_empty() {
|
||||||
@ -629,25 +643,29 @@ impl<B: Backend> State<B> {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_pod(&mut self, query: &PodState) {
|
fn query_pod(&mut self, query: &PodState) -> trie::Result<()> {
|
||||||
for (address, pod_account) in query.get().into_iter()
|
for (address, pod_account) in query.get() {
|
||||||
.filter(|&(a, _)| self.ensure_cached(a, RequireCache::Code, true, |a| a.is_some()))
|
if !self.ensure_cached(address, RequireCache::Code, true, |a| a.is_some())? {
|
||||||
{
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// needs to be split into two parts for the refcell code here
|
// needs to be split into two parts for the refcell code here
|
||||||
// to work.
|
// to work.
|
||||||
for key in pod_account.storage.keys() {
|
for key in pod_account.storage.keys() {
|
||||||
self.storage_at(address, key);
|
self.storage_at(address, key)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a `StateDiff` describing the difference from `orig` to `self`.
|
/// Returns a `StateDiff` describing the difference from `orig` to `self`.
|
||||||
/// Consumes self.
|
/// Consumes self.
|
||||||
pub fn diff_from<X: Backend>(&self, orig: State<X>) -> StateDiff {
|
pub fn diff_from<X: Backend>(&self, orig: State<X>) -> trie::Result<StateDiff> {
|
||||||
let pod_state_post = self.to_pod();
|
let pod_state_post = self.to_pod();
|
||||||
let mut state_pre = orig;
|
let mut state_pre = orig;
|
||||||
state_pre.query_pod(&pod_state_post);
|
state_pre.query_pod(&pod_state_post)?;
|
||||||
pod_state::diff_pod(&state_pre.to_pod(), &pod_state_post)
|
Ok(pod_state::diff_pod(&state_pre.to_pod(), &pod_state_post))
|
||||||
}
|
}
|
||||||
|
|
||||||
// load required account data from the databases.
|
// load required account data from the databases.
|
||||||
@ -681,16 +699,16 @@ impl<B: Backend> State<B> {
|
|||||||
/// Check caches for required data
|
/// Check caches for required data
|
||||||
/// First searches for account in the local, then the shared cache.
|
/// First searches for account in the local, then the shared cache.
|
||||||
/// Populates local cache if nothing found.
|
/// Populates local cache if nothing found.
|
||||||
fn ensure_cached<F, U>(&self, a: &Address, require: RequireCache, check_null: bool, f: F) -> U
|
fn ensure_cached<F, U>(&self, a: &Address, require: RequireCache, check_null: bool, f: F) -> trie::Result<U>
|
||||||
where F: Fn(Option<&Account>) -> U {
|
where F: Fn(Option<&Account>) -> U {
|
||||||
// check local cache first
|
// check local cache first
|
||||||
if let Some(ref mut maybe_acc) = self.cache.borrow_mut().get_mut(a) {
|
if let Some(ref mut maybe_acc) = self.cache.borrow_mut().get_mut(a) {
|
||||||
if let Some(ref mut account) = maybe_acc.account {
|
if let Some(ref mut account) = maybe_acc.account {
|
||||||
let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a));
|
let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a));
|
||||||
Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb());
|
Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb());
|
||||||
return f(Some(account));
|
return Ok(f(Some(account)));
|
||||||
}
|
}
|
||||||
return f(None);
|
return Ok(f(None));
|
||||||
}
|
}
|
||||||
// check global cache
|
// check global cache
|
||||||
let result = self.db.get_cached(a, |mut acc| {
|
let result = self.db.get_cached(a, |mut acc| {
|
||||||
@ -701,37 +719,34 @@ impl<B: Backend> State<B> {
|
|||||||
f(acc.map(|a| &*a))
|
f(acc.map(|a| &*a))
|
||||||
});
|
});
|
||||||
match result {
|
match result {
|
||||||
Some(r) => r,
|
Some(r) => Ok(r),
|
||||||
None => {
|
None => {
|
||||||
// first check if it is not in database for sure
|
// first check if it is not in database for sure
|
||||||
if check_null && self.db.is_known_null(a) { return f(None); }
|
if check_null && self.db.is_known_null(a) { return Ok(f(None)); }
|
||||||
|
|
||||||
// not found in the global cache, get from the DB and insert into local
|
// not found in the global cache, get from the DB and insert into local
|
||||||
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root)?;
|
||||||
let mut maybe_acc = match db.get_with(a, Account::from_rlp) {
|
let mut maybe_acc = db.get_with(a, Account::from_rlp)?;
|
||||||
Ok(acc) => acc,
|
|
||||||
Err(e) => panic!("Potential DB corruption encountered: {}", e),
|
|
||||||
};
|
|
||||||
if let Some(ref mut account) = maybe_acc.as_mut() {
|
if let Some(ref mut account) = maybe_acc.as_mut() {
|
||||||
let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a));
|
let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a));
|
||||||
Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb());
|
Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb());
|
||||||
}
|
}
|
||||||
let r = f(maybe_acc.as_ref());
|
let r = f(maybe_acc.as_ref());
|
||||||
self.insert_cache(a, AccountEntry::new_clean(maybe_acc));
|
self.insert_cache(a, AccountEntry::new_clean(maybe_acc));
|
||||||
r
|
Ok(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
|
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
|
||||||
fn require<'a>(&'a self, a: &Address, require_code: bool) -> RefMut<'a, Account> {
|
fn require<'a>(&'a self, a: &Address, require_code: bool) -> trie::Result<RefMut<'a, Account>> {
|
||||||
self.require_or_from(a, require_code, || Account::new_basic(U256::from(0u8), self.account_start_nonce), |_|{})
|
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.
|
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
|
||||||
/// If it doesn't exist, make account equal the evaluation of `default`.
|
/// If it doesn't exist, make account equal the evaluation of `default`.
|
||||||
fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&'a self, a: &Address, require_code: bool, default: F, not_default: G)
|
fn require_or_from<'a, F, G>(&'a self, a: &Address, require_code: bool, default: F, not_default: G) -> trie::Result<RefMut<'a, Account>>
|
||||||
-> RefMut<'a, Account>
|
where F: FnOnce() -> Account, G: FnOnce(&mut Account),
|
||||||
{
|
{
|
||||||
let contains_key = self.cache.borrow().contains_key(a);
|
let contains_key = self.cache.borrow().contains_key(a);
|
||||||
if !contains_key {
|
if !contains_key {
|
||||||
@ -739,11 +754,8 @@ impl<B: Backend> State<B> {
|
|||||||
Some(acc) => self.insert_cache(a, AccountEntry::new_clean_cached(acc)),
|
Some(acc) => self.insert_cache(a, AccountEntry::new_clean_cached(acc)),
|
||||||
None => {
|
None => {
|
||||||
let maybe_acc = if !self.db.is_known_null(a) {
|
let maybe_acc = if !self.db.is_known_null(a) {
|
||||||
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root)?;
|
||||||
match db.get_with(a, Account::from_rlp) {
|
AccountEntry::new_clean(db.get_with(a, Account::from_rlp)?)
|
||||||
Ok(acc) => AccountEntry::new_clean(acc),
|
|
||||||
Err(e) => panic!("Potential DB corruption encountered: {}", e),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
AccountEntry::new_clean(None)
|
AccountEntry::new_clean(None)
|
||||||
};
|
};
|
||||||
@ -754,7 +766,7 @@ impl<B: Backend> State<B> {
|
|||||||
self.note_cache(a);
|
self.note_cache(a);
|
||||||
|
|
||||||
// at this point the entry is guaranteed to be in the cache.
|
// at this point the entry is guaranteed to be in the cache.
|
||||||
RefMut::map(self.cache.borrow_mut(), |c| {
|
Ok(RefMut::map(self.cache.borrow_mut(), |c| {
|
||||||
let mut entry = c.get_mut(a).expect("entry known to exist in the cache; qed");
|
let mut entry = c.get_mut(a).expect("entry known to exist in the cache; qed");
|
||||||
|
|
||||||
match &mut entry.account {
|
match &mut entry.account {
|
||||||
@ -775,18 +787,18 @@ impl<B: Backend> State<B> {
|
|||||||
},
|
},
|
||||||
_ => panic!("Required account must always exist; qed"),
|
_ => panic!("Required account must always exist; qed"),
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LES state proof implementations.
|
// State proof implementations; useful for light client protocols.
|
||||||
impl<B: Backend> State<B> {
|
impl<B: Backend> State<B> {
|
||||||
/// Prove an account's existence or nonexistence in the state trie.
|
/// Prove an account's existence or nonexistence in the state trie.
|
||||||
/// Returns a merkle proof of the account's trie node with all nodes before `from_level`
|
/// Returns a merkle proof of the account's trie node with all nodes before `from_level`
|
||||||
/// omitted or an encountered trie error.
|
/// omitted or an encountered trie error.
|
||||||
/// Requires a secure trie to be used for accurate results.
|
/// Requires a secure trie to be used for accurate results.
|
||||||
/// `account_key` == sha3(address)
|
/// `account_key` == sha3(address)
|
||||||
pub fn prove_account(&self, account_key: H256, from_level: u32) -> Result<Vec<Bytes>, Box<TrieError>> {
|
pub fn prove_account(&self, account_key: H256, from_level: u32) -> trie::Result<Vec<Bytes>> {
|
||||||
let mut recorder = Recorder::with_depth(from_level);
|
let mut recorder = Recorder::with_depth(from_level);
|
||||||
let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?;
|
let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?;
|
||||||
trie.get_with(&account_key, &mut recorder)?;
|
trie.get_with(&account_key, &mut recorder)?;
|
||||||
@ -799,7 +811,7 @@ impl<B: Backend> State<B> {
|
|||||||
/// `from_level` omitted. Requires a secure trie to be used for correctness.
|
/// `from_level` omitted. Requires a secure trie to be used for correctness.
|
||||||
/// `account_key` == sha3(address)
|
/// `account_key` == sha3(address)
|
||||||
/// `storage_key` == sha3(key)
|
/// `storage_key` == sha3(key)
|
||||||
pub fn prove_storage(&self, account_key: H256, storage_key: H256, from_level: u32) -> Result<Vec<Bytes>, Box<TrieError>> {
|
pub fn prove_storage(&self, account_key: H256, storage_key: H256, from_level: u32) -> trie::Result<Vec<Bytes>> {
|
||||||
// TODO: probably could look into cache somehow but it's keyed by
|
// TODO: probably could look into cache somehow but it's keyed by
|
||||||
// address, not sha3(address).
|
// address, not sha3(address).
|
||||||
let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?;
|
let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?;
|
||||||
@ -814,7 +826,7 @@ impl<B: Backend> State<B> {
|
|||||||
|
|
||||||
/// Get code by address hash.
|
/// Get code by address hash.
|
||||||
/// Only works when backed by a secure trie.
|
/// Only works when backed by a secure trie.
|
||||||
pub fn code_by_address_hash(&self, account_key: H256) -> Result<Option<Bytes>, Box<TrieError>> {
|
pub fn code_by_address_hash(&self, account_key: H256) -> trie::Result<Option<Bytes>> {
|
||||||
let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?;
|
let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?;
|
||||||
let mut acc = match trie.get_with(&account_key, Account::from_rlp)? {
|
let mut acc = match trie.get_with(&account_key, Account::from_rlp)? {
|
||||||
Some(acc) => acc,
|
Some(acc) => acc,
|
||||||
@ -899,7 +911,7 @@ mod tests {
|
|||||||
data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(),
|
data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(),
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
@ -929,13 +941,13 @@ mod tests {
|
|||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let mut state = {
|
let mut state = {
|
||||||
let mut state = get_temp_state_in(temp.as_path());
|
let mut state = get_temp_state_in(temp.as_path());
|
||||||
assert_eq!(state.exists(&a), false);
|
assert_eq!(state.exists(&a).unwrap(), false);
|
||||||
state.inc_nonce(&a);
|
state.inc_nonce(&a).unwrap();
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
state.clone()
|
state.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
state.inc_nonce(&a);
|
state.inc_nonce(&a).unwrap();
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -959,7 +971,7 @@ mod tests {
|
|||||||
data: FromHex::from_hex("5b600056").unwrap(),
|
data: FromHex::from_hex("5b600056").unwrap(),
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
@ -996,8 +1008,8 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap()).unwrap();
|
||||||
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
@ -1039,7 +1051,7 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
@ -1123,7 +1135,7 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()).unwrap();
|
||||||
let result = state.apply(&info, engine, &t, true).unwrap();
|
let result = state.apply(&info, engine, &t, true).unwrap();
|
||||||
|
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
@ -1166,8 +1178,8 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()).unwrap();
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()).unwrap();
|
||||||
let result = state.apply(&info, engine, &t, true).unwrap();
|
let result = state.apply(&info, engine, &t, true).unwrap();
|
||||||
|
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
@ -1228,8 +1240,8 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap()).unwrap();
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()).unwrap();
|
||||||
let result = state.apply(&info, engine, &t, true).unwrap();
|
let result = state.apply(&info, engine, &t, true).unwrap();
|
||||||
|
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
@ -1287,8 +1299,8 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap()).unwrap();
|
||||||
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
@ -1327,9 +1339,9 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()).unwrap();
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()).unwrap();
|
||||||
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
|
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
@ -1387,8 +1399,8 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()).unwrap();
|
||||||
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
@ -1442,8 +1454,8 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds.
|
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()).unwrap(); // not enough funds.
|
||||||
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
@ -1485,9 +1497,9 @@ mod tests {
|
|||||||
data: vec![],//600480600b6000396000f35b600056
|
data: vec![],//600480600b6000396000f35b600056
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()).unwrap();
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap()).unwrap();
|
||||||
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
@ -1541,10 +1553,10 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()).unwrap();
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()).unwrap();
|
||||||
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
|
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()).unwrap();
|
||||||
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
@ -1616,10 +1628,10 @@ mod tests {
|
|||||||
data: vec![],//600480600b6000396000f35b600056
|
data: vec![],//600480600b6000396000f35b600056
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()).unwrap();
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()).unwrap();
|
||||||
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
|
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()).unwrap();
|
||||||
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &(100.into()), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
|
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
@ -1689,9 +1701,9 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&secret(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap()).unwrap();
|
||||||
state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty);
|
state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty).unwrap();
|
||||||
state.add_balance(&t.sender(), &100.into(), CleanupMode::NoEmpty);
|
state.add_balance(&t.sender(), &100.into(), CleanupMode::NoEmpty).unwrap();
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
let expected_trace = vec![FlatTrace {
|
let expected_trace = vec![FlatTrace {
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
@ -1728,16 +1740,16 @@ mod tests {
|
|||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let (root, db) = {
|
let (root, db) = {
|
||||||
let mut state = get_temp_state_in(temp.as_path());
|
let mut state = get_temp_state_in(temp.as_path());
|
||||||
state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{});
|
state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{}).unwrap();
|
||||||
state.init_code(&a, vec![1, 2, 3]);
|
state.init_code(&a, vec![1, 2, 3]).unwrap();
|
||||||
assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec())));
|
assert_eq!(state.code(&a).unwrap(), Some(Arc::new([1u8, 2, 3].to_vec())));
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec())));
|
assert_eq!(state.code(&a).unwrap(), Some(Arc::new([1u8, 2, 3].to_vec())));
|
||||||
state.drop()
|
state.drop()
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||||
assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec())));
|
assert_eq!(state.code(&a).unwrap(), Some(Arc::new([1u8, 2, 3].to_vec())));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1746,13 +1758,13 @@ mod tests {
|
|||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let (root, db) = {
|
let (root, db) = {
|
||||||
let mut state = get_temp_state_in(temp.as_path());
|
let mut state = get_temp_state_in(temp.as_path());
|
||||||
state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(69u64)));
|
state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(69u64))).unwrap();
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
state.drop()
|
state.drop()
|
||||||
};
|
};
|
||||||
|
|
||||||
let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||||
assert_eq!(s.storage_at(&a, &H256::from(&U256::from(1u64))), H256::from(&U256::from(69u64)));
|
assert_eq!(s.storage_at(&a, &H256::from(&U256::from(1u64))).unwrap(), H256::from(&U256::from(69u64)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1761,16 +1773,16 @@ mod tests {
|
|||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let (root, db) = {
|
let (root, db) = {
|
||||||
let mut state = get_temp_state_in(temp.as_path());
|
let mut state = get_temp_state_in(temp.as_path());
|
||||||
state.inc_nonce(&a);
|
state.inc_nonce(&a).unwrap();
|
||||||
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
|
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty).unwrap();
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(69u64));
|
||||||
state.drop()
|
state.drop()
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(69u64));
|
||||||
assert_eq!(state.nonce(&a), U256::from(1u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(1u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1778,16 +1790,16 @@ mod tests {
|
|||||||
let a = Address::zero();
|
let a = Address::zero();
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
assert_eq!(state.exists(&a), false);
|
assert_eq!(state.exists(&a).unwrap(), false);
|
||||||
assert_eq!(state.exists_and_not_null(&a), false);
|
assert_eq!(state.exists_and_not_null(&a).unwrap(), false);
|
||||||
state.inc_nonce(&a);
|
state.inc_nonce(&a).unwrap();
|
||||||
assert_eq!(state.exists(&a), true);
|
assert_eq!(state.exists(&a).unwrap(), true);
|
||||||
assert_eq!(state.exists_and_not_null(&a), true);
|
assert_eq!(state.exists_and_not_null(&a).unwrap(), true);
|
||||||
assert_eq!(state.nonce(&a), U256::from(1u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(1u64));
|
||||||
state.kill_account(&a);
|
state.kill_account(&a);
|
||||||
assert_eq!(state.exists(&a), false);
|
assert_eq!(state.exists(&a).unwrap(), false);
|
||||||
assert_eq!(state.exists_and_not_null(&a), false);
|
assert_eq!(state.exists_and_not_null(&a).unwrap(), false);
|
||||||
assert_eq!(state.nonce(&a), U256::from(0u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(0u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1797,13 +1809,13 @@ mod tests {
|
|||||||
let db = get_temp_state_db_in(path.as_path());
|
let db = get_temp_state_db_in(path.as_path());
|
||||||
let (root, db) = {
|
let (root, db) = {
|
||||||
let mut state = State::new(db, U256::from(0), Default::default());
|
let mut state = State::new(db, U256::from(0), Default::default());
|
||||||
state.add_balance(&a, &U256::default(), CleanupMode::NoEmpty); // create an empty account
|
state.add_balance(&a, &U256::default(), CleanupMode::NoEmpty).unwrap(); // create an empty account
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
state.drop()
|
state.drop()
|
||||||
};
|
};
|
||||||
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||||
assert!(!state.exists(&a));
|
assert!(!state.exists(&a).unwrap());
|
||||||
assert!(!state.exists_and_not_null(&a));
|
assert!(!state.exists_and_not_null(&a).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1813,13 +1825,13 @@ mod tests {
|
|||||||
let db = get_temp_state_db_in(path.as_path());
|
let db = get_temp_state_db_in(path.as_path());
|
||||||
let (root, db) = {
|
let (root, db) = {
|
||||||
let mut state = State::new(db, U256::from(0), Default::default());
|
let mut state = State::new(db, U256::from(0), Default::default());
|
||||||
state.add_balance(&a, &U256::default(), CleanupMode::ForceCreate); // create an empty account
|
state.add_balance(&a, &U256::default(), CleanupMode::ForceCreate).unwrap(); // create an empty account
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
state.drop()
|
state.drop()
|
||||||
};
|
};
|
||||||
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||||
assert!(state.exists(&a));
|
assert!(state.exists(&a).unwrap());
|
||||||
assert!(!state.exists_and_not_null(&a));
|
assert!(!state.exists_and_not_null(&a).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1828,27 +1840,27 @@ mod tests {
|
|||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let (root, db) = {
|
let (root, db) = {
|
||||||
let mut state = get_temp_state_in(temp.as_path());
|
let mut state = get_temp_state_in(temp.as_path());
|
||||||
state.inc_nonce(&a);
|
state.inc_nonce(&a).unwrap();
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
assert_eq!(state.exists(&a), true);
|
assert_eq!(state.exists(&a).unwrap(), true);
|
||||||
assert_eq!(state.nonce(&a), U256::from(1u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(1u64));
|
||||||
state.drop()
|
state.drop()
|
||||||
};
|
};
|
||||||
|
|
||||||
let (root, db) = {
|
let (root, db) = {
|
||||||
let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||||
assert_eq!(state.exists(&a), true);
|
assert_eq!(state.exists(&a).unwrap(), true);
|
||||||
assert_eq!(state.nonce(&a), U256::from(1u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(1u64));
|
||||||
state.kill_account(&a);
|
state.kill_account(&a);
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
assert_eq!(state.exists(&a), false);
|
assert_eq!(state.exists(&a).unwrap(), false);
|
||||||
assert_eq!(state.nonce(&a), U256::from(0u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(0u64));
|
||||||
state.drop()
|
state.drop()
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||||
assert_eq!(state.exists(&a), false);
|
assert_eq!(state.exists(&a).unwrap(), false);
|
||||||
assert_eq!(state.nonce(&a), U256::from(0u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(0u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1857,20 +1869,20 @@ mod tests {
|
|||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
let a = Address::zero();
|
let a = Address::zero();
|
||||||
let b = 1u64.into();
|
let b = 1u64.into();
|
||||||
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
|
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty).unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(69u64));
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(69u64));
|
||||||
state.sub_balance(&a, &U256::from(42u64));
|
state.sub_balance(&a, &U256::from(42u64)).unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(27u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(27u64));
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(27u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(27u64));
|
||||||
state.transfer_balance(&a, &b, &U256::from(18u64), CleanupMode::NoEmpty);
|
state.transfer_balance(&a, &b, &U256::from(18u64), CleanupMode::NoEmpty).unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(9u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(9u64));
|
||||||
assert_eq!(state.balance(&b), U256::from(18u64));
|
assert_eq!(state.balance(&b).unwrap(), U256::from(18u64));
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(9u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(9u64));
|
||||||
assert_eq!(state.balance(&b), U256::from(18u64));
|
assert_eq!(state.balance(&b).unwrap(), U256::from(18u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1878,16 +1890,16 @@ mod tests {
|
|||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
let a = Address::zero();
|
let a = Address::zero();
|
||||||
state.inc_nonce(&a);
|
state.inc_nonce(&a).unwrap();
|
||||||
assert_eq!(state.nonce(&a), U256::from(1u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(1u64));
|
||||||
state.inc_nonce(&a);
|
state.inc_nonce(&a).unwrap();
|
||||||
assert_eq!(state.nonce(&a), U256::from(2u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(2u64));
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
assert_eq!(state.nonce(&a), U256::from(2u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(2u64));
|
||||||
state.inc_nonce(&a);
|
state.inc_nonce(&a).unwrap();
|
||||||
assert_eq!(state.nonce(&a), U256::from(3u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(3u64));
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
assert_eq!(state.nonce(&a), U256::from(3u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(3u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1895,11 +1907,11 @@ mod tests {
|
|||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
let a = Address::zero();
|
let a = Address::zero();
|
||||||
assert_eq!(state.balance(&a), U256::from(0u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(0u64));
|
||||||
assert_eq!(state.nonce(&a), U256::from(0u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(0u64));
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(0u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(0u64));
|
||||||
assert_eq!(state.nonce(&a), U256::from(0u64));
|
assert_eq!(state.nonce(&a).unwrap(), U256::from(0u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1907,7 +1919,7 @@ mod tests {
|
|||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
let a = Address::zero();
|
let a = Address::zero();
|
||||||
state.require(&a, false);
|
state.require(&a, false).unwrap();
|
||||||
state.commit().unwrap();
|
state.commit().unwrap();
|
||||||
assert_eq!(state.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785");
|
assert_eq!(state.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785");
|
||||||
}
|
}
|
||||||
@ -1918,15 +1930,15 @@ mod tests {
|
|||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
let a = Address::zero();
|
let a = Address::zero();
|
||||||
state.checkpoint();
|
state.checkpoint();
|
||||||
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
|
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty).unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(69u64));
|
||||||
state.discard_checkpoint();
|
state.discard_checkpoint();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(69u64));
|
||||||
state.checkpoint();
|
state.checkpoint();
|
||||||
state.add_balance(&a, &U256::from(1u64), CleanupMode::NoEmpty);
|
state.add_balance(&a, &U256::from(1u64), CleanupMode::NoEmpty).unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(70u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(70u64));
|
||||||
state.revert_to_checkpoint();
|
state.revert_to_checkpoint();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(69u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1936,12 +1948,12 @@ mod tests {
|
|||||||
let a = Address::zero();
|
let a = Address::zero();
|
||||||
state.checkpoint();
|
state.checkpoint();
|
||||||
state.checkpoint();
|
state.checkpoint();
|
||||||
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
|
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty).unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(69u64));
|
||||||
state.discard_checkpoint();
|
state.discard_checkpoint();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(69u64));
|
||||||
state.revert_to_checkpoint();
|
state.revert_to_checkpoint();
|
||||||
assert_eq!(state.balance(&a), U256::from(0));
|
assert_eq!(state.balance(&a).unwrap(), U256::from(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1958,14 +1970,14 @@ mod tests {
|
|||||||
let mut state = state.reference().clone();
|
let mut state = state.reference().clone();
|
||||||
|
|
||||||
let a: Address = 0xa.into();
|
let a: Address = 0xa.into();
|
||||||
state.init_code(&a, b"abcdefg".to_vec());
|
state.init_code(&a, b"abcdefg".to_vec()).unwrap();;
|
||||||
state.add_balance(&a, &256.into(), CleanupMode::NoEmpty);
|
state.add_balance(&a, &256.into(), CleanupMode::NoEmpty).unwrap();
|
||||||
state.set_storage(&a, 0xb.into(), 0xc.into());
|
state.set_storage(&a, 0xb.into(), 0xc.into()).unwrap();
|
||||||
|
|
||||||
let mut new_state = state.clone();
|
let mut new_state = state.clone();
|
||||||
new_state.set_storage(&a, 0xb.into(), 0xd.into());
|
new_state.set_storage(&a, 0xb.into(), 0xd.into()).unwrap();
|
||||||
|
|
||||||
new_state.diff_from(state);
|
new_state.diff_from(state).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -291,7 +291,7 @@ fn change_history_size() {
|
|||||||
|
|
||||||
for _ in 0..20 {
|
for _ in 0..20 {
|
||||||
let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]);
|
let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]);
|
||||||
b.block_mut().fields_mut().state.add_balance(&address, &5.into(), CleanupMode::NoEmpty);
|
b.block_mut().fields_mut().state.add_balance(&address, &5.into(), CleanupMode::NoEmpty).unwrap();
|
||||||
b.block_mut().fields_mut().state.commit().unwrap();
|
b.block_mut().fields_mut().state.commit().unwrap();
|
||||||
let b = b.close_and_lock().seal(&*test_spec.engine, vec![]).unwrap();
|
let b = b.close_and_lock().seal(&*test_spec.engine, vec![]).unwrap();
|
||||||
client.import_sealed_block(b).unwrap(); // account change is in the journal overlay
|
client.import_sealed_block(b).unwrap(); // account change is in the journal overlay
|
||||||
@ -306,7 +306,7 @@ fn change_history_size() {
|
|||||||
Arc::new(Miner::with_spec(&test_spec)),
|
Arc::new(Miner::with_spec(&test_spec)),
|
||||||
IoChannel::disconnected(),
|
IoChannel::disconnected(),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
assert_eq!(client.state().balance(&address), 100.into());
|
assert_eq!(client.state().balance(&address).unwrap(), 100.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
//! Transaction execution format module.
|
//! Transaction execution format module.
|
||||||
|
|
||||||
use util::{Bytes, U256, Address, U512};
|
use util::{Bytes, U256, Address, U512, trie};
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
use evm;
|
use evm;
|
||||||
use trace::{VMTrace, FlatTrace};
|
use trace::{VMTrace, FlatTrace};
|
||||||
@ -146,27 +146,33 @@ pub enum ExecutionError {
|
|||||||
got: U512
|
got: U512
|
||||||
},
|
},
|
||||||
/// Returned when internal evm error occurs.
|
/// Returned when internal evm error occurs.
|
||||||
Internal,
|
Internal(String),
|
||||||
/// Returned when generic transaction occurs
|
/// Returned when generic transaction occurs
|
||||||
TransactionMalformed(String),
|
TransactionMalformed(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Box<trie::TrieError>> for ExecutionError {
|
||||||
|
fn from(err: Box<trie::TrieError>) -> Self {
|
||||||
|
ExecutionError::Internal(format!("{}", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for ExecutionError {
|
impl fmt::Display for ExecutionError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use self::ExecutionError::*;
|
use self::ExecutionError::*;
|
||||||
|
|
||||||
let msg = match *self {
|
let msg = match *self {
|
||||||
NotEnoughBaseGas { required, got } =>
|
NotEnoughBaseGas { ref required, ref got } =>
|
||||||
format!("Not enough base gas. {} is required, but only {} paid", required, got),
|
format!("Not enough base gas. {} is required, but only {} paid", required, got),
|
||||||
BlockGasLimitReached { gas_limit, gas_used, gas } =>
|
BlockGasLimitReached { ref gas_limit, ref gas_used, ref gas } =>
|
||||||
format!("Block gas limit reached. The limit is {}, {} has \
|
format!("Block gas limit reached. The limit is {}, {} has \
|
||||||
already been used, and {} more is required", gas_limit, gas_used, gas),
|
already been used, and {} more is required", gas_limit, gas_used, gas),
|
||||||
InvalidNonce { expected, got } =>
|
InvalidNonce { ref expected, ref got } =>
|
||||||
format!("Invalid transaction nonce: expected {}, found {}", expected, got),
|
format!("Invalid transaction nonce: expected {}, found {}", expected, got),
|
||||||
NotEnoughCash { required, got } =>
|
NotEnoughCash { ref required, ref got } =>
|
||||||
format!("Cost of transaction exceeds sender balance. {} is required \
|
format!("Cost of transaction exceeds sender balance. {} is required \
|
||||||
but the sender only has {}", required, got),
|
but the sender only has {}", required, got),
|
||||||
Internal => "Internal evm error".into(),
|
Internal(ref msg) => msg.clone(),
|
||||||
TransactionMalformed(ref err) => format!("Malformed transaction: {}", err),
|
TransactionMalformed(ref err) => format!("Malformed transaction: {}", err),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -184,6 +190,8 @@ pub enum CallError {
|
|||||||
StatePruned,
|
StatePruned,
|
||||||
/// Couldn't find an amount of gas that didn't result in an exception.
|
/// Couldn't find an amount of gas that didn't result in an exception.
|
||||||
Exceptional,
|
Exceptional,
|
||||||
|
/// Corrupt state.
|
||||||
|
StateCorrupt,
|
||||||
/// Error executing.
|
/// Error executing.
|
||||||
Execution(ExecutionError),
|
Execution(ExecutionError),
|
||||||
}
|
}
|
||||||
@ -202,6 +210,7 @@ impl fmt::Display for CallError {
|
|||||||
TransactionNotFound => "Transaction couldn't be found in the chain".into(),
|
TransactionNotFound => "Transaction couldn't be found in the chain".into(),
|
||||||
StatePruned => "Couldn't find the transaction block's state in the chain".into(),
|
StatePruned => "Couldn't find the transaction block's state in the chain".into(),
|
||||||
Exceptional => "An exception happened in the execution".into(),
|
Exceptional => "An exception happened in the execution".into(),
|
||||||
|
StateCorrupt => "Stored state found to be corrupted.".into(),
|
||||||
Execution(ref e) => format!("{}", e),
|
Execution(ref e) => format!("{}", e),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -40,19 +40,25 @@ pub enum Error {
|
|||||||
Internal,
|
Internal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EvmError> for Error {
|
impl<'a> From<&'a EvmError> for Error {
|
||||||
fn from(e: EvmError) -> Self {
|
fn from(e: &'a EvmError) -> Self {
|
||||||
match e {
|
match *e {
|
||||||
EvmError::OutOfGas => Error::OutOfGas,
|
EvmError::OutOfGas => Error::OutOfGas,
|
||||||
EvmError::BadJumpDestination { .. } => Error::BadJumpDestination,
|
EvmError::BadJumpDestination { .. } => Error::BadJumpDestination,
|
||||||
EvmError::BadInstruction { .. } => Error::BadInstruction,
|
EvmError::BadInstruction { .. } => Error::BadInstruction,
|
||||||
EvmError::StackUnderflow { .. } => Error::StackUnderflow,
|
EvmError::StackUnderflow { .. } => Error::StackUnderflow,
|
||||||
EvmError::OutOfStack { .. } => Error::OutOfStack,
|
EvmError::OutOfStack { .. } => Error::OutOfStack,
|
||||||
EvmError::Internal => Error::Internal,
|
EvmError::Internal(_) => Error::Internal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<EvmError> for Error {
|
||||||
|
fn from(e: EvmError) -> Self {
|
||||||
|
Error::from(&e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use self::Error::*;
|
use self::Error::*;
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use util::{U256, H256, Address, Bytes, FixedHash};
|
use util::{U256, H256, Address, Bytes, FixedHash, trie};
|
||||||
use ethcore::client::EnvInfo;
|
use ethcore::client::EnvInfo;
|
||||||
use ethcore::evm::{self, Ext, ContractCreateResult, MessageCallResult, Schedule, CallType};
|
use ethcore::evm::{self, Ext, ContractCreateResult, MessageCallResult, Schedule, CallType};
|
||||||
|
|
||||||
@ -39,27 +39,28 @@ impl Default for FakeExt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ext for FakeExt {
|
impl Ext for FakeExt {
|
||||||
fn storage_at(&self, key: &H256) -> H256 {
|
fn storage_at(&self, key: &H256) -> trie::Result<H256> {
|
||||||
self.store.get(key).unwrap_or(&H256::new()).clone()
|
Ok(self.store.get(key).unwrap_or(&H256::new()).clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_storage(&mut self, key: H256, value: H256) {
|
fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()> {
|
||||||
self.store.insert(key, value);
|
self.store.insert(key, value);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists(&self, _address: &Address) -> bool {
|
fn exists(&self, _address: &Address) -> trie::Result<bool> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists_and_not_null(&self, _address: &Address) -> bool {
|
fn exists_and_not_null(&self, _address: &Address) -> trie::Result<bool> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn origin_balance(&self) -> U256 {
|
fn origin_balance(&self) -> trie::Result<U256> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn balance(&self, _address: &Address) -> U256 {
|
fn balance(&self, _address: &Address) -> trie::Result<U256> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,11 +84,11 @@ impl Ext for FakeExt {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcode(&self, _address: &Address) -> Arc<Bytes> {
|
fn extcode(&self, _address: &Address) -> trie::Result<Arc<Bytes>> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcodesize(&self, _address: &Address) -> usize {
|
fn extcodesize(&self, _address: &Address) -> trie::Result<usize> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +100,7 @@ impl Ext for FakeExt {
|
|||||||
Ok(*gas)
|
Ok(*gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suicide(&mut self, _refund_address: &Address) {
|
fn suicide(&mut self, _refund_address: &Address) -> trie::Result<()> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +132,10 @@ pub fn state_pruned() -> Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn state_corrupt() -> Error {
|
||||||
|
internal("State corrupt", "")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn exceptional() -> Error {
|
pub fn exceptional() -> Error {
|
||||||
Error {
|
Error {
|
||||||
code: ErrorCode::ServerError(codes::EXCEPTION_ERROR),
|
code: ErrorCode::ServerError(codes::EXCEPTION_ERROR),
|
||||||
@ -296,6 +300,7 @@ pub fn from_rlp_error(error: DecoderError) -> Error {
|
|||||||
pub fn from_call_error(error: CallError) -> Error {
|
pub fn from_call_error(error: CallError) -> Error {
|
||||||
match error {
|
match error {
|
||||||
CallError::StatePruned => state_pruned(),
|
CallError::StatePruned => state_pruned(),
|
||||||
|
CallError::StateCorrupt => state_corrupt(),
|
||||||
CallError::Exceptional => exceptional(),
|
CallError::Exceptional => exceptional(),
|
||||||
CallError::Execution(e) => execution(e),
|
CallError::Execution(e) => execution(e),
|
||||||
CallError::TransactionNotFound => internal("{}, this should not be the case with eth_call, most likely a bug.", CallError::TransactionNotFound),
|
CallError::TransactionNotFound => internal("{}, this should not be the case with eth_call, most likely a bug.", CallError::TransactionNotFound),
|
||||||
|
@ -349,7 +349,13 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
let address = address.into();
|
let address = address.into();
|
||||||
|
|
||||||
let res = match num.0.clone() {
|
let res = match num.0.clone() {
|
||||||
BlockNumber::Pending => Ok(take_weakf!(self.miner).balance(&*take_weakf!(self.client), &address).into()),
|
BlockNumber::Pending => {
|
||||||
|
let client = take_weakf!(self.client);
|
||||||
|
match take_weakf!(self.miner).balance(&*client, &address) {
|
||||||
|
Some(balance) => Ok(balance.into()),
|
||||||
|
None => Err(errors::internal("Unable to load balance from database", ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
id => {
|
id => {
|
||||||
let client = take_weakf!(self.client);
|
let client = take_weakf!(self.client);
|
||||||
|
|
||||||
@ -369,7 +375,13 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
let position: U256 = RpcU256::into(pos);
|
let position: U256 = RpcU256::into(pos);
|
||||||
|
|
||||||
let res = match num.0.clone() {
|
let res = match num.0.clone() {
|
||||||
BlockNumber::Pending => Ok(take_weakf!(self.miner).storage_at(&*take_weakf!(self.client), &address, &H256::from(position)).into()),
|
BlockNumber::Pending => {
|
||||||
|
let client = take_weakf!(self.client);
|
||||||
|
match take_weakf!(self.miner).storage_at(&*client, &address, &H256::from(position)) {
|
||||||
|
Some(s) => Ok(s.into()),
|
||||||
|
None => Err(errors::internal("Unable to load storage from database", ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
id => {
|
id => {
|
||||||
let client = take_weakf!(self.client);
|
let client = take_weakf!(self.client);
|
||||||
|
|
||||||
@ -387,7 +399,13 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
fn transaction_count(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256, Error> {
|
fn transaction_count(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256, Error> {
|
||||||
let address: Address = RpcH160::into(address);
|
let address: Address = RpcH160::into(address);
|
||||||
let res = match num.0.clone() {
|
let res = match num.0.clone() {
|
||||||
BlockNumber::Pending => Ok(take_weakf!(self.miner).nonce(&*take_weakf!(self.client), &address).into()),
|
BlockNumber::Pending => {
|
||||||
|
let client = take_weakf!(self.client);
|
||||||
|
match take_weakf!(self.miner).nonce(&*client, &address) {
|
||||||
|
Some(nonce) => Ok(nonce.into()),
|
||||||
|
None => Err(errors::internal("Unable to load nonce from database", ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
id => {
|
id => {
|
||||||
let client = take_weakf!(self.client);
|
let client = take_weakf!(self.client);
|
||||||
|
|
||||||
@ -437,7 +455,13 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
let address: Address = RpcH160::into(address);
|
let address: Address = RpcH160::into(address);
|
||||||
|
|
||||||
let res = match num.0.clone() {
|
let res = match num.0.clone() {
|
||||||
BlockNumber::Pending => Ok(take_weakf!(self.miner).code(&*take_weakf!(self.client), &address).map_or_else(Bytes::default, Bytes::new)),
|
BlockNumber::Pending => {
|
||||||
|
let client = take_weakf!(self.client);
|
||||||
|
match take_weakf!(self.miner).code(&*client, &address) {
|
||||||
|
Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)),
|
||||||
|
None => Err(errors::internal("Unable to load code from database", ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
id => {
|
id => {
|
||||||
let client = take_weakf!(self.client);
|
let client = take_weakf!(self.client);
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use devtools::RandomTempPath;
|
|
||||||
use ethcore::client::{BlockChainClient, Client, ClientConfig};
|
use ethcore::client::{BlockChainClient, Client, ClientConfig};
|
||||||
use ethcore::ids::BlockId;
|
use ethcore::ids::BlockId;
|
||||||
use ethcore::spec::{Genesis, Spec};
|
use ethcore::spec::{Genesis, Spec};
|
||||||
|
@ -254,26 +254,39 @@ impl MinerService for TestMinerService {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn balance(&self, _chain: &MiningBlockChainClient, address: &Address) -> U256 {
|
fn balance(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<U256> {
|
||||||
self.latest_closed_block.lock().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.balance(address).clone())
|
self.latest_closed_block.lock()
|
||||||
|
.as_ref()
|
||||||
|
.map(|b| b.block().fields().state.balance(address))
|
||||||
|
.map(|b| b.ok())
|
||||||
|
.unwrap_or(Some(U256::default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, CallError> {
|
fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn storage_at(&self, _chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256 {
|
fn storage_at(&self, _chain: &MiningBlockChainClient, address: &Address, position: &H256) -> Option<H256> {
|
||||||
self.latest_closed_block.lock().as_ref().map_or_else(H256::default, |b| b.block().fields().state.storage_at(address, position).clone())
|
self.latest_closed_block.lock()
|
||||||
|
.as_ref()
|
||||||
|
.map(|b| b.block().fields().state.storage_at(address, position))
|
||||||
|
.map(|s| s.ok())
|
||||||
|
.unwrap_or(Some(H256::default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nonce(&self, _chain: &MiningBlockChainClient, address: &Address) -> U256 {
|
fn nonce(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<U256> {
|
||||||
// we assume all transactions are in a pending block, ignoring the
|
// we assume all transactions are in a pending block, ignoring the
|
||||||
// reality of gas limits.
|
// reality of gas limits.
|
||||||
self.last_nonce(address).unwrap_or(U256::zero())
|
Some(self.last_nonce(address).unwrap_or(U256::zero()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn code(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<Bytes> {
|
fn code(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<Option<Bytes>> {
|
||||||
self.latest_closed_block.lock().as_ref().map_or(None, |b| b.block().fields().state.code(address).map(|c| (*c).clone()))
|
self.latest_closed_block.lock()
|
||||||
|
.as_ref()
|
||||||
|
.map(|b| b.block().fields().state.code(address))
|
||||||
|
.map(|c| c.ok())
|
||||||
|
.unwrap_or(None)
|
||||||
|
.map(|c| c.map(|c| (&*c).clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sensible_gas_price(&self) -> U256 {
|
fn sensible_gas_price(&self) -> U256 {
|
||||||
|
Loading…
Reference in New Issue
Block a user