diff --git a/ethcore/res/ethereum/classic.json b/ethcore/res/ethereum/classic.json index f7cb4dacaa0..6edfef460d8 100644 --- a/ethcore/res/ethereum/classic.json +++ b/ethcore/res/ethereum/classic.json @@ -16,6 +16,7 @@ "eip160Transition": 3000000, "ecip1010PauseTransition": 3000000, "ecip1010ContinueTransition": 5000000, + "ecip1017EraRounds": 5000000, "eip161abcTransition": "0x7fffffffffffffff", "eip161dTransition": "0x7fffffffffffffff" diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 6e698150bd1..38305ad6f4b 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -86,6 +86,8 @@ pub struct EthashParams { pub ecip1010_pause_transition: u64, /// Number of first block where ECIP-1010 ends. pub ecip1010_continue_transition: u64, + /// Total block number for one ECIP-1017 era. + pub ecip1017_era_rounds: u64, /// Maximum amount of code that can be deploying into a contract. pub max_code_size: u64, /// Number of first block where the max gas limit becomes effective. @@ -124,6 +126,7 @@ impl From for EthashParams { eip161d_transition: p.eip161d_transition.map_or(u64::max_value(), Into::into), ecip1010_pause_transition: p.ecip1010_pause_transition.map_or(u64::max_value(), Into::into), ecip1010_continue_transition: p.ecip1010_continue_transition.map_or(u64::max_value(), Into::into), + ecip1017_era_rounds: p.ecip1017_era_rounds.map_or(u64::max_value(), Into::into), max_code_size: p.max_code_size.map_or(u64::max_value(), Into::into), max_gas_limit_transition: p.max_gas_limit_transition.map_or(u64::max_value(), Into::into), max_gas_limit: p.max_gas_limit.map_or(U256::max_value(), Into::into), @@ -272,6 +275,8 @@ impl Engine for Arc { fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { let reward = self.ethash_params.block_reward; let fields = block.fields_mut(); + let eras_rounds = self.ethash_params.ecip1017_era_rounds; + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, fields.header.number()); // Bestow block reward fields.state.add_balance( @@ -283,11 +288,19 @@ impl Engine for Arc { // Bestow uncle rewards let current_number = fields.header.number(); for u in fields.uncles.iter() { - fields.state.add_balance( - u.author(), - &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)), - CleanupMode::NoEmpty - )?; + if eras == 0 { + fields.state.add_balance( + u.author(), + &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)), + CleanupMode::NoEmpty + ) + } else { + fields.state.add_balance( + u.author(), + &(reward / U256::from(32)), + CleanupMode::NoEmpty + ) + }?; } // Commit state so that we can actually figure out the state root. @@ -413,6 +426,18 @@ fn round_block_gas_limit(gas_limit: U256, lower_limit: U256, upper_limit: U256) } } +fn ecip1017_eras_block_reward(era_rounds: u64, mut reward: U256, block_number:u64) -> (u64, U256){ + let eras = if block_number != 0 && block_number % era_rounds == 0 { + block_number / era_rounds - 1 + } else { + block_number / era_rounds + }; + for _ in 0..eras { + reward = reward / U256::from(5) * U256::from(4); + } + (eras, reward) +} + #[cfg_attr(feature="dev", allow(wrong_self_convention))] impl Ethash { fn calculate_difficulty(&self, header: &Header, parent: &Header) -> U256 { @@ -524,7 +549,7 @@ mod tests { use error::{BlockError, Error}; use header::Header; use super::super::{new_morden, new_homestead_test}; - use super::{Ethash, EthashParams, PARITY_GAS_LIMIT_DETERMINANT}; + use super::{Ethash, EthashParams, PARITY_GAS_LIMIT_DETERMINANT, ecip1017_eras_block_reward}; use rlp; #[test] @@ -760,6 +785,42 @@ mod tests { assert_eq!(U256::from_str("1fc50f118efe").unwrap(), difficulty); } + #[test] + fn has_valid_ecip1017_eras_block_reward() { + let ethparams = EthashParams { + // see ethcore/res/ethereum/classic.json + ecip1017_era_rounds: 5000000, + block_reward: U256::from_str("4563918244F40000").unwrap(), + ..get_default_ethash_params() + }; + let eras_rounds = ethparams.ecip1017_era_rounds; + let reward = ethparams.block_reward; + let block_number = 0; + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number); + assert_eq!(0, eras); + assert_eq!(U256::from_str("4563918244F40000").unwrap(), reward); + let reward = ethparams.block_reward; + let block_number = 5000000; + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number); + assert_eq!(0, eras); + assert_eq!(U256::from_str("4563918244F40000").unwrap(), reward); + let reward = ethparams.block_reward; + let block_number = 10000000; + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number); + assert_eq!(1, eras); + assert_eq!(U256::from_str("3782DACE9D900000").unwrap(), reward); + let reward = ethparams.block_reward; + let block_number = 20000000; + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number); + assert_eq!(3, eras); + assert_eq!(U256::from_str("2386F26FC1000000").unwrap(), reward); + let reward = ethparams.block_reward; + let block_number = 80000000; + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number); + assert_eq!(15, eras); + assert_eq!(U256::from_str("271000000000000").unwrap(), reward); + } + #[test] fn difficulty_classic_bomb_delay() { let spec = new_homestead_test(); diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index ed77657ad15..c54933fd1d9 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -418,6 +418,7 @@ pub fn get_default_ethash_params() -> EthashParams{ eip161d_transition: u64::max_value(), ecip1010_pause_transition: u64::max_value(), ecip1010_continue_transition: u64::max_value(), + ecip1017_era_rounds: u64::max_value(), max_code_size: u64::max_value(), max_gas_limit_transition: u64::max_value(), max_gas_limit: U256::max_value(), diff --git a/json/src/spec/ethash.rs b/json/src/spec/ethash.rs index 926dcaceec7..75d8bc0f43f 100644 --- a/json/src/spec/ethash.rs +++ b/json/src/spec/ethash.rs @@ -100,6 +100,10 @@ pub struct EthashParams { #[serde(rename="ecip1010ContinueTransition")] pub ecip1010_continue_transition: Option, + /// See main EthashParams docs. + #[serde(rename="ecip1017EraRounds")] + pub ecip1017_era_rounds: Option, + /// See main EthashParams docs. #[serde(rename="maxCodeSize")] pub max_code_size: Option,