Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

gas_limit for blocks, mined by Parity will be divisible by 37 #4154

Merged
merged 8 commits into from
Jan 16, 2017
87 changes: 80 additions & 7 deletions ethcore/src/ethereum/ethash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ use ethjson;
use rlp::{self, UntrustedRlp, View};
use blockchain::extras::BlockDetails;

/// Parity tries to round block.gas_limit to multiple of this constant
pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]);

/// Ethash params.
#[derive(Debug, PartialEq)]
pub struct EthashParams {
Expand Down Expand Up @@ -180,14 +183,23 @@ impl Engine for Ethash {
let bound_divisor = self.ethash_params.gas_limit_bound_divisor;
let lower_limit = gas_limit - gas_limit / bound_divisor + 1.into();
let upper_limit = gas_limit + gas_limit / bound_divisor - 1.into();
if gas_limit < gas_floor_target {
min(gas_floor_target, upper_limit)
let gas_limit = if gas_limit < gas_floor_target {
let gas_limit = min(gas_floor_target, upper_limit);
round_block_gas_limit(gas_limit, lower_limit, upper_limit)
} else if gas_limit > gas_ceil_target {
max(gas_ceil_target, lower_limit)
let gas_limit = max(gas_ceil_target, lower_limit);
round_block_gas_limit(gas_limit, lower_limit, upper_limit)
} else {
max(gas_floor_target, min(min(gas_ceil_target, upper_limit),
lower_limit + (header.gas_used().clone() * 6.into() / 5.into()) / bound_divisor))
}
let total_lower_limit = max(lower_limit, gas_floor_target);
let total_upper_limit = min(upper_limit, gas_ceil_target);
let gas_limit = max(gas_floor_target, min(total_upper_limit,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would make more sense to have max(total_upper_limit, .. (I know it wasn't like this in previous implementation, but still it would make sense)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I change this to max(total_upper_limit, .. it will always stick to the upper_limit:
max(upper_limit, lower_limit + something) = uper_limit
So this definitely changes the logic significantly and in strange way :)
Maybe you mean max(total_lower_limit, ... - I see that this is logical. However:
max(N, N + M), where N && M are U256 are always larger than N (let's omit overflows)
Previously it wasn't there, because there were no total_lower_limit && it is an extra-op, but now everything is known && I could easily change this, if this is what you meant. Just ping me

lower_limit + (header.gas_used().clone() * 6.into() / 5.into()) / bound_divisor));
round_block_gas_limit(gas_limit, total_lower_limit, total_upper_limit)
};
// ensure that we are not violating protocol limits
debug_assert!(gas_limit >= lower_limit);
debug_assert!(gas_limit <= upper_limit);
gas_limit
};
header.set_difficulty(difficulty);
header.set_gas_limit(gas_limit);
Expand Down Expand Up @@ -334,6 +346,23 @@ pub fn is_new_best_block(best_total_difficulty: U256, parent_details: &BlockDeta
parent_details.total_difficulty + new_header.difficulty() > best_total_difficulty
}

// Try to round gas_limit a bit so that:
// 1) it will still be in desired range
// 2) it will be a nearest (with tendency to increase) multiple of PARITY_GAS_LIMIT_DETERMINANT
fn round_block_gas_limit(gas_limit: U256, lower_limit: U256, upper_limit: U256) -> U256 {
let increased_gas_limit = gas_limit + (PARITY_GAS_LIMIT_DETERMINANT - gas_limit % PARITY_GAS_LIMIT_DETERMINANT);
if increased_gas_limit > upper_limit {
let decreased_gas_limit = increased_gas_limit - PARITY_GAS_LIMIT_DETERMINANT;
if decreased_gas_limit < lower_limit {
gas_limit
} else {
decreased_gas_limit
}
} else {
increased_gas_limit
}
}

#[cfg_attr(feature="dev", allow(wrong_self_convention))]
impl Ethash {
fn calculate_difficulty(&self, header: &Header, parent: &Header) -> U256 {
Expand Down Expand Up @@ -431,11 +460,12 @@ mod tests {
use util::*;
use block::*;
use tests::helpers::*;
use engines::Engine;
use env_info::EnvInfo;
use error::{BlockError, Error};
use header::Header;
use super::super::{new_morden, new_homestead_test};
use super::{Ethash, EthashParams};
use super::{Ethash, EthashParams, PARITY_GAS_LIMIT_DETERMINANT};
use rlp;

#[test]
Expand Down Expand Up @@ -773,4 +803,47 @@ mod tests {
ethash.calculate_difficulty(&header, &parent_header)
);
}

#[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 mut parent = Header::new();
let mut header = Header::new();
header.set_number(1);

// this test will work for this constant only
assert_eq!(PARITY_GAS_LIMIT_DETERMINANT, U256::from(37));

// when parent.gas_limit < gas_floor_target:
parent.set_gas_limit(U256::from(50_000));
ethash.populate_from_parent(&mut header, &parent, U256::from(100_000), U256::from(200_000));
assert_eq!(*header.gas_limit(), U256::from(50_024));

// when parent.gas_limit > gas_ceil_target:
parent.set_gas_limit(U256::from(250_000));
ethash.populate_from_parent(&mut header, &parent, U256::from(100_000), U256::from(200_000));
assert_eq!(*header.gas_limit(), U256::from(249_787));

// when parent.gas_limit is in miner's range
header.set_gas_used(U256::from(150_000));
parent.set_gas_limit(U256::from(150_000));
ethash.populate_from_parent(&mut header, &parent, U256::from(100_000), U256::from(200_000));
assert_eq!(*header.gas_limit(), U256::from(150_035));

// when parent.gas_limit is in miner's range
// && we can NOT increase it to be multiple of constant
header.set_gas_used(U256::from(150_000));
parent.set_gas_limit(U256::from(150_000));
ethash.populate_from_parent(&mut header, &parent, U256::from(100_000), U256::from(150_002));
assert_eq!(*header.gas_limit(), U256::from(149_998));

// when parent.gas_limit is in miner's range
// && we can NOT increase it to be multiple of constant
// && we can NOT decrease it to be multiple of constant
header.set_gas_used(U256::from(150_000));
parent.set_gas_limit(U256::from(150_000));
ethash.populate_from_parent(&mut header, &parent, U256::from(150_000), U256::from(150_002));
assert_eq!(*header.gas_limit(), U256::from(150_002));
}
}