Maximum uncle count transition (#7196)
* Enable delayed maximum_uncle_count activation. * Fix tests. * Defer kovan HF.
This commit is contained in:
parent
d60fe51553
commit
fdaedc8c00
@ -24,6 +24,7 @@
|
|||||||
},
|
},
|
||||||
"validateScoreTransition": 1000000,
|
"validateScoreTransition": 1000000,
|
||||||
"validateStepTransition": 1500000,
|
"validateStepTransition": 1500000,
|
||||||
|
"maximumUncleCountTransition": 10000000,
|
||||||
"maximumUncleCount": 2
|
"maximumUncleCount": 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,8 +380,13 @@ impl<'x> OpenBlock<'x> {
|
|||||||
/// NOTE Will check chain constraints and the uncle number but will NOT check
|
/// NOTE Will check chain constraints and the uncle number but will NOT check
|
||||||
/// that the header itself is actually valid.
|
/// that the header itself is actually valid.
|
||||||
pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> {
|
pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> {
|
||||||
if self.block.uncles.len() + 1 > self.engine.maximum_uncle_count() {
|
let max_uncles = self.engine.maximum_uncle_count(self.block.header().number());
|
||||||
return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.uncles.len() + 1}));
|
if self.block.uncles.len() + 1 > max_uncles {
|
||||||
|
return Err(BlockError::TooManyUncles(OutOfBounds{
|
||||||
|
min: None,
|
||||||
|
max: Some(max_uncles),
|
||||||
|
found: self.block.uncles.len() + 1,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
// TODO: check number
|
// TODO: check number
|
||||||
// TODO: check not a direct ancestor (use last_hashes for that)
|
// TODO: check not a direct ancestor (use last_hashes for that)
|
||||||
|
@ -1869,7 +1869,7 @@ impl MiningBlockChainClient for Client {
|
|||||||
.find_uncle_headers(&h, engine.maximum_uncle_age())
|
.find_uncle_headers(&h, engine.maximum_uncle_age())
|
||||||
.unwrap_or_else(Vec::new)
|
.unwrap_or_else(Vec::new)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.take(engine.maximum_uncle_count())
|
.take(engine.maximum_uncle_count(open_block.header().number()))
|
||||||
.foreach(|h| {
|
.foreach(|h| {
|
||||||
open_block.push_uncle(h).expect("pushing maximum_uncle_count;
|
open_block.push_uncle(h).expect("pushing maximum_uncle_count;
|
||||||
open_block was just created;
|
open_block was just created;
|
||||||
@ -1884,7 +1884,7 @@ impl MiningBlockChainClient for Client {
|
|||||||
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
|
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
|
||||||
let engine = &*self.engine;
|
let engine = &*self.engine;
|
||||||
let mut block = block.reopen(engine);
|
let mut block = block.reopen(engine);
|
||||||
let max_uncles = engine.maximum_uncle_count();
|
let max_uncles = engine.maximum_uncle_count(block.header().number());
|
||||||
if block.uncles().len() < max_uncles {
|
if block.uncles().len() < max_uncles {
|
||||||
let chain = self.chain.read();
|
let chain = self.chain.read();
|
||||||
let h = chain.best_block_hash();
|
let h = chain.best_block_hash();
|
||||||
|
@ -65,6 +65,8 @@ pub struct AuthorityRoundParams {
|
|||||||
pub immediate_transitions: bool,
|
pub immediate_transitions: bool,
|
||||||
/// Block reward in base units.
|
/// Block reward in base units.
|
||||||
pub block_reward: U256,
|
pub block_reward: U256,
|
||||||
|
/// Number of accepted uncles transition block.
|
||||||
|
pub maximum_uncle_count_transition: u64,
|
||||||
/// Number of accepted uncles.
|
/// Number of accepted uncles.
|
||||||
pub maximum_uncle_count: usize,
|
pub maximum_uncle_count: usize,
|
||||||
}
|
}
|
||||||
@ -79,6 +81,7 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
|||||||
validate_step_transition: p.validate_step_transition.map_or(0, Into::into),
|
validate_step_transition: p.validate_step_transition.map_or(0, Into::into),
|
||||||
immediate_transitions: p.immediate_transitions.unwrap_or(false),
|
immediate_transitions: p.immediate_transitions.unwrap_or(false),
|
||||||
block_reward: p.block_reward.map_or_else(Default::default, Into::into),
|
block_reward: p.block_reward.map_or_else(Default::default, Into::into),
|
||||||
|
maximum_uncle_count_transition: p.maximum_uncle_count_transition.map_or(0, Into::into),
|
||||||
maximum_uncle_count: p.maximum_uncle_count.map_or(0, Into::into),
|
maximum_uncle_count: p.maximum_uncle_count.map_or(0, Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,6 +224,7 @@ pub struct AuthorityRound {
|
|||||||
epoch_manager: Mutex<EpochManager>,
|
epoch_manager: Mutex<EpochManager>,
|
||||||
immediate_transitions: bool,
|
immediate_transitions: bool,
|
||||||
block_reward: U256,
|
block_reward: U256,
|
||||||
|
maximum_uncle_count_transition: u64,
|
||||||
maximum_uncle_count: usize,
|
maximum_uncle_count: usize,
|
||||||
machine: EthereumMachine,
|
machine: EthereumMachine,
|
||||||
}
|
}
|
||||||
@ -369,6 +373,7 @@ impl AuthorityRound {
|
|||||||
epoch_manager: Mutex::new(EpochManager::blank()),
|
epoch_manager: Mutex::new(EpochManager::blank()),
|
||||||
immediate_transitions: our_params.immediate_transitions,
|
immediate_transitions: our_params.immediate_transitions,
|
||||||
block_reward: our_params.block_reward,
|
block_reward: our_params.block_reward,
|
||||||
|
maximum_uncle_count_transition: our_params.maximum_uncle_count_transition,
|
||||||
maximum_uncle_count: our_params.maximum_uncle_count,
|
maximum_uncle_count: our_params.maximum_uncle_count,
|
||||||
machine: machine,
|
machine: machine,
|
||||||
});
|
});
|
||||||
@ -441,7 +446,14 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maximum_uncle_count(&self) -> usize { self.maximum_uncle_count }
|
fn maximum_uncle_count(&self, block: BlockNumber) -> usize {
|
||||||
|
if block >= self.maximum_uncle_count_transition {
|
||||||
|
self.maximum_uncle_count
|
||||||
|
} else {
|
||||||
|
// fallback to default value
|
||||||
|
2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
|
fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
|
||||||
// Chain scoring: total weight is sqrt(U256::max_value())*height - step
|
// Chain scoring: total weight is sqrt(U256::max_value())*height - step
|
||||||
@ -956,6 +968,7 @@ mod tests {
|
|||||||
validate_score_transition: 0,
|
validate_score_transition: 0,
|
||||||
validate_step_transition: 0,
|
validate_step_transition: 0,
|
||||||
immediate_transitions: true,
|
immediate_transitions: true,
|
||||||
|
maximum_uncle_count_transition: 0,
|
||||||
maximum_uncle_count: 0,
|
maximum_uncle_count: 0,
|
||||||
block_reward: Default::default(),
|
block_reward: Default::default(),
|
||||||
};
|
};
|
||||||
@ -984,4 +997,31 @@ mod tests {
|
|||||||
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
|
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
|
||||||
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 1);
|
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uncles_transition() {
|
||||||
|
let last_benign = Arc::new(AtomicUsize::new(0));
|
||||||
|
let params = AuthorityRoundParams {
|
||||||
|
step_duration: Default::default(),
|
||||||
|
start_step: Some(1),
|
||||||
|
validators: Box::new(TestSet::new(Default::default(), last_benign.clone())),
|
||||||
|
validate_score_transition: 0,
|
||||||
|
validate_step_transition: 0,
|
||||||
|
immediate_transitions: true,
|
||||||
|
maximum_uncle_count_transition: 1,
|
||||||
|
maximum_uncle_count: 0,
|
||||||
|
block_reward: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let aura = {
|
||||||
|
let mut c_params = ::spec::CommonParams::default();
|
||||||
|
c_params.gas_limit_bound_divisor = 5.into();
|
||||||
|
let machine = ::machine::EthereumMachine::regular(c_params, Default::default());
|
||||||
|
AuthorityRound::new(params, machine).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(aura.maximum_uncle_count(0), 2);
|
||||||
|
assert_eq!(aura.maximum_uncle_count(1), 0);
|
||||||
|
assert_eq!(aura.maximum_uncle_count(100), 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,8 @@ pub trait Engine<M: Machine>: Sync + Send {
|
|||||||
fn extra_info(&self, _header: &M::Header) -> BTreeMap<String, String> { BTreeMap::new() }
|
fn extra_info(&self, _header: &M::Header) -> BTreeMap<String, String> { BTreeMap::new() }
|
||||||
|
|
||||||
/// Maximum number of uncles a block is allowed to declare.
|
/// Maximum number of uncles a block is allowed to declare.
|
||||||
fn maximum_uncle_count(&self) -> usize { 0 }
|
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 0 }
|
||||||
|
|
||||||
/// The number of generations back that uncles can be.
|
/// The number of generations back that uncles can be.
|
||||||
fn maximum_uncle_age(&self) -> usize { 6 }
|
fn maximum_uncle_age(&self) -> usize { 6 }
|
||||||
|
|
||||||
@ -363,7 +364,7 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The nonce with which accounts begin at given block.
|
/// The nonce with which accounts begin at given block.
|
||||||
fn account_start_nonce(&self, block: u64) -> U256 {
|
fn account_start_nonce(&self, block: BlockNumber) -> U256 {
|
||||||
self.machine().account_start_nonce(block)
|
self.machine().account_start_nonce(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
use bigint::prelude::U256;
|
use bigint::prelude::U256;
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
|
use header::BlockNumber;
|
||||||
use parity_machine::{Header, LiveBlock, WithBalances};
|
use parity_machine::{Header, LiveBlock, WithBalances};
|
||||||
|
|
||||||
/// Params for a null engine.
|
/// Params for a null engine.
|
||||||
@ -95,7 +96,7 @@ impl<M: WithBalances> Engine<M> for NullEngine<M> {
|
|||||||
self.machine.note_rewards(block, &[(author, result_block_reward)], &uncle_rewards)
|
self.machine.note_rewards(block, &[(author, result_block_reward)], &uncle_rewards)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maximum_uncle_count(&self) -> usize { 2 }
|
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 }
|
||||||
|
|
||||||
fn verify_local_seal(&self, _header: &M::Header) -> Result<(), M::Error> {
|
fn verify_local_seal(&self, _header: &M::Header) -> Result<(), M::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -450,7 +450,7 @@ impl Engine<EthereumMachine> for Tendermint {
|
|||||||
|
|
||||||
fn machine(&self) -> &EthereumMachine { &self.machine }
|
fn machine(&self) -> &EthereumMachine { &self.machine }
|
||||||
|
|
||||||
fn maximum_uncle_count(&self) -> usize { 0 }
|
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 0 }
|
||||||
|
|
||||||
fn maximum_uncle_age(&self) -> usize { 0 }
|
fn maximum_uncle_age(&self) -> usize { 0 }
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ use util::Address;
|
|||||||
use unexpected::{OutOfBounds, Mismatch};
|
use unexpected::{OutOfBounds, Mismatch};
|
||||||
use block::*;
|
use block::*;
|
||||||
use error::{BlockError, Error};
|
use error::{BlockError, Error};
|
||||||
use header::Header;
|
use header::{Header, BlockNumber};
|
||||||
use engines::{self, Engine};
|
use engines::{self, Engine};
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use rlp::{self, UntrustedRlp};
|
use rlp::{self, UntrustedRlp};
|
||||||
@ -181,7 +181,7 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maximum_uncle_count(&self) -> usize { 2 }
|
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 }
|
||||||
|
|
||||||
fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
|
fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
|
||||||
let difficulty = self.calculate_difficulty(header, parent);
|
let difficulty = self.calculate_difficulty(header, parent);
|
||||||
@ -520,7 +520,7 @@ mod tests {
|
|||||||
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number);
|
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number);
|
||||||
assert_eq!(15, eras);
|
assert_eq!(15, eras);
|
||||||
assert_eq!(U256::from_str("271000000000000").unwrap(), reward);
|
assert_eq!(U256::from_str("271000000000000").unwrap(), reward);
|
||||||
|
|
||||||
let block_number = 250000000;
|
let block_number = 250000000;
|
||||||
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number);
|
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number);
|
||||||
assert_eq!(49, eras);
|
assert_eq!(49, eras);
|
||||||
|
@ -137,9 +137,14 @@ pub fn verify_block_family(header: &Header, parent: &Header, engine: &EthEngine,
|
|||||||
|
|
||||||
fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &EthEngine) -> Result<(), Error> {
|
fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &EthEngine) -> Result<(), Error> {
|
||||||
let num_uncles = UntrustedRlp::new(bytes).at(2)?.item_count()?;
|
let num_uncles = UntrustedRlp::new(bytes).at(2)?.item_count()?;
|
||||||
|
let max_uncles = engine.maximum_uncle_count(header.number());
|
||||||
if num_uncles != 0 {
|
if num_uncles != 0 {
|
||||||
if num_uncles > engine.maximum_uncle_count() {
|
if num_uncles > max_uncles {
|
||||||
return Err(From::from(BlockError::TooManyUncles(OutOfBounds { min: None, max: Some(engine.maximum_uncle_count()), found: num_uncles })));
|
return Err(From::from(BlockError::TooManyUncles(OutOfBounds {
|
||||||
|
min: None,
|
||||||
|
max: Some(max_uncles),
|
||||||
|
found: num_uncles,
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut excluded = HashSet::new();
|
let mut excluded = HashSet::new();
|
||||||
@ -653,7 +658,7 @@ mod tests {
|
|||||||
let mut bad_uncles = good_uncles.clone();
|
let mut bad_uncles = good_uncles.clone();
|
||||||
bad_uncles.push(good_uncle1.clone());
|
bad_uncles.push(good_uncle1.clone());
|
||||||
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
|
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
|
||||||
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count()), min: None, found: bad_uncles.len() }));
|
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count(header.number())), min: None, found: bad_uncles.len() }));
|
||||||
|
|
||||||
header = good.clone();
|
header = good.clone();
|
||||||
bad_uncles = vec![ good_uncle1.clone(), good_uncle1.clone() ];
|
bad_uncles = vec![ good_uncle1.clone(), good_uncle1.clone() ];
|
||||||
|
@ -43,6 +43,10 @@ pub struct AuthorityRoundParams {
|
|||||||
/// Reward per block in wei.
|
/// Reward per block in wei.
|
||||||
#[serde(rename="blockReward")]
|
#[serde(rename="blockReward")]
|
||||||
pub block_reward: Option<Uint>,
|
pub block_reward: Option<Uint>,
|
||||||
|
/// Block at which maximum uncle count should be considered.
|
||||||
|
#[serde(rename="maximumUncleCountTransition")]
|
||||||
|
pub maximum_uncle_count_transition: Option<Uint>,
|
||||||
|
/// Maximum number of accepted uncles.
|
||||||
#[serde(rename="maximumUncleCount")]
|
#[serde(rename="maximumUncleCount")]
|
||||||
pub maximum_uncle_count: Option<Uint>,
|
pub maximum_uncle_count: Option<Uint>,
|
||||||
}
|
}
|
||||||
@ -73,7 +77,9 @@ mod tests {
|
|||||||
},
|
},
|
||||||
"startStep" : 24,
|
"startStep" : 24,
|
||||||
"validateStepTransition": 150,
|
"validateStepTransition": 150,
|
||||||
"blockReward": 5000000
|
"blockReward": 5000000,
|
||||||
|
"maximumUncleCountTransition": 10000000,
|
||||||
|
"maximumUncleCount": 5
|
||||||
}
|
}
|
||||||
}"#;
|
}"#;
|
||||||
|
|
||||||
@ -82,6 +88,8 @@ mod tests {
|
|||||||
assert_eq!(deserialized.params.validators, ValidatorSet::List(vec![Address(H160::from("0xc6d9d2cd449a754c494264e1809c50e34d64562b"))]));
|
assert_eq!(deserialized.params.validators, ValidatorSet::List(vec![Address(H160::from("0xc6d9d2cd449a754c494264e1809c50e34d64562b"))]));
|
||||||
assert_eq!(deserialized.params.start_step, Some(Uint(U256::from(24))));
|
assert_eq!(deserialized.params.start_step, Some(Uint(U256::from(24))));
|
||||||
assert_eq!(deserialized.params.immediate_transitions, None);
|
assert_eq!(deserialized.params.immediate_transitions, None);
|
||||||
|
assert_eq!(deserialized.params.maximum_uncle_count_transition, Some(Uint(10_000_000.into())));
|
||||||
|
assert_eq!(deserialized.params.maximum_uncle_count, Some(Uint(5.into())));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user