v2.5.8-stable (#11041)
* add more tx tests (#11038) * Fix parallel transactions race-condition (#10995) * Add blake2_f precompile (#11017) * [trace] introduce trace failed to Ext (#11019) * Edit publish-onchain.sh to use https (#11016) * Fix deadlock in network-devp2p (#11013) * EIP 1108: Reduce alt_bn128 precompile gas costs (#11008) * xDai chain support and nodes list update (#10989) * EIP 2028: transaction gas lowered from 68 to 16 (#10987) * EIP-1344 Add CHAINID op-code (#10983) * manual publish jobs for releases, no changes for nightlies (#10977) * [blooms-db] Fix benchmarks (#10974) * Verify transaction against its block during import (#10954) * Better error message for rpc gas price errors (#10931) * tx-pool: accept local tx with higher gas price when pool full (#10901) * Fix fork choice (#10837) * Cleanup unused vm dependencies (#10787) * Fix compilation on recent nightlies (#10991)
This commit is contained in:
@@ -47,7 +47,7 @@ impl Factory {
|
||||
/// for caching jump destinations.
|
||||
pub fn new(evm: VMType, cache_size: usize) -> Self {
|
||||
Factory {
|
||||
evm: evm,
|
||||
evm,
|
||||
evm_cache: Arc::new(SharedCache::new(cache_size)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +149,8 @@ enum_with_from_u8! {
|
||||
DIFFICULTY = 0x44,
|
||||
#[doc = "get the block's gas limit"]
|
||||
GASLIMIT = 0x45,
|
||||
#[doc = "get chain ID"]
|
||||
CHAINID = 0x46,
|
||||
|
||||
#[doc = "remove item from stack"]
|
||||
POP = 0x50,
|
||||
@@ -442,12 +444,7 @@ pub struct InstructionInfo {
|
||||
impl InstructionInfo {
|
||||
/// Create new instruction info.
|
||||
pub fn new(name: &'static str, args: usize, ret: usize, tier: GasPriceTier) -> Self {
|
||||
InstructionInfo {
|
||||
name: name,
|
||||
args: args,
|
||||
ret: ret,
|
||||
tier: tier
|
||||
}
|
||||
InstructionInfo { name, args, ret, tier }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,6 +501,7 @@ lazy_static! {
|
||||
arr[NUMBER as usize] = Some(InstructionInfo::new("NUMBER", 0, 1, GasPriceTier::Base));
|
||||
arr[DIFFICULTY as usize] = Some(InstructionInfo::new("DIFFICULTY", 0, 1, GasPriceTier::Base));
|
||||
arr[GASLIMIT as usize] = Some(InstructionInfo::new("GASLIMIT", 0, 1, GasPriceTier::Base));
|
||||
arr[CHAINID as usize] = Some(InstructionInfo::new("CHAINID", 0, 1, GasPriceTier::Base));
|
||||
arr[POP as usize] = Some(InstructionInfo::new("POP", 1, 0, GasPriceTier::Base));
|
||||
arr[MLOAD as usize] = Some(InstructionInfo::new("MLOAD", 1, 1, GasPriceTier::VeryLow));
|
||||
arr[MSTORE as usize] = Some(InstructionInfo::new("MSTORE", 2, 0, GasPriceTier::VeryLow));
|
||||
|
||||
@@ -119,8 +119,6 @@ enum InstructionResult<Gas> {
|
||||
Trap(TrapKind),
|
||||
}
|
||||
|
||||
enum Never {}
|
||||
|
||||
/// ActionParams without code, so that it can be feed into CodeReader.
|
||||
#[derive(Debug)]
|
||||
struct InterpreterParams {
|
||||
@@ -178,12 +176,6 @@ pub enum InterpreterResult {
|
||||
Trap(TrapKind),
|
||||
}
|
||||
|
||||
impl From<vm::Error> for InterpreterResult {
|
||||
fn from(error: vm::Error) -> InterpreterResult {
|
||||
InterpreterResult::Done(Err(error))
|
||||
}
|
||||
}
|
||||
|
||||
/// Intepreter EVM implementation
|
||||
pub struct Interpreter<Cost: CostType> {
|
||||
mem: Vec<u8>,
|
||||
@@ -294,6 +286,8 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
cache, params, reader, informant,
|
||||
valid_jump_destinations, gasometer, stack,
|
||||
done: false,
|
||||
// Overridden in `step_inner` based on
|
||||
// the result of `ext.trace_next_instruction`.
|
||||
do_trace: true,
|
||||
mem: Vec::new(),
|
||||
return_data: ReturnData::empty(),
|
||||
@@ -316,7 +310,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
} else if self.reader.len() == 0 {
|
||||
InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_ref().expect("Gasometer None case is checked above; qed").current_gas.as_u256())))
|
||||
} else {
|
||||
self.step_inner(ext).err().expect("step_inner never returns Ok(()); qed")
|
||||
self.step_inner(ext)
|
||||
};
|
||||
|
||||
if let &InterpreterResult::Done(_) = &result {
|
||||
@@ -328,7 +322,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
|
||||
/// Inner helper function for step.
|
||||
#[inline(always)]
|
||||
fn step_inner(&mut self, ext: &mut vm::Ext) -> Result<Never, InterpreterResult> {
|
||||
fn step_inner(&mut self, ext: &mut dyn vm::Ext) -> InterpreterResult {
|
||||
let result = match self.resume_result.take() {
|
||||
Some(result) => result,
|
||||
None => {
|
||||
@@ -343,22 +337,31 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
|
||||
let instruction = match instruction {
|
||||
Some(i) => i,
|
||||
None => return Err(InterpreterResult::Done(Err(vm::Error::BadInstruction {
|
||||
None => return InterpreterResult::Done(Err(vm::Error::BadInstruction {
|
||||
instruction: opcode
|
||||
}))),
|
||||
})),
|
||||
};
|
||||
|
||||
let info = instruction.info();
|
||||
self.last_stack_ret_len = info.ret;
|
||||
self.verify_instruction(ext, instruction, info)?;
|
||||
if let Err(e) = self.verify_instruction(ext, instruction, info) {
|
||||
return InterpreterResult::Done(Err(e));
|
||||
};
|
||||
|
||||
// Calculate gas cost
|
||||
let requirements = self.gasometer.as_mut().expect(GASOMETER_PROOF).requirements(ext, instruction, info, &self.stack, self.mem.size())?;
|
||||
let requirements = match self.gasometer.as_mut().expect(GASOMETER_PROOF).requirements(ext, instruction, info, &self.stack, self.mem.size()) {
|
||||
Ok(t) => t,
|
||||
Err(e) => return InterpreterResult::Done(Err(e)),
|
||||
};
|
||||
if self.do_trace {
|
||||
ext.trace_prepare_execute(self.reader.position - 1, opcode, requirements.gas_cost.as_u256(), Self::mem_written(instruction, &self.stack), Self::store_written(instruction, &self.stack));
|
||||
}
|
||||
|
||||
self.gasometer.as_mut().expect(GASOMETER_PROOF).verify_gas(&requirements.gas_cost)?;
|
||||
if let Err(e) = self.gasometer.as_mut().expect(GASOMETER_PROOF).verify_gas(&requirements.gas_cost) {
|
||||
if self.do_trace {
|
||||
ext.trace_failed();
|
||||
}
|
||||
return InterpreterResult::Done(Err(e));
|
||||
}
|
||||
self.mem.expand(requirements.memory_required_size);
|
||||
self.gasometer.as_mut().expect(GASOMETER_PROOF).current_mem_gas = requirements.memory_total_gas;
|
||||
self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas = self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas - requirements.gas_cost;
|
||||
@@ -367,18 +370,24 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
|
||||
// Execute instruction
|
||||
let current_gas = self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas;
|
||||
let result = self.exec_instruction(
|
||||
let result = match self.exec_instruction(
|
||||
current_gas, ext, instruction, requirements.provide_gas
|
||||
)?;
|
||||
|
||||
) {
|
||||
Err(x) => {
|
||||
if self.do_trace {
|
||||
ext.trace_failed();
|
||||
}
|
||||
return InterpreterResult::Done(Err(x));
|
||||
},
|
||||
Ok(x) => x,
|
||||
};
|
||||
evm_debug!({ self.informant.after_instruction(instruction) });
|
||||
|
||||
result
|
||||
},
|
||||
};
|
||||
|
||||
if let InstructionResult::Trap(trap) = result {
|
||||
return Err(InterpreterResult::Trap(trap));
|
||||
return InterpreterResult::Trap(trap);
|
||||
}
|
||||
|
||||
if let InstructionResult::UnusedGas(ref gas) = result {
|
||||
@@ -400,28 +409,31 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
self.valid_jump_destinations = Some(self.cache.jump_destinations(&self.params.code_hash, &self.reader.code));
|
||||
}
|
||||
let jump_destinations = self.valid_jump_destinations.as_ref().expect("jump_destinations are initialized on first jump; qed");
|
||||
let pos = self.verify_jump(position, jump_destinations)?;
|
||||
let pos = match self.verify_jump(position, jump_destinations) {
|
||||
Ok(x) => x,
|
||||
Err(e) => return InterpreterResult::Done(Err(e))
|
||||
};
|
||||
self.reader.position = pos;
|
||||
},
|
||||
InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => {
|
||||
let mem = mem::replace(&mut self.mem, Vec::new());
|
||||
return Err(InterpreterResult::Done(Ok(GasLeft::NeedsReturn {
|
||||
return InterpreterResult::Done(Ok(GasLeft::NeedsReturn {
|
||||
gas_left: gas.as_u256(),
|
||||
data: mem.into_return_data(init_off, init_size),
|
||||
apply_state: apply
|
||||
})));
|
||||
}));
|
||||
},
|
||||
InstructionResult::StopExecution => {
|
||||
return Err(InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256()))));
|
||||
return InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256())));
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
if self.reader.position >= self.reader.len() {
|
||||
return Err(InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256()))));
|
||||
return InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256())));
|
||||
}
|
||||
|
||||
Err(InterpreterResult::Continue)
|
||||
InterpreterResult::Continue
|
||||
}
|
||||
|
||||
fn verify_instruction(&self, ext: &vm::Ext, instruction: Instruction, info: &InstructionInfo) -> vm::Result<()> {
|
||||
@@ -433,7 +445,8 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) ||
|
||||
(instruction == instructions::REVERT && !schedule.have_revert) ||
|
||||
((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) ||
|
||||
(instruction == instructions::EXTCODEHASH && !schedule.have_extcodehash)
|
||||
(instruction == instructions::EXTCODEHASH && !schedule.have_extcodehash) ||
|
||||
(instruction == instructions::CHAINID && !schedule.have_chain_id)
|
||||
{
|
||||
return Err(vm::Error::BadInstruction {
|
||||
instruction: instruction as u8
|
||||
@@ -848,6 +861,9 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
instructions::GASLIMIT => {
|
||||
self.stack.push(ext.env_info().gas_limit.clone());
|
||||
},
|
||||
instructions::CHAINID => {
|
||||
self.stack.push(ext.chain_id().into())
|
||||
},
|
||||
|
||||
// Stack instructions
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ extern crate log;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate rustc_hex;
|
||||
#[cfg(test)]
|
||||
extern crate hex_literal;
|
||||
|
||||
pub mod evm;
|
||||
pub mod interpreter;
|
||||
|
||||
@@ -25,6 +25,7 @@ use vm::{self, ActionParams, ActionValue, Ext};
|
||||
use vm::tests::{FakeExt, FakeCall, FakeCallType, test_finalize};
|
||||
use factory::Factory;
|
||||
use vmtype::VMType;
|
||||
use hex_literal::hex;
|
||||
|
||||
evm_test!{test_add: test_add_int}
|
||||
fn test_add(factory: super::Factory) {
|
||||
@@ -130,6 +131,27 @@ fn test_sender(factory: super::Factory) {
|
||||
assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681");
|
||||
}
|
||||
|
||||
evm_test!{test_chain_id: test_chain_id_int}
|
||||
fn test_chain_id(factory: super::Factory) {
|
||||
// 46 CHAINID
|
||||
// 60 00 PUSH 0
|
||||
// 55 SSTORE
|
||||
let code = hex!("46 60 00 55").to_vec();
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new_istanbul().with_chain_id(9);
|
||||
|
||||
let gas_left = {
|
||||
let vm = factory.create(params, ext.schedule(), ext.depth());
|
||||
test_finalize(vm.exec(&mut ext).ok().unwrap()).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(79_995));
|
||||
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000009");
|
||||
}
|
||||
|
||||
evm_test!{test_extcodecopy: test_extcodecopy_int}
|
||||
fn test_extcodecopy(factory: super::Factory) {
|
||||
// 33 - sender
|
||||
@@ -262,7 +284,6 @@ fn test_calldataload(factory: super::Factory) {
|
||||
|
||||
assert_eq!(gas_left, U256::from(79_991));
|
||||
assert_store(&ext, 0, "23ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23");
|
||||
|
||||
}
|
||||
|
||||
evm_test!{test_author: test_author_int}
|
||||
|
||||
Reference in New Issue
Block a user