[beta] EIP150.1c (#2599)

* EIP150.1c

Conflicts:
	ethcore/res/ethereum/expanse.json
	ethcore/res/ethereum/morden.json
	ethcore/res/ethereum/tests
	ethcore/src/blockchain/blockchain.rs
	ethcore/src/ethereum/ethash.rs
	ethcore/src/evm/interpreter/mod.rs
	json/src/spec/ethash.rs

* Update json test suite (#2574)

* update json test suite

* comment out the incomplete test

Conflicts:
	ethcore/res/ethereum/tests

* Updating tests

* Adding state tests

* Updating tests

* Updating HF block

* Removing flushln [ci:skip]

* Commenting out suicide test

* New tests.

* Switch to EIP tests.

* Rename some stuff, combine transition tests.

* Fix U256 overflows.

* Name cleanups and an effort to fix tests.

* Rename back for clarity.

* Fix non-EIP-150 OOG CALLs

* New transition block number & additional EIP150 tests

* Morden transition block set; Tests updated

* Added missing test
This commit is contained in:
Tomasz Drwięga 2016-10-15 15:16:26 +02:00 committed by Arkadiy Paronyan
parent 2ce43434f1
commit e0778fc069
28 changed files with 1107 additions and 749 deletions

View File

@ -10,7 +10,8 @@
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x118c30" "homesteadTransition": "0x118c30",
"eip150Transition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -0,0 +1,43 @@
{
"name": "Homestead (Test)",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x0",
"eip150Transition": "0x0"
}
}
},
"params": {
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x1"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
}
}

View File

@ -0,0 +1,70 @@
{
"name": "Expanse",
"forkName": "expanse",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"difficultyIncrementDivisor": "60",
"durationLimit": "0x3C",
"blockReward": "0x6f05b59d3b200000",
"registrar" : "0x6c221ca53705f3497ec90ca7b84c59ae7382fc21",
"homesteadTransition": "0x30d40",
"difficultyHardforkTransition": "0x59d9",
"difficultyHardforkBoundDivisor": "0x0200",
"bombDefuseTransition": "0x30d40",
"eip150Transition": "0x7fffffffffffffff"
}
}
},
"params": {
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID": "0x1",
"subprotocolName": "exp"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x214652414e4b4f21",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x40000000",
"author": "0x93decab0cd745598860f782ac1e8f046cb99e898",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x4672616e6b6f497346726565646f6d",
"gasLimit": "0x1388"
},
"nodes": [
"enode://7f335a047654f3e70d6f91312a7cf89c39704011f1a584e2698250db3d63817e74b88e26b7854111e16b2c9d0c7173c05419aeee2d0321850227b126d8b1be3f@46.101.156.249:42786",
"enode://df872f81e25f72356152b44cab662caf1f2e57c3a156ecd20e9ac9246272af68a2031b4239a0bc831f2c6ab34733a041464d46b3ea36dce88d6c11714446e06b@178.62.208.109:42786",
"enode://96d3919b903e7f5ad59ac2f73c43be9172d9d27e2771355db03fd194732b795829a31fe2ea6de109d0804786c39a807e155f065b4b94c6fce167becd0ac02383@45.55.22.34:42786",
"enode://5f6c625bf287e3c08aad568de42d868781e961cbda805c8397cfb7be97e229419bef9a5a25a75f97632787106bba8a7caf9060fab3887ad2cfbeb182ab0f433f@46.101.182.53:42786",
"enode://d33a8d4c2c38a08971ed975b750f21d54c927c0bf7415931e214465a8d01651ecffe4401e1db913f398383381413c78105656d665d83f385244ab302d6138414@128.199.183.48:42786",
"enode://df872f81e25f72356152b44cab662caf1f2e57c3a156ecd20e9ac9246272af68a2031b4239a0bc831f2c6ab34733a041464d46b3ea36dce88d6c11714446e06b@178.62.208.109:42786",
"enode://f6f0d6b9b7d02ec9e8e4a16e38675f3621ea5e69860c739a65c1597ca28aefb3cec7a6d84e471ac927d42a1b64c1cbdefad75e7ce8872d57548ddcece20afdd1@159.203.64.95:42786"
],
"accounts": {
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"bb94f0ceb32257275b2a7a9c094c13e469b4563e": {
"balance": "10000000000000000000000000"
},
"15656715068ab0dbdf0ab00748a8a19e40f28192": {
"balance": "1000000000000000000000000"
},
"c075fa11f85bda3aaba67106226aaf086ac16f4e": {
"balance": "100000000000000000000000"
},
"93decab0cd745598860f782ac1e8f046cb99e898": {
"balance": "10000000000000000000000"
}
}
}

View File

@ -9,10 +9,10 @@
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x118c30", "homesteadTransition": "0x118c30",
"daoHardforkTransition": "0x1d4c00", "daoHardforkTransition": "0x1d4c00",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754", "daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [ "daoHardforkAccounts": [
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728", "0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425", "0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425",
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f", "0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
@ -129,7 +129,8 @@
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97", "0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a" "0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
] ],
"eip150Transition": "0x259518"
} }
} }
}, },

View File

@ -9,7 +9,7 @@
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x118c30", "homesteadTransition": "0x118c30",
"daoHardforkTransition": "0x1d4c00", "daoHardforkTransition": "0x1d4c00",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754", "daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [ "daoHardforkAccounts": [
@ -129,7 +129,8 @@
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97", "0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a" "0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
] ],
"eip150Transition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -9,7 +9,8 @@
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0xffffffffffffffff" "homesteadTransition": "0x7fffffffffffffff",
"eip150Transition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -9,7 +9,8 @@
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x0" "homesteadTransition": "0x0",
"eip150Transition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -9,7 +9,8 @@
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar": "0x8e4e9b13d4b45cb0befc93c3061b1408f67316b2", "registrar": "0x8e4e9b13d4b45cb0befc93c3061b1408f67316b2",
"frontierCompatibilityModeLimit": "0x789b0" "homesteadTransition": "0x789b0",
"eip150Transition": "0x1b34d8"
} }
} }
}, },

View File

