Reformat the source code
This commit is contained in:
@@ -15,10 +15,10 @@
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Evm input params.
|
||||
use ethereum_types::{U256, H256, Address};
|
||||
use bytes::Bytes;
|
||||
use hash::{keccak, KECCAK_EMPTY};
|
||||
use ethereum_types::{Address, H256, U256};
|
||||
use ethjson;
|
||||
use hash::{keccak, KECCAK_EMPTY};
|
||||
|
||||
use call_type::CallType;
|
||||
|
||||
@@ -27,107 +27,110 @@ use std::sync::Arc;
|
||||
/// Transaction value
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ActionValue {
|
||||
/// Value that should be transfered
|
||||
Transfer(U256),
|
||||
/// Apparent value for transaction (not transfered)
|
||||
Apparent(U256)
|
||||
/// Value that should be transfered
|
||||
Transfer(U256),
|
||||
/// Apparent value for transaction (not transfered)
|
||||
Apparent(U256),
|
||||
}
|
||||
|
||||
/// Type of the way parameters encoded
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ParamsType {
|
||||
/// Parameters are included in code
|
||||
Embedded,
|
||||
/// Parameters are passed in data section
|
||||
Separate,
|
||||
/// Parameters are included in code
|
||||
Embedded,
|
||||
/// Parameters are passed in data section
|
||||
Separate,
|
||||
}
|
||||
|
||||
impl ActionValue {
|
||||
/// Returns action value as U256.
|
||||
pub fn value(&self) -> U256 {
|
||||
match *self {
|
||||
ActionValue::Transfer(x) | ActionValue::Apparent(x) => x
|
||||
}
|
||||
}
|
||||
/// Returns action value as U256.
|
||||
pub fn value(&self) -> U256 {
|
||||
match *self {
|
||||
ActionValue::Transfer(x) | ActionValue::Apparent(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the transfer action value of the U256-convertable raw value
|
||||
pub fn transfer<T: Into<U256>>(transfer_value: T) -> ActionValue {
|
||||
ActionValue::Transfer(transfer_value.into())
|
||||
}
|
||||
/// Returns the transfer action value of the U256-convertable raw value
|
||||
pub fn transfer<T: Into<U256>>(transfer_value: T) -> ActionValue {
|
||||
ActionValue::Transfer(transfer_value.into())
|
||||
}
|
||||
|
||||
/// Returns the apparent action value of the U256-convertable raw value
|
||||
pub fn apparent<T: Into<U256>>(apparent_value: T) -> ActionValue {
|
||||
ActionValue::Apparent(apparent_value.into())
|
||||
}
|
||||
/// Returns the apparent action value of the U256-convertable raw value
|
||||
pub fn apparent<T: Into<U256>>(apparent_value: T) -> ActionValue {
|
||||
ActionValue::Apparent(apparent_value.into())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: should be a trait, possible to avoid cloning everything from a Transaction(/View).
|
||||
/// Action (call/create) input params. Everything else should be specified in Externalities.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ActionParams {
|
||||
/// Address of currently executed code.
|
||||
pub code_address: Address,
|
||||
/// Hash of currently executed code.
|
||||
pub code_hash: Option<H256>,
|
||||
/// Receive address. Usually equal to code_address,
|
||||
/// except when called using CALLCODE.
|
||||
pub address: Address,
|
||||
/// Sender of current part of the transaction.
|
||||
pub sender: Address,
|
||||
/// Transaction initiator.
|
||||
pub origin: Address,
|
||||
/// Gas paid up front for transaction execution
|
||||
pub gas: U256,
|
||||
/// Gas price.
|
||||
pub gas_price: U256,
|
||||
/// Transaction value.
|
||||
pub value: ActionValue,
|
||||
/// Code being executed.
|
||||
pub code: Option<Arc<Bytes>>,
|
||||
/// Input data.
|
||||
pub data: Option<Bytes>,
|
||||
/// Type of call
|
||||
pub call_type: CallType,
|
||||
/// Param types encoding
|
||||
pub params_type: ParamsType,
|
||||
/// Address of currently executed code.
|
||||
pub code_address: Address,
|
||||
/// Hash of currently executed code.
|
||||
pub code_hash: Option<H256>,
|
||||
/// Receive address. Usually equal to code_address,
|
||||
/// except when called using CALLCODE.
|
||||
pub address: Address,
|
||||
/// Sender of current part of the transaction.
|
||||
pub sender: Address,
|
||||
/// Transaction initiator.
|
||||
pub origin: Address,
|
||||
/// Gas paid up front for transaction execution
|
||||
pub gas: U256,
|
||||
/// Gas price.
|
||||
pub gas_price: U256,
|
||||
/// Transaction value.
|
||||
pub value: ActionValue,
|
||||
/// Code being executed.
|
||||
pub code: Option<Arc<Bytes>>,
|
||||
/// Input data.
|
||||
pub data: Option<Bytes>,
|
||||
/// Type of call
|
||||
pub call_type: CallType,
|
||||
/// Param types encoding
|
||||
pub params_type: ParamsType,
|
||||
}
|
||||
|
||||
impl Default for ActionParams {
|
||||
/// Returns default ActionParams initialized with zeros
|
||||
fn default() -> ActionParams {
|
||||
ActionParams {
|
||||
code_address: Address::new(),
|
||||
code_hash: Some(KECCAK_EMPTY),
|
||||
address: Address::new(),
|
||||
sender: Address::new(),
|
||||
origin: Address::new(),
|
||||
gas: U256::zero(),
|
||||
gas_price: U256::zero(),
|
||||
value: ActionValue::Transfer(U256::zero()),
|
||||
code: None,
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
params_type: ParamsType::Separate,
|
||||
}
|
||||
}
|
||||
/// Returns default ActionParams initialized with zeros
|
||||
fn default() -> ActionParams {
|
||||
ActionParams {
|
||||
code_address: Address::new(),
|
||||
code_hash: Some(KECCAK_EMPTY),
|
||||
address: Address::new(),
|
||||
sender: Address::new(),
|
||||
origin: Address::new(),
|
||||
gas: U256::zero(),
|
||||
gas_price: U256::zero(),
|
||||
value: ActionValue::Transfer(U256::zero()),
|
||||
code: None,
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
params_type: ParamsType::Separate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ethjson::vm::Transaction> for ActionParams {
|
||||
fn from(t: ethjson::vm::Transaction) -> Self {
|
||||
let address: Address = t.address.into();
|
||||
ActionParams {
|
||||
code_address: Address::new(),
|
||||
code_hash: Some(keccak(&*t.code)),
|
||||
address: address,
|
||||
sender: t.sender.into(),
|
||||
origin: t.origin.into(),
|
||||
code: Some(Arc::new(t.code.into())),
|
||||
data: Some(t.data.into()),
|
||||
gas: t.gas.into(),
|
||||
gas_price: t.gas_price.into(),
|
||||
value: ActionValue::Transfer(t.value.into()),
|
||||
call_type: match address.is_zero() { true => CallType::None, false => CallType::Call }, // TODO @debris is this correct?
|
||||
params_type: ParamsType::Separate,
|
||||
}
|
||||
}
|
||||
fn from(t: ethjson::vm::Transaction) -> Self {
|
||||
let address: Address = t.address.into();
|
||||
ActionParams {
|
||||
code_address: Address::new(),
|
||||
code_hash: Some(keccak(&*t.code)),
|
||||
address: address,
|
||||
sender: t.sender.into(),
|
||||
origin: t.origin.into(),
|
||||
code: Some(Arc::new(t.code.into())),
|
||||
data: Some(t.data.into()),
|
||||
gas: t.gas.into(),
|
||||
gas_price: t.gas_price.into(),
|
||||
value: ActionValue::Transfer(t.value.into()),
|
||||
call_type: match address.is_zero() {
|
||||
true => CallType::None,
|
||||
false => CallType::Call,
|
||||
}, // TODO @debris is this correct?
|
||||
params_type: ParamsType::Separate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,71 +16,73 @@
|
||||
|
||||
//! EVM call types.
|
||||
|
||||
use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp};
|
||||
use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};
|
||||
|
||||
/// The type of the call-like instruction.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum CallType {
|
||||
/// Not a CALL.
|
||||
None,
|
||||
/// CALL.
|
||||
Call,
|
||||
/// CALLCODE.
|
||||
CallCode,
|
||||
/// DELEGATECALL.
|
||||
DelegateCall,
|
||||
/// STATICCALL
|
||||
StaticCall,
|
||||
/// Not a CALL.
|
||||
None,
|
||||
/// CALL.
|
||||
Call,
|
||||
/// CALLCODE.
|
||||
CallCode,
|
||||
/// DELEGATECALL.
|
||||
DelegateCall,
|
||||
/// STATICCALL
|
||||
StaticCall,
|
||||
}
|
||||
|
||||
impl Encodable for CallType {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
let v = match *self {
|
||||
CallType::None => 0u32,
|
||||
CallType::Call => 1,
|
||||
CallType::CallCode => 2,
|
||||
CallType::DelegateCall => 3,
|
||||
CallType::StaticCall => 4,
|
||||
};
|
||||
Encodable::rlp_append(&v, s);
|
||||
}
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
let v = match *self {
|
||||
CallType::None => 0u32,
|
||||
CallType::Call => 1,
|
||||
CallType::CallCode => 2,
|
||||
CallType::DelegateCall => 3,
|
||||
CallType::StaticCall => 4,
|
||||
};
|
||||
Encodable::rlp_append(&v, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for CallType {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
rlp.as_val().and_then(|v| Ok(match v {
|
||||
0u32 => CallType::None,
|
||||
1 => CallType::Call,
|
||||
2 => CallType::CallCode,
|
||||
3 => CallType::DelegateCall,
|
||||
4 => CallType::StaticCall,
|
||||
_ => return Err(DecoderError::Custom("Invalid value of CallType item")),
|
||||
}))
|
||||
}
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
rlp.as_val().and_then(|v| {
|
||||
Ok(match v {
|
||||
0u32 => CallType::None,
|
||||
1 => CallType::Call,
|
||||
2 => CallType::CallCode,
|
||||
3 => CallType::DelegateCall,
|
||||
4 => CallType::StaticCall,
|
||||
_ => return Err(DecoderError::Custom("Invalid value of CallType item")),
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rlp::*;
|
||||
use super::CallType;
|
||||
use super::CallType;
|
||||
use rlp::*;
|
||||
|
||||
#[test]
|
||||
fn encode_call_type() {
|
||||
let ct = CallType::Call;
|
||||
#[test]
|
||||
fn encode_call_type() {
|
||||
let ct = CallType::Call;
|
||||
|
||||
let mut s = RlpStream::new_list(2);
|
||||
s.append(&ct);
|
||||
assert!(!s.is_finished(), "List shouldn't finished yet");
|
||||
s.append(&ct);
|
||||
assert!(s.is_finished(), "List should be finished now");
|
||||
s.out();
|
||||
}
|
||||
let mut s = RlpStream::new_list(2);
|
||||
s.append(&ct);
|
||||
assert!(!s.is_finished(), "List shouldn't finished yet");
|
||||
s.append(&ct);
|
||||
assert!(s.is_finished(), "List should be finished now");
|
||||
s.out();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_encode_and_decode_call_type() {
|
||||
let original = CallType::Call;
|
||||
let encoded = encode(&original);
|
||||
let decoded = decode(&encoded).expect("failure decoding CallType");
|
||||
assert_eq!(original, decoded);
|
||||
}
|
||||
#[test]
|
||||
fn should_encode_and_decode_call_type() {
|
||||
let original = CallType::Call;
|
||||
let encoded = encode(&original);
|
||||
let decoded = decode(&encoded).expect("failure decoding CallType");
|
||||
assert_eq!(original, decoded);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,10 @@
|
||||
|
||||
//! Environment information for transaction execution.
|
||||
|
||||
use std::cmp;
|
||||
use std::sync::Arc;
|
||||
use hash::keccak;
|
||||
use ethereum_types::{U256, H256, Address};
|
||||
use ethereum_types::{Address, H256, U256};
|
||||
use ethjson;
|
||||
use hash::keccak;
|
||||
use std::{cmp, sync::Arc};
|
||||
|
||||
type BlockNumber = u64;
|
||||
|
||||
@@ -31,79 +30,88 @@ pub type LastHashes = Vec<H256>;
|
||||
/// Information concerning the execution environment for a message-call/contract-creation.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EnvInfo {
|
||||
/// The block number.
|
||||
pub number: BlockNumber,
|
||||
/// The block author.
|
||||
pub author: Address,
|
||||
/// The block timestamp.
|
||||
pub timestamp: u64,
|
||||
/// The block difficulty.
|
||||
pub difficulty: U256,
|
||||
/// The block gas limit.
|
||||
pub gas_limit: U256,
|
||||
/// The last 256 block hashes.
|
||||
pub last_hashes: Arc<LastHashes>,
|
||||
/// The gas used.
|
||||
pub gas_used: U256,
|
||||
/// The block number.
|
||||
pub number: BlockNumber,
|
||||
/// The block author.
|
||||
pub author: Address,
|
||||
/// The block timestamp.
|
||||
pub timestamp: u64,
|
||||
/// The block difficulty.
|
||||
pub difficulty: U256,
|
||||
/// The block gas limit.
|
||||
pub gas_limit: U256,
|
||||
/// The last 256 block hashes.
|
||||
pub last_hashes: Arc<LastHashes>,
|
||||
/// The gas used.
|
||||
pub gas_used: U256,
|
||||
}
|
||||
|
||||
impl Default for EnvInfo {
|
||||
fn default() -> Self {
|
||||
EnvInfo {
|
||||
number: 0,
|
||||
author: Address::default(),
|
||||
timestamp: 0,
|
||||
difficulty: 0.into(),
|
||||
gas_limit: 0.into(),
|
||||
last_hashes: Arc::new(vec![]),
|
||||
gas_used: 0.into(),
|
||||
}
|
||||
}
|
||||
fn default() -> Self {
|
||||
EnvInfo {
|
||||
number: 0,
|
||||
author: Address::default(),
|
||||
timestamp: 0,
|
||||
difficulty: 0.into(),
|
||||
gas_limit: 0.into(),
|
||||
last_hashes: Arc::new(vec![]),
|
||||
gas_used: 0.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ethjson::vm::Env> for EnvInfo {
|
||||
fn from(e: ethjson::vm::Env) -> Self {
|
||||
let number = e.number.into();
|
||||
EnvInfo {
|
||||
number,
|
||||
author: e.author.into(),
|
||||
difficulty: e.difficulty.into(),
|
||||
gas_limit: e.gas_limit.into(),
|
||||
timestamp: e.timestamp.into(),
|
||||
last_hashes: Arc::new((1..cmp::min(number + 1, 257)).map(|i| keccak(format!("{}", number - i).as_bytes())).collect()),
|
||||
gas_used: U256::default(),
|
||||
}
|
||||
}
|
||||
fn from(e: ethjson::vm::Env) -> Self {
|
||||
let number = e.number.into();
|
||||
EnvInfo {
|
||||
number,
|
||||
author: e.author.into(),
|
||||
difficulty: e.difficulty.into(),
|
||||
gas_limit: e.gas_limit.into(),
|
||||
timestamp: e.timestamp.into(),
|
||||
last_hashes: Arc::new(
|
||||
(1..cmp::min(number + 1, 257))
|
||||
.map(|i| keccak(format!("{}", number - i).as_bytes()))
|
||||
.collect(),
|
||||
),
|
||||
gas_used: U256::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
use super::*;
|
||||
use ethereum_types::{U256, Address};
|
||||
use ethjson;
|
||||
use super::*;
|
||||
use ethereum_types::{Address, U256};
|
||||
use ethjson;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn it_serializes_from_json() {
|
||||
let env_info = EnvInfo::from(ethjson::vm::Env {
|
||||
author: ethjson::hash::Address(Address::from_str("000000f00000000f000000000000f00000000f00").unwrap()),
|
||||
number: ethjson::uint::Uint(U256::from(1_112_339)),
|
||||
difficulty: ethjson::uint::Uint(U256::from(50_000)),
|
||||
gas_limit: ethjson::uint::Uint(U256::from(40_000)),
|
||||
timestamp: ethjson::uint::Uint(U256::from(1_100))
|
||||
});
|
||||
#[test]
|
||||
fn it_serializes_from_json() {
|
||||
let env_info = EnvInfo::from(ethjson::vm::Env {
|
||||
author: ethjson::hash::Address(
|
||||
Address::from_str("000000f00000000f000000000000f00000000f00").unwrap(),
|
||||
),
|
||||
number: ethjson::uint::Uint(U256::from(1_112_339)),
|
||||
difficulty: ethjson::uint::Uint(U256::from(50_000)),
|
||||
gas_limit: ethjson::uint::Uint(U256::from(40_000)),
|
||||
timestamp: ethjson::uint::Uint(U256::from(1_100)),
|
||||
});
|
||||
|
||||
assert_eq!(env_info.number, 1112339);
|
||||
assert_eq!(env_info.author, Address::from_str("000000f00000000f000000000000f00000000f00").unwrap());
|
||||
assert_eq!(env_info.gas_limit, 40000.into());
|
||||
assert_eq!(env_info.difficulty, 50000.into());
|
||||
assert_eq!(env_info.gas_used, 0.into());
|
||||
}
|
||||
assert_eq!(env_info.number, 1112339);
|
||||
assert_eq!(
|
||||
env_info.author,
|
||||
Address::from_str("000000f00000000f000000000000f00000000f00").unwrap()
|
||||
);
|
||||
assert_eq!(env_info.gas_limit, 40000.into());
|
||||
assert_eq!(env_info.difficulty, 50000.into());
|
||||
assert_eq!(env_info.gas_used, 0.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_can_be_created_as_default() {
|
||||
let default_env_info = EnvInfo::default();
|
||||
#[test]
|
||||
fn it_can_be_created_as_default() {
|
||||
let default_env_info = EnvInfo::default();
|
||||
|
||||
assert_eq!(default_env_info.difficulty, 0.into());
|
||||
}
|
||||
assert_eq!(default_env_info.difficulty, 0.into());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,104 +16,115 @@
|
||||
|
||||
//! VM errors module
|
||||
|
||||
use ::{ResumeCall, ResumeCreate};
|
||||
use ethereum_types::Address;
|
||||
use action_params::ActionParams;
|
||||
use std::fmt;
|
||||
use ethereum_types::Address;
|
||||
use ethtrie;
|
||||
use std::fmt;
|
||||
use ResumeCall;
|
||||
use ResumeCreate;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TrapKind {
|
||||
Call(ActionParams),
|
||||
Create(ActionParams, Address),
|
||||
Call(ActionParams),
|
||||
Create(ActionParams, Address),
|
||||
}
|
||||
|
||||
pub enum TrapError<Call, Create> {
|
||||
Call(ActionParams, Call),
|
||||
Create(ActionParams, Address, Create),
|
||||
Call(ActionParams, Call),
|
||||
Create(ActionParams, Address, Create),
|
||||
}
|
||||
|
||||
/// VM errors.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Error {
|
||||
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
||||
/// The state should be reverted to the state from before the
|
||||
/// transaction execution. But it does not mean that transaction
|
||||
/// was invalid. Balance still should be transfered and nonce
|
||||
/// should be increased.
|
||||
OutOfGas,
|
||||
/// `BadJumpDestination` is returned when execution tried to move
|
||||
/// to position that wasn't marked with JUMPDEST instruction
|
||||
BadJumpDestination {
|
||||
/// Position the code tried to jump to.
|
||||
destination: usize
|
||||
},
|
||||
/// `BadInstructions` is returned when given instruction is not supported
|
||||
BadInstruction {
|
||||
/// Unrecognized opcode
|
||||
instruction: u8,
|
||||
},
|
||||
/// `StackUnderflow` when there is not enough stack elements to execute instruction
|
||||
StackUnderflow {
|
||||
/// Invoked instruction
|
||||
instruction: &'static str,
|
||||
/// How many stack elements was requested by instruction
|
||||
wanted: usize,
|
||||
/// How many elements were on stack
|
||||
on_stack: usize
|
||||
},
|
||||
/// When execution would exceed defined Stack Limit
|
||||
OutOfStack {
|
||||
/// Invoked instruction
|
||||
instruction: &'static str,
|
||||
/// How many stack elements instruction wanted to push
|
||||
wanted: usize,
|
||||
/// What was the stack limit
|
||||
limit: usize
|
||||
},
|
||||
/// Built-in contract failed on given input
|
||||
BuiltIn(&'static str),
|
||||
/// When execution tries to modify the state in static context
|
||||
MutableCallInStaticContext,
|
||||
/// Likely to cause consensus issues.
|
||||
Internal(String),
|
||||
/// Wasm runtime error
|
||||
Wasm(String),
|
||||
/// Out of bounds access in RETURNDATACOPY.
|
||||
OutOfBounds,
|
||||
/// Execution has been reverted with REVERT.
|
||||
Reverted,
|
||||
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
||||
/// The state should be reverted to the state from before the
|
||||
/// transaction execution. But it does not mean that transaction
|
||||
/// was invalid. Balance still should be transfered and nonce
|
||||
/// should be increased.
|
||||
OutOfGas,
|
||||
/// `BadJumpDestination` is returned when execution tried to move
|
||||
/// to position that wasn't marked with JUMPDEST instruction
|
||||
BadJumpDestination {
|
||||
/// Position the code tried to jump to.
|
||||
destination: usize,
|
||||
},
|
||||
/// `BadInstructions` is returned when given instruction is not supported
|
||||
BadInstruction {
|
||||
/// Unrecognized opcode
|
||||
instruction: u8,
|
||||
},
|
||||
/// `StackUnderflow` when there is not enough stack elements to execute instruction
|
||||
StackUnderflow {
|
||||
/// Invoked instruction
|
||||
instruction: &'static str,
|
||||
/// How many stack elements was requested by instruction
|
||||
wanted: usize,
|
||||
/// How many elements were on stack
|
||||
on_stack: usize,
|
||||
},
|
||||
/// When execution would exceed defined Stack Limit
|
||||
OutOfStack {
|
||||
/// Invoked instruction
|
||||
instruction: &'static str,
|
||||
/// How many stack elements instruction wanted to push
|
||||
wanted: usize,
|
||||
/// What was the stack limit
|
||||
limit: usize,
|
||||
},
|
||||
/// Built-in contract failed on given input
|
||||
BuiltIn(&'static str),
|
||||
/// When execution tries to modify the state in static context
|
||||
MutableCallInStaticContext,
|
||||
/// Likely to cause consensus issues.
|
||||
Internal(String),
|
||||
/// Wasm runtime error
|
||||
Wasm(String),
|
||||
/// Out of bounds access in RETURNDATACOPY.
|
||||
OutOfBounds,
|
||||
/// Execution has been reverted with REVERT.
|
||||
Reverted,
|
||||
}
|
||||
|
||||
impl From<Box<ethtrie::TrieError>> for Error {
|
||||
fn from(err: Box<ethtrie::TrieError>) -> Self {
|
||||
Error::Internal(format!("Internal error: {}", err))
|
||||
}
|
||||
fn from(err: Box<ethtrie::TrieError>) -> Self {
|
||||
Error::Internal(format!("Internal error: {}", err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ethtrie::TrieError> for Error {
|
||||
fn from(err: ethtrie::TrieError) -> Self {
|
||||
Error::Internal(format!("Internal error: {}", err))
|
||||
}
|
||||
fn from(err: ethtrie::TrieError) -> Self {
|
||||
Error::Internal(format!("Internal error: {}", err))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::Error::*;
|
||||
match *self {
|
||||
OutOfGas => write!(f, "Out of gas"),
|
||||
BadJumpDestination { destination } => write!(f, "Bad jump destination {:x}", destination),
|
||||
BadInstruction { instruction } => write!(f, "Bad instruction {:x}", instruction),
|
||||
StackUnderflow { instruction, wanted, on_stack } => write!(f, "Stack underflow {} {}/{}", instruction, wanted, on_stack),
|
||||
OutOfStack { instruction, wanted, limit } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit),
|
||||
BuiltIn(name) => write!(f, "Built-in failed: {}", name),
|
||||
Internal(ref msg) => write!(f, "Internal error: {}", msg),
|
||||
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
|
||||
Wasm(ref msg) => write!(f, "Internal error: {}", msg),
|
||||
OutOfBounds => write!(f, "Out of bounds"),
|
||||
Reverted => write!(f, "Reverted"),
|
||||
}
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::Error::*;
|
||||
match *self {
|
||||
OutOfGas => write!(f, "Out of gas"),
|
||||
BadJumpDestination { destination } => {
|
||||
write!(f, "Bad jump destination {:x}", destination)
|
||||
}
|
||||
BadInstruction { instruction } => write!(f, "Bad instruction {:x}", instruction),
|
||||
StackUnderflow {
|
||||
instruction,
|
||||
wanted,
|
||||
on_stack,
|
||||
} => write!(f, "Stack underflow {} {}/{}", instruction, wanted, on_stack),
|
||||
OutOfStack {
|
||||
instruction,
|
||||
wanted,
|
||||
limit,
|
||||
} => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit),
|
||||
BuiltIn(name) => write!(f, "Built-in failed: {}", name),
|
||||
Internal(ref msg) => write!(f, "Internal error: {}", msg),
|
||||
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
|
||||
Wasm(ref msg) => write!(f, "Internal error: {}", msg),
|
||||
OutOfBounds => write!(f, "Out of bounds"),
|
||||
Reverted => write!(f, "Reverted"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
||||
@@ -16,162 +16,172 @@
|
||||
|
||||
//! Interface for Evm externalities.
|
||||
|
||||
use std::sync::Arc;
|
||||
use ethereum_types::{U256, H256, Address};
|
||||
use bytes::Bytes;
|
||||
use call_type::CallType;
|
||||
use env_info::EnvInfo;
|
||||
use schedule::Schedule;
|
||||
use return_data::ReturnData;
|
||||
use error::{Result, TrapKind};
|
||||
use ethereum_types::{Address, H256, U256};
|
||||
use return_data::ReturnData;
|
||||
use schedule::Schedule;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Result of externalities create function.
|
||||
pub enum ContractCreateResult {
|
||||
/// Returned when creation was successfull.
|
||||
/// Contains an address of newly created contract and gas left.
|
||||
Created(Address, U256),
|
||||
/// Returned when contract creation failed.
|
||||
/// VM doesn't have to know the reason.
|
||||
Failed,
|
||||
/// Reverted with REVERT.
|
||||
Reverted(U256, ReturnData),
|
||||
/// Returned when creation was successfull.
|
||||
/// Contains an address of newly created contract and gas left.
|
||||
Created(Address, U256),
|
||||
/// Returned when contract creation failed.
|
||||
/// VM doesn't have to know the reason.
|
||||
Failed,
|
||||
/// Reverted with REVERT.
|
||||
Reverted(U256, ReturnData),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Result of externalities call function.
|
||||
pub enum MessageCallResult {
|
||||
/// Returned when message call was successfull.
|
||||
/// Contains gas left and output data.
|
||||
Success(U256, ReturnData),
|
||||
/// Returned when message call failed.
|
||||
/// VM doesn't have to know the reason.
|
||||
Failed,
|
||||
/// Returned when message call was reverted.
|
||||
/// Contains gas left and output data.
|
||||
Reverted(U256, ReturnData),
|
||||
/// Returned when message call was successfull.
|
||||
/// Contains gas left and output data.
|
||||
Success(U256, ReturnData),
|
||||
/// Returned when message call failed.
|
||||
/// VM doesn't have to know the reason.
|
||||
Failed,
|
||||
/// Returned when message call was reverted.
|
||||
/// Contains gas left and output data.
|
||||
Reverted(U256, ReturnData),
|
||||
}
|
||||
|
||||
/// Specifies how an address is calculated for a new contract.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum CreateContractAddress {
|
||||
/// Address is calculated from sender and nonce. pWASM `create` scheme.
|
||||
FromSenderAndNonce,
|
||||
/// Address is calculated from sender, salt and code hash. pWASM `create2` scheme and EIP-1014 CREATE2 scheme.
|
||||
FromSenderSaltAndCodeHash(H256),
|
||||
/// Address is calculated from code hash and sender. Used by pwasm create ext.
|
||||
FromSenderAndCodeHash,
|
||||
/// Address is calculated from sender and nonce. pWASM `create` scheme.
|
||||
FromSenderAndNonce,
|
||||
/// Address is calculated from sender, salt and code hash. pWASM `create2` scheme and EIP-1014 CREATE2 scheme.
|
||||
FromSenderSaltAndCodeHash(H256),
|
||||
/// Address is calculated from code hash and sender. Used by pwasm create ext.
|
||||
FromSenderAndCodeHash,
|
||||
}
|
||||
|
||||
/// Externalities interface for EVMs
|
||||
pub trait Ext {
|
||||
/// Returns the storage value for a given key if reversion happens on the current transaction.
|
||||
fn initial_storage_at(&self, key: &H256) -> Result<H256>;
|
||||
/// Returns the storage value for a given key if reversion happens on the current transaction.
|
||||
fn initial_storage_at(&self, key: &H256) -> Result<H256>;
|
||||
|
||||
/// Returns a value for given key.
|
||||
fn storage_at(&self, key: &H256) -> Result<H256>;
|
||||
/// Returns a value for given key.
|
||||
fn storage_at(&self, key: &H256) -> Result<H256>;
|
||||
|
||||
/// Stores a value for given key.
|
||||
fn set_storage(&mut self, key: H256, value: H256) -> Result<()>;
|
||||
/// Stores a value for given key.
|
||||
fn set_storage(&mut self, key: H256, value: H256) -> Result<()>;
|
||||
|
||||
/// Determine whether an account exists.
|
||||
fn exists(&self, address: &Address) -> Result<bool>;
|
||||
/// Determine whether an account exists.
|
||||
fn exists(&self, address: &Address) -> Result<bool>;
|
||||
|
||||
/// Determine whether an account exists and is not null (zero balance/nonce, no code).
|
||||
fn exists_and_not_null(&self, address: &Address) -> Result<bool>;
|
||||
/// Determine whether an account exists and is not null (zero balance/nonce, no code).
|
||||
fn exists_and_not_null(&self, address: &Address) -> Result<bool>;
|
||||
|
||||
/// Balance of the origin account.
|
||||
fn origin_balance(&self) -> Result<U256>;
|
||||
/// Balance of the origin account.
|
||||
fn origin_balance(&self) -> Result<U256>;
|
||||
|
||||
/// Returns address balance.
|
||||
fn balance(&self, address: &Address) -> Result<U256>;
|
||||
/// Returns address balance.
|
||||
fn balance(&self, address: &Address) -> Result<U256>;
|
||||
|
||||
/// Returns the hash of one of the 256 most recent complete blocks.
|
||||
fn blockhash(&mut self, number: &U256) -> H256;
|
||||
/// Returns the hash of one of the 256 most recent complete blocks.
|
||||
fn blockhash(&mut self, number: &U256) -> H256;
|
||||
|
||||
/// Creates new contract.
|
||||
///
|
||||
/// Returns gas_left and contract address if contract creation was successful.
|
||||
fn create(
|
||||
&mut self,
|
||||
gas: &U256,
|
||||
value: &U256,
|
||||
code: &[u8],
|
||||
address: CreateContractAddress,
|
||||
trap: bool,
|
||||
) -> ::std::result::Result<ContractCreateResult, TrapKind>;
|
||||
/// Creates new contract.
|
||||
///
|
||||
/// Returns gas_left and contract address if contract creation was successful.
|
||||
fn create(
|
||||
&mut self,
|
||||
gas: &U256,
|
||||
value: &U256,
|
||||
code: &[u8],
|
||||
address: CreateContractAddress,
|
||||
trap: bool,
|
||||
) -> ::std::result::Result<ContractCreateResult, TrapKind>;
|
||||
|
||||
/// Message call.
|
||||
///
|
||||
/// Returns Err, if we run out of gas.
|
||||
/// Otherwise returns call_result which contains gas left
|
||||
/// and true if subcall was successfull.
|
||||
fn call(
|
||||
&mut self,
|
||||
gas: &U256,
|
||||
sender_address: &Address,
|
||||
receive_address: &Address,
|
||||
value: Option<U256>,
|
||||
data: &[u8],
|
||||
code_address: &Address,
|
||||
call_type: CallType,
|
||||
trap: bool
|
||||
) -> ::std::result::Result<MessageCallResult, TrapKind>;
|
||||
/// Message call.
|
||||
///
|
||||
/// Returns Err, if we run out of gas.
|
||||
/// Otherwise returns call_result which contains gas left
|
||||
/// and true if subcall was successfull.
|
||||
fn call(
|
||||
&mut self,
|
||||
gas: &U256,
|
||||
sender_address: &Address,
|
||||
receive_address: &Address,
|
||||
value: Option<U256>,
|
||||
data: &[u8],
|
||||
code_address: &Address,
|
||||
call_type: CallType,
|
||||
trap: bool,
|
||||
) -> ::std::result::Result<MessageCallResult, TrapKind>;
|
||||
|
||||
/// Returns code at given address
|
||||
fn extcode(&self, address: &Address) -> Result<Option<Arc<Bytes>>>;
|
||||
/// Returns code at given address
|
||||
fn extcode(&self, address: &Address) -> Result<Option<Arc<Bytes>>>;
|
||||
|
||||
/// Returns code hash at given address
|
||||
fn extcodehash(&self, address: &Address) -> Result<Option<H256>>;
|
||||
/// Returns code hash at given address
|
||||
fn extcodehash(&self, address: &Address) -> Result<Option<H256>>;
|
||||
|
||||
/// Returns code size at given address
|
||||
fn extcodesize(&self, address: &Address) -> Result<Option<usize>>;
|
||||
/// Returns code size at given address
|
||||
fn extcodesize(&self, address: &Address) -> Result<Option<usize>>;
|
||||
|
||||
/// Creates log entry with given topics and data
|
||||
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> Result<()>;
|
||||
/// Creates log entry with given topics and data
|
||||
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> Result<()>;
|
||||
|
||||
/// Should be called when transaction calls `RETURN` opcode.
|
||||
/// Returns gas_left if cost of returning the data is not too high.
|
||||
fn ret(self, gas: &U256, data: &ReturnData, apply_state: bool) -> Result<U256>;
|
||||
/// Should be called when transaction calls `RETURN` opcode.
|
||||
/// Returns gas_left if cost of returning the data is not too high.
|
||||
fn ret(self, gas: &U256, data: &ReturnData, apply_state: bool) -> Result<U256>;
|
||||
|
||||
/// Should be called when contract commits suicide.
|
||||
/// Address to which funds should be refunded.
|
||||
fn suicide(&mut self, refund_address: &Address) -> Result<()> ;
|
||||
/// Should be called when contract commits suicide.
|
||||
/// Address to which funds should be refunded.
|
||||
fn suicide(&mut self, refund_address: &Address) -> Result<()>;
|
||||
|
||||
/// Returns schedule.
|
||||
fn schedule(&self) -> &Schedule;
|
||||
/// Returns schedule.
|
||||
fn schedule(&self) -> &Schedule;
|
||||
|
||||
/// Returns environment info.
|
||||
fn env_info(&self) -> &EnvInfo;
|
||||
/// Returns environment info.
|
||||
fn env_info(&self) -> &EnvInfo;
|
||||
|
||||
/// Returns the chain ID of the blockchain
|
||||
fn chain_id(&self) -> u64;
|
||||
/// Returns the chain ID of the blockchain
|
||||
fn chain_id(&self) -> u64;
|
||||
|
||||
/// Returns current depth of execution.
|
||||
///
|
||||
/// If contract A calls contract B, and contract B calls C,
|
||||
/// then A depth is 0, B is 1, C is 2 and so on.
|
||||
fn depth(&self) -> usize;
|
||||
/// Returns current depth of execution.
|
||||
///
|
||||
/// If contract A calls contract B, and contract B calls C,
|
||||
/// then A depth is 0, B is 1, C is 2 and so on.
|
||||
fn depth(&self) -> usize;
|
||||
|
||||
/// Increments sstore refunds counter.
|
||||
fn add_sstore_refund(&mut self, value: usize);
|
||||
/// Increments sstore refunds counter.
|
||||
fn add_sstore_refund(&mut self, value: usize);
|
||||
|
||||
/// Decrements sstore refunds counter.
|
||||
fn sub_sstore_refund(&mut self, value: usize);
|
||||
/// Decrements sstore refunds counter.
|
||||
fn sub_sstore_refund(&mut self, value: usize);
|
||||
|
||||
/// Decide if any more operations should be traced. Passthrough for the VM trace.
|
||||
fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8, _current_gas: U256) -> bool { false }
|
||||
/// Decide if any more operations should be traced. Passthrough for the VM trace.
|
||||
fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8, _current_gas: U256) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Prepare to trace an operation. Passthrough for the VM trace.
|
||||
/// For each call of `trace_prepare_execute` either `trace_failed` or `trace_executed` MUST be called.
|
||||
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: U256, _mem_written: Option<(usize, usize)>, _store_written: Option<(U256, U256)>) {}
|
||||
/// Prepare to trace an operation. Passthrough for the VM trace.
|
||||
/// For each call of `trace_prepare_execute` either `trace_failed` or `trace_executed` MUST be called.
|
||||
fn trace_prepare_execute(
|
||||
&mut self,
|
||||
_pc: usize,
|
||||
_instruction: u8,
|
||||
_gas_cost: U256,
|
||||
_mem_written: Option<(usize, usize)>,
|
||||
_store_written: Option<(U256, U256)>,
|
||||
) {
|
||||
}
|
||||
|
||||
/// Trace the execution failure of a single instruction.
|
||||
fn trace_failed(&mut self) {}
|
||||
/// Trace the execution failure of a single instruction.
|
||||
fn trace_failed(&mut self) {}
|
||||
|
||||
/// Trace the finalised execution of a single instruction.
|
||||
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem: &[u8]) {}
|
||||
/// Trace the finalised execution of a single instruction.
|
||||
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem: &[u8]) {}
|
||||
|
||||
/// Check if running in static context.
|
||||
fn is_static(&self) -> bool;
|
||||
/// Check if running in static context.
|
||||
fn is_static(&self) -> bool;
|
||||
}
|
||||
|
||||
@@ -17,46 +17,46 @@
|
||||
//! Virtual machines support library
|
||||
|
||||
extern crate ethereum_types;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate ethjson;
|
||||
extern crate rlp;
|
||||
extern crate keccak_hash as hash;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate patricia_trie_ethereum as ethtrie;
|
||||
extern crate rlp;
|
||||
|
||||
mod action_params;
|
||||
mod call_type;
|
||||
mod env_info;
|
||||
mod schedule;
|
||||
mod error;
|
||||
mod ext;
|
||||
mod return_data;
|
||||
mod error;
|
||||
mod schedule;
|
||||
|
||||
pub mod tests;
|
||||
|
||||
pub use action_params::{ActionParams, ActionValue, ParamsType};
|
||||
pub use call_type::CallType;
|
||||
pub use env_info::{EnvInfo, LastHashes};
|
||||
pub use schedule::{Schedule, CleanDustMode, WasmCosts};
|
||||
pub use ext::{Ext, MessageCallResult, ContractCreateResult, CreateContractAddress};
|
||||
pub use return_data::{ReturnData, GasLeft};
|
||||
pub use error::{Error, Result, TrapResult, TrapError, TrapKind, ExecTrapResult, ExecTrapError};
|
||||
pub use error::{Error, ExecTrapError, ExecTrapResult, Result, TrapError, TrapKind, TrapResult};
|
||||
pub use ext::{ContractCreateResult, CreateContractAddress, Ext, MessageCallResult};
|
||||
pub use return_data::{GasLeft, ReturnData};
|
||||
pub use schedule::{CleanDustMode, Schedule, WasmCosts};
|
||||
|
||||
/// Virtual Machine interface
|
||||
pub trait Exec: Send {
|
||||
/// This function should be used to execute transaction.
|
||||
/// It returns either an error, a known amount of gas left, or parameters to be used
|
||||
/// to compute the final gas left.
|
||||
fn exec(self: Box<Self>, ext: &mut Ext) -> ExecTrapResult<GasLeft>;
|
||||
/// This function should be used to execute transaction.
|
||||
/// It returns either an error, a known amount of gas left, or parameters to be used
|
||||
/// to compute the final gas left.
|
||||
fn exec(self: Box<Self>, ext: &mut Ext) -> ExecTrapResult<GasLeft>;
|
||||
}
|
||||
|
||||
/// Resume call interface
|
||||
pub trait ResumeCall: Send {
|
||||
/// Resume an execution for call, returns back the Vm interface.
|
||||
fn resume_call(self: Box<Self>, result: MessageCallResult) -> Box<Exec>;
|
||||
/// Resume an execution for call, returns back the Vm interface.
|
||||
fn resume_call(self: Box<Self>, result: MessageCallResult) -> Box<Exec>;
|
||||
}
|
||||
|
||||
/// Resume create interface
|
||||
pub trait ResumeCreate: Send {
|
||||
/// Resume an execution from create, returns back the Vm interface.
|
||||
fn resume_create(self: Box<Self>, result: ContractCreateResult) -> Box<Exec>;
|
||||
/// Resume an execution from create, returns back the Vm interface.
|
||||
fn resume_create(self: Box<Self>, result: ContractCreateResult) -> Box<Exec>;
|
||||
}
|
||||
|
||||
@@ -21,46 +21,46 @@ use ethereum_types::U256;
|
||||
/// Return data buffer. Holds memory from a previous call and a slice into that memory.
|
||||
#[derive(Debug)]
|
||||
pub struct ReturnData {
|
||||
mem: Vec<u8>,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
mem: Vec<u8>,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
impl ::std::ops::Deref for ReturnData {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
&self.mem[self.offset..self.offset + self.size]
|
||||
}
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
&self.mem[self.offset..self.offset + self.size]
|
||||
}
|
||||
}
|
||||
|
||||
impl ReturnData {
|
||||
/// Create empty `ReturnData`.
|
||||
pub fn empty() -> Self {
|
||||
ReturnData {
|
||||
mem: Vec::new(),
|
||||
offset: 0,
|
||||
size: 0,
|
||||
}
|
||||
}
|
||||
/// Create `ReturnData` from give buffer and slice.
|
||||
pub fn new(mem: Vec<u8>, offset: usize, size: usize) -> Self {
|
||||
ReturnData { mem, offset, size }
|
||||
}
|
||||
/// Create empty `ReturnData`.
|
||||
pub fn empty() -> Self {
|
||||
ReturnData {
|
||||
mem: Vec::new(),
|
||||
offset: 0,
|
||||
size: 0,
|
||||
}
|
||||
}
|
||||
/// Create `ReturnData` from give buffer and slice.
|
||||
pub fn new(mem: Vec<u8>, offset: usize, size: usize) -> Self {
|
||||
ReturnData { mem, offset, size }
|
||||
}
|
||||
}
|
||||
|
||||
/// Gas Left: either it is a known value, or it needs to be computed by processing
|
||||
/// a return instruction.
|
||||
#[derive(Debug)]
|
||||
pub enum GasLeft {
|
||||
/// Known gas left
|
||||
Known(U256),
|
||||
/// Return or Revert instruction must be processed.
|
||||
NeedsReturn {
|
||||
/// Amount of gas left.
|
||||
gas_left: U256,
|
||||
/// Return data buffer.
|
||||
data: ReturnData,
|
||||
/// Apply or revert state changes on revert.
|
||||
apply_state: bool
|
||||
},
|
||||
/// Known gas left
|
||||
Known(U256),
|
||||
/// Return or Revert instruction must be processed.
|
||||
NeedsReturn {
|
||||
/// Amount of gas left.
|
||||
gas_left: U256,
|
||||
/// Return data buffer.
|
||||
data: ReturnData,
|
||||
/// Apply or revert state changes on revert.
|
||||
apply_state: bool,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -15,379 +15,386 @@
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Cost schedule and other parameterisations for the EVM.
|
||||
use std::collections::HashMap;
|
||||
use ethereum_types::U256;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Definition of schedules that can be applied to a version.
|
||||
#[derive(Debug)]
|
||||
pub enum VersionedSchedule {
|
||||
PWasm,
|
||||
PWasm,
|
||||
}
|
||||
|
||||
/// Definition of the cost schedule and other parameterisations for the EVM.
|
||||
#[derive(Debug)]
|
||||
pub struct Schedule {
|
||||
/// Does it support exceptional failed code deposit
|
||||
pub exceptional_failed_code_deposit: bool,
|
||||
/// Does it have a delegate cal
|
||||
pub have_delegate_call: bool,
|
||||
/// Does it have a CREATE2 instruction
|
||||
pub have_create2: bool,
|
||||
/// Does it have a REVERT instruction
|
||||
pub have_revert: bool,
|
||||
/// Does it have a EXTCODEHASH instruction
|
||||
pub have_extcodehash: bool,
|
||||
/// VM stack limit
|
||||
pub stack_limit: usize,
|
||||
/// Max number of nested calls/creates
|
||||
pub max_depth: usize,
|
||||
/// Gas prices for instructions in all tiers
|
||||
pub tier_step_gas: [usize; 8],
|
||||
/// Gas price for `EXP` opcode
|
||||
pub exp_gas: usize,
|
||||
/// Additional gas for `EXP` opcode for each byte of exponent
|
||||
pub exp_byte_gas: usize,
|
||||
/// Gas price for `SHA3` opcode
|
||||
pub sha3_gas: usize,
|
||||
/// Additional gas for `SHA3` opcode for each word of hashed memory
|
||||
pub sha3_word_gas: usize,
|
||||
/// Gas price for loading from storage
|
||||
pub sload_gas: usize,
|
||||
/// Gas price for setting new value to storage (`storage==0`, `new!=0`)
|
||||
pub sstore_set_gas: usize,
|
||||
/// Gas price for altering value in storage
|
||||
pub sstore_reset_gas: usize,
|
||||
/// Gas refund for `SSTORE` clearing (when `storage!=0`, `new==0`)
|
||||
pub sstore_refund_gas: usize,
|
||||
/// Gas price for `JUMPDEST` opcode
|
||||
pub jumpdest_gas: usize,
|
||||
/// Gas price for `LOG*`
|
||||
pub log_gas: usize,
|
||||
/// Additional gas for data in `LOG*`
|
||||
pub log_data_gas: usize,
|
||||
/// Additional gas for each topic in `LOG*`
|
||||
pub log_topic_gas: usize,
|
||||
/// Gas price for `CREATE` opcode
|
||||
pub create_gas: usize,
|
||||
/// Gas price for `*CALL*` opcodes
|
||||
pub call_gas: usize,
|
||||
/// Stipend for transfer for `CALL|CALLCODE` opcode when `value>0`
|
||||
pub call_stipend: usize,
|
||||
/// Additional gas required for value transfer (`CALL|CALLCODE`)
|
||||
pub call_value_transfer_gas: usize,
|
||||
/// Additional gas for creating new account (`CALL|CALLCODE`)
|
||||
pub call_new_account_gas: usize,
|
||||
/// Refund for SUICIDE
|
||||
pub suicide_refund_gas: usize,
|
||||
/// Gas for used memory
|
||||
pub memory_gas: usize,
|
||||
/// Coefficient used to convert memory size to gas price for memory
|
||||
pub quad_coeff_div: usize,
|
||||
/// Cost for contract length when executing `CREATE`
|
||||
pub create_data_gas: usize,
|
||||
/// Maximum code size when creating a contract.
|
||||
pub create_data_limit: usize,
|
||||
/// Transaction cost
|
||||
pub tx_gas: usize,
|
||||
/// `CREATE` transaction cost
|
||||
pub tx_create_gas: usize,
|
||||
/// Additional cost for empty data transaction
|
||||
pub tx_data_zero_gas: usize,
|
||||
/// Additional cost for non-empty data transaction
|
||||
pub tx_data_non_zero_gas: usize,
|
||||
/// Gas price for copying memory
|
||||
pub copy_gas: usize,
|
||||
/// Price of EXTCODESIZE
|
||||
pub extcodesize_gas: usize,
|
||||
/// Base price of EXTCODECOPY
|
||||
pub extcodecopy_base_gas: usize,
|
||||
/// Price of BALANCE
|
||||
pub balance_gas: usize,
|
||||
/// Price of EXTCODEHASH
|
||||
pub extcodehash_gas: usize,
|
||||
/// Price of SUICIDE
|
||||
pub suicide_gas: usize,
|
||||
/// Amount of additional gas to pay when SUICIDE credits a non-existant account
|
||||
pub suicide_to_new_account_cost: usize,
|
||||
/// If Some(x): let limit = GAS * (x - 1) / x; let CALL's gas = min(requested, limit). let CREATE's gas = limit.
|
||||
/// If None: let CALL's gas = (requested > GAS ? [OOG] : GAS). let CREATE's gas = GAS
|
||||
pub sub_gas_cap_divisor: Option<usize>,
|
||||
/// Don't ever make empty accounts; contracts start with nonce=1. Also, don't charge 25k when sending/suicide zero-value.
|
||||
pub no_empty: bool,
|
||||
/// Kill empty accounts if touched.
|
||||
pub kill_empty: bool,
|
||||
/// Blockhash instruction gas cost.
|
||||
pub blockhash_gas: usize,
|
||||
/// Static Call opcode enabled.
|
||||
pub have_static_call: bool,
|
||||
/// RETURNDATA and RETURNDATASIZE opcodes enabled.
|
||||
pub have_return_data: bool,
|
||||
/// SHL, SHR, SAR opcodes enabled.
|
||||
pub have_bitwise_shifting: bool,
|
||||
/// CHAINID opcode enabled.
|
||||
pub have_chain_id: bool,
|
||||
/// SELFBALANCE opcode enabled.
|
||||
pub have_selfbalance: bool,
|
||||
/// Kill basic accounts below this balance if touched.
|
||||
pub kill_dust: CleanDustMode,
|
||||
/// Enable EIP-1283 rules
|
||||
pub eip1283: bool,
|
||||
/// Enable EIP-1706 rules
|
||||
pub eip1706: bool,
|
||||
/// VM execution does not increase null signed address nonce if this field is true.
|
||||
pub keep_unsigned_nonce: bool,
|
||||
/// Wasm extra schedule settings, if wasm activated
|
||||
pub wasm: Option<WasmCosts>,
|
||||
/// Does it support exceptional failed code deposit
|
||||
pub exceptional_failed_code_deposit: bool,
|
||||
/// Does it have a delegate cal
|
||||
pub have_delegate_call: bool,
|
||||
/// Does it have a CREATE2 instruction
|
||||
pub have_create2: bool,
|
||||
/// Does it have a REVERT instruction
|
||||
pub have_revert: bool,
|
||||
/// Does it have a EXTCODEHASH instruction
|
||||
pub have_extcodehash: bool,
|
||||
/// VM stack limit
|
||||
pub stack_limit: usize,
|
||||
/// Max number of nested calls/creates
|
||||
pub max_depth: usize,
|
||||
/// Gas prices for instructions in all tiers
|
||||
pub tier_step_gas: [usize; 8],
|
||||
/// Gas price for `EXP` opcode
|
||||
pub exp_gas: usize,
|
||||
/// Additional gas for `EXP` opcode for each byte of exponent
|
||||
pub exp_byte_gas: usize,
|
||||
/// Gas price for `SHA3` opcode
|
||||
pub sha3_gas: usize,
|
||||
/// Additional gas for `SHA3` opcode for each word of hashed memory
|
||||
pub sha3_word_gas: usize,
|
||||
/// Gas price for loading from storage
|
||||
pub sload_gas: usize,
|
||||
/// Gas price for setting new value to storage (`storage==0`, `new!=0`)
|
||||
pub sstore_set_gas: usize,
|
||||
/// Gas price for altering value in storage
|
||||
pub sstore_reset_gas: usize,
|
||||
/// Gas refund for `SSTORE` clearing (when `storage!=0`, `new==0`)
|
||||
pub sstore_refund_gas: usize,
|
||||
/// Gas price for `JUMPDEST` opcode
|
||||
pub jumpdest_gas: usize,
|
||||
/// Gas price for `LOG*`
|
||||
pub log_gas: usize,
|
||||
/// Additional gas for data in `LOG*`
|
||||
pub log_data_gas: usize,
|
||||
/// Additional gas for each topic in `LOG*`
|
||||
pub log_topic_gas: usize,
|
||||
/// Gas price for `CREATE` opcode
|
||||
pub create_gas: usize,
|
||||
/// Gas price for `*CALL*` opcodes
|
||||
pub call_gas: usize,
|
||||
/// Stipend for transfer for `CALL|CALLCODE` opcode when `value>0`
|
||||
pub call_stipend: usize,
|
||||
/// Additional gas required for value transfer (`CALL|CALLCODE`)
|
||||
pub call_value_transfer_gas: usize,
|
||||
/// Additional gas for creating new account (`CALL|CALLCODE`)
|
||||
pub call_new_account_gas: usize,
|
||||
/// Refund for SUICIDE
|
||||
pub suicide_refund_gas: usize,
|
||||
/// Gas for used memory
|
||||
pub memory_gas: usize,
|
||||
/// Coefficient used to convert memory size to gas price for memory
|
||||
pub quad_coeff_div: usize,
|
||||
/// Cost for contract length when executing `CREATE`
|
||||
pub create_data_gas: usize,
|
||||
/// Maximum code size when creating a contract.
|
||||
pub create_data_limit: usize,
|
||||
/// Transaction cost
|
||||
pub tx_gas: usize,
|
||||
/// `CREATE` transaction cost
|
||||
pub tx_create_gas: usize,
|
||||
/// Additional cost for empty data transaction
|
||||
pub tx_data_zero_gas: usize,
|
||||
/// Additional cost for non-empty data transaction
|
||||
pub tx_data_non_zero_gas: usize,
|
||||
/// Gas price for copying memory
|
||||
pub copy_gas: usize,
|
||||
/// Price of EXTCODESIZE
|
||||
pub extcodesize_gas: usize,
|
||||
/// Base price of EXTCODECOPY
|
||||
pub extcodecopy_base_gas: usize,
|
||||
/// Price of BALANCE
|
||||
pub balance_gas: usize,
|
||||
/// Price of EXTCODEHASH
|
||||
pub extcodehash_gas: usize,
|
||||
/// Price of SUICIDE
|
||||
pub suicide_gas: usize,
|
||||
/// Amount of additional gas to pay when SUICIDE credits a non-existant account
|
||||
pub suicide_to_new_account_cost: usize,
|
||||
/// If Some(x): let limit = GAS * (x - 1) / x; let CALL's gas = min(requested, limit). let CREATE's gas = limit.
|
||||
/// If None: let CALL's gas = (requested > GAS ? [OOG] : GAS). let CREATE's gas = GAS
|
||||
pub sub_gas_cap_divisor: Option<usize>,
|
||||
/// Don't ever make empty accounts; contracts start with nonce=1. Also, don't charge 25k when sending/suicide zero-value.
|
||||
pub no_empty: bool,
|
||||
/// Kill empty accounts if touched.
|
||||
pub kill_empty: bool,
|
||||
/// Blockhash instruction gas cost.
|
||||
pub blockhash_gas: usize,
|
||||
/// Static Call opcode enabled.
|
||||
pub have_static_call: bool,
|
||||
/// RETURNDATA and RETURNDATASIZE opcodes enabled.
|
||||
pub have_return_data: bool,
|
||||
/// SHL, SHR, SAR opcodes enabled.
|
||||
pub have_bitwise_shifting: bool,
|
||||
/// CHAINID opcode enabled.
|
||||
pub have_chain_id: bool,
|
||||
/// SELFBALANCE opcode enabled.
|
||||
pub have_selfbalance: bool,
|
||||
/// Kill basic accounts below this balance if touched.
|
||||
pub kill_dust: CleanDustMode,
|
||||
/// Enable EIP-1283 rules
|
||||
pub eip1283: bool,
|
||||
/// Enable EIP-1706 rules
|
||||
pub eip1706: bool,
|
||||
/// VM execution does not increase null signed address nonce if this field is true.
|
||||
pub keep_unsigned_nonce: bool,
|
||||
/// Wasm extra schedule settings, if wasm activated
|
||||
pub wasm: Option<WasmCosts>,
|
||||
}
|
||||
|
||||
/// Wasm cost table
|
||||
#[derive(Debug)]
|
||||
pub struct WasmCosts {
|
||||
/// Default opcode cost
|
||||
pub regular: u32,
|
||||
/// Div operations multiplier.
|
||||
pub div: u32,
|
||||
/// Div operations multiplier.
|
||||
pub mul: u32,
|
||||
/// Memory (load/store) operations multiplier.
|
||||
pub mem: u32,
|
||||
/// General static query of U256 value from env-info
|
||||
pub static_u256: u32,
|
||||
/// General static query of Address value from env-info
|
||||
pub static_address: u32,
|
||||
/// Memory stipend. Amount of free memory (in 64kb pages) each contract can use for stack.
|
||||
pub initial_mem: u32,
|
||||
/// Grow memory cost, per page (64kb)
|
||||
pub grow_mem: u32,
|
||||
/// Memory copy cost, per byte
|
||||
pub memcpy: u32,
|
||||
/// Max stack height (native WebAssembly stack limiter)
|
||||
pub max_stack_height: u32,
|
||||
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
|
||||
pub opcodes_mul: u32,
|
||||
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
|
||||
pub opcodes_div: u32,
|
||||
/// Whether create2 extern function is activated.
|
||||
pub have_create2: bool,
|
||||
/// Whether gasleft extern function is activated.
|
||||
pub have_gasleft: bool,
|
||||
/// Default opcode cost
|
||||
pub regular: u32,
|
||||
/// Div operations multiplier.
|
||||
pub div: u32,
|
||||
/// Div operations multiplier.
|
||||
pub mul: u32,
|
||||
/// Memory (load/store) operations multiplier.
|
||||
pub mem: u32,
|
||||
/// General static query of U256 value from env-info
|
||||
pub static_u256: u32,
|
||||
/// General static query of Address value from env-info
|
||||
pub static_address: u32,
|
||||
/// Memory stipend. Amount of free memory (in 64kb pages) each contract can use for stack.
|
||||
pub initial_mem: u32,
|
||||
/// Grow memory cost, per page (64kb)
|
||||
pub grow_mem: u32,
|
||||
/// Memory copy cost, per byte
|
||||
pub memcpy: u32,
|
||||
/// Max stack height (native WebAssembly stack limiter)
|
||||
pub max_stack_height: u32,
|
||||
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
|
||||
pub opcodes_mul: u32,
|
||||
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
|
||||
pub opcodes_div: u32,
|
||||
/// Whether create2 extern function is activated.
|
||||
pub have_create2: bool,
|
||||
/// Whether gasleft extern function is activated.
|
||||
pub have_gasleft: bool,
|
||||
}
|
||||
|
||||
impl Default for WasmCosts {
|
||||
fn default() -> Self {
|
||||
WasmCosts {
|
||||
regular: 1,
|
||||
div: 16,
|
||||
mul: 4,
|
||||
mem: 2,
|
||||
static_u256: 64,
|
||||
static_address: 40,
|
||||
initial_mem: 4096,
|
||||
grow_mem: 8192,
|
||||
memcpy: 1,
|
||||
max_stack_height: 64*1024,
|
||||
opcodes_mul: 3,
|
||||
opcodes_div: 8,
|
||||
have_create2: false,
|
||||
have_gasleft: false,
|
||||
}
|
||||
}
|
||||
fn default() -> Self {
|
||||
WasmCosts {
|
||||
regular: 1,
|
||||
div: 16,
|
||||
mul: 4,
|
||||
mem: 2,
|
||||
static_u256: 64,
|
||||
static_address: 40,
|
||||
initial_mem: 4096,
|
||||
grow_mem: 8192,
|
||||
memcpy: 1,
|
||||
max_stack_height: 64 * 1024,
|
||||
opcodes_mul: 3,
|
||||
opcodes_div: 8,
|
||||
have_create2: false,
|
||||
have_gasleft: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Dust accounts cleanup mode.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum CleanDustMode {
|
||||
/// Dust cleanup is disabled.
|
||||
Off,
|
||||
/// Basic dust accounts will be removed.
|
||||
BasicOnly,
|
||||
/// Basic and contract dust accounts will be removed.
|
||||
WithCodeAndStorage,
|
||||
/// Dust cleanup is disabled.
|
||||
Off,
|
||||
/// Basic dust accounts will be removed.
|
||||
BasicOnly,
|
||||
/// Basic and contract dust accounts will be removed.
|
||||
WithCodeAndStorage,
|
||||
}
|
||||
|
||||
impl Schedule {
|
||||
/// Schedule for the Frontier-era of the Ethereum main net.
|
||||
pub fn new_frontier() -> Schedule {
|
||||
Self::new(false, false, 21000)
|
||||
}
|
||||
/// Schedule for the Frontier-era of the Ethereum main net.
|
||||
pub fn new_frontier() -> Schedule {
|
||||
Self::new(false, false, 21000)
|
||||
}
|
||||
|
||||
/// Schedule for the Homestead-era of the Ethereum main net.
|
||||
pub fn new_homestead() -> Schedule {
|
||||
Self::new(true, true, 53000)
|
||||
}
|
||||
/// Schedule for the Homestead-era of the Ethereum main net.
|
||||
pub fn new_homestead() -> Schedule {
|
||||
Self::new(true, true, 53000)
|
||||
}
|
||||
|
||||
/// Schedule for the post-EIP-150-era of the Ethereum main net.
|
||||
pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool) -> Schedule {
|
||||
Schedule {
|
||||
exceptional_failed_code_deposit: true,
|
||||
have_delegate_call: true,
|
||||
have_create2: false,
|
||||
have_revert: false,
|
||||
have_return_data: false,
|
||||
have_bitwise_shifting: false,
|
||||
have_chain_id: false,
|
||||
have_selfbalance: false,
|
||||
have_extcodehash: false,
|
||||
stack_limit: 1024,
|
||||
max_depth: 1024,
|
||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||
exp_gas: 10,
|
||||
exp_byte_gas: if fix_exp {50} else {10},
|
||||
sha3_gas: 30,
|
||||
sha3_word_gas: 6,
|
||||
sload_gas: 200,
|
||||
sstore_set_gas: 20000,
|
||||
sstore_reset_gas: 5000,
|
||||
sstore_refund_gas: 15000,
|
||||
jumpdest_gas: 1,
|
||||
log_gas: 375,
|
||||
log_data_gas: 8,
|
||||
log_topic_gas: 375,
|
||||
create_gas: 32000,
|
||||
call_gas: 700,
|
||||
call_stipend: 2300,
|
||||
call_value_transfer_gas: 9000,
|
||||
call_new_account_gas: 25000,
|
||||
suicide_refund_gas: 24000,
|
||||
memory_gas: 3,
|
||||
quad_coeff_div: 512,
|
||||
create_data_gas: 200,
|
||||
create_data_limit: max_code_size,
|
||||
tx_gas: 21000,
|
||||
tx_create_gas: 53000,
|
||||
tx_data_zero_gas: 4,
|
||||
tx_data_non_zero_gas: 68,
|
||||
copy_gas: 3,
|
||||
extcodesize_gas: 700,
|
||||
extcodecopy_base_gas: 700,
|
||||
extcodehash_gas: 400,
|
||||
balance_gas: 400,
|
||||
suicide_gas: 5000,
|
||||
suicide_to_new_account_cost: 25000,
|
||||
sub_gas_cap_divisor: Some(64),
|
||||
no_empty: no_empty,
|
||||
kill_empty: kill_empty,
|
||||
blockhash_gas: 20,
|
||||
have_static_call: false,
|
||||
kill_dust: CleanDustMode::Off,
|
||||
eip1283: false,
|
||||
eip1706: false,
|
||||
keep_unsigned_nonce: false,
|
||||
wasm: None,
|
||||
}
|
||||
}
|
||||
/// Schedule for the post-EIP-150-era of the Ethereum main net.
|
||||
pub fn new_post_eip150(
|
||||
max_code_size: usize,
|
||||
fix_exp: bool,
|
||||
no_empty: bool,
|
||||
kill_empty: bool,
|
||||
) -> Schedule {
|
||||
Schedule {
|
||||
exceptional_failed_code_deposit: true,
|
||||
have_delegate_call: true,
|
||||
have_create2: false,
|
||||
have_revert: false,
|
||||
have_return_data: false,
|
||||
have_bitwise_shifting: false,
|
||||
have_chain_id: false,
|
||||
have_selfbalance: false,
|
||||
have_extcodehash: false,
|
||||
stack_limit: 1024,
|
||||
max_depth: 1024,
|
||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||
exp_gas: 10,
|
||||
exp_byte_gas: if fix_exp { 50 } else { 10 },
|
||||
sha3_gas: 30,
|
||||
sha3_word_gas: 6,
|
||||
sload_gas: 200,
|
||||
sstore_set_gas: 20000,
|
||||
sstore_reset_gas: 5000,
|
||||
sstore_refund_gas: 15000,
|
||||
jumpdest_gas: 1,
|
||||
log_gas: 375,
|
||||
log_data_gas: 8,
|
||||
log_topic_gas: 375,
|
||||
create_gas: 32000,
|
||||
call_gas: 700,
|
||||
call_stipend: 2300,
|
||||
call_value_transfer_gas: 9000,
|
||||
call_new_account_gas: 25000,
|
||||
suicide_refund_gas: 24000,
|
||||
memory_gas: 3,
|
||||
quad_coeff_div: 512,
|
||||
create_data_gas: 200,
|
||||
create_data_limit: max_code_size,
|
||||
tx_gas: 21000,
|
||||
tx_create_gas: 53000,
|
||||
tx_data_zero_gas: 4,
|
||||
tx_data_non_zero_gas: 68,
|
||||
copy_gas: 3,
|
||||
extcodesize_gas: 700,
|
||||
extcodecopy_base_gas: 700,
|
||||
extcodehash_gas: 400,
|
||||
balance_gas: 400,
|
||||
suicide_gas: 5000,
|
||||
suicide_to_new_account_cost: 25000,
|
||||
sub_gas_cap_divisor: Some(64),
|
||||
no_empty: no_empty,
|
||||
kill_empty: kill_empty,
|
||||
blockhash_gas: 20,
|
||||
have_static_call: false,
|
||||
kill_dust: CleanDustMode::Off,
|
||||
eip1283: false,
|
||||
eip1706: false,
|
||||
keep_unsigned_nonce: false,
|
||||
wasm: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Schedule for the Byzantium fork of the Ethereum main net.
|
||||
pub fn new_byzantium() -> Schedule {
|
||||
let mut schedule = Self::new_post_eip150(24576, true, true, true);
|
||||
schedule.have_create2 = true;
|
||||
schedule.have_revert = true;
|
||||
schedule.have_static_call = true;
|
||||
schedule.have_return_data = true;
|
||||
schedule
|
||||
}
|
||||
/// Schedule for the Byzantium fork of the Ethereum main net.
|
||||
pub fn new_byzantium() -> Schedule {
|
||||
let mut schedule = Self::new_post_eip150(24576, true, true, true);
|
||||
schedule.have_create2 = true;
|
||||
schedule.have_revert = true;
|
||||
schedule.have_static_call = true;
|
||||
schedule.have_return_data = true;
|
||||
schedule
|
||||
}
|
||||
|
||||
/// Schedule for the Constantinople fork of the Ethereum main net.
|
||||
pub fn new_constantinople() -> Schedule {
|
||||
let mut schedule = Self::new_byzantium();
|
||||
schedule.have_bitwise_shifting = true;
|
||||
schedule
|
||||
}
|
||||
/// Schedule for the Constantinople fork of the Ethereum main net.
|
||||
pub fn new_constantinople() -> Schedule {
|
||||
let mut schedule = Self::new_byzantium();
|
||||
schedule.have_bitwise_shifting = true;
|
||||
schedule
|
||||
}
|
||||
|
||||
/// Schedule for the Istanbul fork of the Ethereum main net.
|
||||
pub fn new_istanbul() -> Schedule {
|
||||
let mut schedule = Self::new_constantinople();
|
||||
schedule.have_chain_id = true; // EIP 1344
|
||||
schedule.tx_data_non_zero_gas = 16; // EIP 2028
|
||||
schedule.sload_gas = 800; // EIP 1884
|
||||
schedule.balance_gas = 700; // EIP 1884
|
||||
schedule.extcodehash_gas = 700; // EIP 1884
|
||||
schedule.have_selfbalance = true; // EIP 1884
|
||||
schedule
|
||||
}
|
||||
/// Schedule for the Istanbul fork of the Ethereum main net.
|
||||
pub fn new_istanbul() -> Schedule {
|
||||
let mut schedule = Self::new_constantinople();
|
||||
schedule.have_chain_id = true; // EIP 1344
|
||||
schedule.tx_data_non_zero_gas = 16; // EIP 2028
|
||||
schedule.sload_gas = 800; // EIP 1884
|
||||
schedule.balance_gas = 700; // EIP 1884
|
||||
schedule.extcodehash_gas = 700; // EIP 1884
|
||||
schedule.have_selfbalance = true; // EIP 1884
|
||||
schedule
|
||||
}
|
||||
|
||||
fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule {
|
||||
Schedule {
|
||||
exceptional_failed_code_deposit: efcd,
|
||||
have_delegate_call: hdc,
|
||||
have_create2: false,
|
||||
have_revert: false,
|
||||
have_return_data: false,
|
||||
have_bitwise_shifting: false,
|
||||
have_chain_id: false,
|
||||
have_selfbalance: false,
|
||||
have_extcodehash: false,
|
||||
stack_limit: 1024,
|
||||
max_depth: 1024,
|
||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||
exp_gas: 10,
|
||||
exp_byte_gas: 10,
|
||||
sha3_gas: 30,
|
||||
sha3_word_gas: 6,
|
||||
sload_gas: 50,
|
||||
sstore_set_gas: 20000,
|
||||
sstore_reset_gas: 5000,
|
||||
sstore_refund_gas: 15000,
|
||||
jumpdest_gas: 1,
|
||||
log_gas: 375,
|
||||
log_data_gas: 8,
|
||||
log_topic_gas: 375,
|
||||
create_gas: 32000,
|
||||
call_gas: 40,
|
||||
call_stipend: 2300,
|
||||
call_value_transfer_gas: 9000,
|
||||
call_new_account_gas: 25000,
|
||||
suicide_refund_gas: 24000,
|
||||
memory_gas: 3,
|
||||
quad_coeff_div: 512,
|
||||
create_data_gas: 200,
|
||||
create_data_limit: usize::max_value(),
|
||||
tx_gas: 21000,
|
||||
tx_create_gas: tcg,
|
||||
tx_data_zero_gas: 4,
|
||||
tx_data_non_zero_gas: 68,
|
||||
copy_gas: 3,
|
||||
extcodesize_gas: 20,
|
||||
extcodecopy_base_gas: 20,
|
||||
extcodehash_gas: 400,
|
||||
balance_gas: 20,
|
||||
suicide_gas: 0,
|
||||
suicide_to_new_account_cost: 0,
|
||||
sub_gas_cap_divisor: None,
|
||||
no_empty: false,
|
||||
kill_empty: false,
|
||||
blockhash_gas: 20,
|
||||
have_static_call: false,
|
||||
kill_dust: CleanDustMode::Off,
|
||||
eip1283: false,
|
||||
eip1706: false,
|
||||
keep_unsigned_nonce: false,
|
||||
wasm: None,
|
||||
}
|
||||
}
|
||||
fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule {
|
||||
Schedule {
|
||||
exceptional_failed_code_deposit: efcd,
|
||||
have_delegate_call: hdc,
|
||||
have_create2: false,
|
||||
have_revert: false,
|
||||
have_return_data: false,
|
||||
have_bitwise_shifting: false,
|
||||
have_chain_id: false,
|
||||
have_selfbalance: false,
|
||||
have_extcodehash: false,
|
||||
stack_limit: 1024,
|
||||
max_depth: 1024,
|
||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||
exp_gas: 10,
|
||||
exp_byte_gas: 10,
|
||||
sha3_gas: 30,
|
||||
sha3_word_gas: 6,
|
||||
sload_gas: 50,
|
||||
sstore_set_gas: 20000,
|
||||
sstore_reset_gas: 5000,
|
||||
sstore_refund_gas: 15000,
|
||||
jumpdest_gas: 1,
|
||||
log_gas: 375,
|
||||
log_data_gas: 8,
|
||||
log_topic_gas: 375,
|
||||
create_gas: 32000,
|
||||
call_gas: 40,
|
||||
call_stipend: 2300,
|
||||
call_value_transfer_gas: 9000,
|
||||
call_new_account_gas: 25000,
|
||||
suicide_refund_gas: 24000,
|
||||
memory_gas: 3,
|
||||
quad_coeff_div: 512,
|
||||
create_data_gas: 200,
|
||||
create_data_limit: usize::max_value(),
|
||||
tx_gas: 21000,
|
||||
tx_create_gas: tcg,
|
||||
tx_data_zero_gas: 4,
|
||||
tx_data_non_zero_gas: 68,
|
||||
copy_gas: 3,
|
||||
extcodesize_gas: 20,
|
||||
extcodecopy_base_gas: 20,
|
||||
extcodehash_gas: 400,
|
||||
balance_gas: 20,
|
||||
suicide_gas: 0,
|
||||
suicide_to_new_account_cost: 0,
|
||||
sub_gas_cap_divisor: None,
|
||||
no_empty: false,
|
||||
kill_empty: false,
|
||||
blockhash_gas: 20,
|
||||
have_static_call: false,
|
||||
kill_dust: CleanDustMode::Off,
|
||||
eip1283: false,
|
||||
eip1706: false,
|
||||
keep_unsigned_nonce: false,
|
||||
wasm: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns wasm schedule
|
||||
///
|
||||
/// May panic if there is no wasm schedule
|
||||
pub fn wasm(&self) -> &WasmCosts {
|
||||
// *** Prefer PANIC here instead of silently breaking consensus! ***
|
||||
self.wasm.as_ref().expect("Wasm schedule expected to exist while checking wasm contract. Misconfigured client?")
|
||||
}
|
||||
/// Returns wasm schedule
|
||||
///
|
||||
/// May panic if there is no wasm schedule
|
||||
pub fn wasm(&self) -> &WasmCosts {
|
||||
// *** Prefer PANIC here instead of silently breaking consensus! ***
|
||||
self.wasm.as_ref().expect(
|
||||
"Wasm schedule expected to exist while checking wasm contract. Misconfigured client?",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Schedule {
|
||||
fn default() -> Self {
|
||||
Schedule::new_frontier()
|
||||
}
|
||||
fn default() -> Self {
|
||||
Schedule::new_frontier()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(test)]
|
||||
fn schedule_evm_assumptions() {
|
||||
let s1 = Schedule::new_frontier();
|
||||
let s2 = Schedule::new_homestead();
|
||||
let s1 = Schedule::new_frontier();
|
||||
let s2 = Schedule::new_homestead();
|
||||
|
||||
// To optimize division we assume 2**9 for quad_coeff_div
|
||||
assert_eq!(s1.quad_coeff_div, 512);
|
||||
assert_eq!(s2.quad_coeff_div, 512);
|
||||
// To optimize division we assume 2**9 for quad_coeff_div
|
||||
assert_eq!(s1.quad_coeff_div, 512);
|
||||
assert_eq!(s2.quad_coeff_div, 512);
|
||||
}
|
||||
|
||||
@@ -14,39 +14,47 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use ethereum_types::{U256, H256, Address};
|
||||
use bytes::Bytes;
|
||||
use {
|
||||
CallType, Schedule, EnvInfo,
|
||||
ReturnData, Ext, ContractCreateResult, MessageCallResult,
|
||||
CreateContractAddress, Result, GasLeft,
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
use hash::keccak;
|
||||
|
||||
use bytes::Bytes;
|
||||
use error::TrapKind;
|
||||
use ethereum_types::{Address, H256, U256};
|
||||
use hash::keccak;
|
||||
use CallType;
|
||||
use ContractCreateResult;
|
||||
use CreateContractAddress;
|
||||
use EnvInfo;
|
||||
use Ext;
|
||||
use GasLeft;
|
||||
use MessageCallResult;
|
||||
use Result;
|
||||
use ReturnData;
|
||||
use Schedule;
|
||||
|
||||
pub struct FakeLogEntry {
|
||||
pub topics: Vec<H256>,
|
||||
pub data: Bytes
|
||||
pub topics: Vec<H256>,
|
||||
pub data: Bytes,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||
pub enum FakeCallType {
|
||||
Call, Create
|
||||
Call,
|
||||
Create,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||
pub struct FakeCall {
|
||||
pub call_type: FakeCallType,
|
||||
pub create_scheme: Option<CreateContractAddress>,
|
||||
pub gas: U256,
|
||||
pub sender_address: Option<Address>,
|
||||
pub receive_address: Option<Address>,
|
||||
pub value: Option<U256>,
|
||||
pub data: Bytes,
|
||||
pub code_address: Option<Address>,
|
||||
pub call_type: FakeCallType,
|
||||
pub create_scheme: Option<CreateContractAddress>,
|
||||
pub gas: U256,
|
||||
pub sender_address: Option<Address>,
|
||||
pub receive_address: Option<Address>,
|
||||
pub value: Option<U256>,
|
||||
pub data: Bytes,
|
||||
pub code_address: Option<Address>,
|
||||
}
|
||||
|
||||
/// Fake externalities test structure.
|
||||
@@ -54,211 +62,211 @@ pub struct FakeCall {
|
||||
/// Can't do recursive calls.
|
||||
#[derive(Default)]
|
||||
pub struct FakeExt {
|
||||
pub store: HashMap<H256, H256>,
|
||||
pub suicides: HashSet<Address>,
|
||||
pub calls: HashSet<FakeCall>,
|
||||
pub sstore_clears: i128,
|
||||
pub depth: usize,
|
||||
pub blockhashes: HashMap<U256, H256>,
|
||||
pub codes: HashMap<Address, Arc<Bytes>>,
|
||||
pub logs: Vec<FakeLogEntry>,
|
||||
pub info: EnvInfo,
|
||||
pub schedule: Schedule,
|
||||
pub balances: HashMap<Address, U256>,
|
||||
pub tracing: bool,
|
||||
pub is_static: bool,
|
||||
pub store: HashMap<H256, H256>,
|
||||
pub suicides: HashSet<Address>,
|
||||
pub calls: HashSet<FakeCall>,
|
||||
pub sstore_clears: i128,
|
||||
pub depth: usize,
|
||||
pub blockhashes: HashMap<U256, H256>,
|
||||
pub codes: HashMap<Address, Arc<Bytes>>,
|
||||
pub logs: Vec<FakeLogEntry>,
|
||||
pub info: EnvInfo,
|
||||
pub schedule: Schedule,
|
||||
pub balances: HashMap<Address, U256>,
|
||||
pub tracing: bool,
|
||||
pub is_static: bool,
|
||||
|
||||
chain_id: u64,
|
||||
chain_id: u64,
|
||||
}
|
||||
|
||||
// similar to the normal `finalize` function, but ignoring NeedsReturn.
|
||||
pub fn test_finalize(res: Result<GasLeft>) -> Result<U256> {
|
||||
match res {
|
||||
Ok(GasLeft::Known(gas)) => Ok(gas),
|
||||
Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented.
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
match res {
|
||||
Ok(GasLeft::Known(gas)) => Ok(gas),
|
||||
Ok(GasLeft::NeedsReturn { .. }) => unimplemented!(), // since ret is unimplemented.
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
impl FakeExt {
|
||||
/// New fake externalities
|
||||
pub fn new() -> Self {
|
||||
FakeExt::default()
|
||||
}
|
||||
/// New fake externalities
|
||||
pub fn new() -> Self {
|
||||
FakeExt::default()
|
||||
}
|
||||
|
||||
/// New fake externalities with byzantium schedule rules
|
||||
pub fn new_byzantium() -> Self {
|
||||
let mut ext = FakeExt::default();
|
||||
ext.schedule = Schedule::new_byzantium();
|
||||
ext
|
||||
}
|
||||
/// New fake externalities with byzantium schedule rules
|
||||
pub fn new_byzantium() -> Self {
|
||||
let mut ext = FakeExt::default();
|
||||
ext.schedule = Schedule::new_byzantium();
|
||||
ext
|
||||
}
|
||||
|
||||
/// New fake externalities with constantinople schedule rules
|
||||
pub fn new_constantinople() -> Self {
|
||||
let mut ext = FakeExt::default();
|
||||
ext.schedule = Schedule::new_constantinople();
|
||||
ext
|
||||
}
|
||||
/// New fake externalities with constantinople schedule rules
|
||||
pub fn new_constantinople() -> Self {
|
||||
let mut ext = FakeExt::default();
|
||||
ext.schedule = Schedule::new_constantinople();
|
||||
ext
|
||||
}
|
||||
|
||||
/// New fake externalities with Istanbul schedule rules
|
||||
pub fn new_istanbul() -> Self {
|
||||
let mut ext = FakeExt::default();
|
||||
ext.schedule = Schedule::new_istanbul();
|
||||
ext
|
||||
}
|
||||
/// New fake externalities with Istanbul schedule rules
|
||||
pub fn new_istanbul() -> Self {
|
||||
let mut ext = FakeExt::default();
|
||||
ext.schedule = Schedule::new_istanbul();
|
||||
ext
|
||||
}
|
||||
|
||||
/// Alter fake externalities to allow wasm
|
||||
pub fn with_wasm(mut self) -> Self {
|
||||
self.schedule.wasm = Some(Default::default());
|
||||
self
|
||||
}
|
||||
/// Alter fake externalities to allow wasm
|
||||
pub fn with_wasm(mut self) -> Self {
|
||||
self.schedule.wasm = Some(Default::default());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set chain ID
|
||||
pub fn with_chain_id(mut self, chain_id: u64) -> Self {
|
||||
self.chain_id = chain_id;
|
||||
self
|
||||
}
|
||||
/// Set chain ID
|
||||
pub fn with_chain_id(mut self, chain_id: u64) -> Self {
|
||||
self.chain_id = chain_id;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Ext for FakeExt {
|
||||
fn initial_storage_at(&self, _key: &H256) -> Result<H256> {
|
||||
Ok(H256::new())
|
||||
}
|
||||
fn initial_storage_at(&self, _key: &H256) -> Result<H256> {
|
||||
Ok(H256::new())
|
||||
}
|
||||
|
||||
fn storage_at(&self, key: &H256) -> Result<H256> {
|
||||
Ok(self.store.get(key).unwrap_or(&H256::new()).clone())
|
||||
}
|
||||
fn storage_at(&self, key: &H256) -> Result<H256> {
|
||||
Ok(self.store.get(key).unwrap_or(&H256::new()).clone())
|
||||
}
|
||||
|
||||
fn set_storage(&mut self, key: H256, value: H256) -> Result<()> {
|
||||
self.store.insert(key, value);
|
||||
Ok(())
|
||||
}
|
||||
fn set_storage(&mut self, key: H256, value: H256) -> Result<()> {
|
||||
self.store.insert(key, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn exists(&self, address: &Address) -> Result<bool> {
|
||||
Ok(self.balances.contains_key(address))
|
||||
}
|
||||
fn exists(&self, address: &Address) -> Result<bool> {
|
||||
Ok(self.balances.contains_key(address))
|
||||
}
|
||||
|
||||
fn exists_and_not_null(&self, address: &Address) -> Result<bool> {
|
||||
Ok(self.balances.get(address).map_or(false, |b| !b.is_zero()))
|
||||
}
|
||||
fn exists_and_not_null(&self, address: &Address) -> Result<bool> {
|
||||
Ok(self.balances.get(address).map_or(false, |b| !b.is_zero()))
|
||||
}
|
||||
|
||||
fn origin_balance(&self) -> Result<U256> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn origin_balance(&self) -> Result<U256> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn balance(&self, address: &Address) -> Result<U256> {
|
||||
Ok(self.balances[address])
|
||||
}
|
||||
fn balance(&self, address: &Address) -> Result<U256> {
|
||||
Ok(self.balances[address])
|
||||
}
|
||||
|
||||
fn blockhash(&mut self, number: &U256) -> H256 {
|
||||
self.blockhashes.get(number).unwrap_or(&H256::new()).clone()
|
||||
}
|
||||
fn blockhash(&mut self, number: &U256) -> H256 {
|
||||
self.blockhashes.get(number).unwrap_or(&H256::new()).clone()
|
||||
}
|
||||
|
||||
fn create(
|
||||
&mut self,
|
||||
gas: &U256,
|
||||
value: &U256,
|
||||
code: &[u8],
|
||||
address: CreateContractAddress,
|
||||
_trap: bool,
|
||||
) -> ::std::result::Result<ContractCreateResult, TrapKind> {
|
||||
self.calls.insert(FakeCall {
|
||||
call_type: FakeCallType::Create,
|
||||
create_scheme: Some(address),
|
||||
gas: *gas,
|
||||
sender_address: None,
|
||||
receive_address: None,
|
||||
value: Some(*value),
|
||||
data: code.to_vec(),
|
||||
code_address: None
|
||||
});
|
||||
// TODO: support traps in testing.
|
||||
Ok(ContractCreateResult::Failed)
|
||||
}
|
||||
fn create(
|
||||
&mut self,
|
||||
gas: &U256,
|
||||
value: &U256,
|
||||
code: &[u8],
|
||||
address: CreateContractAddress,
|
||||
_trap: bool,
|
||||
) -> ::std::result::Result<ContractCreateResult, TrapKind> {
|
||||
self.calls.insert(FakeCall {
|
||||
call_type: FakeCallType::Create,
|
||||
create_scheme: Some(address),
|
||||
gas: *gas,
|
||||
sender_address: None,
|
||||
receive_address: None,
|
||||
value: Some(*value),
|
||||
data: code.to_vec(),
|
||||
code_address: None,
|
||||
});
|
||||
// TODO: support traps in testing.
|
||||
Ok(ContractCreateResult::Failed)
|
||||
}
|
||||
|
||||
fn call(
|
||||
&mut self,
|
||||
gas: &U256,
|
||||
sender_address: &Address,
|
||||
receive_address: &Address,
|
||||
value: Option<U256>,
|
||||
data: &[u8],
|
||||
code_address: &Address,
|
||||
_call_type: CallType,
|
||||
_trap: bool,
|
||||
) -> ::std::result::Result<MessageCallResult, TrapKind> {
|
||||
self.calls.insert(FakeCall {
|
||||
call_type: FakeCallType::Call,
|
||||
create_scheme: None,
|
||||
gas: *gas,
|
||||
sender_address: Some(sender_address.clone()),
|
||||
receive_address: Some(receive_address.clone()),
|
||||
value: value,
|
||||
data: data.to_vec(),
|
||||
code_address: Some(code_address.clone())
|
||||
});
|
||||
// TODO: support traps in testing.
|
||||
Ok(MessageCallResult::Success(*gas, ReturnData::empty()))
|
||||
}
|
||||
fn call(
|
||||
&mut self,
|
||||
gas: &U256,
|
||||
sender_address: &Address,
|
||||
receive_address: &Address,
|
||||
value: Option<U256>,
|
||||
data: &[u8],
|
||||
code_address: &Address,
|
||||
_call_type: CallType,
|
||||
_trap: bool,
|
||||
) -> ::std::result::Result<MessageCallResult, TrapKind> {
|
||||
self.calls.insert(FakeCall {
|
||||
call_type: FakeCallType::Call,
|
||||
create_scheme: None,
|
||||
gas: *gas,
|
||||
sender_address: Some(sender_address.clone()),
|
||||
receive_address: Some(receive_address.clone()),
|
||||
value: value,
|
||||
data: data.to_vec(),
|
||||
code_address: Some(code_address.clone()),
|
||||
});
|
||||
// TODO: support traps in testing.
|
||||
Ok(MessageCallResult::Success(*gas, ReturnData::empty()))
|
||||
}
|
||||
|
||||
fn extcode(&self, address: &Address) -> Result<Option<Arc<Bytes>>> {
|
||||
Ok(self.codes.get(address).cloned())
|
||||
}
|
||||
fn extcode(&self, address: &Address) -> Result<Option<Arc<Bytes>>> {
|
||||
Ok(self.codes.get(address).cloned())
|
||||
}
|
||||
|
||||
fn extcodesize(&self, address: &Address) -> Result<Option<usize>> {
|
||||
Ok(self.codes.get(address).map(|c| c.len()))
|
||||
}
|
||||
fn extcodesize(&self, address: &Address) -> Result<Option<usize>> {
|
||||
Ok(self.codes.get(address).map(|c| c.len()))
|
||||
}
|
||||
|
||||
fn extcodehash(&self, address: &Address) -> Result<Option<H256>> {
|
||||
Ok(self.codes.get(address).map(|c| keccak(c.as_ref())))
|
||||
}
|
||||
fn extcodehash(&self, address: &Address) -> Result<Option<H256>> {
|
||||
Ok(self.codes.get(address).map(|c| keccak(c.as_ref())))
|
||||
}
|
||||
|
||||
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> Result<()> {
|
||||
self.logs.push(FakeLogEntry {
|
||||
topics,
|
||||
data: data.to_vec()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> Result<()> {
|
||||
self.logs.push(FakeLogEntry {
|
||||
topics,
|
||||
data: data.to_vec(),
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ret(self, _gas: &U256, _data: &ReturnData, _apply_state: bool) -> Result<U256> {
|
||||
unimplemented!();
|
||||
}
|
||||
fn ret(self, _gas: &U256, _data: &ReturnData, _apply_state: bool) -> Result<U256> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn suicide(&mut self, refund_address: &Address) -> Result<()> {
|
||||
self.suicides.insert(refund_address.clone());
|
||||
Ok(())
|
||||
}
|
||||
fn suicide(&mut self, refund_address: &Address) -> Result<()> {
|
||||
self.suicides.insert(refund_address.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn schedule(&self) -> &Schedule {
|
||||
&self.schedule
|
||||
}
|
||||
fn schedule(&self) -> &Schedule {
|
||||
&self.schedule
|
||||
}
|
||||
|
||||
fn env_info(&self) -> &EnvInfo {
|
||||
&self.info
|
||||
}
|
||||
fn env_info(&self) -> &EnvInfo {
|
||||
&self.info
|
||||
}
|
||||
|
||||
fn chain_id(&self) -> u64 {
|
||||
self.chain_id
|
||||
}
|
||||
fn chain_id(&self) -> u64 {
|
||||
self.chain_id
|
||||
}
|
||||
|
||||
fn depth(&self) -> usize {
|
||||
self.depth
|
||||
}
|
||||
fn depth(&self) -> usize {
|
||||
self.depth
|
||||
}
|
||||
|
||||
fn is_static(&self) -> bool {
|
||||
self.is_static
|
||||
}
|
||||
fn is_static(&self) -> bool {
|
||||
self.is_static
|
||||
}
|
||||
|
||||
fn add_sstore_refund(&mut self, value: usize) {
|
||||
self.sstore_clears += value as i128;
|
||||
}
|
||||
fn add_sstore_refund(&mut self, value: usize) {
|
||||
self.sstore_clears += value as i128;
|
||||
}
|
||||
|
||||
fn sub_sstore_refund(&mut self, value: usize) {
|
||||
self.sstore_clears -= value as i128;
|
||||
}
|
||||
fn sub_sstore_refund(&mut self, value: usize) {
|
||||
self.sstore_clears -= value as i128;
|
||||
}
|
||||
|
||||
fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8, _gas: U256) -> bool {
|
||||
self.tracing
|
||||
}
|
||||
fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8, _gas: U256) -> bool {
|
||||
self.tracing
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user