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:
parent
a19be3cb51
commit
d152fa3e85
@ -16,6 +16,7 @@
|
||||
"eip160Transition": 3000000,
|
||||
"ecip1010PauseTransition": 3000000,
|
||||
"ecip1010ContinueTransition": 5000000,
|
||||
"ecip1017EraRounds": 5000000,
|
||||
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
|
@ -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();
|
||||
|
@ -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(),
|
||||
|
@ -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>,
|
||||
|
Loading…
Reference in New Issue
Block a user