@ -8,7 +8,9 @@
"difficultyBoundDivisor": "0x0800", "difficultyBoundDivisor": "0x0800",
"durationLimit": "0x08", "durationLimit": "0x08",
"blockReward": "0x14D1120D7B160000", "blockReward": "0x14D1120D7B160000",
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050" "registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
"homesteadTransition": "0x7fffffffffffffff",
"eip150Transition": "0x7fffffffffffffff"
} }
} }
}, },

@ -1 +1 @@
Subproject commit ac5475d676536cb945f98e9ff98384c01abd0599 Subproject commit cd2a6746bb653bf4b1acb6198b40df19ed8dde3b

View File

@ -1,5 +1,5 @@
{ {
"name": "DAO hard-fork consensus test", "name": "EIP150.1b hard-fork consensus test",
"engine": { "engine": {
"Ethash": { "Ethash": {
"params": { "params": {
@ -9,7 +9,7 @@
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x5", "homesteadTransition": "0x5",
"daoHardforkTransition": "0x8", "daoHardforkTransition": "0x8",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754", "daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [ "daoHardforkAccounts": [
@ -129,7 +129,8 @@
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97", "0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a" "0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
] ],
"eip150Transition": "0xa"
} }
} }
}, },

View File

@ -38,13 +38,21 @@ pub struct EthashParams {
/// Namereg contract address. /// Namereg contract address.
pub registrar: Address, pub registrar: Address,
/// Homestead transition block number. /// Homestead transition block number.
pub frontier_compatibility_mode_limit: u64, pub homestead_transition: u64,
/// DAO hard-fork transition block (X). /// DAO hard-fork transition block (X).
pub dao_hardfork_transition: u64, pub dao_hardfork_transition: u64,
/// DAO hard-fork refund contract address (C). /// DAO hard-fork refund contract address (C).
pub dao_hardfork_beneficiary: Address, pub dao_hardfork_beneficiary: Address,
/// DAO hard-fork DAO accounts list (L) /// DAO hard-fork DAO accounts list (L)
pub dao_hardfork_accounts: Vec<Address>, pub dao_hardfork_accounts: Vec<Address>,
/// Transition block for a change of difficulty params (currently just bound_divisor).
pub difficulty_hardfork_transition: u64,
/// Difficulty param after the difficulty transition.
pub difficulty_hardfork_bound_divisor: U256,
/// Block on which there is no additional difficulty from the exponential bomb.
pub bomb_defuse_transition: u64,
/// Bad gas transition block number.
pub eip150_transition: u64,
} }
impl From<ethjson::spec::EthashParams> for EthashParams { impl From<ethjson::spec::EthashParams> for EthashParams {
@ -56,10 +64,14 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
duration_limit: p.duration_limit.into(), duration_limit: p.duration_limit.into(),
block_reward: p.block_reward.into(), block_reward: p.block_reward.into(),
registrar: p.registrar.map_or_else(Address::new, Into::into), registrar: p.registrar.map_or_else(Address::new, Into::into),
frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.map_or(0, Into::into), homestead_transition: p.homestead_transition.map_or(0, Into::into),
dao_hardfork_transition: p.dao_hardfork_transition.map_or(0x7fffffffffffffff, Into::into), dao_hardfork_transition: p.dao_hardfork_transition.map_or(0x7fffffffffffffff, Into::into),
dao_hardfork_beneficiary: p.dao_hardfork_beneficiary.map_or_else(Address::new, Into::into), dao_hardfork_beneficiary: p.dao_hardfork_beneficiary.map_or_else(Address::new, Into::into),
dao_hardfork_accounts: p.dao_hardfork_accounts.unwrap_or_else(Vec::new).into_iter().map(Into::into).collect(), dao_hardfork_accounts: p.dao_hardfork_accounts.unwrap_or_else(Vec::new).into_iter().map(Into::into).collect(),
difficulty_hardfork_transition: p.difficulty_hardfork_transition.map_or(0x7fffffffffffffff, Into::into),
difficulty_hardfork_bound_divisor: p.difficulty_hardfork_bound_divisor.map_or(p.difficulty_bound_divisor.into(), Into::into),
bomb_defuse_transition: p.bomb_defuse_transition.map_or(0x7fffffffffffffff, Into::into),
eip150_transition: p.eip150_transition.map_or(0, Into::into),
} }
} }
} }
@ -104,12 +116,14 @@ impl Engine for Ethash {
} }
fn schedule(&self, env_info: &EnvInfo) -> Schedule { fn schedule(&self, env_info: &EnvInfo) -> Schedule {
trace!(target: "client", "Creating schedule. fCML={}", self.ethash_params.frontier_compatibility_mode_limit); trace!(target: "client", "Creating schedule. fCML={}, bGCML={}", self.ethash_params.homestead_transition, self.ethash_params.eip150_transition);
if env_info.number < self.ethash_params.frontier_compatibility_mode_limit { if env_info.number < self.ethash_params.homestead_transition {
Schedule::new_frontier() Schedule::new_frontier()
} else { } else if env_info.number < self.ethash_params.eip150_transition {
Schedule::new_homestead() Schedule::new_homestead()
} else {
Schedule::new_homestead_gas_fix()
} }
} }
@ -246,7 +260,7 @@ impl Engine for Ethash {
} }
fn verify_transaction_basic(&self, t: &SignedTransaction, header: &Header) -> result::Result<(), Error> { fn verify_transaction_basic(&self, t: &SignedTransaction, header: &Header) -> result::Result<(), Error> {
if header.number() >= self.ethash_params.frontier_compatibility_mode_limit { if header.number() >= self.ethash_params.homestead_transition {
try!(t.check_low_s()); try!(t.check_low_s());
} }
Ok(()) Ok(())
@ -268,7 +282,7 @@ impl Ethash {
let min_difficulty = self.ethash_params.minimum_difficulty; let min_difficulty = self.ethash_params.minimum_difficulty;
let difficulty_bound_divisor = self.ethash_params.difficulty_bound_divisor; let difficulty_bound_divisor = self.ethash_params.difficulty_bound_divisor;
let duration_limit = self.ethash_params.duration_limit; let duration_limit = self.ethash_params.duration_limit;
let frontier_limit = self.ethash_params.frontier_compatibility_mode_limit; let frontier_limit = self.ethash_params.homestead_transition;
let mut target = if header.number < frontier_limit { let mut target = if header.number < frontier_limit {
if header.timestamp >= parent.timestamp + duration_limit { if header.timestamp >= parent.timestamp + duration_limit {

View File

@ -44,8 +44,11 @@ pub fn new_frontier_test() -> Spec { Spec::load(include_bytes!("../../res/ethere
/// Create a new Homestead chain spec as though it never changed from Frontier. /// Create a new Homestead chain spec as though it never changed from Frontier.
pub fn new_homestead_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/homestead_test.json")) } pub fn new_homestead_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/homestead_test.json")) }
/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier.
pub fn new_eip150_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/eip150_test.json")) }
/// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8. /// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8.
pub fn new_daohardfork_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/daohardfork_test.json")) } pub fn new_transition_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/transition_test.json")) }
/// Create a new Frontier main net chain spec without genesis accounts. /// Create a new Frontier main net chain spec without genesis accounts.
pub fn new_mainnet_like() -> Spec { Spec::load(include_bytes!("../../res/ethereum/frontier_like_test.json")) } pub fn new_mainnet_like() -> Spec { Spec::load(include_bytes!("../../res/ethereum/frontier_like_test.json")) }

View File

@ -19,6 +19,7 @@ use super::u256_to_address;
use evm::{self, CostType}; use evm::{self, CostType};
use evm::instructions::{self, Instruction, InstructionInfo}; use evm::instructions::{self, Instruction, InstructionInfo};
use evm::interpreter::stack::Stack; use evm::interpreter::stack::Stack;
use evm::schedule::Schedule;
macro_rules! overflowing { macro_rules! overflowing {
($x: expr) => {{ ($x: expr) => {{
@ -31,7 +32,7 @@ macro_rules! overflowing {
#[cfg_attr(feature="dev", allow(enum_variant_names))] #[cfg_attr(feature="dev", allow(enum_variant_names))]
enum InstructionCost<Cost: CostType> { enum InstructionCost<Cost: CostType> {
Gas(Cost), Gas(Cost),
GasMem(Cost, Cost), GasMem(Cost, Cost, Option<Cost>),
GasMemCopy(Cost, Cost, Cost) GasMemCopy(Cost, Cost, Cost)
} }
@ -56,7 +57,37 @@ impl<Gas: CostType> Gasometer<Gas> {
} }
} }
/// How much gas is provided to a CALL/CREATE, given that we need to deduct `needed` for this operation
/// and that we `requested` some.
pub fn gas_provided(&self, schedule: &Schedule, needed: Gas, requested: Option<evm::Result<Gas>>) -> evm::Result<Gas> {
match schedule.sub_gas_cap_divisor {
Some(cap_divisor) if self.current_gas >= needed => {
let gas_remaining = self.current_gas - needed;
let max_gas_provided = gas_remaining - gas_remaining / Gas::from(cap_divisor);
if let Some(Ok(r)) = requested {
Ok(min(r, max_gas_provided))
} else {
Ok(max_gas_provided)
}
},
_ => {
if let Some(r) = requested {
r
} else if self.current_gas >= needed {
Ok(self.current_gas - needed)
} else {
Ok(0.into())
}
}
}
}
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))] #[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
/// Determine how much gas is used by the given instruction, given the machine's state.
///
/// We guarantee that the final element of the returned tuple (`provided`) will be `Some`
/// iff the `instruction` is one of `CREATE`, or any of the `CALL` variants. In this case,
/// it will be the amount of gas that the current context provides to the child context.
pub fn get_gas_cost_mem( pub fn get_gas_cost_mem(
&mut self, &mut self,
ext: &evm::Ext, ext: &evm::Ext,
@ -64,7 +95,7 @@ impl<Gas: CostType> Gasometer<Gas> {
info: &InstructionInfo, info: &InstructionInfo,
stack: &Stack<U256>, stack: &Stack<U256>,
current_mem_size: usize, current_mem_size: usize,
) -> evm::Result<(Gas, Gas, usize)> { ) -> evm::Result<(Gas, Gas, usize, Option<Gas>)> {
let schedule = ext.schedule(); let schedule = ext.schedule();
let tier = instructions::get_tier_idx(info.tier); let tier = instructions::get_tier_idx(info.tier);
let default_gas = Gas::from(schedule.tier_step_gas[tier]); let default_gas = Gas::from(schedule.tier_step_gas[tier]);
@ -90,26 +121,42 @@ impl<Gas: CostType> Gasometer<Gas> {
instructions::SLOAD => { instructions::SLOAD => {
InstructionCost::Gas(Gas::from(schedule.sload_gas)) InstructionCost::Gas(Gas::from(schedule.sload_gas))
}, },
instructions::BALANCE => {
InstructionCost::Gas(Gas::from(schedule.balance_gas))
},
instructions::EXTCODESIZE => {
InstructionCost::Gas(Gas::from(schedule.extcodesize_gas))
},
instructions::SUICIDE => {
let mut gas = Gas::from(schedule.suicide_gas);
let address = u256_to_address(stack.peek(0));
if !ext.exists(&address) {
gas = overflowing!(gas.overflow_add(schedule.suicide_to_new_account_cost.into()));
}
InstructionCost::Gas(gas)
},
instructions::MSTORE | instructions::MLOAD => { instructions::MSTORE | instructions::MLOAD => {
InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 32))) InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 32)), None)
}, },
instructions::MSTORE8 => { instructions::MSTORE8 => {
InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 1))) InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 1)), None)
}, },
instructions::RETURN => { instructions::RETURN => {
InstructionCost::GasMem(default_gas, try!(mem_needed(stack.peek(0), stack.peek(1)))) InstructionCost::GasMem(default_gas, try!(mem_needed(stack.peek(0), stack.peek(1))), None)
}, },
instructions::SHA3 => { instructions::SHA3 => {
let w = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(1))), 31)); let w = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(1))), 31));
let words = w >> 5; let words = w >> 5;
let gas = Gas::from(schedule.sha3_gas) + (Gas::from(schedule.sha3_word_gas) * words); let gas = Gas::from(schedule.sha3_gas) + (Gas::from(schedule.sha3_word_gas) * words);
InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1)))) InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1))), None)
}, },
instructions::CALLDATACOPY | instructions::CODECOPY => { instructions::CALLDATACOPY | instructions::CODECOPY => {
InstructionCost::GasMemCopy(default_gas, try!(mem_needed(stack.peek(0), stack.peek(2))), try!(Gas::from_u256(*stack.peek(2)))) InstructionCost::GasMemCopy(default_gas, try!(mem_needed(stack.peek(0), stack.peek(2))), try!(Gas::from_u256(*stack.peek(2))))
}, },
instructions::EXTCODECOPY => { instructions::EXTCODECOPY => {
InstructionCost::GasMemCopy(default_gas, try!(mem_needed(stack.peek(1), stack.peek(3))), try!(Gas::from_u256(*stack.peek(3)))) InstructionCost::GasMemCopy(schedule.extcodecopy_base_gas.into(), try!(mem_needed(stack.peek(1), stack.peek(3))), try!(Gas::from_u256(*stack.peek(3))))
}, },
instructions::LOG0...instructions::LOG4 => { instructions::LOG0...instructions::LOG4 => {
let no_of_topics = instructions::get_log_topics(instruction); let no_of_topics = instructions::get_log_topics(instruction);
@ -117,10 +164,10 @@ impl<Gas: CostType> Gasometer<Gas> {
let data_gas = overflowing!(try!(Gas::from_u256(*stack.peek(1))).overflow_mul(Gas::from(schedule.log_data_gas))); let data_gas = overflowing!(try!(Gas::from_u256(*stack.peek(1))).overflow_mul(Gas::from(schedule.log_data_gas)));
let gas = overflowing!(data_gas.overflow_add(Gas::from(log_gas))); let gas = overflowing!(data_gas.overflow_add(Gas::from(log_gas)));
InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1)))) InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1))), None)
}, },
instructions::CALL | instructions::CALLCODE => { instructions::CALL | instructions::CALLCODE => {
let mut gas = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(0))), schedule.call_gas)); let mut gas = Gas::from(schedule.call_gas);
let mem = cmp::max( let mem = cmp::max(
try!(mem_needed(stack.peek(5), stack.peek(6))), try!(mem_needed(stack.peek(5), stack.peek(6))),
try!(mem_needed(stack.peek(3), stack.peek(4))) try!(mem_needed(stack.peek(3), stack.peek(4)))
@ -129,27 +176,49 @@ impl<Gas: CostType> Gasometer<Gas> {
let address = u256_to_address(stack.peek(1)); let address = u256_to_address(stack.peek(1));
if instruction == instructions::CALL && !ext.exists(&address) { if instruction == instructions::CALL && !ext.exists(&address) {
gas = overflowing!(gas.overflow_add(Gas::from(schedule.call_new_account_gas))); gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into()));
}; };
if !stack.peek(2).is_zero() { if !stack.peek(2).is_zero() {
gas = overflowing!(gas.overflow_add(Gas::from(schedule.call_value_transfer_gas))); gas = overflowing!(gas.overflow_add(schedule.call_value_transfer_gas.into()));
}; };
InstructionCost::GasMem(gas,mem) // TODO: refactor to avoid duplicate calculation here and later on.
let (mem_gas_cost, _, _) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem));
let cost_so_far = overflowing!(gas.overflow_add(mem_gas_cost.into()));
let requested = Gas::from_u256(*stack.peek(0));
let provided = try!(self.gas_provided(schedule, cost_so_far, Some(requested)));
gas = overflowing!(gas.overflow_add(provided));
InstructionCost::GasMem(gas, mem, Some(provided))
}, },
instructions::DELEGATECALL => { instructions::DELEGATECALL => {
let gas = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(0))), schedule.call_gas)); let mut gas = Gas::from(schedule.call_gas);
let mem = cmp::max( let mem = cmp::max(
try!(mem_needed(stack.peek(4), stack.peek(5))), try!(mem_needed(stack.peek(4), stack.peek(5))),
try!(mem_needed(stack.peek(2), stack.peek(3))) try!(mem_needed(stack.peek(2), stack.peek(3)))
); );
InstructionCost::GasMem(gas, mem)
// TODO: refactor to avoid duplicate calculation here and later on.
let (mem_gas_cost, _, _) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem));
let cost_so_far = overflowing!(gas.overflow_add(mem_gas_cost.into()));
let requested = Gas::from_u256(*stack.peek(0));
let provided = try!(self.gas_provided(schedule, cost_so_far, Some(requested)));
gas = overflowing!(gas.overflow_add(provided));
InstructionCost::GasMem(gas, mem, Some(provided))
}, },
instructions::CREATE => { instructions::CREATE => {
let gas = Gas::from(schedule.create_gas); let mut gas = Gas::from(schedule.create_gas);
let mem = try!(mem_needed(stack.peek(1), stack.peek(2))); let mem = try!(mem_needed(stack.peek(1), stack.peek(2)));
InstructionCost::GasMem(gas, mem)
// TODO: refactor to avoid duplicate calculation here and later on.
let (mem_gas_cost, _, _) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem));
let cost_so_far = overflowing!(gas.overflow_add(mem_gas_cost.into()));
let provided = try!(self.gas_provided(schedule, cost_so_far, None));
gas = overflowing!(gas.overflow_add(provided));
InstructionCost::GasMem(gas, mem, Some(provided))
}, },
instructions::EXP => { instructions::EXP => {
let expon = stack.peek(1); let expon = stack.peek(1);
@ -157,17 +226,17 @@ impl<Gas: CostType> Gasometer<Gas> {
let gas = Gas::from(schedule.exp_gas + schedule.exp_byte_gas * bytes); let gas = Gas::from(schedule.exp_gas + schedule.exp_byte_gas * bytes);
InstructionCost::Gas(gas) InstructionCost::Gas(gas)
}, },
_ => InstructionCost::Gas(default_gas) _ => InstructionCost::Gas(default_gas),
}; };
match cost { match cost {
InstructionCost::Gas(gas) => { InstructionCost::Gas(gas) => {
Ok((gas, self.current_mem_gas, 0)) Ok((gas, self.current_mem_gas, 0, None))
}, },
InstructionCost::GasMem(gas, mem_size) => { InstructionCost::GasMem(gas, mem_size, provided) => {
let (mem_gas_cost, new_mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size)); let (mem_gas_cost, new_mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size));
let gas = overflowing!(gas.overflow_add(mem_gas_cost)); let gas = overflowing!(gas.overflow_add(mem_gas_cost));
Ok((gas, new_mem_gas, new_mem_size)) Ok((gas, new_mem_gas, new_mem_size, provided))
}, },
InstructionCost::GasMemCopy(gas, mem_size, copy) => { InstructionCost::GasMemCopy(gas, mem_size, copy) => {
let (mem_gas_cost, new_mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size)); let (mem_gas_cost, new_mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size));
@ -175,7 +244,7 @@ impl<Gas: CostType> Gasometer<Gas> {
let copy_gas = Gas::from(schedule.copy_gas) * copy; let copy_gas = Gas::from(schedule.copy_gas) * copy;
let gas = overflowing!(gas.overflow_add(copy_gas)); let gas = overflowing!(gas.overflow_add(copy_gas));
let gas = overflowing!(gas.overflow_add(mem_gas_cost)); let gas = overflowing!(gas.overflow_add(mem_gas_cost));
Ok((gas, new_mem_gas, new_mem_size)) Ok((gas, new_mem_gas, new_mem_size, None))
} }
} }
} }

