This repository has been archived by the owner on Nov 6, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Executive revert fix #115
Merged
Merged
Executive revert fix #115
Changes from 15 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
05246c4
fixing executive finalize in progress
debris d59e074
executive create
debris a6ea012
-1i64..
debris 777ac4d
compiler was not wrong
debris 6fb580f
ext call refactored
debris 9cbf242
call result
debris 98ae8ce
cleanup...
debris 4ca353b
common changes, added json state tests
debris f06d313
fixed env_info lasthashes generation
debris ff373f5
Merge branch 'master' of https://github.com/gavofyork/ethcore into ex…
debris cb0ad01
test_engine should limit max_depth, not stack_limit
debris a619126
tests are passing
debris ceea85a
common fixes..
debris 1b8b1b4
Merge branch 'master' of https://github.com/gavofyork/ethcore into ex…
debris daccbed
removed redundant code
debris 7ace87e
fixes for review issues
debris File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,8 @@ pub struct Substate { | |
logs: Vec<LogEntry>, | ||
/// Refund counter of SSTORE nonzero->zero. | ||
refunds_count: U256, | ||
/// True if transaction, or one of it's subcalls runs out of gas. | ||
out_of_gas: bool, | ||
/// Created contracts. | ||
contracts_created: Vec<Address> | ||
} | ||
|
@@ -32,9 +34,12 @@ impl Substate { | |
suicides: HashSet::new(), | ||
logs: vec![], | ||
refunds_count: U256::zero(), | ||
out_of_gas: false, | ||
contracts_created: vec![] | ||
} | ||
} | ||
|
||
pub fn out_of_gas(&self) -> bool { self.out_of_gas } | ||
} | ||
|
||
/// Transaction execution receipt. | ||
|
@@ -135,7 +140,6 @@ impl<'a> Executive<'a> { | |
self.state.sub_balance(&sender, &U256::from(gas_cost)); | ||
|
||
let mut substate = Substate::new(); | ||
let backup = self.state.clone(); | ||
|
||
let schedule = self.engine.schedule(self.info); | ||
let init_gas = t.gas - U256::from(t.gas_required(&schedule)); | ||
|
@@ -172,14 +176,17 @@ impl<'a> Executive<'a> { | |
}; | ||
|
||
// finalize here! | ||
Ok(try!(self.finalize(t, substate, backup, res))) | ||
Ok(try!(self.finalize(t, substate, res))) | ||
} | ||
|
||
/// Calls contract function with given contract params. | ||
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). | ||
/// Modifies the substate and the output. | ||
/// Returns either gas_left or `evm::Error`. | ||
pub fn call(&mut self, params: &ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result { | ||
// backup used in case of running out of gas | ||
let backup = self.state.clone(); | ||
|
||
// at first, transfer value to destination | ||
self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); | ||
|
||
|
@@ -191,13 +198,19 @@ impl<'a> Executive<'a> { | |
self.engine.execute_builtin(¶ms.address, ¶ms.data, &mut output); | ||
Ok(params.gas - cost) | ||
}, | ||
false => Err(evm::Error::OutOfGas) | ||
// just drain the whole gas | ||
false => Ok(U256::zero()) | ||
} | ||
} else if params.code.len() > 0 { | ||
// if destination is a contract, do normal message call | ||
let mut ext = Externalities::from_executive(self, params, substate, OutputPolicy::Return(output)); | ||
let evm = Factory::create(); | ||
evm.exec(¶ms, &mut ext) | ||
|
||
let res = { | ||
let mut ext = Externalities::from_executive(self, params, substate, OutputPolicy::Return(output)); | ||
let evm = Factory::create(); | ||
evm.exec(¶ms, &mut ext) | ||
}; | ||
self.revert_if_needed(&res, substate, backup); | ||
res | ||
} else { | ||
// otherwise, nothing | ||
Ok(params.gas) | ||
|
@@ -208,32 +221,28 @@ impl<'a> Executive<'a> { | |
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). | ||
/// Modifies the substate. | ||
fn create(&mut self, params: &ActionParams, substate: &mut Substate) -> evm::Result { | ||
// backup used in case of running out of gas | ||
let backup = self.state.clone(); | ||
|
||
// at first create new contract | ||
self.state.new_contract(¶ms.address); | ||
|
||
// then transfer value to it | ||
self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); | ||
|
||
let mut ext = Externalities::from_executive(self, params, substate, OutputPolicy::InitContract); | ||
let evm = Factory::create(); | ||
evm.exec(¶ms, &mut ext) | ||
let res = { | ||
let mut ext = Externalities::from_executive(self, params, substate, OutputPolicy::InitContract); | ||
let evm = Factory::create(); | ||
evm.exec(¶ms, &mut ext) | ||
}; | ||
self.revert_if_needed(&res, substate, backup); | ||
res | ||
} | ||
|
||
/// Finalizes the transaction (does refunds and suicides). | ||
fn finalize(&mut self, t: &Transaction, substate: Substate, backup: State, result: evm::Result) -> ExecutionResult { | ||
fn finalize(&mut self, t: &Transaction, substate: Substate, result: evm::Result) -> ExecutionResult { | ||
match result { | ||
Err(evm::Error::Internal) => Err(ExecutionError::Internal), | ||
Err(evm::Error::OutOfGas) => { | ||
*self.state = backup; | ||
Ok(Executed { | ||
gas: t.gas, | ||
gas_used: t.gas, | ||
refunded: U256::zero(), | ||
cumulative_gas_used: self.info.gas_used + t.gas, | ||
logs: vec![], | ||
out_of_gas: true, | ||
contracts_created: vec![] | ||
}) | ||
}, | ||
Ok(gas_left) => { | ||
let schedule = self.engine.schedule(self.info); | ||
|
||
|
@@ -265,12 +274,30 @@ impl<'a> Executive<'a> { | |
refunded: refund, | ||
cumulative_gas_used: self.info.gas_used + gas_used, | ||
logs: substate.logs, | ||
out_of_gas: false, | ||
out_of_gas: substate.out_of_gas, | ||
contracts_created: substate.contracts_created | ||
}) | ||
}, | ||
_err => { | ||
Ok(Executed { | ||
gas: t.gas, | ||
gas_used: t.gas, | ||
refunded: U256::zero(), | ||
cumulative_gas_used: self.info.gas_used + t.gas, | ||
logs: vec![], | ||
out_of_gas: true, | ||
contracts_created: vec![] | ||
}) | ||
} | ||
} | ||
} | ||
|
||
fn revert_if_needed(&mut self, result: &evm::Result, substate: &mut Substate, backup: State) { | ||
if let &Err(evm::Error::OutOfGas) = result { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just |
||
substate.out_of_gas = true; | ||
self.state.revert(backup); | ||
} | ||
} | ||
} | ||
|
||
/// Policy for handling output data on `RETURN` opcode. | ||
|
@@ -354,10 +381,10 @@ impl<'a> Ext for Externalities<'a> { | |
} | ||
} | ||
|
||
fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> Result<(U256, Option<Address>), evm::Error> { | ||
fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> (U256, Option<Address>) { | ||
// if balance is insufficient or we are to deep, return | ||
if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth { | ||
return Ok((*gas, None)); | ||
return (*gas, None); | ||
} | ||
|
||
// create new contract address | ||
|
@@ -377,10 +404,20 @@ impl<'a> Ext for Externalities<'a> { | |
|
||
let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); | ||
ex.state.inc_nonce(&self.params.address); | ||
ex.create(¶ms, self.substate).map(|gas_left| (gas_left, Some(address))) | ||
match ex.create(¶ms, self.substate) { | ||
Ok(gas_left) => (gas_left, Some(address)), | ||
_ => (U256::zero(), None) | ||
} | ||
} | ||
|
||
fn call(&mut self, gas: &U256, call_gas: &U256, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address, output: &mut [u8]) -> Result<U256, evm::Error> { | ||
fn call(&mut self, | ||
gas: &U256, | ||
call_gas: &U256, | ||
receive_address: &Address, | ||
value: &U256, | ||
data: &[u8], | ||
code_address: &Address, | ||
output: &mut [u8]) -> Result<(U256, bool), evm::Error> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. consider a less general type than |
||
let mut gas_cost = *call_gas; | ||
let mut call_gas = *call_gas; | ||
|
||
|
@@ -396,14 +433,14 @@ impl<'a> Ext for Externalities<'a> { | |
} | ||
|
||
if gas_cost > *gas { | ||
return Err(evm::Error::OutOfGas) | ||
return Err(evm::Error::OutOfGas); | ||
} | ||
|
||
let gas = *gas - gas_cost; | ||
|
||
// if balance is insufficient or we are to deep, return | ||
if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth { | ||
return Ok(gas + call_gas) | ||
return Ok((gas + call_gas, true)); | ||
} | ||
|
||
let params = ActionParams { | ||
|
@@ -418,7 +455,10 @@ impl<'a> Ext for Externalities<'a> { | |
}; | ||
|
||
let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); | ||
ex.call(¶ms, self.substate, BytesRef::Fixed(output)).map(|gas_left| gas + gas_left) | ||
match ex.call(¶ms, self.substate, BytesRef::Fixed(output)) { | ||
Ok(gas_left) => Ok((gas + gas_left, true)), //Some(CallResult::new(gas + gas_left, true)), | ||
_ => Ok((gas, false)) | ||
} | ||
} | ||
|
||
fn extcode(&self, address: &Address) -> Vec<u8> { | ||
|
@@ -832,9 +872,9 @@ mod tests { | |
}; | ||
|
||
assert_eq!(executed.gas, U256::from(100_000)); | ||
assert_eq!(executed.gas_used, U256::from(20_025)); | ||
assert_eq!(executed.refunded, U256::from(79_975)); | ||
assert_eq!(executed.cumulative_gas_used, U256::from(20_025)); | ||
assert_eq!(executed.gas_used, U256::from(41_301)); | ||
assert_eq!(executed.refunded, U256::from(58_699)); | ||
assert_eq!(executed.cumulative_gas_used, U256::from(41_301)); | ||
assert_eq!(executed.logs.len(), 0); | ||
assert_eq!(executed.out_of_gas, false); | ||
assert_eq!(executed.contracts_created.len(), 0); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its