EIP-140 (#5477)
This commit is contained in:
parent
2ab21acf11
commit
dd004aba9f
51
ethcore/res/ethereum/metropolis_test.json
Normal file
51
ethcore/res/ethereum/metropolis_test.json
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"name": "Metropolis (Test)",
|
||||||
|
"engine": {
|
||||||
|
"Ethash": {
|
||||||
|
"params": {
|
||||||
|
"gasLimitBoundDivisor": "0x0400",
|
||||||
|
"minimumDifficulty": "0x020000",
|
||||||
|
"difficultyBoundDivisor": "0x0800",
|
||||||
|
"durationLimit": "0x0d",
|
||||||
|
"blockReward": "0x4563918244F40000",
|
||||||
|
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||||
|
"homesteadTransition": "0x0",
|
||||||
|
"eip150Transition": "0x0",
|
||||||
|
"eip155Transition": "0x7fffffffffffffff",
|
||||||
|
"eip160Transition": "0x0",
|
||||||
|
"eip161abcTransition": "0x0",
|
||||||
|
"eip161dTransition": "0x0",
|
||||||
|
"maxCodeSize": 24576
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"accountStartNonce": "0x00",
|
||||||
|
"maximumExtraDataSize": "0x20",
|
||||||
|
"minGasLimit": "0x1388",
|
||||||
|
"networkID" : "0x1",
|
||||||
|
"eip98Transition": "0x7fffffffffffffff",
|
||||||
|
"eip86Transition": "0x0",
|
||||||
|
"eip140Transition": "0x0"
|
||||||
|
},
|
||||||
|
"genesis": {
|
||||||
|
"seal": {
|
||||||
|
"ethereum": {
|
||||||
|
"nonce": "0x0000000000000042",
|
||||||
|
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"difficulty": "0x400000000",
|
||||||
|
"author": "0x0000000000000000000000000000000000000000",
|
||||||
|
"timestamp": "0x00",
|
||||||
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
|
||||||
|
"gasLimit": "0x1388"
|
||||||
|
},
|
||||||
|
"accounts": {
|
||||||
|
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||||
|
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||||
|
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
Subproject commit ef191fdc61cf76cdb9cdc147465fb447304b0ed2
|
Subproject commit 4e8b9be3fba16ec32e0cdf50b8f9329826283aaa
|
@ -75,6 +75,9 @@ pub fn new_transition_test() -> Spec { load(include_bytes!("../../res/ethereum/t
|
|||||||
/// Create a new Foundation Mainnet chain spec without genesis accounts.
|
/// Create a new Foundation Mainnet chain spec without genesis accounts.
|
||||||
pub fn new_mainnet_like() -> Spec { load(include_bytes!("../../res/ethereum/frontier_like_test.json")) }
|
pub fn new_mainnet_like() -> Spec { load(include_bytes!("../../res/ethereum/frontier_like_test.json")) }
|
||||||
|
|
||||||
|
/// Create a new Foundation Metropolis era spec.
|
||||||
|
pub fn new_metropolis_test() -> Spec { load(include_bytes!("../../res/ethereum/metropolis_test.json")) }
|
||||||
|
|
||||||
/// Create a new Foundation Ropsten chain spec.
|
/// Create a new Foundation Ropsten chain spec.
|
||||||
pub fn new_ropsten() -> Spec { load(include_bytes!("../../res/ethereum/ropsten.json")) }
|
pub fn new_ropsten() -> Spec { load(include_bytes!("../../res/ethereum/ropsten.json")) }
|
||||||
|
|
||||||
|
@ -104,8 +104,25 @@ pub type Result<T> = ::std::result::Result<T, Error>;
|
|||||||
pub enum GasLeft<'a> {
|
pub enum GasLeft<'a> {
|
||||||
/// Known gas left
|
/// Known gas left
|
||||||
Known(U256),
|
Known(U256),
|
||||||
/// Return instruction must be processed.
|
/// Return or Revert instruction must be processed.
|
||||||
NeedsReturn(U256, &'a [u8]),
|
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.
|
/// 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
|
/// In practice, this is just used to define an inherent impl on
|
||||||
/// `Reult<GasLeft<'a>>`.
|
/// `Reult<GasLeft<'a>>`.
|
||||||
pub trait Finalize {
|
pub trait Finalize {
|
||||||
/// Consume the externalities, call return if necessary, and produce a final amount of gas left.
|
/// Consume the externalities, call return if necessary, and produce call result.
|
||||||
fn finalize<E: Ext>(self, ext: E) -> Result<U256>;
|
fn finalize<E: Ext>(self, ext: E) -> Result<FinalizationResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Finalize for Result<GasLeft<'a>> {
|
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 {
|
match self {
|
||||||
Ok(GasLeft::Known(gas)) => Ok(gas),
|
Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true }),
|
||||||
Ok(GasLeft::NeedsReturn(gas, ret_code)) => ext.ret(&gas, ret_code),
|
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),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,6 +279,7 @@ lazy_static! {
|
|||||||
arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 0, 6, 1, true, GasPriceTier::Special);
|
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[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[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
|
arr
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -556,6 +557,8 @@ pub const RETURN: Instruction = 0xf3;
|
|||||||
pub const DELEGATECALL: Instruction = 0xf4;
|
pub const DELEGATECALL: Instruction = 0xf4;
|
||||||
/// create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160
|
/// create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160
|
||||||
pub const CREATE2: Instruction = 0xfb;
|
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
|
/// halt execution and register account for later deletion
|
||||||
pub const SUICIDE: Instruction = 0xff;
|
pub const SUICIDE: Instruction = 0xff;
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ impl<Gas: CostType> Gasometer<Gas> {
|
|||||||
instructions::MSTORE8 => {
|
instructions::MSTORE8 => {
|
||||||
Request::GasMem(default_gas, mem_needed_const(stack.peek(0), 1)?)
|
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))?)
|
Request::GasMem(default_gas, mem_needed(stack.peek(0), stack.peek(1))?)
|
||||||
},
|
},
|
||||||
instructions::SHA3 => {
|
instructions::SHA3 => {
|
||||||
|
@ -84,8 +84,16 @@ enum InstructionResult<Gas> {
|
|||||||
Ok,
|
Ok,
|
||||||
UnusedGas(Gas),
|
UnusedGas(Gas),
|
||||||
JumpToPosition(U256),
|
JumpToPosition(U256),
|
||||||
// gas left, init_orf, init_size
|
StopExecutionNeedsReturn {
|
||||||
StopExecutionNeedsReturn(Gas, U256, U256),
|
/// Gas left.
|
||||||
|
gas: Gas,
|
||||||
|
/// Return data offset.
|
||||||
|
init_off: U256,
|
||||||
|
/// Return data size.
|
||||||
|
init_size: U256,
|
||||||
|
/// Apply or revert state changes.
|
||||||
|
apply: bool,
|
||||||
|
},
|
||||||
StopExecution,
|
StopExecution,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,9 +164,13 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
|
|||||||
let pos = self.verify_jump(position, &valid_jump_destinations)?;
|
let pos = self.verify_jump(position, &valid_jump_destinations)?;
|
||||||
reader.position = pos;
|
reader.position = pos;
|
||||||
},
|
},
|
||||||
InstructionResult::StopExecutionNeedsReturn(gas, off, size) => {
|
InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => {
|
||||||
informant.done();
|
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,
|
InstructionResult::StopExecution => break,
|
||||||
_ => {},
|
_ => {},
|
||||||
@ -183,7 +195,8 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
let schedule = ext.schedule();
|
let schedule = ext.schedule();
|
||||||
|
|
||||||
if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
|
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 {
|
return Err(evm::Error::BadInstruction {
|
||||||
instruction: instruction
|
instruction: instruction
|
||||||
@ -363,7 +376,13 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
let init_off = stack.pop_back();
|
let init_off = stack.pop_back();
|
||||||
let init_size = 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 => {
|
instructions::STOP => {
|
||||||
return Ok(InstructionResult::StopExecution);
|
return Ok(InstructionResult::StopExecution);
|
||||||
|
@ -31,7 +31,7 @@ mod tests;
|
|||||||
#[cfg(all(feature="benches", test))]
|
#[cfg(all(feature="benches", test))]
|
||||||
mod benches;
|
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::ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress};
|
||||||
pub use self::factory::{Factory, VMType};
|
pub use self::factory::{Factory, VMType};
|
||||||
pub use self::schedule::Schedule;
|
pub use self::schedule::Schedule;
|
||||||
|
@ -24,6 +24,8 @@ pub struct Schedule {
|
|||||||
pub have_delegate_call: bool,
|
pub have_delegate_call: bool,
|
||||||
/// Does it have a CREATE_P2SH instruction
|
/// Does it have a CREATE_P2SH instruction
|
||||||
pub have_create2: bool,
|
pub have_create2: bool,
|
||||||
|
/// Does it have a REVERT instruction
|
||||||
|
pub have_revert: bool,
|
||||||
/// VM stack limit
|
/// VM stack limit
|
||||||
pub stack_limit: usize,
|
pub stack_limit: usize,
|
||||||
/// Max number of nested calls/creates
|
/// Max number of nested calls/creates
|
||||||
@ -120,6 +122,7 @@ impl Schedule {
|
|||||||
exceptional_failed_code_deposit: true,
|
exceptional_failed_code_deposit: true,
|
||||||
have_delegate_call: true,
|
have_delegate_call: true,
|
||||||
have_create2: have_metropolis_instructions,
|
have_create2: have_metropolis_instructions,
|
||||||
|
have_revert: have_metropolis_instructions,
|
||||||
stack_limit: 1024,
|
stack_limit: 1024,
|
||||||
max_depth: 1024,
|
max_depth: 1024,
|
||||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||||
@ -171,6 +174,7 @@ impl Schedule {
|
|||||||
exceptional_failed_code_deposit: efcd,
|
exceptional_failed_code_deposit: efcd,
|
||||||
have_delegate_call: hdc,
|
have_delegate_call: hdc,
|
||||||
have_create2: false,
|
have_create2: false,
|
||||||
|
have_revert: false,
|
||||||
stack_limit: 1024,
|
stack_limit: 1024,
|
||||||
max_depth: 1024,
|
max_depth: 1024,
|
||||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
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> {
|
fn test_finalize(res: Result<GasLeft, evm::Error>) -> Result<U256, evm::Error> {
|
||||||
match res {
|
match res {
|
||||||
Ok(GasLeft::Known(gas)) => Ok(gas),
|
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),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ use engines::Engine;
|
|||||||
use types::executed::CallType;
|
use types::executed::CallType;
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use error::ExecutionError;
|
use error::ExecutionError;
|
||||||
use evm::{self, Ext, Factory, Finalize, CreateContractAddress};
|
use evm::{self, Ext, Factory, Finalize, CreateContractAddress, FinalizationResult};
|
||||||
use externalities::*;
|
use externalities::*;
|
||||||
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
|
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
|
||||||
use transaction::{Action, SignedTransaction};
|
use transaction::{Action, SignedTransaction};
|
||||||
@ -246,7 +246,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
output_policy: OutputPolicy,
|
output_policy: OutputPolicy,
|
||||||
tracer: &mut T,
|
tracer: &mut T,
|
||||||
vm_tracer: &mut V
|
vm_tracer: &mut V
|
||||||
) -> evm::Result<U256> where T: Tracer, V: VMTracer {
|
) -> evm::Result<FinalizationResult> where T: Tracer, V: VMTracer {
|
||||||
|
|
||||||
let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH);
|
let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH);
|
||||||
|
|
||||||
@ -366,9 +366,9 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
|
|
||||||
let traces = subtracer.traces();
|
let traces = subtracer.traces();
|
||||||
match res {
|
match res {
|
||||||
Ok(ref gas_left) => tracer.trace_call(
|
Ok(ref res) => tracer.trace_call(
|
||||||
trace_info,
|
trace_info,
|
||||||
gas - *gas_left,
|
gas - res.gas_left,
|
||||||
trace_output,
|
trace_output,
|
||||||
traces
|
traces
|
||||||
),
|
),
|
||||||
@ -379,7 +379,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
|
|
||||||
self.enact_result(&res, substate, unconfirmed_substate);
|
self.enact_result(&res, substate, unconfirmed_substate);
|
||||||
trace!(target: "executive", "enacted: substate={:?}\n", substate);
|
trace!(target: "executive", "enacted: substate={:?}\n", substate);
|
||||||
res
|
res.map(|r| r.gas_left)
|
||||||
} else {
|
} else {
|
||||||
// otherwise it's just a basic transaction, only do tracing, if necessary.
|
// otherwise it's just a basic transaction, only do tracing, if necessary.
|
||||||
self.state.discard_checkpoint();
|
self.state.discard_checkpoint();
|
||||||
@ -438,9 +438,9 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
vm_tracer.done_subtrace(subvmtracer);
|
vm_tracer.done_subtrace(subvmtracer);
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(ref gas_left) => tracer.trace_create(
|
Ok(ref res) => tracer.trace_create(
|
||||||
trace_info,
|
trace_info,
|
||||||
gas - *gas_left,
|
gas - res.gas_left,
|
||||||
trace_output,
|
trace_output,
|
||||||
created,
|
created,
|
||||||
subtracer.traces()
|
subtracer.traces()
|
||||||
@ -449,7 +449,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.enact_result(&res, substate, unconfirmed_substate);
|
self.enact_result(&res, substate, unconfirmed_substate);
|
||||||
res
|
res.map(|r| r.gas_left)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finalizes the transaction (does refunds and suicides).
|
/// Finalizes the transaction (does refunds and suicides).
|
||||||
@ -536,14 +536,15 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enact_result(&mut self, result: &evm::Result<U256>, substate: &mut Substate, un_substate: Substate) {
|
fn enact_result(&mut self, result: &evm::Result<FinalizationResult>, substate: &mut Substate, un_substate: Substate) {
|
||||||
match *result {
|
match *result {
|
||||||
Err(evm::Error::OutOfGas)
|
Err(evm::Error::OutOfGas)
|
||||||
| Err(evm::Error::BadJumpDestination {..})
|
| Err(evm::Error::BadJumpDestination {..})
|
||||||
| Err(evm::Error::BadInstruction {.. })
|
| Err(evm::Error::BadInstruction {.. })
|
||||||
| Err(evm::Error::StackUnderflow {..})
|
| Err(evm::Error::StackUnderflow {..})
|
||||||
| Err(evm::Error::BuiltIn {..})
|
| Err(evm::Error::BuiltIn {..})
|
||||||
| Err(evm::Error::OutOfStack {..}) => {
|
| Err(evm::Error::OutOfStack {..})
|
||||||
|
| Ok(FinalizationResult { apply_state: false, .. }) => {
|
||||||
self.state.revert_to_checkpoint();
|
self.state.revert_to_checkpoint();
|
||||||
},
|
},
|
||||||
Ok(_) | Err(evm::Error::Internal(_)) => {
|
Ok(_) | Err(evm::Error::Internal(_)) => {
|
||||||
@ -1242,11 +1243,43 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Err(_) => {
|
Err(_) => {},
|
||||||
},
|
_ => panic!("Expected OutOfGas"),
|
||||||
_ => {
|
|
||||||
panic!("Expected OutOfGas");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evm_test!{test_revert: test_revert_jit, test_revert_int}
|
||||||
|
fn test_revert(factory: Factory) {
|
||||||
|
let contract_address = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
|
||||||
|
let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||||
|
// EIP-140 test case
|
||||||
|
let code = "6c726576657274656420646174616000557f726576657274206d657373616765000000000000000000000000000000000000600052600e6000fd".from_hex().unwrap();
|
||||||
|
let returns = "726576657274206d657373616765".from_hex().unwrap();
|
||||||
|
let mut state = get_temp_state();
|
||||||
|
state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap();
|
||||||
|
state.commit().unwrap();
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.address = contract_address.clone();
|
||||||
|
params.sender = sender.clone();
|
||||||
|
params.origin = sender.clone();
|
||||||
|
params.gas = U256::from(20025);
|
||||||
|
params.code = Some(Arc::new(code));
|
||||||
|
params.value = ActionValue::Transfer(U256::zero());
|
||||||
|
let mut state = get_temp_state();
|
||||||
|
state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap();
|
||||||
|
let info = EnvInfo::default();
|
||||||
|
let engine = TestEngine::new_metropolis();
|
||||||
|
let mut substate = Substate::new();
|
||||||
|
|
||||||
|
let mut output = [0u8; 14];
|
||||||
|
let result = {
|
||||||
|
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||||
|
ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(result, U256::from(1));
|
||||||
|
assert_eq!(output[..], returns[..]);
|
||||||
|
assert_eq!(state.storage_at(&contract_address, &H256::from(&U256::zero())).unwrap(), H256::from(&U256::from(0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,9 +254,9 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
|
|||||||
|
|
||||||
match res {
|
match res {
|
||||||
Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."),
|
Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."),
|
||||||
Ok(gas_left) => {
|
Ok(res) => {
|
||||||
fail_unless(!out_of_gas, "expected to run out of gas.");
|
fail_unless(!out_of_gas, "expected to run out of gas.");
|
||||||
fail_unless(Some(gas_left) == vm.gas_left.map(Into::into), "gas_left is incorrect");
|
fail_unless(Some(res.gas_left) == vm.gas_left.map(Into::into), "gas_left is incorrect");
|
||||||
let vm_output: Option<Vec<u8>> = vm.output.map(Into::into);
|
let vm_output: Option<Vec<u8>> = vm.output.map(Into::into);
|
||||||
fail_unless(Some(output) == vm_output, "output is incorrect");
|
fail_unless(Some(output) == vm_output, "output is incorrect");
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ lazy_static! {
|
|||||||
pub static ref HOMESTEAD: Spec = ethereum::new_homestead_test();
|
pub static ref HOMESTEAD: Spec = ethereum::new_homestead_test();
|
||||||
pub static ref EIP150: Spec = ethereum::new_eip150_test();
|
pub static ref EIP150: Spec = ethereum::new_eip150_test();
|
||||||
pub static ref EIP161: Spec = ethereum::new_eip161_test();
|
pub static ref EIP161: Spec = ethereum::new_eip161_test();
|
||||||
|
pub static ref _METROPOLIS: Spec = ethereum::new_metropolis_test();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn json_chain_test(json_data: &[u8]) -> Vec<String> {
|
pub fn json_chain_test(json_data: &[u8]) -> Vec<String> {
|
||||||
@ -92,7 +93,6 @@ mod state_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare_test!{GeneralStateTest_stAttackTest, "GeneralStateTests/stAttackTest/"}
|
declare_test!{GeneralStateTest_stAttackTest, "GeneralStateTests/stAttackTest/"}
|
||||||
declare_test!{GeneralStateTest_stBlockHashTest, "GeneralStateTests/stBlockHashTest/"}
|
|
||||||
declare_test!{GeneralStateTest_stBoundsTest, "GeneralStateTests/stBoundsTest/"}
|
declare_test!{GeneralStateTest_stBoundsTest, "GeneralStateTests/stBoundsTest/"}
|
||||||
declare_test!{GeneralStateTest_stCallCodes, "GeneralStateTests/stCallCodes/"}
|
declare_test!{GeneralStateTest_stCallCodes, "GeneralStateTests/stCallCodes/"}
|
||||||
declare_test!{skip => [ "createJS_ExampleContract" ], GeneralStateTest_stCallCreateCallCodeTest, "GeneralStateTests/stCallCreateCallCodeTest/"}
|
declare_test!{skip => [ "createJS_ExampleContract" ], GeneralStateTest_stCallCreateCallCodeTest, "GeneralStateTests/stCallCreateCallCodeTest/"}
|
||||||
|
@ -61,6 +61,8 @@ pub struct CommonParams {
|
|||||||
pub validate_receipts_transition: u64,
|
pub validate_receipts_transition: u64,
|
||||||
/// Number of first block where EIP-86 (Metropolis) rules begin.
|
/// Number of first block where EIP-86 (Metropolis) rules begin.
|
||||||
pub eip86_transition: BlockNumber,
|
pub eip86_transition: BlockNumber,
|
||||||
|
/// Number of first block where EIP-140 (Metropolis: REVERT opcode) rules begin.
|
||||||
|
pub eip140_transition: BlockNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethjson::spec::Params> for CommonParams {
|
impl From<ethjson::spec::Params> for CommonParams {
|
||||||
@ -76,6 +78,7 @@ impl From<ethjson::spec::Params> for CommonParams {
|
|||||||
eip98_transition: p.eip98_transition.map_or(0, Into::into),
|
eip98_transition: p.eip98_transition.map_or(0, Into::into),
|
||||||
validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into),
|
validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into),
|
||||||
eip86_transition: p.eip86_transition.map_or(BlockNumber::max_value(), Into::into),
|
eip86_transition: p.eip86_transition.map_or(BlockNumber::max_value(), Into::into),
|
||||||
|
eip140_transition: p.eip140_transition.map_or(BlockNumber::max_value(), Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,13 @@ impl TestEngine {
|
|||||||
max_depth: max_depth,
|
max_depth: max_depth,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_metropolis() -> TestEngine {
|
||||||
|
TestEngine {
|
||||||
|
engine: ethereum::new_metropolis_test().engine,
|
||||||
|
max_depth: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine for TestEngine {
|
impl Engine for TestEngine {
|
||||||
@ -72,7 +79,7 @@ impl Engine for TestEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn schedule(&self, _block_number: u64) -> Schedule {
|
fn schedule(&self, _block_number: u64) -> Schedule {
|
||||||
let mut schedule = Schedule::new_frontier();
|
let mut schedule = self.engine.schedule(0);
|
||||||
schedule.max_depth = self.max_depth;
|
schedule.max_depth = self.max_depth;
|
||||||
schedule
|
schedule
|
||||||
}
|
}
|
||||||
|
@ -75,12 +75,12 @@ pub fn run_vm(params: ActionParams) -> Result<Success, Failure> {
|
|||||||
let mut ext = ext::FakeExt::default();
|
let mut ext = ext::FakeExt::default();
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let gas_left = vm.exec(params, &mut ext).finalize(ext);
|
let res = vm.exec(params, &mut ext).finalize(ext);
|
||||||
let duration = start.elapsed();
|
let duration = start.elapsed();
|
||||||
|
|
||||||
match gas_left {
|
match res {
|
||||||
Ok(gas_left) => Ok(Success {
|
Ok(res) => Ok(Success {
|
||||||
gas_used: initial_gas - gas_left,
|
gas_used: initial_gas - res.gas_left,
|
||||||
// TODO [ToDr] get output from ext
|
// TODO [ToDr] get output from ext
|
||||||
output: Vec::new(),
|
output: Vec::new(),
|
||||||
time: duration,
|
time: duration,
|
||||||
|
@ -59,6 +59,9 @@ pub struct Params {
|
|||||||
/// See `CommonParams` docs.
|
/// See `CommonParams` docs.
|
||||||
#[serde(rename="eip86Transition")]
|
#[serde(rename="eip86Transition")]
|
||||||
pub eip86_transition: Option<Uint>,
|
pub eip86_transition: Option<Uint>,
|
||||||
|
/// See `CommonParams` docs.
|
||||||
|
#[serde(rename="eip140Transition")]
|
||||||
|
pub eip140_transition: Option<Uint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
Reference in New Issue
Block a user