View File

@ -89,8 +89,6 @@ impl<'a> CodeReader<'a> {
enum InstructionResult<Gas> { enum InstructionResult<Gas> {
Ok, Ok,
UseAllGas,
GasLeft(Gas),
UnusedGas(Gas), UnusedGas(Gas),
JumpToPosition(U256), JumpToPosition(U256),
// gas left, init_orf, init_size // gas left, init_orf, init_size
@ -129,7 +127,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
try!(self.verify_instruction(ext, instruction, &info, &stack)); try!(self.verify_instruction(ext, instruction, &info, &stack));
// Calculate gas cost // Calculate gas cost
let (gas_cost, mem_gas, mem_size) = try!(gasometer.get_gas_cost_mem(ext, instruction, &info, &stack, self.mem.size())); let (gas_cost, mem_gas, mem_size, provided) = try!(gasometer.get_gas_cost_mem(ext, instruction, &info, &stack, self.mem.size()));
// TODO: make compile-time removable if too much of a performance hit. // TODO: make compile-time removable if too much of a performance hit.
let trace_executed = ext.trace_prepare_execute(reader.position - 1, instruction, &gas_cost.as_u256()); let trace_executed = ext.trace_prepare_execute(reader.position - 1, instruction, &gas_cost.as_u256());
@ -155,25 +153,19 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
// Execute instruction // Execute instruction
let result = try!(self.exec_instruction( let result = try!(self.exec_instruction(
gasometer.current_gas, &params, ext, instruction, &mut reader, &mut stack gasometer.current_gas, &params, ext, instruction, &mut reader, &mut stack, provided
)); ));
if let InstructionResult::UnusedGas(ref gas) = result {
gasometer.current_gas = gasometer.current_gas + *gas;
}
if trace_executed { if trace_executed {
ext.trace_executed(gasometer.current_gas.as_u256(), stack.peek_top(info.ret), mem_written.map(|(o, s)| (o, &(self.mem[o..(o + s)]))), store_written); ext.trace_executed(gasometer.current_gas.as_u256(), stack.peek_top(info.ret), mem_written.map(|(o, s)| (o, &(self.mem[o..(o + s)]))), store_written);
} }
// Advance // Advance
match result { match result {
InstructionResult::Ok => {},
InstructionResult::UnusedGas(gas) => {
gasometer.current_gas = gasometer.current_gas + gas;
},
InstructionResult::UseAllGas => {
gasometer.current_gas = Cost::from(0);
},
InstructionResult::GasLeft(gas_left) => {
gasometer.current_gas = gas_left;
},
InstructionResult::JumpToPosition(position) => { InstructionResult::JumpToPosition(position) => {
let pos = try!(self.verify_jump(position, &valid_jump_destinations)); let pos = try!(self.verify_jump(position, &valid_jump_destinations));
reader.position = pos; reader.position = pos;
@ -182,6 +174,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
return Ok(GasLeft::NeedsReturn(gas.as_u256(), self.mem.read_slice(off, size))); return Ok(GasLeft::NeedsReturn(gas.as_u256(), self.mem.read_slice(off, size)));
}, },
InstructionResult::StopExecution => break, InstructionResult::StopExecution => break,
_ => {},
} }
} }
@ -264,7 +257,8 @@ impl<Cost: CostType> Interpreter<Cost> {
ext: &mut evm::Ext, ext: &mut evm::Ext,
instruction: Instruction, instruction: Instruction,
code: &mut CodeReader, code: &mut CodeReader,
stack: &mut Stack<U256> stack: &mut Stack<U256>,
provided: Option<Cost>
) -> evm::Result<InstructionResult<Cost>> { ) -> evm::Result<InstructionResult<Cost>> {
match instruction { match instruction {
instructions::JUMP => { instructions::JUMP => {
@ -289,31 +283,32 @@ impl<Cost: CostType> Interpreter<Cost> {
let endowment = stack.pop_back(); let endowment = stack.pop_back();
let init_off = stack.pop_back(); let init_off = stack.pop_back();
let init_size = stack.pop_back(); let init_size = stack.pop_back();
let create_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is `CREATE`; qed");
let contract_code = self.mem.read_slice(init_off, init_size); let contract_code = self.mem.read_slice(init_off, init_size);
let can_create = ext.balance(&params.address) >= endowment && ext.depth() < ext.schedule().max_depth; let can_create = ext.balance(&params.address) >= endowment && ext.depth() < ext.schedule().max_depth;
if !can_create { if !can_create {
stack.push(U256::zero()); stack.push(U256::zero());
return Ok(InstructionResult::Ok); return Ok(InstructionResult::UnusedGas(create_gas));
} }
let create_result = ext.create(&gas.as_u256(), &endowment, contract_code); let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code);
return match create_result { return match create_result {
ContractCreateResult::Created(address, gas_left) => { ContractCreateResult::Created(address, gas_left) => {
stack.push(address_to_u256(address)); stack.push(address_to_u256(address));
Ok(InstructionResult::GasLeft(Cost::from_u256(gas_left).expect("Gas left cannot be greater."))) Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater.")))
}, },
ContractCreateResult::Failed => { ContractCreateResult::Failed => {
stack.push(U256::zero()); stack.push(U256::zero());
// TODO [todr] Should we just StopExecution here? Ok(InstructionResult::Ok)
Ok(InstructionResult::UseAllGas)
} }
}; };
}, },
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => { instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => {
assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible"); assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible");
let call_gas = Cost::from_u256(stack.pop_back()).expect("Gas is already validated."); stack.pop_back();
let call_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is one of `CALL`/`CALLCODE`/`DELEGATECALL`; qed");
let code_address = stack.pop_back(); let code_address = stack.pop_back();
let code_address = u256_to_address(&code_address); let code_address = u256_to_address(&code_address);
@ -331,7 +326,7 @@ impl<Cost: CostType> Interpreter<Cost> {
// Add stipend (only CALL|CALLCODE when value > 0) // Add stipend (only CALL|CALLCODE when value > 0)
let call_gas = call_gas + value.map_or_else(|| Cost::from(0), |val| match val.is_zero() { let call_gas = call_gas + value.map_or_else(|| Cost::from(0), |val| match val.is_zero() {
false => Cost::from(ext.schedule().call_stipend), false => Cost::from(ext.schedule().call_stipend),
true => Cost::from(0) true => Cost::from(0),
}); });
// Get sender & receive addresses, check if we have balance // Get sender & receive addresses, check if we have balance

View File

@ -80,6 +80,19 @@ pub struct Schedule {
pub tx_data_non_zero_gas: usize, pub tx_data_non_zero_gas: usize,
/// Gas price for copying memory /// Gas price for copying memory
pub copy_gas: usize, 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 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>,
} }
impl Schedule { impl Schedule {
@ -93,6 +106,49 @@ impl Schedule {
Self::new(true, true, 53000) Self::new(true, true, 53000)
} }
/// Schedule for the Homestead-era of the Ethereum main net.
pub fn new_homestead_gas_fix() -> Schedule {
Schedule{
exceptional_failed_code_deposit: true,
have_delegate_call: true,
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: 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,
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,
balance_gas: 400,
suicide_gas: 5000,
suicide_to_new_account_cost: 25000,
sub_gas_cap_divisor: Some(64),
}
}
fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule { fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule {
Schedule{ Schedule{
exceptional_failed_code_deposit: efcd, exceptional_failed_code_deposit: efcd,
@ -126,6 +182,12 @@ impl Schedule {
tx_data_zero_gas: 4, tx_data_zero_gas: 4,
tx_data_non_zero_gas: 68, tx_data_non_zero_gas: 68,
copy_gas: 3, copy_gas: 3,
extcodesize_gas: 20,
extcodecopy_base_gas: 20,
balance_gas: 20,
suicide_gas: 0,
suicide_to_new_account_cost: 0,
sub_gas_cap_divisor: None,
} }
} }
} }

View File

@ -693,7 +693,7 @@ mod tests {
VMOperation { pc: 33, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99985.into(), stack_push: vec_into![29], mem_diff: None, store_diff: None }) }, VMOperation { pc: 33, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99985.into(), stack_push: vec_into![29], mem_diff: None, store_diff: None }) },
VMOperation { pc: 35, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99982.into(), stack_push: vec_into![3], mem_diff: None, store_diff: None }) }, VMOperation { pc: 35, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99982.into(), stack_push: vec_into![3], mem_diff: None, store_diff: None }) },
VMOperation { pc: 37, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99979.into(), stack_push: vec_into![23], mem_diff: None, store_diff: None }) }, VMOperation { pc: 37, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99979.into(), stack_push: vec_into![23], mem_diff: None, store_diff: None }) },
VMOperation { pc: 39, instruction: 240, gas_cost: 32000.into(), executed: Some(VMExecutedOperation { gas_used: 67979.into(), stack_push: vec_into![U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap()], mem_diff: None, store_diff: None }) }, VMOperation { pc: 39, instruction: 240, gas_cost: 99979.into(), executed: Some(VMExecutedOperation { gas_used: 64755.into(), stack_push: vec_into![U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap()], mem_diff: None, store_diff: None }) },
VMOperation { pc: 40, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 64752.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) }, VMOperation { pc: 40, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 64752.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) },
VMOperation { pc: 42, instruction: 85, gas_cost: 20000.into(), executed: Some(VMExecutedOperation { gas_used: 44752.into(), stack_push: vec_into![], mem_diff: None, store_diff: Some(StorageDiff { location: 0.into(), value: U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap() }) }) } VMOperation { pc: 42, instruction: 85, gas_cost: 20000.into(), executed: Some(VMExecutedOperation { gas_used: 44752.into(), stack_push: vec_into![], mem_diff: None, store_diff: Some(StorageDiff { location: 0.into(), value: U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap() }) }) }
], ],

