Set the block gas limit to the value returned by a contract call (#10928)
* Block gas limit contract Lower gas limit if TxPermission.limitBlockGas. Call blockGasLimit before every block. Make the block gas limit contract a separate config option. Add `info` level logging of block gas limit switching block-gas-limit subcrate and responses to review comments simplified call_contract_before moved block_gas_limit_contract_transitions to AuRa params removed call_contract_before Update and fix test_verify_block. Remove some unused imports and functions. * Move gas limit override check to verify_block_basic. Co-authored-by: Andreas Fackler <afck@users.noreply.github.com>
This commit is contained in:
parent
87e1080581
commit
73354d8d93
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -177,6 +177,7 @@ dependencies = [
|
|||||||
name = "authority-round"
|
name = "authority-round"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"block-gas-limit 0.1.0",
|
||||||
"block-reward 0.1.0",
|
"block-reward 0.1.0",
|
||||||
"client-traits 0.1.0",
|
"client-traits 0.1.0",
|
||||||
"common-types 0.1.0",
|
"common-types 0.1.0",
|
||||||
@ -364,6 +365,21 @@ dependencies = [
|
|||||||
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-gas-limit"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"client-traits 0.1.0",
|
||||||
|
"common-types 0.1.0",
|
||||||
|
"ethabi 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ethabi-contract 9.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ethabi-derive 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ethcore 1.12.0",
|
||||||
|
"ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"spec 0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-modes"
|
name = "block-modes"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
20
ethcore/block-gas-limit/Cargo.toml
Normal file
20
ethcore/block-gas-limit/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
description = "A crate to interact with the block gas limit contract"
|
||||||
|
name = "block-gas-limit"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "GPL-3.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
client-traits = { path = "../client-traits" }
|
||||||
|
common-types = { path = "../types" }
|
||||||
|
ethabi = "9.0.1"
|
||||||
|
ethabi-derive = "9.0.1"
|
||||||
|
ethabi-contract = "9.0.0"
|
||||||
|
ethereum-types = "0.8.0"
|
||||||
|
log = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
ethcore = { path = "..", features = ["test-helpers"] }
|
||||||
|
spec = { path = "../spec" }
|
16
ethcore/block-gas-limit/res/block_gas_limit.json
Normal file
16
ethcore/block-gas-limit/res/block_gas_limit.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "blockGasLimit",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]
|
39
ethcore/block-gas-limit/src/lib.rs
Normal file
39
ethcore/block-gas-limit/src/lib.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! A client interface for interacting with the block gas limit contract.
|
||||||
|
|
||||||
|
use client_traits::BlockChainClient;
|
||||||
|
use common_types::{header::Header, ids::BlockId};
|
||||||
|
use ethabi::FunctionOutputDecoder;
|
||||||
|
use ethabi_contract::use_contract;
|
||||||
|
use ethereum_types::{Address, U256};
|
||||||
|
use log::{debug, error};
|
||||||
|
|
||||||
|
use_contract!(contract, "res/block_gas_limit.json");
|
||||||
|
|
||||||
|
pub fn block_gas_limit(full_client: &dyn BlockChainClient, header: &Header, address: Address) -> Option<U256> {
|
||||||
|
let (data, decoder) = contract::functions::block_gas_limit::call();
|
||||||
|
let value = full_client.call_contract(BlockId::Hash(*header.parent_hash()), address, data).map_err(|err| {
|
||||||
|
error!(target: "block_gas_limit", "Contract call failed. Not changing the block gas limit. {:?}", err);
|
||||||
|
}).ok()?;
|
||||||
|
if value.is_empty() {
|
||||||
|
debug!(target: "block_gas_limit", "Contract call returned nothing. Not changing the block gas limit.");
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
decoder.decode(&value).ok()
|
||||||
|
}
|
||||||
|
}
|
@ -347,6 +347,12 @@ pub trait Engine: Sync + Send {
|
|||||||
Ok(*header.author())
|
Ok(*header.author())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Overrides the block gas limit. Whenever this returns `Some` for a header, the next block's gas limit must be
|
||||||
|
/// exactly that value.
|
||||||
|
fn gas_limit_override(&self, _header: &Header) -> Option<U256> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the general parameters of the chain.
|
/// Get the general parameters of the chain.
|
||||||
fn params(&self) -> &CommonParams;
|
fn params(&self) -> &CommonParams;
|
||||||
|
|
||||||
@ -397,6 +403,11 @@ pub trait Engine: Sync + Send {
|
|||||||
fn decode_transaction(&self, transaction: &[u8]) -> Result<UnverifiedTransaction, transaction::Error> {
|
fn decode_transaction(&self, transaction: &[u8]) -> Result<UnverifiedTransaction, transaction::Error> {
|
||||||
self.machine().decode_transaction(transaction)
|
self.machine().decode_transaction(transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The configured minimum gas limit.
|
||||||
|
fn min_gas_limit(&self) -> U256 {
|
||||||
|
self.params().min_gas_limit
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verifier for all blocks within an epoch with self-contained state.
|
/// Verifier for all blocks within an epoch with self-contained state.
|
||||||
|
@ -7,6 +7,7 @@ edition = "2018"
|
|||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
block-gas-limit = { path = "../../block-gas-limit" }
|
||||||
block-reward = { path = "../../block-reward" }
|
block-reward = { path = "../../block-reward" }
|
||||||
client-traits = { path = "../../client-traits" }
|
client-traits = { path = "../../client-traits" }
|
||||||
common-types = { path = "../../types" }
|
common-types = { path = "../../types" }
|
||||||
|
@ -42,6 +42,7 @@ use std::u64;
|
|||||||
|
|
||||||
use client_traits::{EngineClient, ForceUpdateSealing, TransactionRequest};
|
use client_traits::{EngineClient, ForceUpdateSealing, TransactionRequest};
|
||||||
use engine::{Engine, ConstructedVerifier};
|
use engine::{Engine, ConstructedVerifier};
|
||||||
|
use block_gas_limit::block_gas_limit;
|
||||||
use block_reward::{self, BlockRewardContract, RewardKind};
|
use block_reward::{self, BlockRewardContract, RewardKind};
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use machine::{
|
use machine::{
|
||||||
@ -51,6 +52,7 @@ use machine::{
|
|||||||
use macros::map;
|
use macros::map;
|
||||||
use keccak_hash::keccak;
|
use keccak_hash::keccak;
|
||||||
use log::{info, debug, error, trace, warn};
|
use log::{info, debug, error, trace, warn};
|
||||||
|
use lru_cache::LruCache;
|
||||||
use engine::signer::EngineSigner;
|
use engine::signer::EngineSigner;
|
||||||
use parity_crypto::publickey::Signature;
|
use parity_crypto::publickey::Signature;
|
||||||
use io::{IoContext, IoHandler, TimerToken, IoService};
|
use io::{IoContext, IoHandler, TimerToken, IoService};
|
||||||
@ -78,7 +80,6 @@ use common_types::{
|
|||||||
transaction::SignedTransaction,
|
transaction::SignedTransaction,
|
||||||
};
|
};
|
||||||
use unexpected::{Mismatch, OutOfBounds};
|
use unexpected::{Mismatch, OutOfBounds};
|
||||||
|
|
||||||
use validator_set::{ValidatorSet, SimpleList, new_validator_set};
|
use validator_set::{ValidatorSet, SimpleList, new_validator_set};
|
||||||
|
|
||||||
mod finality;
|
mod finality;
|
||||||
@ -124,10 +125,16 @@ pub struct AuthorityRoundParams {
|
|||||||
pub strict_empty_steps_transition: u64,
|
pub strict_empty_steps_transition: u64,
|
||||||
/// If set, enables random number contract integration. It maps the transition block to the contract address.
|
/// If set, enables random number contract integration. It maps the transition block to the contract address.
|
||||||
pub randomness_contract_address: BTreeMap<u64, Address>,
|
pub randomness_contract_address: BTreeMap<u64, Address>,
|
||||||
|
/// The addresses of contracts that determine the block gas limit with their associated block
|
||||||
|
/// numbers.
|
||||||
|
pub block_gas_limit_contract_transitions: BTreeMap<u64, Address>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const U16_MAX: usize = ::std::u16::MAX as usize;
|
const U16_MAX: usize = ::std::u16::MAX as usize;
|
||||||
|
|
||||||
|
/// The number of recent block hashes for which the gas limit override is memoized.
|
||||||
|
const GAS_LIMIT_OVERRIDE_CACHE_CAPACITY: usize = 10;
|
||||||
|
|
||||||
impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
||||||
fn from(p: ethjson::spec::AuthorityRoundParams) -> Self {
|
fn from(p: ethjson::spec::AuthorityRoundParams) -> Self {
|
||||||
let map_step_duration = |u: ethjson::uint::Uint| {
|
let map_step_duration = |u: ethjson::uint::Uint| {
|
||||||
@ -180,6 +187,12 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
|||||||
(block.as_u64(), addr.into())
|
(block.as_u64(), addr.into())
|
||||||
}).collect()
|
}).collect()
|
||||||
});
|
});
|
||||||
|
let block_gas_limit_contract_transitions: BTreeMap<_, _> =
|
||||||
|
p.block_gas_limit_contract_transitions
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_iter()
|
||||||
|
.map(|(block_num, address)| (block_num.into(), address.into()))
|
||||||
|
.collect();
|
||||||
AuthorityRoundParams {
|
AuthorityRoundParams {
|
||||||
step_durations,
|
step_durations,
|
||||||
validators: new_validator_set(p.validators),
|
validators: new_validator_set(p.validators),
|
||||||
@ -196,6 +209,7 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
|||||||
two_thirds_majority_transition: p.two_thirds_majority_transition.map_or_else(BlockNumber::max_value, Into::into),
|
two_thirds_majority_transition: p.two_thirds_majority_transition.map_or_else(BlockNumber::max_value, Into::into),
|
||||||
strict_empty_steps_transition: p.strict_empty_steps_transition.map_or(0, Into::into),
|
strict_empty_steps_transition: p.strict_empty_steps_transition.map_or(0, Into::into),
|
||||||
randomness_contract_address,
|
randomness_contract_address,
|
||||||
|
block_gas_limit_contract_transitions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -565,6 +579,10 @@ pub struct AuthorityRound {
|
|||||||
received_step_hashes: RwLock<BTreeMap<(u64, Address), H256>>,
|
received_step_hashes: RwLock<BTreeMap<(u64, Address), H256>>,
|
||||||
/// If set, enables random number contract integration. It maps the transition block to the contract address.
|
/// If set, enables random number contract integration. It maps the transition block to the contract address.
|
||||||
randomness_contract_address: BTreeMap<u64, Address>,
|
randomness_contract_address: BTreeMap<u64, Address>,
|
||||||
|
/// The addresses of contracts that determine the block gas limit.
|
||||||
|
block_gas_limit_contract_transitions: BTreeMap<u64, Address>,
|
||||||
|
/// Memoized gas limit overrides, by block hash.
|
||||||
|
gas_limit_override_cache: Mutex<LruCache<H256, Option<U256>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// header-chain validator.
|
// header-chain validator.
|
||||||
@ -867,6 +885,8 @@ impl AuthorityRound {
|
|||||||
machine,
|
machine,
|
||||||
received_step_hashes: RwLock::new(Default::default()),
|
received_step_hashes: RwLock::new(Default::default()),
|
||||||
randomness_contract_address: our_params.randomness_contract_address,
|
randomness_contract_address: our_params.randomness_contract_address,
|
||||||
|
block_gas_limit_contract_transitions: our_params.block_gas_limit_contract_transitions,
|
||||||
|
gas_limit_override_cache: Mutex::new(LruCache::new(GAS_LIMIT_OVERRIDE_CACHE_CAPACITY)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Do not initialize timeouts for tests.
|
// Do not initialize timeouts for tests.
|
||||||
@ -1218,6 +1238,14 @@ impl Engine for AuthorityRound {
|
|||||||
|
|
||||||
let score = calculate_score(parent_step, current_step, current_empty_steps_len);
|
let score = calculate_score(parent_step, current_step, current_empty_steps_len);
|
||||||
header.set_difficulty(score);
|
header.set_difficulty(score);
|
||||||
|
if let Some(gas_limit) = self.gas_limit_override(header) {
|
||||||
|
trace!(target: "engine", "Setting gas limit to {} for block {}.", gas_limit, header.number());
|
||||||
|
let parent_gas_limit = *parent.gas_limit();
|
||||||
|
header.set_gas_limit(gas_limit);
|
||||||
|
if parent_gas_limit != gas_limit {
|
||||||
|
info!(target: "engine", "Block gas limit was changed from {} to {}.", parent_gas_limit, gas_limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sealing_state(&self) -> SealingState {
|
fn sealing_state(&self) -> SealingState {
|
||||||
@ -1834,6 +1862,30 @@ impl Engine for AuthorityRound {
|
|||||||
fn params(&self) -> &CommonParams {
|
fn params(&self) -> &CommonParams {
|
||||||
self.machine.params()
|
self.machine.params()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gas_limit_override(&self, header: &Header) -> Option<U256> {
|
||||||
|
let (_, &address) = self.block_gas_limit_contract_transitions.range(..=header.number()).last()?;
|
||||||
|
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
|
||||||
|
Some(client) => client,
|
||||||
|
None => {
|
||||||
|
error!(target: "engine", "Unable to prepare block: missing client ref.");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let full_client = match client.as_full_client() {
|
||||||
|
Some(full_client) => full_client,
|
||||||
|
None => {
|
||||||
|
error!(target: "engine", "Failed to upgrade to BlockchainClient.");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(limit) = self.gas_limit_override_cache.lock().get_mut(&header.hash()) {
|
||||||
|
return *limit;
|
||||||
|
}
|
||||||
|
let limit = block_gas_limit(full_client, header, address);
|
||||||
|
self.gas_limit_override_cache.lock().insert(header.hash(), limit);
|
||||||
|
limit
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A helper accumulator function mapping a step duration and a step duration transition timestamp
|
/// A helper accumulator function mapping a step duration and a step duration transition timestamp
|
||||||
@ -1910,6 +1962,7 @@ mod tests {
|
|||||||
strict_empty_steps_transition: 0,
|
strict_empty_steps_transition: 0,
|
||||||
two_thirds_majority_transition: 0,
|
two_thirds_majority_transition: 0,
|
||||||
randomness_contract_address: BTreeMap::new(),
|
randomness_contract_address: BTreeMap::new(),
|
||||||
|
block_gas_limit_contract_transitions: BTreeMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// mutate aura params
|
// mutate aura params
|
||||||
|
@ -61,6 +61,14 @@ pub fn verify_block_basic(block: &Unverified, engine: &dyn Engine, check_seal: b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(gas_limit) = engine.gas_limit_override(&block.header) {
|
||||||
|
if *block.header.gas_limit() != gas_limit {
|
||||||
|
return Err(From::from(BlockError::InvalidGasLimit(
|
||||||
|
OutOfBounds { min: Some(gas_limit), max: Some(gas_limit), found: *block.header.gas_limit() }
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for t in &block.transactions {
|
for t in &block.transactions {
|
||||||
engine.verify_transaction_basic(t, &block.header)?;
|
engine.verify_transaction_basic(t, &block.header)?;
|
||||||
}
|
}
|
||||||
@ -284,7 +292,8 @@ pub(crate) fn verify_header_params(header: &Header, engine: &dyn Engine, check_s
|
|||||||
found: *header.gas_used()
|
found: *header.gas_used()
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
let min_gas_limit = engine.params().min_gas_limit;
|
if engine.gas_limit_override(header).is_none() {
|
||||||
|
let min_gas_limit = engine.min_gas_limit();
|
||||||
if header.gas_limit() < &min_gas_limit {
|
if header.gas_limit() < &min_gas_limit {
|
||||||
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds {
|
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds {
|
||||||
min: Some(min_gas_limit),
|
min: Some(min_gas_limit),
|
||||||
@ -301,6 +310,7 @@ pub(crate) fn verify_header_params(header: &Header, engine: &dyn Engine, check_s
|
|||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
let maximum_extra_data_size = engine.maximum_extra_data_size();
|
let maximum_extra_data_size = engine.maximum_extra_data_size();
|
||||||
if header.number() != 0 && header.extra_data().len() > maximum_extra_data_size {
|
if header.number() != 0 && header.extra_data().len() > maximum_extra_data_size {
|
||||||
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds {
|
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds {
|
||||||
@ -358,8 +368,6 @@ fn verify_parent(header: &Header, parent: &Header, engine: &dyn Engine) -> Resul
|
|||||||
assert!(header.parent_hash().is_zero() || &parent.hash() == header.parent_hash(),
|
assert!(header.parent_hash().is_zero() || &parent.hash() == header.parent_hash(),
|
||||||
"Parent hash should already have been verified; qed");
|
"Parent hash should already have been verified; qed");
|
||||||
|
|
||||||
let gas_limit_divisor = engine.params().gas_limit_bound_divisor;
|
|
||||||
|
|
||||||
if !engine.is_timestamp_valid(header.timestamp(), parent.timestamp()) {
|
if !engine.is_timestamp_valid(header.timestamp(), parent.timestamp()) {
|
||||||
let now = SystemTime::now();
|
let now = SystemTime::now();
|
||||||
let min = CheckedSystemTime::checked_add(now, Duration::from_secs(parent.timestamp().saturating_add(1)))
|
let min = CheckedSystemTime::checked_add(now, Duration::from_secs(parent.timestamp().saturating_add(1)))
|
||||||
@ -382,7 +390,8 @@ fn verify_parent(header: &Header, parent: &Header, engine: &dyn Engine) -> Resul
|
|||||||
found: header.number()
|
found: header.number()
|
||||||
}).into());
|
}).into());
|
||||||
}
|
}
|
||||||
|
if engine.gas_limit_override(header).is_none() {
|
||||||
|
let gas_limit_divisor = engine.params().gas_limit_bound_divisor;
|
||||||
let parent_gas_limit = *parent.gas_limit();
|
let parent_gas_limit = *parent.gas_limit();
|
||||||
let min_gas = parent_gas_limit - parent_gas_limit / gas_limit_divisor;
|
let min_gas = parent_gas_limit - parent_gas_limit / gas_limit_divisor;
|
||||||
let max_gas = parent_gas_limit + parent_gas_limit / gas_limit_divisor;
|
let max_gas = parent_gas_limit + parent_gas_limit / gas_limit_divisor;
|
||||||
@ -393,6 +402,7 @@ fn verify_parent(header: &Header, parent: &Header, engine: &dyn Engine) -> Resul
|
|||||||
found: *header.gas_limit()
|
found: *header.gas_limit()
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -522,7 +532,7 @@ mod tests {
|
|||||||
// that's an invalid transaction list rlp
|
// that's an invalid transaction list rlp
|
||||||
let invalid_transactions = vec![vec![0u8]];
|
let invalid_transactions = vec![vec![0u8]];
|
||||||
header.set_transactions_root(ordered_trie_root(&invalid_transactions));
|
header.set_transactions_root(ordered_trie_root(&invalid_transactions));
|
||||||
header.set_gas_limit(engine.params().min_gas_limit);
|
header.set_gas_limit(engine.min_gas_limit());
|
||||||
rlp.append(&header);
|
rlp.append(&header);
|
||||||
rlp.append_list::<Vec<u8>, _>(&invalid_transactions);
|
rlp.append_list::<Vec<u8>, _>(&invalid_transactions);
|
||||||
rlp.append_raw(&rlp::EMPTY_LIST_RLP, 1);
|
rlp.append_raw(&rlp::EMPTY_LIST_RLP, 1);
|
||||||
@ -541,7 +551,7 @@ mod tests {
|
|||||||
let spec = spec::new_test();
|
let spec = spec::new_test();
|
||||||
let engine = &*spec.engine;
|
let engine = &*spec.engine;
|
||||||
|
|
||||||
let min_gas_limit = engine.params().min_gas_limit;
|
let min_gas_limit = engine.min_gas_limit();
|
||||||
good.set_gas_limit(min_gas_limit);
|
good.set_gas_limit(min_gas_limit);
|
||||||
good.set_timestamp(40);
|
good.set_timestamp(40);
|
||||||
good.set_number(10);
|
good.set_number(10);
|
||||||
|
@ -97,23 +97,29 @@ pub struct AuthorityRoundParams {
|
|||||||
pub two_thirds_majority_transition: Option<Uint>,
|
pub two_thirds_majority_transition: Option<Uint>,
|
||||||
/// The random number contract's address, or a map of contract transitions.
|
/// The random number contract's address, or a map of contract transitions.
|
||||||
pub randomness_contract_address: Option<BTreeMap<Uint, Address>>,
|
pub randomness_contract_address: Option<BTreeMap<Uint, Address>>,
|
||||||
|
/// The addresses of contracts that determine the block gas limit starting from the block number
|
||||||
|
/// associated with each of those contracts.
|
||||||
|
pub block_gas_limit_contract_transitions: Option<BTreeMap<Uint, Address>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authority engine deserialization.
|
/// Authority engine deserialization.
|
||||||
#[derive(Debug, PartialEq, Deserialize)]
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct AuthorityRound {
|
pub struct AuthorityRound {
|
||||||
/// Ethash params.
|
/// Authority Round parameters.
|
||||||
pub params: AuthorityRoundParams,
|
pub params: AuthorityRoundParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Address, Uint, StepDuration};
|
|
||||||
use ethereum_types::{U256, H160};
|
|
||||||
use crate::spec::{validator_set::ValidatorSet, authority_round::AuthorityRound};
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use ethereum_types::{U256, H160};
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
|
use super::{Address, Uint, StepDuration};
|
||||||
|
use crate::{spec::{validator_set::ValidatorSet, authority_round::AuthorityRound}};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn authority_round_deserialization() {
|
fn authority_round_deserialization() {
|
||||||
let s = r#"{
|
let s = r#"{
|
||||||
@ -130,6 +136,10 @@ mod tests {
|
|||||||
"randomnessContractAddress": {
|
"randomnessContractAddress": {
|
||||||
"10": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
"10": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||||
"20": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
"20": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
||||||
|
},
|
||||||
|
"blockGasLimitContractTransitions": {
|
||||||
|
"10": "0x1000000000000000000000000000000000000001",
|
||||||
|
"20": "0x2000000000000000000000000000000000000002"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}"#;
|
}"#;
|
||||||
@ -149,5 +159,10 @@ mod tests {
|
|||||||
(Uint(10.into()), Address(H160::from_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap())),
|
(Uint(10.into()), Address(H160::from_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap())),
|
||||||
(Uint(20.into()), Address(H160::from_str("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb").unwrap())),
|
(Uint(20.into()), Address(H160::from_str("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb").unwrap())),
|
||||||
].into_iter().collect());
|
].into_iter().collect());
|
||||||
|
let expected_bglc =
|
||||||
|
[(Uint(10.into()), Address(H160::from_str("1000000000000000000000000000000000000001").unwrap())),
|
||||||
|
(Uint(20.into()), Address(H160::from_str("2000000000000000000000000000000000000002").unwrap()))];
|
||||||
|
assert_eq!(deserialized.params.block_gas_limit_contract_transitions,
|
||||||
|
Some(expected_bglc.to_vec().into_iter().collect()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user