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:
Robert Habermeier
2017-02-26 13:10:50 +01:00
committed by Gav Wood
parent eb9ee35d6c
commit 1bf2b27708
27 changed files with 598 additions and 456 deletions

View File

@@ -17,12 +17,12 @@
//! Evm interface.
use std::{ops, cmp, fmt};
use util::{U128, U256, U512, Uint};
use util::{U128, U256, U512, Uint, trie};
use action_params::ActionParams;
use evm::Ext;
/// Evm errors.
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub enum Error {
/// `OutOfGas` is returned when transaction execution runs out of gas.
/// 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.
/// Likely to cause consensus issues.
#[allow(dead_code)] // created only by jit
Internal,
Internal(String),
}
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 {
@@ -74,7 +79,7 @@ impl fmt::Display for Error {
BadInstruction { .. } => "Bad instruction",
StackUnderflow { .. } => "Stack underflow",
OutOfStack { .. } => "Out of stack",
Internal => "Internal error",
Internal(ref msg) => msg,
};
message.fmt(f)
}

View File

@@ -42,24 +42,25 @@ pub enum MessageCallResult {
}
/// Externalities interface for EVMs
// TODO: [rob] associated error type instead of `trie::Result`. Not all EVMs are trie powered.
pub trait Ext {
/// 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.
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.
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).
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.
fn origin_balance(&self) -> U256;
fn origin_balance(&self) -> trie::Result<U256>;
/// 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.
fn blockhash(&self, number: &U256) -> H256;
@@ -87,10 +88,10 @@ pub trait Ext {
) -> MessageCallResult;
/// 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
fn extcodesize(&self, address: &Address) -> usize;
fn extcodesize(&self, address: &Address) -> trie::Result<usize>;
/// Creates log entry with given topics and data
fn log(&mut self, topics: Vec<H256>, data: &[u8]);
@@ -101,7 +102,7 @@ pub trait Ext {
/// Should be called when contract commits suicide.
/// 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.
fn schedule(&self) -> &Schedule;

View File

@@ -123,7 +123,7 @@ impl<Gas: CostType> Gasometer<Gas> {
instructions::SSTORE => {
let address = H256::from(stack.peek(0));
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() {
schedule.sstore_set_gas
@@ -146,12 +146,12 @@ impl<Gas: CostType> Gasometer<Gas> {
instructions::SUICIDE => {
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));
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()));
}
@@ -198,9 +198,9 @@ impl<Gas: CostType> Gasometer<Gas> {
let is_value_transfer = !stack.peek(2).is_zero();
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()));
}

View File

@@ -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 contract_code = self.mem.read_slice(init_off, init_size);
let can_create = ext.balance(&params.address) >= endowment && ext.depth() < ext.schedule().max_depth;
let can_create = ext.balance(&params.address)? >= endowment && ext.depth() < ext.schedule().max_depth;
if !can_create {
stack.push(U256::zero());
@@ -319,11 +319,11 @@ impl<Cost: CostType> Interpreter<Cost> {
// Get sender & receive addresses, check if we have balance
let (sender_address, receive_address, has_balance, call_type) = match instruction {
instructions::CALL => {
let has_balance = ext.balance(&params.address) >= value.expect("value set for all but delegate call; qed");
let has_balance = ext.balance(&params.address)? >= value.expect("value set for all but delegate call; qed");
(&params.address, &code_address, has_balance, CallType::Call)
},
instructions::CALLCODE => {
let has_balance = ext.balance(&params.address) >= value.expect("value set for all but delegate call; qed");
let has_balance = ext.balance(&params.address)? >= value.expect("value set for all but delegate call; qed");
(&params.address, &params.address, has_balance, CallType::CallCode)
},
instructions::DELEGATECALL => (&params.sender, &params.address, true, CallType::DelegateCall),
@@ -366,7 +366,7 @@ impl<Cost: CostType> Interpreter<Cost> {
},
instructions::SUICIDE => {
let address = stack.pop_back();
ext.suicide(&u256_to_address(&address));
ext.suicide(&u256_to_address(&address))?;
return Ok(InstructionResult::StopExecution);
},
instructions::LOG0...instructions::LOG4 => {
@@ -410,19 +410,19 @@ impl<Cost: CostType> Interpreter<Cost> {
},
instructions::SLOAD => {
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);
},
instructions::SSTORE => {
let address = H256::from(&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
if !self.is_zero(&current_val) && self.is_zero(&val) {
ext.inc_sstore_clears();
}
ext.set_storage(address, H256::from(&val));
ext.set_storage(address, H256::from(&val))?;
},
instructions::PC => {
stack.push(U256::from(code.position - 1));
@@ -438,7 +438,7 @@ impl<Cost: CostType> Interpreter<Cost> {
},
instructions::BALANCE => {
let address = u256_to_address(&stack.pop_back());
let balance = ext.balance(&address);
let balance = ext.balance(&address)?;
stack.push(balance);
},
instructions::CALLER => {
@@ -474,7 +474,7 @@ impl<Cost: CostType> Interpreter<Cost> {
},
instructions::EXTCODESIZE => {
let address = u256_to_address(&stack.pop_back());
let len = ext.extcodesize(&address);
let len = ext.extcodesize(&address)?;
stack.push(U256::from(len));
},
instructions::CALLDATACOPY => {
@@ -485,7 +485,7 @@ impl<Cost: CostType> Interpreter<Cost> {
},
instructions::EXTCODECOPY => {
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);
},
instructions::GASPRICE => {

View File

@@ -82,28 +82,29 @@ impl Default for Schedule {
}
impl Ext for FakeExt {
fn storage_at(&self, key: &H256) -> H256 {
self.store.get(key).unwrap_or(&H256::new()).clone()
fn storage_at(&self, key: &H256) -> trie::Result<H256> {
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);
Ok(())
}
fn exists(&self, address: &Address) -> bool {
self.balances.contains_key(address)
fn exists(&self, address: &Address) -> trie::Result<bool> {
Ok(self.balances.contains_key(address))
}
fn exists_and_not_null(&self, address: &Address) -> bool {
self.balances.get(address).map_or(false, |b| !b.is_zero())
fn exists_and_not_null(&self, address: &Address) -> trie::Result<bool> {
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!()
}
fn balance(&self, address: &Address) -> U256 {
self.balances[address]
fn balance(&self, address: &Address) -> trie::Result<U256> {
Ok(self.balances[address])
}
fn blockhash(&self, number: &U256) -> H256 {
@@ -146,12 +147,12 @@ impl Ext for FakeExt {
MessageCallResult::Success(*gas)
}
fn extcode(&self, address: &Address) -> Arc<Bytes> {
self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone()
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>> {
Ok(self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone())
}
fn extcodesize(&self, address: &Address) -> usize {
self.codes.get(address).map_or(0, |c| c.len())
fn extcodesize(&self, address: &Address) -> trie::Result<usize> {
Ok(self.codes.get(address).map_or(0, |c| c.len()))
}
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
@@ -165,7 +166,7 @@ impl Ext for FakeExt {
unimplemented!();
}
fn suicide(&mut self, _refund_address: &Address) {
fn suicide(&mut self, _refund_address: &Address) -> trie::Result<()> {
unimplemented!();
}