View File

@ -48,7 +48,8 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
let mut spec = match era { let mut spec = match era {
ChainEra::Frontier => ethereum::new_frontier_test(), ChainEra::Frontier => ethereum::new_frontier_test(),
ChainEra::Homestead => ethereum::new_homestead_test(), ChainEra::Homestead => ethereum::new_homestead_test(),
ChainEra::DaoHardfork => ethereum::new_daohardfork_test(), ChainEra::Eip150 => ethereum::new_eip150_test(),
ChainEra::TransitionTest => ethereum::new_transition_test(),
}; };
spec.set_genesis_state(state); spec.set_genesis_state(state);
spec.overwrite_genesis_params(genesis); spec.overwrite_genesis_params(genesis);
@ -114,14 +115,38 @@ mod frontier_era_tests {
declare_test!{BlockchainTests_RandomTests_bl201507071825GO, "BlockchainTests/RandomTests/bl201507071825GO"} declare_test!{BlockchainTests_RandomTests_bl201507071825GO, "BlockchainTests/RandomTests/bl201507071825GO"}
} }
mod daohardfork_tests { mod transition_tests {
use tests::helpers::*; use tests::helpers::*;
use super::json_chain_test; use super::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> { fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::DaoHardfork) json_chain_test(json_data, ChainEra::TransitionTest)
} }
declare_test!{BlockchainTests_TestNetwork_bcSimpleTransitionTest, "BlockchainTests/TestNetwork/bcSimpleTransitionTest"} declare_test!{BlockchainTests_TestNetwork_bcSimpleTransitionTest, "BlockchainTests/TestNetwork/bcSimpleTransitionTest"}
declare_test!{BlockchainTests_TestNetwork_bcTheDaoTest, "BlockchainTests/TestNetwork/bcTheDaoTest"} declare_test!{BlockchainTests_TestNetwork_bcTheDaoTest, "BlockchainTests/TestNetwork/bcTheDaoTest"}
declare_test!{BlockchainTests_TestNetwork_bcEIP150Test, "BlockchainTests/TestNetwork/bcEIP150Test"}
}
mod eip150_blockchain_tests {
use tests::helpers::*;
use super::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Eip150)
}
declare_test!{BlockchainTests_EIP150_bcBlockGasLimitTest, "BlockchainTests/EIP150/bcBlockGasLimitTest"}
declare_test!{BlockchainTests_EIP150_bcForkStressTest, "BlockchainTests/EIP150/bcForkStressTest"}
declare_test!{BlockchainTests_EIP150_bcGasPricerTest, "BlockchainTests/EIP150/bcGasPricerTest"}
declare_test!{BlockchainTests_EIP150_bcInvalidHeaderTest, "BlockchainTests/EIP150/bcInvalidHeaderTest"}
declare_test!{BlockchainTests_EIP150_bcInvalidRLPTest, "BlockchainTests/EIP150/bcInvalidRLPTest"}
declare_test!{BlockchainTests_EIP150_bcMultiChainTest, "BlockchainTests/EIP150/bcMultiChainTest"}
declare_test!{BlockchainTests_EIP150_bcRPC_API_Test, "BlockchainTests/EIP150/bcRPC_API_Test"}
declare_test!{BlockchainTests_EIP150_bcStateTest, "BlockchainTests/EIP150/bcStateTest"}
declare_test!{BlockchainTests_EIP150_bcTotalDifficultyTest, "BlockchainTests/EIP150/bcTotalDifficultyTest"}
declare_test!{BlockchainTests_EIP150_bcUncleHeaderValiditiy, "BlockchainTests/EIP150/bcUncleHeaderValiditiy"}
declare_test!{BlockchainTests_EIP150_bcUncleTest, "BlockchainTests/EIP150/bcUncleTest"}
declare_test!{BlockchainTests_EIP150_bcValidBlockTest, "BlockchainTests/EIP150/bcValidBlockTest"}
declare_test!{BlockchainTests_EIP150_bcWalletTest, "BlockchainTests/EIP150/bcWalletTest"}
} }

