diff --git a/ethcore/res/contracts/block_gas_limit.json b/ethcore/res/contracts/block_gas_limit.json new file mode 100644 index 00000000000..bb2671b4571 --- /dev/null +++ b/ethcore/res/contracts/block_gas_limit.json @@ -0,0 +1,16 @@ +[ + { + "constant": true, + "inputs": [], + "name": "blockGasLimit", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] diff --git a/ethcore/res/contracts/tx_acl_gas_price.json b/ethcore/res/contracts/tx_acl_gas_price.json index a8a2af22152..bc355dee7e6 100644 --- a/ethcore/res/contracts/tx_acl_gas_price.json +++ b/ethcore/res/contracts/tx_acl_gas_price.json @@ -41,20 +41,6 @@ "stateMutability": "view", "type": "function" }, - { - "constant": true, - "inputs": [], - "name": "blockGasLimit", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, { "constant": true, "inputs": [ diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index d5da8c65135..280eb6e473e 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -45,7 +45,6 @@ use itertools::{self, Itertools}; use rlp::{encode, Decodable, DecoderError, Encodable, RlpStream, Rlp}; use ethereum_types::{H256, H520, Address, U128, U256}; use parking_lot::{Mutex, RwLock}; -use tx_filter::transact_acl_gas_price; use types::BlockNumber; use types::ancestry_action::AncestryAction; use types::header::{Header, ExtendedHeader}; @@ -55,6 +54,8 @@ use unexpected::{Mismatch, OutOfBounds}; #[cfg(not(time_checked_add))] use time_utils::CheckedSystemTime; +use_contract!(block_gas_limit, "res/contracts/block_gas_limit.json"); + mod finality; mod randomness; pub(crate) mod util; @@ -1791,6 +1792,8 @@ impl Engine for AuthorityRound { } fn gas_limit_override(&self, header: &Header) -> Option { + let (_, &address) = self.machine.params().block_gas_limit_contract.range(..header.number()).last()?; + let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) { Some(client) => client, None => { @@ -1806,15 +1809,7 @@ impl Engine for AuthorityRound { } }; - let address = match self.machine.tx_filter() { - Some(tx_filter) => *tx_filter.contract_address(), - None => { - debug!(target: "engine", "No transaction filter configured. Not changing the block gas limit."); - return None; - } - }; - - let (data, decoder) = transact_acl_gas_price::functions::block_gas_limit::call(); + let (data, decoder) = block_gas_limit::functions::block_gas_limit::call(); let value = full_client.call_contract_before(header, address, data).map_err(|err| { error!(target: "engine", "Failed to call blockGasLimit. Not changing the block gas limit. {:?}", err); }).ok()?; diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 4813fbc1040..ef18dcad76e 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -79,6 +79,8 @@ pub struct CommonParams { pub subprotocol_name: String, /// Minimum gas limit. pub min_gas_limit: U256, + /// The address of a contract that determines the block gas limit. + pub block_gas_limit_contract: BTreeMap, /// Fork block to check. pub fork_block: Option<(BlockNumber, H256)>, /// EIP150 transition block number. @@ -243,6 +245,7 @@ impl From for CommonParams { }, subprotocol_name: p.subprotocol_name.unwrap_or_else(|| "eth".to_owned()), min_gas_limit: p.min_gas_limit.into(), + block_gas_limit_contract: p.block_gas_limit_contract.map(|bglc| bglc.into()).unwrap_or_default(), fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index 765384a6b91..5d381c5e602 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -16,6 +16,9 @@ //! Spec params deserialization. +use std::collections::BTreeMap; +use std::iter; +use ethereum_types::H160; use uint::{self, Uint}; use hash::{H256, Address}; use bytes::Bytes; @@ -31,6 +34,8 @@ pub struct Params { pub maximum_extra_data_size: Uint, /// Minimum gas limit. pub min_gas_limit: Uint, + /// The address of a contract that determines the block gas limit. + pub block_gas_limit_contract: Option, /// Network id. #[serde(rename = "networkID")] @@ -126,12 +131,36 @@ pub struct Params { pub kip6_transition: Option, } +/// A contract that determines block gas limits can be configured either as a single address, or as a map, assigning +/// to each starting block number the contract address that should be used from that block on. +#[derive(Debug, PartialEq, Deserialize)] +#[serde(deny_unknown_fields, untagged)] +pub enum BlockGasLimitContract { + /// A single address for a block gas limit contract. + Single(Address), + /// A map from block numbers to the contract addresses that should be used for the gas limit after that block. + Transitions(BTreeMap), +} + +impl From for BTreeMap { + fn from(contract: BlockGasLimitContract) -> Self { + match contract { + BlockGasLimitContract::Single(Address(addr)) => iter::once((0, addr)).collect(), + BlockGasLimitContract::Transitions(transitions) => { + transitions.into_iter().map(|(Uint(block), Address(addr))| (block.into(), addr)).collect() + } + } + } +} + #[cfg(test)] mod tests { + use std::str::FromStr; use serde_json; use uint::Uint; - use ethereum_types::U256; - use spec::params::Params; + use ethereum_types::{U256, H160}; + use hash::Address; + use spec::params::{BlockGasLimitContract, Params}; #[test] fn params_deserialization() { @@ -144,7 +173,11 @@ mod tests { "accountStartNonce": "0x01", "gasLimitBoundDivisor": "0x20", "maxCodeSize": "0x1000", - "wasmActivationTransition": "0x1010" + "wasmActivationTransition": "0x1010", + "blockGasLimitContract": { + "10": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "20": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + } }"#; let deserialized: Params = serde_json::from_str(s).unwrap();