Merge branch 'master' into ui-2
This commit is contained in:
commit
265618f306
@ -11,7 +11,7 @@
|
||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||
"homesteadTransition": "0x0",
|
||||
"eip150Transition": "0x0",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip155Transition": "0x0",
|
||||
"eip160Transition": "0x0",
|
||||
"eip161abcTransition": "0x0",
|
||||
"eip161dTransition": "0x0",
|
||||
@ -24,9 +24,10 @@
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x1",
|
||||
"eip98Transition": "0x7fffffffffffffff",
|
||||
"eip98Transition": "0x0",
|
||||
"eip86Transition": "0x0",
|
||||
"eip140Transition": "0x0"
|
||||
"eip140Transition": "0x0",
|
||||
"eip210Transition": "0x0"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -265,7 +265,7 @@ impl<'x> OpenBlock<'x> {
|
||||
let mut r = OpenBlock {
|
||||
block: ExecutedBlock::new(state, tracing),
|
||||
engine: engine,
|
||||
last_hashes: last_hashes,
|
||||
last_hashes: last_hashes.clone(),
|
||||
};
|
||||
|
||||
r.block.header.set_parent_hash(parent.hash());
|
||||
@ -278,7 +278,7 @@ impl<'x> OpenBlock<'x> {
|
||||
let gas_floor_target = cmp::max(gas_range_target.0, engine.params().min_gas_limit);
|
||||
let gas_ceil_target = cmp::max(gas_range_target.1, gas_floor_target);
|
||||
engine.populate_from_parent(&mut r.block.header, parent, gas_floor_target, gas_ceil_target);
|
||||
engine.on_new_block(&mut r.block);
|
||||
engine.on_new_block(&mut r.block, last_hashes)?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
@ -373,7 +373,9 @@ impl<'x> OpenBlock<'x> {
|
||||
|
||||
let unclosed_state = s.block.state.clone();
|
||||
|
||||
s.engine.on_close_block(&mut s.block);
|
||||
if let Err(e) = s.engine.on_close_block(&mut s.block) {
|
||||
warn!("Encountered error on closing the block: {}", e);
|
||||
}
|
||||
if let Err(e) = s.block.state.commit() {
|
||||
warn!("Encountered error on state commit: {}", e);
|
||||
}
|
||||
@ -397,7 +399,9 @@ impl<'x> OpenBlock<'x> {
|
||||
pub fn close_and_lock(self) -> LockedBlock {
|
||||
let mut s = self;
|
||||
|
||||
s.engine.on_close_block(&mut s.block);
|
||||
if let Err(e) = s.engine.on_close_block(&mut s.block) {
|
||||
warn!("Encountered error on closing the block: {}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = s.block.state.commit() {
|
||||
warn!("Encountered error on state commit: {}", e);
|
||||
|
@ -1032,8 +1032,7 @@ impl BlockChainClient for Client {
|
||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm)
|
||||
.transact_virtual(t, options)?;
|
||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact_virtual(t, options)?;
|
||||
|
||||
// TODO gav move this into Executive.
|
||||
if let Some(original) = original_state {
|
||||
@ -1063,7 +1062,7 @@ impl BlockChainClient for Client {
|
||||
let tx = tx.fake_sign(sender);
|
||||
|
||||
let mut state = original_state.clone();
|
||||
Ok(Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm)
|
||||
Ok(Executive::new(&mut state, &env_info, &*self.engine)
|
||||
.transact_virtual(&tx, options.clone())
|
||||
.map(|r| r.exception.is_none())
|
||||
.unwrap_or(false))
|
||||
@ -1125,13 +1124,13 @@ impl BlockChainClient for Client {
|
||||
let rest = txs.split_off(address.index);
|
||||
for t in txs {
|
||||
let t = SignedTransaction::new(t).expect(PROOF);
|
||||
let x = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(&t, Default::default())?;
|
||||
let x = Executive::new(&mut state, &env_info, &*self.engine).transact(&t, Default::default())?;
|
||||
env_info.gas_used = env_info.gas_used + x.gas_used;
|
||||
}
|
||||
let first = rest.into_iter().next().expect("We split off < `address.index`; Length is checked earlier; qed");
|
||||
let t = SignedTransaction::new(first).expect(PROOF);
|
||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(&t, options)?;
|
||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact(&t, options)?;
|
||||
if let Some(original) = original_state {
|
||||
ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?)
|
||||
}
|
||||
@ -1753,7 +1752,7 @@ impl ProvingBlockChainClient for Client {
|
||||
|
||||
let mut state = state.replace_backend(backend);
|
||||
let options = TransactOptions { tracing: false, vm_tracing: false, check_nonce: false };
|
||||
let res = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(&transaction, options);
|
||||
let res = Executive::new(&mut state, &env_info, &*self.engine).transact(&transaction, options);
|
||||
|
||||
match res {
|
||||
Err(ExecutionError::Internal(_)) => None,
|
||||
|
@ -103,7 +103,7 @@ impl EvmTestClient {
|
||||
let mut substate = state::Substate::new();
|
||||
let mut tracer = trace::NoopTracer;
|
||||
let mut output = vec![];
|
||||
let mut executive = executive::Executive::new(&mut state, &info, &*self.spec.engine, &self.factories.vm);
|
||||
let mut executive = executive::Executive::new(&mut state, &info, &*self.spec.engine);
|
||||
let gas_left = executive.call(
|
||||
params,
|
||||
&mut substate,
|
||||
|
@ -413,7 +413,7 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
|
||||
fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> {
|
||||
match id {
|
||||
BlockId::Latest => Some(self.nonces.read().get(address).cloned().unwrap_or(self.spec.params.account_start_nonce)),
|
||||
BlockId::Latest => Some(self.nonces.read().get(address).cloned().unwrap_or(self.spec.params().account_start_nonce)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -747,7 +747,7 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
value: U256::default(),
|
||||
data: data,
|
||||
};
|
||||
let network_id = Some(self.spec.params.network_id);
|
||||
let network_id = Some(self.spec.params().network_id);
|
||||
let sig = self.spec.engine.sign(transaction.hash(network_id)).unwrap();
|
||||
let signed = SignedTransaction::new(transaction.with_signature(sig, network_id)).unwrap();
|
||||
self.miner.import_own_transaction(self, signed.into())
|
||||
|
@ -340,16 +340,17 @@ impl Engine for AuthorityRound {
|
||||
}
|
||||
|
||||
/// Apply the block reward on finalisation of the block.
|
||||
fn on_close_block(&self, block: &mut ExecutedBlock) {
|
||||
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
|
||||
let fields = block.fields_mut();
|
||||
// Bestow block reward
|
||||
let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty)
|
||||
.map_err(::error::Error::from)
|
||||
.and_then(|_| fields.state.commit());
|
||||
// Commit state so that we can actually figure out the state root.
|
||||
if let Err(e) = res {
|
||||
if let Err(ref e) = res {
|
||||
warn!("Encountered error on closing block: {}", e);
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
/// Check the number of seal fields.
|
||||
|
@ -40,7 +40,7 @@ use account_provider::AccountProvider;
|
||||
use block::ExecutedBlock;
|
||||
use builtin::Builtin;
|
||||
use client::Client;
|
||||
use env_info::EnvInfo;
|
||||
use env_info::{EnvInfo, LastHashes};
|
||||
use error::Error;
|
||||
use evm::Schedule;
|
||||
use header::{Header, BlockNumber};
|
||||
@ -53,6 +53,10 @@ use evm::CreateContractAddress;
|
||||
use ethkey::Signature;
|
||||
use util::*;
|
||||
|
||||
/// Default EIP-210 contrat code.
|
||||
/// As defined in https://github.com/ethereum/EIPs/pull/210/commits/9df24a3714af42e3bf350265bdc75b486c909d7f#diff-e02a92c2fb96c1a1bfb05e4c6e2ef5daR49
|
||||
pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561007a57600143036020526000356101006020510755600061010060205107141561005057600035610100610100602051050761010001555b6000620100006020510714156100755760003561010062010000602051050761020001555b610161565b436000351215801561008c5780610095565b623567e0600035125b9050156100a757600060605260206060f35b610100600035430312156100ca57610100600035075460805260206080f3610160565b62010000600035430312156100e857600061010060003507146100eb565b60005b1561010d576101006101006000350507610100015460a052602060a0f361015f565b63010000006000354303121561012d576000620100006000350714610130565b60005b1561015357610100620100006000350507610200015460c052602060c0f361015e565b600060e052602060e0f35b5b5b5b5b";
|
||||
|
||||
/// Voting errors.
|
||||
#[derive(Debug)]
|
||||
pub enum EngineError {
|
||||
@ -159,9 +163,15 @@ pub trait Engine : Sync + Send {
|
||||
fn account_start_nonce(&self) -> U256 { self.params().account_start_nonce }
|
||||
|
||||
/// Block transformation functions, before the transactions.
|
||||
fn on_new_block(&self, _block: &mut ExecutedBlock) {}
|
||||
fn on_new_block(&self, block: &mut ExecutedBlock, last_hashes: Arc<LastHashes>) -> Result<(), Error> {
|
||||
let parent_hash = block.fields().header.parent_hash().clone();
|
||||
common::push_last_hash(block, last_hashes, self, &parent_hash)
|
||||
}
|
||||
|
||||
/// Block transformation functions, after the transactions.
|
||||
fn on_close_block(&self, _block: &mut ExecutedBlock) {}
|
||||
fn on_close_block(&self, _block: &mut ExecutedBlock) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// None means that it requires external input (e.g. PoW) to seal a block.
|
||||
/// Some(true) means the engine is currently prime for seal generation (i.e. node is the current validator).
|
||||
@ -314,3 +324,64 @@ pub trait Engine : Sync + Send {
|
||||
if number >= self.params().eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Common engine utilities
|
||||
pub mod common {
|
||||
use block::ExecutedBlock;
|
||||
use env_info::{EnvInfo, LastHashes};
|
||||
use error::Error;
|
||||
use transaction::SYSTEM_ADDRESS;
|
||||
use executive::Executive;
|
||||
use types::executed::CallType;
|
||||
use action_params::{ActionParams, ActionValue};
|
||||
use trace::{NoopTracer, NoopVMTracer};
|
||||
use state::Substate;
|
||||
|
||||
use util::*;
|
||||
use super::Engine;
|
||||
|
||||
/// Push last known block hash to the state.
|
||||
pub fn push_last_hash<E: Engine + ?Sized>(block: &mut ExecutedBlock, last_hashes: Arc<LastHashes>, engine: &E, hash: &H256) -> Result<(), Error> {
|
||||
if block.fields().header.number() == engine.params().eip210_transition {
|
||||
let state = block.fields_mut().state;
|
||||
state.init_code(&engine.params().eip210_contract_address, engine.params().eip210_contract_code.clone())?;
|
||||
}
|
||||
if block.fields().header.number() >= engine.params().eip210_transition {
|
||||
let env_info = {
|
||||
let header = block.fields().header;
|
||||
EnvInfo {
|
||||
number: header.number(),
|
||||
author: header.author().clone(),
|
||||
timestamp: header.timestamp(),
|
||||
difficulty: header.difficulty().clone(),
|
||||
last_hashes: last_hashes,
|
||||
gas_used: U256::zero(),
|
||||
gas_limit: engine.params().eip210_contract_gas,
|
||||
}
|
||||
};
|
||||
let mut state = block.fields_mut().state;
|
||||
let contract_address = engine.params().eip210_contract_address;
|
||||
let params = ActionParams {
|
||||
code_address: contract_address.clone(),
|
||||
address: contract_address.clone(),
|
||||
sender: SYSTEM_ADDRESS.clone(),
|
||||
origin: SYSTEM_ADDRESS.clone(),
|
||||
gas: engine.params().eip210_contract_gas,
|
||||
gas_price: 0.into(),
|
||||
value: ActionValue::Transfer(0.into()),
|
||||
code: state.code(&contract_address)?,
|
||||
code_hash: state.code_hash(&contract_address)?,
|
||||
data: Some(hash.to_vec()),
|
||||
call_type: CallType::Call,
|
||||
};
|
||||
let mut ex = Executive::new(&mut state, &env_info, engine);
|
||||
let mut substate = Substate::new();
|
||||
let mut output = [];
|
||||
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
|
||||
warn!("Encountered error on updating last hashes: {}", e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -482,16 +482,17 @@ impl Engine for Tendermint {
|
||||
}
|
||||
|
||||
/// Apply the block reward on finalisation of the block.
|
||||
fn on_close_block(&self, block: &mut ExecutedBlock) {
|
||||
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error>{
|
||||
let fields = block.fields_mut();
|
||||
// Bestow block reward
|
||||
let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty)
|
||||
.map_err(::error::Error::from)
|
||||
.and_then(|_| fields.state.commit());
|
||||
// Commit state so that we can actually figure out the state root.
|
||||
if let Err(e) = res {
|
||||
if let Err(ref e) = res {
|
||||
warn!("Encountered error on closing block: {}", e);
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||
|
@ -28,6 +28,7 @@ use engines::Engine;
|
||||
use evm::Schedule;
|
||||
use ethjson;
|
||||
use rlp::{self, UntrustedRlp};
|
||||
use env_info::LastHashes;
|
||||
|
||||
/// Parity tries to round block.gas_limit to multiple of this constant
|
||||
pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]);
|
||||
@ -252,60 +253,46 @@ impl Engine for Arc<Ethash> {
|
||||
// info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number(), header.difficulty(), header.gas_limit());
|
||||
}
|
||||
|
||||
fn on_new_block(&self, block: &mut ExecutedBlock) {
|
||||
fn on_new_block(&self, block: &mut ExecutedBlock, last_hashes: Arc<LastHashes>) -> Result<(), Error> {
|
||||
let parent_hash = block.fields().header.parent_hash().clone();
|
||||
try!(::engines::common::push_last_hash(block, last_hashes, self, &parent_hash));
|
||||
if block.fields().header.number() == self.ethash_params.dao_hardfork_transition {
|
||||
// TODO: enable trigger function maybe?
|
||||
// if block.fields().header.gas_limit() <= 4_000_000.into() {
|
||||
let state = block.fields_mut().state;
|
||||
for child in &self.ethash_params.dao_hardfork_accounts {
|
||||
let beneficiary = &self.ethash_params.dao_hardfork_beneficiary;
|
||||
let res = state.balance(child)
|
||||
.and_then(|b| state.transfer_balance(child, beneficiary, &b, CleanupMode::NoEmpty));
|
||||
|
||||
if let Err(_) = res {
|
||||
warn!("Unable to apply DAO hardfork due to database corruption.");
|
||||
warn!("Your node is now likely out of consensus.");
|
||||
}
|
||||
}
|
||||
// }
|
||||
let state = block.fields_mut().state;
|
||||
for child in &self.ethash_params.dao_hardfork_accounts {
|
||||
let beneficiary = &self.ethash_params.dao_hardfork_beneficiary;
|
||||
try!(state.balance(child)
|
||||
.and_then(|b| state.transfer_balance(child, beneficiary, &b, CleanupMode::NoEmpty)));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Apply the block reward on finalisation of the block.
|
||||
/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
|
||||
fn on_close_block(&self, block: &mut ExecutedBlock) {
|
||||
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
|
||||
let reward = self.ethash_params.block_reward;
|
||||
let fields = block.fields_mut();
|
||||
|
||||
// Bestow block reward
|
||||
let res = fields.state.add_balance(
|
||||
fields.state.add_balance(
|
||||
fields.header.author(),
|
||||
&(reward + reward / U256::from(32) * U256::from(fields.uncles.len())),
|
||||
CleanupMode::NoEmpty
|
||||
);
|
||||
|
||||
if let Err(e) = res {
|
||||
warn!("Failed to give block reward: {}", e);
|
||||
}
|
||||
)?;
|
||||
|
||||
// Bestow uncle rewards
|
||||
let current_number = fields.header.number();
|
||||
for u in fields.uncles.iter() {
|
||||
let res = fields.state.add_balance(
|
||||
fields.state.add_balance(
|
||||
u.author(),
|
||||
&(reward * U256::from(8 + u.number() - current_number) / U256::from(8)),
|
||||
CleanupMode::NoEmpty
|
||||
);
|
||||
|
||||
if let Err(e) = res {
|
||||
warn!("Failed to give uncle reward: {}", e);
|
||||
}
|
||||
)?;
|
||||
}
|
||||
|
||||
// Commit state so that we can actually figure out the state root.
|
||||
if let Err(e) = fields.state.commit() {
|
||||
warn!("Encountered error on state commit: {}", e);
|
||||
}
|
||||
fields.state.commit()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
||||
@ -741,7 +728,7 @@ mod tests {
|
||||
fn difficulty_frontier() {
|
||||
let spec = new_homestead_test();
|
||||
let ethparams = get_default_ethash_params();
|
||||
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new());
|
||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
||||
|
||||
let mut parent_header = Header::default();
|
||||
parent_header.set_number(1000000);
|
||||
@ -759,7 +746,7 @@ mod tests {
|
||||
fn difficulty_homestead() {
|
||||
let spec = new_homestead_test();
|
||||
let ethparams = get_default_ethash_params();
|
||||
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new());
|
||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
||||
|
||||
let mut parent_header = Header::default();
|
||||
parent_header.set_number(1500000);
|
||||
@ -780,7 +767,7 @@ mod tests {
|
||||
ecip1010_pause_transition: 3000000,
|
||||
..get_default_ethash_params()
|
||||
};
|
||||
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new());
|
||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
||||
|
||||
let mut parent_header = Header::default();
|
||||
parent_header.set_number(3500000);
|
||||
@ -814,7 +801,7 @@ mod tests {
|
||||
ecip1010_continue_transition: 5000000,
|
||||
..get_default_ethash_params()
|
||||
};
|
||||
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new());
|
||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
||||
|
||||
let mut parent_header = Header::default();
|
||||
parent_header.set_number(5000102);
|
||||
@ -859,7 +846,7 @@ mod tests {
|
||||
#[test]
|
||||
fn gas_limit_is_multiple_of_determinant() {
|
||||
let spec = new_homestead_test();
|
||||
let ethash = Ethash::new(spec.params, get_default_ethash_params(), BTreeMap::new());
|
||||
let ethash = Ethash::new(spec.params().clone(), get_default_ethash_params(), BTreeMap::new());
|
||||
let mut parent = Header::new();
|
||||
let mut header = Header::new();
|
||||
header.set_number(1);
|
||||
@ -903,7 +890,7 @@ mod tests {
|
||||
fn difficulty_max_timestamp() {
|
||||
let spec = new_homestead_test();
|
||||
let ethparams = get_default_ethash_params();
|
||||
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new());
|
||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
||||
|
||||
let mut parent_header = Header::default();
|
||||
parent_header.set_number(1000000);
|
||||
@ -931,7 +918,7 @@ mod tests {
|
||||
header.set_number(parent_header.number() + 1);
|
||||
header.set_gas_limit(100_001.into());
|
||||
header.set_difficulty(ethparams.minimum_difficulty);
|
||||
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new());
|
||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
||||
assert!(ethash.verify_block_family(&header, &parent_header, None).is_ok());
|
||||
|
||||
parent_header.set_number(9);
|
||||
@ -986,7 +973,7 @@ mod tests {
|
||||
nonce: U256::zero(),
|
||||
}.sign(keypair.secret(), None).into();
|
||||
|
||||
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new());
|
||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
||||
assert!(ethash.verify_transaction_basic(&tx1, &header).is_ok());
|
||||
assert!(ethash.verify_transaction_basic(&tx2, &header).is_ok());
|
||||
|
||||
|
@ -82,16 +82,15 @@ impl From<builtin::Error> for Error {
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::Error::*;
|
||||
let message = match *self {
|
||||
OutOfGas => "Out of gas",
|
||||
BadJumpDestination { .. } => "Bad jump destination",
|
||||
BadInstruction { .. } => "Bad instruction",
|
||||
StackUnderflow { .. } => "Stack underflow",
|
||||
OutOfStack { .. } => "Out of stack",
|
||||
BuiltIn { .. } => "Built-in failed",
|
||||
Internal(ref msg) => msg,
|
||||
};
|
||||
message.fmt(f)
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ pub trait Ext {
|
||||
fn balance(&self, address: &Address) -> trie::Result<U256>;
|
||||
|
||||
/// Returns the hash of one of the 256 most recent complete blocks.
|
||||
fn blockhash(&self, number: &U256) -> H256;
|
||||
fn blockhash(&mut self, number: &U256) -> H256;
|
||||
|
||||
/// Creates new contract.
|
||||
///
|
||||
|
@ -235,6 +235,9 @@ impl<Gas: CostType> Gasometer<Gas> {
|
||||
let gas = Gas::from(schedule.exp_gas + schedule.exp_byte_gas * bytes);
|
||||
Request::Gas(gas)
|
||||
},
|
||||
instructions::BLOCKHASH => {
|
||||
Request::Gas(Gas::from(schedule.blockhash_gas))
|
||||
},
|
||||
_ => Request::Gas(default_gas),
|
||||
};
|
||||
|
||||
|
@ -103,6 +103,8 @@ pub struct Schedule {
|
||||
pub no_empty: bool,
|
||||
/// Kill empty accounts if touched.
|
||||
pub kill_empty: bool,
|
||||
/// Blockhash instruction gas cost.
|
||||
pub blockhash_gas: usize,
|
||||
}
|
||||
|
||||
impl Schedule {
|
||||
@ -161,6 +163,7 @@ impl Schedule {
|
||||
sub_gas_cap_divisor: Some(64),
|
||||
no_empty: no_empty,
|
||||
kill_empty: kill_empty,
|
||||
blockhash_gas: if have_metropolis_instructions { 350 } else { 20 },
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,6 +216,7 @@ impl Schedule {
|
||||
sub_gas_cap_divisor: None,
|
||||
no_empty: false,
|
||||
kill_empty: false,
|
||||
blockhash_gas: 20,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,11 @@ use env_info::EnvInfo;
|
||||
use types::executed::CallType;
|
||||
use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress};
|
||||
use std::fmt::Debug;
|
||||
use tests::helpers::*;
|
||||
use types::transaction::SYSTEM_ADDRESS;
|
||||
use executive::Executive;
|
||||
use state::Substate;
|
||||
use trace::{NoopVMTracer, NoopTracer};
|
||||
|
||||
pub struct FakeLogEntry {
|
||||
topics: Vec<H256>,
|
||||
@ -107,7 +112,7 @@ impl Ext for FakeExt {
|
||||
Ok(self.balances[address])
|
||||
}
|
||||
|
||||
fn blockhash(&self, number: &U256) -> H256 {
|
||||
fn blockhash(&mut self, number: &U256) -> H256 {
|
||||
self.blockhashes.get(number).unwrap_or(&H256::new()).clone()
|
||||
}
|
||||
|
||||
@ -430,6 +435,67 @@ fn test_blockhash(factory: super::Factory) {
|
||||
assert_eq!(ext.store.get(&H256::new()).unwrap(), &blockhash);
|
||||
}
|
||||
|
||||
evm_test!{test_blockhash_eip210: test_blockhash_eip210_jit, test_blockhash_eip210_int}
|
||||
fn test_blockhash_eip210(factory: super::Factory) {
|
||||
let get_prev_hash_code = Arc::new("600143034060205260206020f3".from_hex().unwrap()); // this returns previous block hash
|
||||
let get_prev_hash_code_hash = get_prev_hash_code.sha3();
|
||||
// This is same as DEFAULT_BLOCKHASH_CONTRACT except for metropolis transition block check removed.
|
||||
let test_blockhash_contract = "73fffffffffffffffffffffffffffffffffffffffe33141561007a57600143036020526000356101006020510755600061010060205107141561005057600035610100610100602051050761010001555b6000620100006020510714156100755760003561010062010000602051050761020001555b61014a565b4360003512151561009057600060405260206040f35b610100600035430312156100b357610100600035075460605260206060f3610149565b62010000600035430312156100d157600061010060003507146100d4565b60005b156100f6576101006101006000350507610100015460805260206080f3610148565b630100000060003543031215610116576000620100006000350714610119565b60005b1561013c57610100620100006000350507610200015460a052602060a0f3610147565b600060c052602060c0f35b5b5b5b5b";
|
||||
let blockhash_contract_code = Arc::new(test_blockhash_contract.from_hex().unwrap());
|
||||
let blockhash_contract_code_hash = blockhash_contract_code.sha3();
|
||||
let engine = TestEngine::new_metropolis();
|
||||
let mut env_info = EnvInfo::default();
|
||||
|
||||
// populate state with 256 last hashes
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
let contract_address: Address = 0xf0.into();
|
||||
state.init_code(&contract_address, (*blockhash_contract_code).clone()).unwrap();
|
||||
for i in 1 .. 257 {
|
||||
env_info.number = i.into();
|
||||
let params = ActionParams {
|
||||
code_address: contract_address.clone(),
|
||||
address: contract_address,
|
||||
sender: SYSTEM_ADDRESS.clone(),
|
||||
origin: SYSTEM_ADDRESS.clone(),
|
||||
gas: 100000.into(),
|
||||
gas_price: 0.into(),
|
||||
value: ActionValue::Transfer(0.into()),
|
||||
code: Some(blockhash_contract_code.clone()),
|
||||
code_hash: blockhash_contract_code_hash,
|
||||
data: Some(H256::from(i - 1).to_vec()),
|
||||
call_type: CallType::Call,
|
||||
};
|
||||
let mut ex = Executive::new(&mut state, &env_info, &engine);
|
||||
let mut substate = Substate::new();
|
||||
let mut output = [];
|
||||
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
|
||||
panic!("Encountered error on updating last hashes: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
env_info.number = 256;
|
||||
let params = ActionParams {
|
||||
code_address: Address::new(),
|
||||
address: Address::new(),
|
||||
sender: Address::new(),
|
||||
origin: Address::new(),
|
||||
gas: 100000.into(),
|
||||
gas_price: 0.into(),
|
||||
value: ActionValue::Transfer(0.into()),
|
||||
code: Some(get_prev_hash_code),
|
||||
code_hash: get_prev_hash_code_hash,
|
||||
data: None,
|
||||
call_type: CallType::Call,
|
||||
};
|
||||
let mut ex = Executive::new(&mut state, &env_info, &engine);
|
||||
let mut substate = Substate::new();
|
||||
let mut output = H256::new();
|
||||
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
|
||||
panic!("Encountered error on getting last hash: {}", e);
|
||||
}
|
||||
assert_eq!(output, 255.into());
|
||||
}
|
||||
|
||||
evm_test!{test_calldataload: test_calldataload_jit, test_calldataload_int}
|
||||
fn test_calldataload(factory: super::Factory) {
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
|
@ -22,7 +22,7 @@ use engines::Engine;
|
||||
use types::executed::CallType;
|
||||
use env_info::EnvInfo;
|
||||
use error::ExecutionError;
|
||||
use evm::{self, Ext, Factory, Finalize, CreateContractAddress, FinalizationResult};
|
||||
use evm::{self, Ext, Finalize, CreateContractAddress, FinalizationResult};
|
||||
use externalities::*;
|
||||
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
|
||||
use transaction::{Action, SignedTransaction};
|
||||
@ -71,33 +71,30 @@ pub struct TransactOptions {
|
||||
}
|
||||
|
||||
/// Transaction executor.
|
||||
pub struct Executive<'a, B: 'a + StateBackend> {
|
||||
pub struct Executive<'a, B: 'a + StateBackend, E: 'a + Engine + ?Sized> {
|
||||
state: &'a mut State<B>,
|
||||
info: &'a EnvInfo,
|
||||
engine: &'a Engine,
|
||||
vm_factory: &'a Factory,
|
||||
engine: &'a E,
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
/// Basic constructor.
|
||||
pub fn new(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory) -> Self {
|
||||
pub fn new(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a E) -> Self {
|
||||
Executive {
|
||||
state: state,
|
||||
info: info,
|
||||
engine: engine,
|
||||
vm_factory: vm_factory,
|
||||
depth: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Populates executive from parent properties. Increments executive depth.
|
||||
pub fn from_parent(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory, parent_depth: usize) -> Self {
|
||||
pub fn from_parent(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a E, parent_depth: usize) -> Self {
|
||||
Executive {
|
||||
state: state,
|
||||
info: info,
|
||||
engine: engine,
|
||||
vm_factory: vm_factory,
|
||||
depth: parent_depth + 1,
|
||||
}
|
||||
}
|
||||
@ -110,8 +107,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
output: OutputPolicy<'any, 'any>,
|
||||
tracer: &'any mut T,
|
||||
vm_tracer: &'any mut V
|
||||
) -> Externalities<'any, T, V, B> where T: Tracer, V: VMTracer {
|
||||
Externalities::new(self.state, self.info, self.engine, self.vm_factory, self.depth, origin_info, substate, output, tracer, vm_tracer)
|
||||
) -> Externalities<'any, T, V, B, E> where T: Tracer, V: VMTracer {
|
||||
Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output, tracer, vm_tracer)
|
||||
}
|
||||
|
||||
/// This function should be used to execute transaction.
|
||||
@ -252,7 +249,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
|
||||
// Ordinary execution - keep VM in same thread
|
||||
if (self.depth + 1) % depth_threshold != 0 {
|
||||
let vm_factory = self.vm_factory;
|
||||
let vm_factory = self.state.vm_factory();
|
||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer);
|
||||
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
|
||||
return vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext);
|
||||
@ -262,7 +259,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
// TODO [todr] No thread builder yet, so we need to reset once for a while
|
||||
// https://github.com/aturon/crossbeam/issues/16
|
||||
crossbeam::scope(|scope| {
|
||||
let vm_factory = self.vm_factory;
|
||||
let vm_factory = self.state.vm_factory();
|
||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer);
|
||||
|
||||
scope.spawn(move || {
|
||||
@ -594,14 +591,14 @@ mod tests {
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new("3331600055".from_hex().unwrap()));
|
||||
params.value = ActionValue::Transfer(U256::from(0x7));
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty).unwrap();
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(0);
|
||||
let mut substate = Substate::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
@ -652,14 +649,14 @@ mod tests {
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(0);
|
||||
let mut substate = Substate::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
@ -671,8 +668,6 @@ mod tests {
|
||||
#[test]
|
||||
// Tracing is not suported in JIT
|
||||
fn test_call_to_create() {
|
||||
let factory = Factory::new(VMType::Interpreter, 1024 * 32);
|
||||
|
||||
// code:
|
||||
//
|
||||
// 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes?
|
||||
@ -719,7 +714,7 @@ mod tests {
|
||||
let mut vm_tracer = ExecutiveVMTracer::toplevel();
|
||||
|
||||
let gas_left = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let output = BytesRef::Fixed(&mut[0u8;0]);
|
||||
ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap()
|
||||
};
|
||||
@ -796,7 +791,6 @@ mod tests {
|
||||
#[test]
|
||||
fn test_create_contract() {
|
||||
// Tracing is not supported in JIT
|
||||
let factory = Factory::new(VMType::Interpreter, 1024 * 32);
|
||||
// code:
|
||||
//
|
||||
// 60 10 - push 16
|
||||
@ -829,7 +823,7 @@ mod tests {
|
||||
let mut vm_tracer = ExecutiveVMTracer::toplevel();
|
||||
|
||||
let gas_left = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params.clone(), &mut substate, &mut tracer, &mut vm_tracer).unwrap()
|
||||
};
|
||||
|
||||
@ -907,14 +901,14 @@ mod tests {
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(0);
|
||||
let mut substate = Substate::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
@ -958,14 +952,14 @@ mod tests {
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(1024);
|
||||
let mut substate = Substate::new();
|
||||
|
||||
{
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap();
|
||||
}
|
||||
|
||||
@ -1015,7 +1009,7 @@ mod tests {
|
||||
params.code = Some(Arc::new(code_a.clone()));
|
||||
params.value = ActionValue::Transfer(U256::from(100_000));
|
||||
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.init_code(&address_a, code_a.clone()).unwrap();
|
||||
state.init_code(&address_b, code_b.clone()).unwrap();
|
||||
state.add_balance(&sender, &U256::from(100_000), CleanupMode::NoEmpty).unwrap();
|
||||
@ -1025,7 +1019,7 @@ mod tests {
|
||||
let mut substate = Substate::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
@ -1062,14 +1056,14 @@ mod tests {
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code.clone()));
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.init_code(&address, code).unwrap();
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(0);
|
||||
let mut substate = Substate::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
@ -1094,14 +1088,14 @@ mod tests {
|
||||
let sender = t.sender();
|
||||
let contract = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default());
|
||||
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from(18), CleanupMode::NoEmpty).unwrap();
|
||||
let mut info = EnvInfo::default();
|
||||
info.gas_limit = U256::from(100_000);
|
||||
let engine = TestEngine::new(0);
|
||||
|
||||
let executed = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
ex.transact(&t, opts).unwrap()
|
||||
};
|
||||
@ -1131,14 +1125,14 @@ mod tests {
|
||||
}.sign(keypair.secret(), None);
|
||||
let sender = t.sender();
|
||||
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty).unwrap();
|
||||
let mut info = EnvInfo::default();
|
||||
info.gas_limit = U256::from(100_000);
|
||||
let engine = TestEngine::new(0);
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
@ -1163,7 +1157,7 @@ mod tests {
|
||||
}.sign(keypair.secret(), None);
|
||||
let sender = t.sender();
|
||||
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty).unwrap();
|
||||
let mut info = EnvInfo::default();
|
||||
info.gas_used = U256::from(20_000);
|
||||
@ -1171,7 +1165,7 @@ mod tests {
|
||||
let engine = TestEngine::new(0);
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
@ -1197,14 +1191,14 @@ mod tests {
|
||||
}.sign(keypair.secret(), None);
|
||||
let sender = t.sender();
|
||||
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from(100_017), CleanupMode::NoEmpty).unwrap();
|
||||
let mut info = EnvInfo::default();
|
||||
info.gas_limit = U256::from(100_000);
|
||||
let engine = TestEngine::new(0);
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
@ -1231,14 +1225,14 @@ mod tests {
|
||||
params.gas = U256::from(0x0186a0);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap());
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty).unwrap();
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(0);
|
||||
let mut substate = Substate::new();
|
||||
|
||||
let result = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer)
|
||||
};
|
||||
|
||||
@ -1255,7 +1249,7 @@ mod tests {
|
||||
// EIP-140 test case
|
||||
let code = "6c726576657274656420646174616000557f726576657274206d657373616765000000000000000000000000000000000000600052600e6000fd".from_hex().unwrap();
|
||||
let returns = "726576657274206d657373616765".from_hex().unwrap();
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory.clone());
|
||||
state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap();
|
||||
state.commit().unwrap();
|
||||
|
||||
@ -1266,7 +1260,7 @@ mod tests {
|
||||
params.gas = U256::from(20025);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::zero());
|
||||
let mut state = get_temp_state();
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap();
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new_metropolis();
|
||||
@ -1274,7 +1268,7 @@ mod tests {
|
||||
|
||||
let mut output = [0u8; 14];
|
||||
let result = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine, &factory);
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
|
@ -21,7 +21,7 @@ use state::{Backend as StateBackend, State, Substate};
|
||||
use engines::Engine;
|
||||
use env_info::EnvInfo;
|
||||
use executive::*;
|
||||
use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, Factory, CreateContractAddress};
|
||||
use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress};
|
||||
use types::executed::CallType;
|
||||
use types::transaction::UNSIGNED_SENDER;
|
||||
use trace::{Tracer, VMTracer};
|
||||
@ -58,13 +58,12 @@ impl OriginInfo {
|
||||
}
|
||||
|
||||
/// Implementation of evm Externalities.
|
||||
pub struct Externalities<'a, T: 'a, V: 'a, B: 'a>
|
||||
pub struct Externalities<'a, T: 'a, V: 'a, B: 'a, E: 'a + Engine + ?Sized>
|
||||
where T: Tracer, V: VMTracer, B: StateBackend
|
||||
{
|
||||
state: &'a mut State<B>,
|
||||
env_info: &'a EnvInfo,
|
||||
engine: &'a Engine,
|
||||
vm_factory: &'a Factory,
|
||||
engine: &'a E,
|
||||
depth: usize,
|
||||
origin_info: OriginInfo,
|
||||
substate: &'a mut Substate,
|
||||
@ -74,15 +73,14 @@ pub struct Externalities<'a, T: 'a, V: 'a, B: 'a>
|
||||
vm_tracer: &'a mut V,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B>
|
||||
where T: Tracer, V: VMTracer, B: StateBackend
|
||||
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Externalities<'a, T, V, B, E>
|
||||
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
|
||||
{
|
||||
/// Basic `Externalities` constructor.
|
||||
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||
pub fn new(state: &'a mut State<B>,
|
||||
env_info: &'a EnvInfo,
|
||||
engine: &'a Engine,
|
||||
vm_factory: &'a Factory,
|
||||
engine: &'a E,
|
||||
depth: usize,
|
||||
origin_info: OriginInfo,
|
||||
substate: &'a mut Substate,
|
||||
@ -94,7 +92,6 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B>
|
||||
state: state,
|
||||
env_info: env_info,
|
||||
engine: engine,
|
||||
vm_factory: vm_factory,
|
||||
depth: depth,
|
||||
origin_info: origin_info,
|
||||
substate: substate,
|
||||
@ -106,8 +103,8 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
||||
where T: Tracer, V: VMTracer, B: StateBackend
|
||||
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
|
||||
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
|
||||
{
|
||||
fn storage_at(&self, key: &H256) -> trie::Result<H256> {
|
||||
self.state.storage_at(&self.origin_info.address, key)
|
||||
@ -131,20 +128,51 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
||||
self.state.balance(address)
|
||||
}
|
||||
|
||||
fn blockhash(&self, number: &U256) -> H256 {
|
||||
// TODO: comment out what this function expects from env_info, since it will produce panics if the latter is inconsistent
|
||||
match *number < U256::from(self.env_info.number) && number.low_u64() >= cmp::max(256, self.env_info.number) - 256 {
|
||||
true => {
|
||||
let index = self.env_info.number - number.low_u64() - 1;
|
||||
assert!(index < self.env_info.last_hashes.len() as u64, format!("Inconsistent env_info, should contain at least {:?} last hashes", index+1));
|
||||
let r = self.env_info.last_hashes[index as usize].clone();
|
||||
trace!("ext: blockhash({}) -> {} self.env_info.number={}\n", number, r, self.env_info.number);
|
||||
r
|
||||
},
|
||||
false => {
|
||||
trace!("ext: blockhash({}) -> null self.env_info.number={}\n", number, self.env_info.number);
|
||||
H256::zero()
|
||||
},
|
||||
fn blockhash(&mut self, number: &U256) -> H256 {
|
||||
if self.env_info.number + 256 >= self.engine.params().eip210_transition {
|
||||
let blockhash_contract_address = self.engine.params().eip210_contract_address;
|
||||
let code_res = self.state.code(&blockhash_contract_address)
|
||||
.and_then(|code| self.state.code_hash(&blockhash_contract_address).map(|hash| (code, hash)));
|
||||
|
||||
let (code, code_hash) = match code_res {
|
||||
Ok((code, hash)) => (code, hash),
|
||||
Err(_) => return H256::zero(),
|
||||
};
|
||||
|
||||
let params = ActionParams {
|
||||
sender: self.origin_info.address.clone(),
|
||||
address: blockhash_contract_address.clone(),
|
||||
value: ActionValue::Apparent(self.origin_info.value),
|
||||
code_address: blockhash_contract_address.clone(),
|
||||
origin: self.origin_info.origin.clone(),
|
||||
gas: self.engine.params().eip210_contract_gas,
|
||||
gas_price: 0.into(),
|
||||
code: code,
|
||||
code_hash: code_hash,
|
||||
data: Some(H256::from(number).to_vec()),
|
||||
call_type: CallType::Call,
|
||||
};
|
||||
|
||||
let mut output = H256::new();
|
||||
let mut ex = Executive::new(self.state, self.env_info, self.engine);
|
||||
let r = ex.call(params, self.substate, BytesRef::Fixed(&mut output), self.tracer, self.vm_tracer);
|
||||
trace!("ext: blockhash contract({}) -> {:?}({}) self.env_info.number={}\n", number, r, output, self.env_info.number);
|
||||
output
|
||||
} else {
|
||||
// TODO: comment out what this function expects from env_info, since it will produce panics if the latter is inconsistent
|
||||
match *number < U256::from(self.env_info.number) && number.low_u64() >= cmp::max(256, self.env_info.number) - 256 {
|
||||
true => {
|
||||
let index = self.env_info.number - number.low_u64() - 1;
|
||||
assert!(index < self.env_info.last_hashes.len() as u64, format!("Inconsistent env_info, should contain at least {:?} last hashes", index+1));
|
||||
let r = self.env_info.last_hashes[index as usize].clone();
|
||||
trace!("ext: blockhash({}) -> {} self.env_info.number={}\n", number, r, self.env_info.number);
|
||||
r
|
||||
},
|
||||
false => {
|
||||
trace!("ext: blockhash({}) -> null self.env_info.number={}\n", number, self.env_info.number);
|
||||
H256::zero()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,7 +208,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
||||
return ContractCreateResult::Failed
|
||||
}
|
||||
}
|
||||
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.vm_factory, self.depth);
|
||||
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth);
|
||||
|
||||
// TODO: handle internal error separately
|
||||
match ex.create(params, self.substate, self.tracer, self.vm_tracer) {
|
||||
@ -230,7 +258,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
||||
params.value = ActionValue::Transfer(value);
|
||||
}
|
||||
|
||||
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.vm_factory, self.depth);
|
||||
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth);
|
||||
|
||||
match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) {
|
||||
Ok(gas_left) => MessageCallResult::Success(gas_left),
|
||||
@ -406,8 +434,7 @@ mod tests {
|
||||
let mut tracer = NoopTracer;
|
||||
let mut vm_tracer = NoopVMTracer;
|
||||
|
||||
let vm_factory = Default::default();
|
||||
let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
|
||||
assert_eq!(ext.env_info().number, 100);
|
||||
}
|
||||
@ -419,8 +446,7 @@ mod tests {
|
||||
let mut tracer = NoopTracer;
|
||||
let mut vm_tracer = NoopVMTracer;
|
||||
|
||||
let vm_factory = Default::default();
|
||||
let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
|
||||
let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
|
||||
|
||||
@ -444,8 +470,7 @@ mod tests {
|
||||
let mut tracer = NoopTracer;
|
||||
let mut vm_tracer = NoopVMTracer;
|
||||
|
||||
let vm_factory = Default::default();
|
||||
let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
|
||||
let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
|
||||
|
||||
@ -460,8 +485,7 @@ mod tests {
|
||||
let mut tracer = NoopTracer;
|
||||
let mut vm_tracer = NoopVMTracer;
|
||||
|
||||
let vm_factory = Default::default();
|
||||
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
|
||||
let mut output = vec![];
|
||||
|
||||
@ -489,8 +513,7 @@ mod tests {
|
||||
let mut vm_tracer = NoopVMTracer;
|
||||
|
||||
{
|
||||
let vm_factory = Default::default();
|
||||
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
ext.log(log_topics, &log_data);
|
||||
}
|
||||
|
||||
@ -507,8 +530,7 @@ mod tests {
|
||||
let mut vm_tracer = NoopVMTracer;
|
||||
|
||||
{
|
||||
let vm_factory = Default::default();
|
||||
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
|
||||
ext.suicide(refund_account).unwrap();
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ use executive::*;
|
||||
use engines::Engine;
|
||||
use env_info::EnvInfo;
|
||||
use evm;
|
||||
use evm::{Schedule, Ext, Factory, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress};
|
||||
use evm::{Schedule, Ext, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress};
|
||||
use externalities::*;
|
||||
use types::executed::CallType;
|
||||
use tests::helpers::*;
|
||||
@ -51,23 +51,22 @@ impl From<ethjson::vm::Call> for CallCreate {
|
||||
|
||||
/// Tiny wrapper around executive externalities.
|
||||
/// Stores callcreates.
|
||||
struct TestExt<'a, T: 'a, V: 'a, B: 'a>
|
||||
where T: Tracer, V: VMTracer, B: StateBackend
|
||||
struct TestExt<'a, T: 'a, V: 'a, B: 'a, E: 'a>
|
||||
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
|
||||
{
|
||||
ext: Externalities<'a, T, V, B>,
|
||||
ext: Externalities<'a, T, V, B, E>,
|
||||
callcreates: Vec<CallCreate>,
|
||||
nonce: U256,
|
||||
sender: Address,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B>
|
||||
where T: Tracer, V: VMTracer, B: StateBackend
|
||||
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> TestExt<'a, T, V, B, E>
|
||||
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
|
||||
{
|
||||
fn new(
|
||||
state: &'a mut State<B>,
|
||||
info: &'a EnvInfo,
|
||||
engine: &'a Engine,
|
||||
vm_factory: &'a Factory,
|
||||
engine: &'a E,
|
||||
depth: usize,
|
||||
origin_info: OriginInfo,
|
||||
substate: &'a mut Substate,
|
||||
@ -78,15 +77,15 @@ impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B>
|
||||
) -> trie::Result<Self> {
|
||||
Ok(TestExt {
|
||||
nonce: state.nonce(&address)?,
|
||||
ext: Externalities::new(state, info, engine, vm_factory, depth, origin_info, substate, output, tracer, vm_tracer),
|
||||
ext: Externalities::new(state, info, engine, depth, origin_info, substate, output, tracer, vm_tracer),
|
||||
callcreates: vec![],
|
||||
sender: address,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
|
||||
where T: Tracer, V: VMTracer, B: StateBackend
|
||||
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E>
|
||||
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
|
||||
{
|
||||
fn storage_at(&self, key: &H256) -> trie::Result<H256> {
|
||||
self.ext.storage_at(key)
|
||||
@ -112,7 +111,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
|
||||
self.ext.origin_balance()
|
||||
}
|
||||
|
||||
fn blockhash(&self, number: &U256) -> H256 {
|
||||
fn blockhash(&mut self, number: &U256) -> H256 {
|
||||
self.ext.blockhash(number)
|
||||
}
|
||||
|
||||
@ -222,13 +221,13 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
|
||||
state.populate_from(From::from(vm.pre_state.clone()));
|
||||
let info = From::from(vm.env);
|
||||
let engine = TestEngine::new(1);
|
||||
let vm_factory = Factory::new(vm_type.clone(), 1024 * 32);
|
||||
let params = ActionParams::from(vm.transaction);
|
||||
|
||||
let mut substate = Substate::new();
|
||||
let mut tracer = NoopTracer;
|
||||
let mut vm_tracer = NoopVMTracer;
|
||||
let mut output = vec![];
|
||||
let vm_factory = state.vm_factory();
|
||||
|
||||
// execute
|
||||
let (res, callcreates) = {
|
||||
@ -236,7 +235,6 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
|
||||
&mut state,
|
||||
&info,
|
||||
&engine,
|
||||
&vm_factory,
|
||||
0,
|
||||
OriginInfo::from(¶ms),
|
||||
&mut substate,
|
||||
|
@ -728,7 +728,7 @@ impl MinerService for Miner {
|
||||
.map_err(ExecutionError::from)?;
|
||||
}
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, client.vm_factory()).transact(t, options)?;
|
||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact(t, options)?;
|
||||
|
||||
// TODO gav move this into Executive.
|
||||
if let Some(original) = original_state {
|
||||
|
@ -470,7 +470,7 @@ impl Rebuilder for ChunkRebuilder {
|
||||
db.boxed_clone(),
|
||||
self.manifest.state_root.clone(),
|
||||
engine.account_start_nonce(),
|
||||
factories.clone(),
|
||||
factories,
|
||||
).map_err(|e| format!("State root mismatch: {}", e))?;
|
||||
|
||||
let (tx, env_info) = make_tx_and_env(
|
||||
@ -482,7 +482,7 @@ impl Rebuilder for ChunkRebuilder {
|
||||
);
|
||||
|
||||
let options = TransactOptions { tracing: false, vm_tracing: false, check_nonce: false };
|
||||
Executive::new(&mut state, &env_info, engine, &factories.vm)
|
||||
Executive::new(&mut state, &env_info, engine)
|
||||
.transact_virtual(&tx, options)
|
||||
.map(|e| e.output)
|
||||
.map_err(|e| format!("Error executing: {}", e))
|
||||
|
@ -21,7 +21,7 @@ use super::seal::Generic as GenericSeal;
|
||||
|
||||
use action_params::{ActionValue, ActionParams};
|
||||
use builtin::Builtin;
|
||||
use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint};
|
||||
use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint, DEFAULT_BLOCKHASH_CONTRACT};
|
||||
use env_info::EnvInfo;
|
||||
use error::Error;
|
||||
use ethereum;
|
||||
@ -39,7 +39,8 @@ use types::executed::CallType;
|
||||
use util::*;
|
||||
|
||||
/// Parameters common to all engines.
|
||||
#[derive(Debug, PartialEq, Clone, Default)]
|
||||
#[derive(Debug, PartialEq, Default)]
|
||||
#[cfg_attr(test, derive(Clone))]
|
||||
pub struct CommonParams {
|
||||
/// Account start nonce.
|
||||
pub account_start_nonce: U256,
|
||||
@ -63,6 +64,14 @@ pub struct CommonParams {
|
||||
pub eip86_transition: BlockNumber,
|
||||
/// Number of first block where EIP-140 (Metropolis: REVERT opcode) rules begin.
|
||||
pub eip140_transition: BlockNumber,
|
||||
/// Number of first block where EIP-210 (Metropolis: BLOCKHASH changes) rules begin.
|
||||
pub eip210_transition: BlockNumber,
|
||||
/// EIP-210 Blockhash contract address.
|
||||
pub eip210_contract_address: Address,
|
||||
/// EIP-210 Blockhash contract code.
|
||||
pub eip210_contract_code: Bytes,
|
||||
/// Gas allocated for EIP-210 blockhash update.
|
||||
pub eip210_contract_gas: U256,
|
||||
}
|
||||
|
||||
impl From<ethjson::spec::Params> for CommonParams {
|
||||
@ -79,6 +88,12 @@ impl From<ethjson::spec::Params> for CommonParams {
|
||||
validate_receipts_transition: p.validate_receipts_transition.map_or(0, 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),
|
||||
eip210_transition: p.eip210_transition.map_or(BlockNumber::max_value(), Into::into),
|
||||
eip210_contract_address: p.eip210_contract_address.map_or(0xf0.into(), Into::into),
|
||||
eip210_contract_code: p.eip210_contract_code.map_or_else(
|
||||
|| DEFAULT_BLOCKHASH_CONTRACT.from_hex().expect("Default BLOCKHASH contract is valid"),
|
||||
Into::into),
|
||||
eip210_contract_gas: p.eip210_contract_gas.map_or(1000000.into(), Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,9 +111,6 @@ pub struct Spec {
|
||||
/// Known nodes on the network in enode format.
|
||||
pub nodes: Vec<String>,
|
||||
|
||||
/// Parameters common to all engines.
|
||||
pub params: CommonParams,
|
||||
|
||||
/// The genesis block's parent hash field.
|
||||
pub parent_hash: H256,
|
||||
/// The genesis block's author field.
|
||||
@ -138,7 +150,6 @@ fn load_from(s: ethjson::spec::Spec) -> Result<Spec, Error> {
|
||||
|
||||
let mut s = Spec {
|
||||
name: s.name.clone().into(),
|
||||
params: params.clone(),
|
||||
engine: Spec::engine(s.engine, params, builtins),
|
||||
data_dir: s.data_dir.unwrap_or(s.name).into(),
|
||||
nodes: s.nodes.unwrap_or_else(Vec::new),
|
||||
@ -250,7 +261,7 @@ impl Spec {
|
||||
state.kill_account(&address);
|
||||
|
||||
{
|
||||
let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref(), &factories.vm);
|
||||
let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref());
|
||||
if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) {
|
||||
warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e);
|
||||
}
|
||||
@ -275,17 +286,20 @@ impl Spec {
|
||||
self.state_root_memo.read().clone()
|
||||
}
|
||||
|
||||
/// Get common blockchain parameters.
|
||||
pub fn params(&self) -> &CommonParams { &self.engine.params() }
|
||||
|
||||
/// Get the known knodes of the network in enode format.
|
||||
pub fn nodes(&self) -> &[String] { &self.nodes }
|
||||
|
||||
/// Get the configured Network ID.
|
||||
pub fn network_id(&self) -> u64 { self.params.network_id }
|
||||
pub fn network_id(&self) -> u64 { self.params().network_id }
|
||||
|
||||
/// Get the configured subprotocol name.
|
||||
pub fn subprotocol_name(&self) -> String { self.params.subprotocol_name.clone() }
|
||||
pub fn subprotocol_name(&self) -> String { self.params().subprotocol_name.clone() }
|
||||
|
||||
/// Get the configured network fork block.
|
||||
pub fn fork_block(&self) -> Option<(BlockNumber, H256)> { self.params.fork_block }
|
||||
pub fn fork_block(&self) -> Option<(BlockNumber, H256)> { self.params().fork_block }
|
||||
|
||||
/// Get the header of the genesis block.
|
||||
pub fn genesis_header(&self) -> Header {
|
||||
@ -362,7 +376,6 @@ impl Spec {
|
||||
// TODO: could optimize so we don't re-run, but `ensure_db_good` is barely ever
|
||||
// called anyway.
|
||||
let db = self.run_constructors(factories, db)?;
|
||||
|
||||
Ok(db)
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ use types::executed::{Executed, ExecutionError};
|
||||
use types::state_diff::StateDiff;
|
||||
use transaction::SignedTransaction;
|
||||
use state_db::StateDB;
|
||||
use evm::{Factory as EvmFactory};
|
||||
|
||||
use util::*;
|
||||
|
||||
@ -310,6 +311,11 @@ impl<B: Backend> State<B> {
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
/// Get a VM factory that can execute on this state.
|
||||
pub fn vm_factory(&self) -> EvmFactory {
|
||||
self.factories.vm.clone()
|
||||
}
|
||||
|
||||
/// Swap the current backend for another.
|
||||
// TODO: [rob] find a less hacky way to avoid duplication of `Client::state_at`.
|
||||
pub fn replace_backend<T: Backend>(self, backend: T) -> State<T> {
|
||||
@ -579,6 +585,7 @@ impl<B: Backend> State<B> {
|
||||
|
||||
/// Mutate storage of account `a` so that it is `value` for `key`.
|
||||
pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) -> trie::Result<()> {
|
||||
trace!(target: "state", "set_storage({}:{} to {})", a, key.hex(), value.hex());
|
||||
if self.storage_at(a, &key)? != value {
|
||||
self.require(a, false)?.set_storage(key, value)
|
||||
}
|
||||
@ -625,9 +632,7 @@ impl<B: Backend> State<B> {
|
||||
-> Result<Executed, ExecutionError>
|
||||
{
|
||||
let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true };
|
||||
let vm_factory = self.factories.vm.clone();
|
||||
|
||||
let mut e = Executive::new(self, env_info, engine, &vm_factory);
|
||||
let mut e = Executive::new(self, env_info, engine);
|
||||
|
||||
match virt {
|
||||
true => e.transact_virtual(t, options),
|
||||
@ -635,7 +640,6 @@ impl<B: Backend> State<B> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit.
|
||||
/// `accounts` is mutable because we may need to commit the code or storage and record that.
|
||||
#[cfg_attr(feature="dev", allow(match_ref_pats))]
|
||||
|
@ -358,7 +358,7 @@ fn transaction_proof() {
|
||||
let root = client.best_block_header().state_root();
|
||||
|
||||
let mut state = State::from_existing(backend, root, 0.into(), factories.clone()).unwrap();
|
||||
Executive::new(&mut state, &client.latest_env_info(), &*test_spec.engine, &factories.vm)
|
||||
Executive::new(&mut state, &client.latest_env_info(), &*test_spec.engine)
|
||||
.transact(&transaction, Default::default()).unwrap();
|
||||
|
||||
assert_eq!(state.balance(&Address::default()).unwrap(), 5.into());
|
||||
|
@ -25,7 +25,8 @@ use block::{OpenBlock, Drain};
|
||||
use blockchain::{BlockChain, Config as BlockChainConfig};
|
||||
use builtin::Builtin;
|
||||
use state::*;
|
||||
use evm::Schedule;
|
||||
use evm::{Schedule, Factory as EvmFactory};
|
||||
use factory::Factories;
|
||||
use engines::Engine;
|
||||
use ethereum;
|
||||
use ethereum::ethash::EthashParams;
|
||||
@ -318,6 +319,13 @@ pub fn get_temp_state() -> State<::state_db::StateDB> {
|
||||
State::new(journal_db, U256::from(0), Default::default())
|
||||
}
|
||||
|
||||
pub fn get_temp_state_with_factory(factory: EvmFactory) -> State<::state_db::StateDB> {
|
||||
let journal_db = get_temp_state_db();
|
||||
let mut factories = Factories::default();
|
||||
factories.vm = factory;
|
||||
State::new(journal_db, U256::from(0), factories)
|
||||
}
|
||||
|
||||
pub fn get_temp_state_db() -> StateDB {
|
||||
let db = new_db();
|
||||
let journal_db = journaldb::new(db, journaldb::Algorithm::EarlyMerge, ::db::COL_STATE);
|
||||
|
@ -29,6 +29,9 @@ use ethjson;
|
||||
/// Fake address for unsigned transactions as defined by EIP-86.
|
||||
pub const UNSIGNED_SENDER: Address = ::util::H160([0xff; 20]);
|
||||
|
||||
/// System sender address for internal state updates.
|
||||
pub const SYSTEM_ADDRESS: Address = ::util::H160([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xfe]);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "ipc", binary)]
|
||||
/// Transaction action type.
|
||||
|
@ -17,7 +17,8 @@
|
||||
//! Spec params deserialization.
|
||||
|
||||
use uint::Uint;
|
||||
use hash::H256;
|
||||
use hash::{H256, Address};
|
||||
use bytes::Bytes;
|
||||
|
||||
/// Spec params.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
@ -62,6 +63,18 @@ pub struct Params {
|
||||
/// See `CommonParams` docs.
|
||||
#[serde(rename="eip140Transition")]
|
||||
pub eip140_transition: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
#[serde(rename="eip210Transition")]
|
||||
pub eip210_transition: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
#[serde(rename="eip210ContractAddress")]
|
||||
pub eip210_contract_address: Option<Address>,
|
||||
/// See `CommonParams` docs.
|
||||
#[serde(rename="eip210ContractCode")]
|
||||
pub eip210_contract_code: Option<Bytes>,
|
||||
/// See `CommonParams` docs.
|
||||
#[serde(rename="eip210ContractGas")]
|
||||
pub eip210_contract_gas: Option<Uint>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
Loading…
Reference in New Issue
Block a user