View File

@ -0,0 +1,43 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use super::test_common::*;
use tests::helpers::*;
use super::state::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Eip150)
}
declare_test!{StateTests_EIP150_stEIPSpecificTest, "StateTests/EIP150/stEIPSpecificTest"}
declare_test!{StateTests_EIP150_stEIPsingleCodeGasPrices, "StateTests/EIP150/stEIPsingleCodeGasPrices"}
declare_test!{StateTests_EIP150_stMemExpandingEIPCalls, "StateTests/EIP150/stMemExpandingEIPCalls"}
declare_test!{StateTests_EIP150_stCallCodes, "StateTests/EIP150/Homestead/stCallCodes"}
declare_test!{StateTests_EIP150_stCallCreateCallCodeTest, "StateTests/EIP150/Homestead/stCallCreateCallCodeTest"}
declare_test!{StateTests_EIP150_stDelegatecallTest, "StateTests/EIP150/Homestead/stDelegatecallTest"}
declare_test!{StateTests_EIP150_stInitCodeTest, "StateTests/EIP150/Homestead/stInitCodeTest"}
declare_test!{StateTests_EIP150_stLogTests, "StateTests/EIP150/Homestead/stLogTests"}
declare_test!{heavy => StateTests_EIP150_stMemoryStressTest, "StateTests/EIP150/Homestead/stMemoryStressTest"}
declare_test!{heavy => StateTests_EIP150_stMemoryTest, "StateTests/EIP150/Homestead/stMemoryTest"}
declare_test!{StateTests_EIP150_stPreCompiledContracts, "StateTests/EIP150/Homestead/stPreCompiledContracts"}
declare_test!{heavy => StateTests_EIP150_stQuadraticComplexityTest, "StateTests/EIP150/Homestead/stQuadraticComplexityTest"}
declare_test!{StateTests_EIP150_stRecursiveCreate, "StateTests/EIP150/Homestead/stRecursiveCreate"}
declare_test!{StateTests_EIP150_stRefundTest, "StateTests/EIP150/Homestead/stRefundTest"}
declare_test!{StateTests_EIP150_stSpecialTest, "StateTests/EIP150/Homestead/stSpecialTest"}
declare_test!{StateTests_EIP150_stSystemOperationsTest, "StateTests/EIP150/Homestead/stSystemOperationsTest"}
declare_test!{StateTests_EIP150_stTransactionTest, "StateTests/EIP150/Homestead/stTransactionTest"}
declare_test!{StateTests_EIP150_stWalletTest, "StateTests/EIP150/Homestead/stWalletTest"}

