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

@@ -74,39 +74,39 @@ impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B>
address: Address,
tracer: &'a mut T,
vm_tracer: &'a mut V,
) -> Self {
TestExt {
contract_address: contract_address(&address, &state.nonce(&address)),
) -> trie::Result<Self> {
Ok(TestExt {
contract_address: contract_address(&address, &state.nonce(&address)?),
ext: Externalities::new(state, info, engine, vm_factory, depth, origin_info, substate, output, tracer, vm_tracer),
callcreates: vec![]
}
})
}
}
impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
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)
}
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)
}
fn exists(&self, address: &Address) -> bool {
fn exists(&self, address: &Address) -> trie::Result<bool> {
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)
}
fn balance(&self, address: &Address) -> U256 {
fn balance(&self, address: &Address) -> trie::Result<U256> {
self.ext.balance(address)
}
fn origin_balance(&self) -> U256 {
fn origin_balance(&self) -> trie::Result<U256> {
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)
}
fn extcode(&self, address: &Address) -> Arc<Bytes> {
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>> {
self.ext.extcode(address)
}
fn extcodesize(&self, address: &Address) -> usize {
fn extcodesize(&self, address: &Address) -> trie::Result<usize> {
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)
}
fn suicide(&mut self, refund_address: &Address) {
fn suicide(&mut self, refund_address: &Address) -> trie::Result<()> {
self.ext.suicide(refund_address)
}
@@ -201,6 +201,19 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
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 mut state_result = get_temp_state();
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
let (res, callcreates) = {
let mut ex = TestExt::new(
let mut ex = try_fail!(TestExt::new(
&mut state,
&info,
&engine,
@@ -229,7 +242,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
params.address.clone(),
&mut tracer,
&mut vm_tracer,
);
));
let mut evm = vm_factory.create(params.gas);
let res = evm.exec(params, &mut ex);
// 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() {
let address = address.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");
fail_unless(state.balance(&address) == account.balance.into(), "balance is incorrect");
fail_unless(state.nonce(&address) == account.nonce.into(), "nonce is incorrect");
account.storage.into_iter().foreach(|(k, v)| {
let found_code = try_fail!(state.code(&address));
let found_balance = try_fail!(state.balance(&address));
let found_nonce = try_fail!(state.nonce(&address));
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 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());