Max gas limit and min gas price (#4661)

* Max gas limit and min gas price

* Tests

* Limit gas limit ceiling
This commit is contained in:
Arkadiy Paronyan 2017-02-24 17:34:32 +01:00 committed by Gav Wood
parent af45d05aee
commit ef7998f473
3 changed files with 124 additions and 3 deletions

View File

@ -79,6 +79,14 @@ pub struct EthashParams {
pub ecip1010_continue_transition: 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.
pub max_gas_limit_transition: u64,
/// Maximum valid block gas limit,
pub max_gas_limit: U256,
/// Number of first block where the minimum gas price becomes effective.
pub min_gas_price_transition: u64,
/// Do not alow transactions with lower gas price.
pub min_gas_price: U256,
}
impl From<ethjson::spec::EthashParams> for EthashParams {
@ -106,6 +114,10 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
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),
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),
min_gas_price_transition: p.min_gas_price_transition.map_or(u64::max_value(), Into::into),
min_gas_price: p.min_gas_price.map_or(U256::zero(), Into::into),
}
}
}
@ -174,8 +186,12 @@ impl Engine for Ethash {
}
}
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, gas_ceil_target: U256) {
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, mut gas_ceil_target: U256) {
let difficulty = self.calculate_difficulty(header, parent);
if header.number() >= self.ethash_params.max_gas_limit_transition && gas_ceil_target > self.ethash_params.max_gas_limit {
warn!("Gas limit target is limited to {}", self.ethash_params.max_gas_limit);
gas_ceil_target = self.ethash_params.max_gas_limit;
}
let gas_limit = {
let gas_limit = parent.gas_limit().clone();
let bound_divisor = self.ethash_params.gas_limit_bound_divisor;
@ -312,11 +328,15 @@ impl Engine for Ethash {
return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: expected_difficulty, found: header.difficulty().clone() })))
}
let gas_limit_divisor = self.ethash_params.gas_limit_bound_divisor;
let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor;
let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
let parent_gas_limit = *parent.gas_limit();
let min_gas = parent_gas_limit - parent_gas_limit / gas_limit_divisor;
let max_gas = parent_gas_limit + parent_gas_limit / gas_limit_divisor;
if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() })));
}
if header.number() >= self.ethash_params.max_gas_limit_transition && header.gas_limit() > &self.ethash_params.max_gas_limit && header.gas_limit() > &parent_gas_limit {
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(self.ethash_params.max_gas_limit), found: header.gas_limit().clone() })));
}
Ok(())
}
@ -331,6 +351,10 @@ impl Engine for Ethash {
}
}
if header.number() >= self.ethash_params.min_gas_price_transition && t.gas_price < self.ethash_params.min_gas_price {
return Err(TransactionError::InsufficientGasPrice { minimal: self.ethash_params.min_gas_price, got: t.gas_price }.into());
}
Ok(())
}
}
@ -853,4 +877,82 @@ mod tests {
let difficulty = ethash.calculate_difficulty(&header, &parent_header);
assert_eq!(U256::from(12543204905719u64), difficulty);
}
#[test]
fn rejects_blocks_over_max_gas_limit() {
let spec = new_homestead_test();
let mut ethparams = get_default_ethash_params();
ethparams.max_gas_limit_transition = 10;
ethparams.max_gas_limit = 100_000.into();
let mut parent_header = Header::default();
parent_header.set_number(1);
parent_header.set_gas_limit(100_000.into());
let mut header = Header::default();
header.set_number(parent_header.number() + 1);
header.set_gas_limit(100_001.into());
header.set_difficulty(ethparams.minimum_difficulty);
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new());
assert!(ethash.verify_block_family(&header, &parent_header, None).is_ok());
parent_header.set_number(9);
header.set_number(parent_header.number() + 1);
parent_header.set_gas_limit(99_999.into());
header.set_gas_limit(100_000.into());
assert!(ethash.verify_block_family(&header, &parent_header, None).is_ok());
parent_header.set_gas_limit(200_000.into());
header.set_gas_limit(200_000.into());
assert!(ethash.verify_block_family(&header, &parent_header, None).is_ok());
parent_header.set_gas_limit(100_000.into());
header.set_gas_limit(100_001.into());
assert!(ethash.verify_block_family(&header, &parent_header, None).is_err());
parent_header.set_gas_limit(200_000.into());
header.set_gas_limit(200_001.into());
assert!(ethash.verify_block_family(&header, &parent_header, None).is_err());
}
#[test]
fn rejects_transactions_below_min_gas_price() {
use ethkey::{Generator, Random};
use types::transaction::{Transaction, Action};
let spec = new_homestead_test();
let mut ethparams = get_default_ethash_params();
ethparams.min_gas_price_transition = 10;
ethparams.min_gas_price = 100000.into();
let mut header = Header::default();
header.set_number(1);
let keypair = Random.generate().unwrap();
let tx1 = Transaction {
action: Action::Create,
value: U256::zero(),
data: Vec::new(),
gas: 100_000.into(),
gas_price: 100_000.into(),
nonce: U256::zero(),
}.sign(keypair.secret(), None).into();
let tx2 = Transaction {
action: Action::Create,
value: U256::zero(),
data: Vec::new(),
gas: 100_000.into(),
gas_price: 99_999.into(),
nonce: U256::zero(),
}.sign(keypair.secret(), None).into();
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new());
assert!(ethash.verify_transaction_basic(&tx1, &header).is_ok());
assert!(ethash.verify_transaction_basic(&tx2, &header).is_ok());
header.set_number(10);
assert!(ethash.verify_transaction_basic(&tx1, &header).is_ok());
assert!(ethash.verify_transaction_basic(&tx2, &header).is_err());
}
}

View File

@ -456,5 +456,9 @@ pub fn get_default_ethash_params() -> EthashParams{
ecip1010_pause_transition: u64::max_value(),
ecip1010_continue_transition: u64::max_value(),
max_code_size: u64::max_value(),
max_gas_limit_transition: u64::max_value(),
max_gas_limit: U256::max_value(),
min_gas_price_transition: u64::max_value(),
min_gas_price: U256::zero(),
}
}

View File

@ -97,6 +97,21 @@ pub struct EthashParams {
#[serde(rename="maxCodeSize")]
pub max_code_size: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="maxGasLimitTransition")]
pub max_gas_limit_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="maxGasLimit")]
pub max_gas_limit: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="minGasPriceTransition")]
pub min_gas_price_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="minGasPrice")]
pub min_gas_price: Option<Uint>,
}
/// Ethash engine deserialization.