View File

@ -36,3 +36,6 @@ declare_test!{BlockchainTests_Homestead_bcUncleHeaderValiditiy, "BlockchainTests
declare_test!{BlockchainTests_Homestead_bcUncleTest, "BlockchainTests/Homestead/bcUncleTest"} declare_test!{BlockchainTests_Homestead_bcUncleTest, "BlockchainTests/Homestead/bcUncleTest"}
declare_test!{BlockchainTests_Homestead_bcValidBlockTest, "BlockchainTests/Homestead/bcValidBlockTest"} declare_test!{BlockchainTests_Homestead_bcValidBlockTest, "BlockchainTests/Homestead/bcValidBlockTest"}
declare_test!{BlockchainTests_Homestead_bcWalletTest, "BlockchainTests/Homestead/bcWalletTest"} declare_test!{BlockchainTests_Homestead_bcWalletTest, "BlockchainTests/Homestead/bcWalletTest"}
declare_test!{BlockchainTests_Homestead_bcShanghaiLove, "BlockchainTests/Homestead/bcShanghaiLove"}
// declare_test!{BlockchainTests_Homestead_bcSuicideIssue, "BlockchainTests/Homestead/bcSuicideIssue"}
declare_test!{BlockchainTests_Homestead_bcExploitTest, "BlockchainTests/Homestead/bcExploitTest"}

View File

@ -23,4 +23,5 @@ mod state;
mod chain; mod chain;
mod homestead_state; mod homestead_state;
mod homestead_chain; mod homestead_chain;
mod eip150_state;
mod trie; mod trie;

File diff suppressed because it is too large Load Diff

View File

@ -32,19 +32,20 @@ use miner::Miner;
pub enum ChainEra { pub enum ChainEra {
Frontier, Frontier,
Homestead, Homestead,
DaoHardfork, Eip150,
TransitionTest,
} }
pub struct TestEngine { pub struct TestEngine {
engine: Arc<Engine>, engine: Arc<Engine>,
max_depth: usize max_depth: usize,
} }
impl TestEngine { impl TestEngine {
pub fn new(max_depth: usize) -> TestEngine { pub fn new(max_depth: usize) -> TestEngine {
TestEngine { TestEngine {
engine: ethereum::new_frontier_test().engine, engine: ethereum::new_frontier_test().engine,
max_depth: max_depth max_depth: max_depth,
} }
} }
} }

View File

@ -63,7 +63,7 @@ mod tests {
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit" : "0x", "homesteadTransition" : "0x",
"daoHardforkTransition": "0xffffffffffffffff", "daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000", "daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": [] "daoHardforkAccounts": []

View File

@ -40,8 +40,8 @@ pub struct EthashParams {
/// See main EthashParams docs. /// See main EthashParams docs.
pub registrar: Option<Address>, pub registrar: Option<Address>,
/// See main EthashParams docs. /// See main EthashParams docs.
#[serde(rename="frontierCompatibilityModeLimit")] #[serde(rename="homesteadTransition")]
pub frontier_compatibility_mode_limit: Option<Uint>, pub homestead_transition: Option<Uint>,
/// See main EthashParams docs. /// See main EthashParams docs.
#[serde(rename="daoHardforkTransition")] #[serde(rename="daoHardforkTransition")]
pub dao_hardfork_transition: Option<Uint>, pub dao_hardfork_transition: Option<Uint>,
@ -51,6 +51,18 @@ pub struct EthashParams {
/// See main EthashParams docs. /// See main EthashParams docs.
#[serde(rename="daoHardforkAccounts")] #[serde(rename="daoHardforkAccounts")]
pub dao_hardfork_accounts: Option<Vec<Address>>, pub dao_hardfork_accounts: Option<Vec<Address>>,
/// See main EthashParams docs.
#[serde(rename="difficultyHardforkTransition")]
pub difficulty_hardfork_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="difficultyHardforkBoundDivisor")]
pub difficulty_hardfork_bound_divisor: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="bombDefuseTransition")]
pub bomb_defuse_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="eip150Transition")]
pub eip150_transition: Option<Uint>,
} }
/// Ethash engine deserialization. /// Ethash engine deserialization.
@ -75,7 +87,7 @@ mod tests {
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0x42", "homesteadTransition": "0x42",
"daoHardforkTransition": "0x08", "daoHardforkTransition": "0x08",
"daoHardforkBeneficiary": "0xabcabcabcabcabcabcabcabcabcabcabcabcabca", "daoHardforkBeneficiary": "0xabcabcabcabcabcabcabcabcabcabcabcabcabca",
"daoHardforkAccounts": [ "daoHardforkAccounts": [
@ -99,7 +111,11 @@ mod tests {
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97", "0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a" "0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
] ],
"difficultyHardforkTransition": "0x59d9",
"difficultyHardforkBoundDivisor": "0x0200",
"bombDefuseTransition": "0x42",
"eip150Transition": "0x42"
} }
}"#; }"#;

