Ethereum Classic Monetary Policy (#5741)

* Ethereum Classic Monetary Policy

Create a new parameter `ecip1017EraRounds`. When the block number
passes one era rounds, the reward is reduced by 20%.

See https://github.com/ethereumproject/ECIPs/blob/master/ECIPs/ECIP-1017.md

* Update rewards for uncle miners for ECIP1017

In the monetary policy, the rewards are changed from "up to 7/8 of the
reward" to "1/32 of the reward".

* Fix an off-by-one error in ECIP1017 era calculation

According to
https://github.com/ethereumproject/ECIPs/blob/master/ECIPs/ECIP-1017.md,
when in block number 5,000,000, it should still be in Era 1 (which in
our code `era == 0`). So we need to check whether the `rem` equals to
zero and act accordingly when calculating the era.

* `ecip1017_era_rounds` missing from EthashParams when run in build bot

* strip out ecip1017_eras_block_reward function and add unit test
This commit is contained in:
Stewart Mackenzie 2017-06-20 00:56:37 +08:00 committed by Gav Wood
parent a19be3cb51
commit d152fa3e85
4 changed files with 73 additions and 6 deletions

View File

@ -16,6 +16,7 @@
"eip160Transition": 3000000,
"ecip1010PauseTransition": 3000000,
"ecip1010ContinueTransition": 5000000,
"ecip1017EraRounds": 5000000,
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"

View File

@ -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<ethjson::spec::EthashParams> 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<Ethash> {
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<Ethash> {
// 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();

View File

@ -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(),

View File

@ -100,6 +100,10 @@ pub struct EthashParams {
#[serde(rename="ecip1010ContinueTransition")]
pub ecip1010_continue_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="ecip1017EraRounds")]
pub ecip1017_era_rounds: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="maxCodeSize")]
pub max_code_size: Option<Uint>,