EIP-140 (#5477)
This commit is contained in:
committed by
Nikolay Volf
parent
2ab21acf11
commit
dd004aba9f
@@ -104,8 +104,25 @@ pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
pub enum GasLeft<'a> {
|
||||
/// Known gas left
|
||||
Known(U256),
|
||||
/// Return instruction must be processed.
|
||||
NeedsReturn(U256, &'a [u8]),
|
||||
/// Return or Revert instruction must be processed.
|
||||
NeedsReturn {
|
||||
/// Amount of gas left.
|
||||
gas_left: U256,
|
||||
/// Return data buffer.
|
||||
data: &'a [u8],
|
||||
/// Apply or revert state changes on revert.
|
||||
apply_state: bool
|
||||
},
|
||||
}
|
||||
|
||||
/// Finalization result. Gas Left: either it is a known value, or it needs to be computed by processing
|
||||
/// a return instruction.
|
||||
#[derive(Debug)]
|
||||
pub struct FinalizationResult {
|
||||
/// Final amount of gas left.
|
||||
pub gas_left: U256,
|
||||
/// Apply execution state changes or revert them.
|
||||
pub apply_state: bool,
|
||||
}
|
||||
|
||||
/// Types that can be "finalized" using an EVM.
|
||||
@@ -113,15 +130,18 @@ pub enum GasLeft<'a> {
|
||||
/// In practice, this is just used to define an inherent impl on
|
||||
/// `Reult<GasLeft<'a>>`.
|
||||
pub trait Finalize {
|
||||
/// Consume the externalities, call return if necessary, and produce a final amount of gas left.
|
||||
fn finalize<E: Ext>(self, ext: E) -> Result<U256>;
|
||||
/// Consume the externalities, call return if necessary, and produce call result.
|
||||
fn finalize<E: Ext>(self, ext: E) -> Result<FinalizationResult>;
|
||||
}
|
||||
|
||||
impl<'a> Finalize for Result<GasLeft<'a>> {
|
||||
fn finalize<E: Ext>(self, ext: E) -> Result<U256> {
|
||||
fn finalize<E: Ext>(self, ext: E) -> Result<FinalizationResult> {
|
||||
match self {
|
||||
Ok(GasLeft::Known(gas)) => Ok(gas),
|
||||
Ok(GasLeft::NeedsReturn(gas, ret_code)) => ext.ret(&gas, ret_code),
|
||||
Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true }),
|
||||
Ok(GasLeft::NeedsReturn {gas_left, data, apply_state}) => ext.ret(&gas_left, data).map(|gas_left| FinalizationResult {
|
||||
gas_left: gas_left,
|
||||
apply_state: apply_state,
|
||||
}),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,6 +279,7 @@ lazy_static! {
|
||||
arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 0, 6, 1, true, GasPriceTier::Special);
|
||||
arr[SUICIDE as usize] = InstructionInfo::new("SUICIDE", 0, 1, 0, true, GasPriceTier::Special);
|
||||
arr[CREATE2 as usize] = InstructionInfo::new("CREATE2", 0, 3, 1, true, GasPriceTier::Special);
|
||||
arr[REVERT as usize] = InstructionInfo::new("REVERT", 0, 2, 0, true, GasPriceTier::Zero);
|
||||
arr
|
||||
};
|
||||
}
|
||||
@@ -556,6 +557,8 @@ pub const RETURN: Instruction = 0xf3;
|
||||
pub const DELEGATECALL: Instruction = 0xf4;
|
||||
/// create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160
|
||||
pub const CREATE2: Instruction = 0xfb;
|
||||
/// stop execution and revert state changes. Return output data.
|
||||
pub const REVERT: Instruction = 0xfd;
|
||||
/// halt execution and register account for later deletion
|
||||
pub const SUICIDE: Instruction = 0xff;
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ impl<Gas: CostType> Gasometer<Gas> {
|
||||
instructions::MSTORE8 => {
|
||||
Request::GasMem(default_gas, mem_needed_const(stack.peek(0), 1)?)
|
||||
},
|
||||
instructions::RETURN => {
|
||||
instructions::RETURN | instructions::REVERT => {
|
||||
Request::GasMem(default_gas, mem_needed(stack.peek(0), stack.peek(1))?)
|
||||
},
|
||||
instructions::SHA3 => {
|
||||
|
||||
@@ -84,8 +84,16 @@ enum InstructionResult<Gas> {
|
||||
Ok,
|
||||
UnusedGas(Gas),
|
||||
JumpToPosition(U256),
|
||||
// gas left, init_orf, init_size
|
||||
StopExecutionNeedsReturn(Gas, U256, U256),
|
||||
StopExecutionNeedsReturn {
|
||||
/// Gas left.
|
||||
gas: Gas,
|
||||
/// Return data offset.
|
||||
init_off: U256,
|
||||
/// Return data size.
|
||||
init_size: U256,
|
||||
/// Apply or revert state changes.
|
||||
apply: bool,
|
||||
},
|
||||
StopExecution,
|
||||
}
|
||||
|
||||
@@ -156,9 +164,13 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
|
||||
let pos = self.verify_jump(position, &valid_jump_destinations)?;
|
||||
reader.position = pos;
|
||||
},
|
||||
InstructionResult::StopExecutionNeedsReturn(gas, off, size) => {
|
||||
InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => {
|
||||
informant.done();
|
||||
return Ok(GasLeft::NeedsReturn(gas.as_u256(), self.mem.read_slice(off, size)));
|
||||
return Ok(GasLeft::NeedsReturn {
|
||||
gas_left: gas.as_u256(),
|
||||
data: self.mem.read_slice(init_off, init_size),
|
||||
apply_state: apply
|
||||
});
|
||||
},
|
||||
InstructionResult::StopExecution => break,
|
||||
_ => {},
|
||||
@@ -183,7 +195,8 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
let schedule = ext.schedule();
|
||||
|
||||
if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
|
||||
(instruction == instructions::CREATE2 && !schedule.have_create2) {
|
||||
(instruction == instructions::CREATE2 && !schedule.have_create2) ||
|
||||
(instruction == instructions::REVERT && !schedule.have_revert) {
|
||||
|
||||
return Err(evm::Error::BadInstruction {
|
||||
instruction: instruction
|
||||
@@ -363,7 +376,13 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
let init_off = stack.pop_back();
|
||||
let init_size = stack.pop_back();
|
||||
|
||||
return Ok(InstructionResult::StopExecutionNeedsReturn(gas, init_off, init_size))
|
||||
return Ok(InstructionResult::StopExecutionNeedsReturn {gas: gas, init_off: init_off, init_size: init_size, apply: true})
|
||||
},
|
||||
instructions::REVERT => {
|
||||
let init_off = stack.pop_back();
|
||||
let init_size = stack.pop_back();
|
||||
|
||||
return Ok(InstructionResult::StopExecutionNeedsReturn {gas: gas, init_off: init_off, init_size: init_size, apply: false})
|
||||
},
|
||||
instructions::STOP => {
|
||||
return Ok(InstructionResult::StopExecution);
|
||||
|
||||
@@ -31,7 +31,7 @@ mod tests;
|
||||
#[cfg(all(feature="benches", test))]
|
||||
mod benches;
|
||||
|
||||
pub use self::evm::{Evm, Error, Finalize, GasLeft, Result, CostType};
|
||||
pub use self::evm::{Evm, Error, Finalize, FinalizationResult, GasLeft, Result, CostType};
|
||||
pub use self::ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress};
|
||||
pub use self::factory::{Factory, VMType};
|
||||
pub use self::schedule::Schedule;
|
||||
|
||||
@@ -24,6 +24,8 @@ pub struct Schedule {
|
||||
pub have_delegate_call: bool,
|
||||
/// Does it have a CREATE_P2SH instruction
|
||||
pub have_create2: bool,
|
||||
/// Does it have a REVERT instruction
|
||||
pub have_revert: bool,
|
||||
/// VM stack limit
|
||||
pub stack_limit: usize,
|
||||
/// Max number of nested calls/creates
|
||||
@@ -120,6 +122,7 @@ impl Schedule {
|
||||
exceptional_failed_code_deposit: true,
|
||||
have_delegate_call: true,
|
||||
have_create2: have_metropolis_instructions,
|
||||
have_revert: have_metropolis_instructions,
|
||||
stack_limit: 1024,
|
||||
max_depth: 1024,
|
||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||
@@ -171,6 +174,7 @@ impl Schedule {
|
||||
exceptional_failed_code_deposit: efcd,
|
||||
have_delegate_call: hdc,
|
||||
have_create2: false,
|
||||
have_revert: false,
|
||||
stack_limit: 1024,
|
||||
max_depth: 1024,
|
||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||
|
||||
@@ -64,7 +64,7 @@ pub struct FakeExt {
|
||||
fn test_finalize(res: Result<GasLeft, evm::Error>) -> Result<U256, evm::Error> {
|
||||
match res {
|
||||
Ok(GasLeft::Known(gas)) => Ok(gas),
|
||||
Ok(GasLeft::NeedsReturn(_, _)) => unimplemented!(), // since ret is unimplemented.
|
||||
Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented.
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user