View File

@ -50,7 +50,7 @@ mod tests {
#[test] #[test]
fn params_deserialization() { fn params_deserialization() {
let s = r#"{ let s = r#"{
"frontierCompatibilityModeLimit": "0x118c30", "homesteadTransition": "0x118c30",
"maximumExtraDataSize": "0x20", "maximumExtraDataSize": "0x20",
"networkID" : "0x1", "networkID" : "0x1",
"minGasLimit": "0x1388", "minGasLimit": "0x1388",

View File

@ -66,7 +66,7 @@ mod tests {
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit" : "0x", "homesteadTransition" : "0x",
"daoHardforkTransition": "0xffffffffffffffff", "daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000", "daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": [] "daoHardforkAccounts": []
@ -75,7 +75,7 @@ mod tests {
}, },
"params": { "params": {
"accountStartNonce": "0x0100000", "accountStartNonce": "0x0100000",
"frontierCompatibilityModeLimit": "0x789b0", "homesteadTransition": "0x789b0",
"maximumExtraDataSize": "0x20", "maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388", "minGasLimit": "0x1388",
"networkID" : "0x2", "networkID" : "0x2",

View File

@ -201,7 +201,7 @@ const TRANSACTION_COUNT_SPEC: &'static [u8] = br#"{
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0xffffffffffffffff", "homesteadTransition": "0xffffffffffffffff",
"daoHardforkTransition": "0xffffffffffffffff", "daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000", "daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": [] "daoHardforkAccounts": []
@ -249,7 +249,7 @@ const POSITIVE_NONCE_SPEC: &'static [u8] = br#"{
"durationLimit": "0x0d", "durationLimit": "0x0d",
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"frontierCompatibilityModeLimit": "0xffffffffffffffff", "homesteadTransition": "0xffffffffffffffff",
"daoHardforkTransition": "0xffffffffffffffff", "daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000", "daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": [] "daoHardforkAccounts": []