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:
committed by
Gav Wood
parent
eb9ee35d6c
commit
1bf2b27708
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
@@ -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(¶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 {
|
||||
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(¶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)
|
||||
},
|
||||
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)
|
||||
},
|
||||
instructions::DELEGATECALL => (¶ms.sender, ¶ms.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(¤t_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 => {
|
||||
|
||||
@@ -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!();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user