Strict validation transitions (#4988)
* ability to make validation stricter * fix consensus * remove logger
This commit is contained in:
parent
7039eaf995
commit
a61b1567d0
@ -23,7 +23,8 @@
|
|||||||
|
|
||||||
"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de"
|
"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"validateScoreTransition": 1000000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -31,7 +32,7 @@
|
|||||||
"maximumExtraDataSize": "0x20",
|
"maximumExtraDataSize": "0x20",
|
||||||
"minGasLimit": "0x1388",
|
"minGasLimit": "0x1388",
|
||||||
"networkID" : "0x2A",
|
"networkID" : "0x2A",
|
||||||
"validateReceipts" : false
|
"validateReceiptsTransition" : 1000000
|
||||||
},
|
},
|
||||||
"genesis": {
|
"genesis": {
|
||||||
"seal": {
|
"seal": {
|
||||||
|
@ -393,7 +393,7 @@ impl Client {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Final Verification
|
// Final Verification
|
||||||
if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header(), self.engine().params().validate_receipts) {
|
if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header(), self.engine().params().validate_receipts_transition) {
|
||||||
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,8 @@ pub struct AuthorityRoundParams {
|
|||||||
pub start_step: Option<u64>,
|
pub start_step: Option<u64>,
|
||||||
/// Valid validators.
|
/// Valid validators.
|
||||||
pub validators: ethjson::spec::ValidatorSet,
|
pub validators: ethjson::spec::ValidatorSet,
|
||||||
|
/// Chain score validation transition block.
|
||||||
|
pub validate_score_transition: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
||||||
@ -64,6 +66,7 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
|||||||
block_reward: p.block_reward.map_or_else(U256::zero, Into::into),
|
block_reward: p.block_reward.map_or_else(U256::zero, Into::into),
|
||||||
registrar: p.registrar.map_or_else(Address::new, Into::into),
|
registrar: p.registrar.map_or_else(Address::new, Into::into),
|
||||||
start_step: p.start_step.map(Into::into),
|
start_step: p.start_step.map(Into::into),
|
||||||
|
validate_score_transition: p.validate_score_transition.map_or(0, Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,6 +88,7 @@ pub struct AuthorityRound {
|
|||||||
validators: Box<ValidatorSet>,
|
validators: Box<ValidatorSet>,
|
||||||
/// Is this Engine just for testing (prevents step calibration).
|
/// Is this Engine just for testing (prevents step calibration).
|
||||||
calibrate_step: bool,
|
calibrate_step: bool,
|
||||||
|
validate_score_transition: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_step(header: &Header) -> Result<usize, ::rlp::DecoderError> {
|
fn header_step(header: &Header) -> Result<usize, ::rlp::DecoderError> {
|
||||||
@ -125,6 +129,7 @@ impl AuthorityRound {
|
|||||||
signer: Default::default(),
|
signer: Default::default(),
|
||||||
validators: new_validator_set(our_params.validators),
|
validators: new_validator_set(our_params.validators),
|
||||||
calibrate_step: our_params.start_step.is_none(),
|
calibrate_step: our_params.start_step.is_none(),
|
||||||
|
validate_score_transition: our_params.validate_score_transition,
|
||||||
});
|
});
|
||||||
// Do not initialize timeouts for tests.
|
// Do not initialize timeouts for tests.
|
||||||
if should_timeout {
|
if should_timeout {
|
||||||
@ -295,13 +300,17 @@ impl Engine for AuthorityRound {
|
|||||||
Err(From::from(BlockError::InvalidSealArity(
|
Err(From::from(BlockError::InvalidSealArity(
|
||||||
Mismatch { expected: self.seal_fields(), found: header.seal().len() }
|
Mismatch { expected: self.seal_fields(), found: header.seal().len() }
|
||||||
)))
|
)))
|
||||||
|
} else if header.number() >= self.validate_score_transition && *header.difficulty() >= U256::from(U128::max_value()) {
|
||||||
|
Err(From::from(BlockError::DifficultyOutOfBounds(
|
||||||
|
OutOfBounds { min: None, max: Some(U256::from(U128::max_value())), found: *header.difficulty() }
|
||||||
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Do the validator and gas limit validation.
|
/// Do the validator and gas limit validation.
|
||||||
@ -327,7 +336,8 @@ impl Engine for AuthorityRound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if parent is from a previous step.
|
// Check if parent is from a previous step.
|
||||||
if step == header_step(parent)? {
|
let parent_step = header_step(parent)?;
|
||||||
|
if step == parent_step {
|
||||||
trace!(target: "engine", "Multiple blocks proposed for step {}.", step);
|
trace!(target: "engine", "Multiple blocks proposed for step {}.", step);
|
||||||
self.validators.report_malicious(header.author());
|
self.validators.report_malicious(header.author());
|
||||||
Err(EngineError::DoubleVote(header.author().clone()))?;
|
Err(EngineError::DoubleVote(header.author().clone()))?;
|
||||||
|
@ -56,7 +56,7 @@ pub struct CommonParams {
|
|||||||
/// Number of first block where EIP-98 rules begin.
|
/// Number of first block where EIP-98 rules begin.
|
||||||
pub eip98_transition: BlockNumber,
|
pub eip98_transition: BlockNumber,
|
||||||
/// Validate block receipts root.
|
/// Validate block receipts root.
|
||||||
pub validate_receipts: bool,
|
pub validate_receipts_transition: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethjson::spec::Params> for CommonParams {
|
impl From<ethjson::spec::Params> for CommonParams {
|
||||||
@ -70,7 +70,7 @@ impl From<ethjson::spec::Params> for CommonParams {
|
|||||||
min_gas_limit: p.min_gas_limit.into(),
|
min_gas_limit: p.min_gas_limit.into(),
|
||||||
fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None },
|
fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None },
|
||||||
eip98_transition: p.eip98_transition.map_or(0, Into::into),
|
eip98_transition: p.eip98_transition.map_or(0, Into::into),
|
||||||
validate_receipts: p.validate_receipts.unwrap_or(true),
|
validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ impl Verifier for CanonVerifier {
|
|||||||
verification::verify_block_family(header, bytes, engine, bc)
|
verification::verify_block_family(header, bytes, engine, bc)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_final(&self, expected: &Header, got: &Header, receipts: bool) -> Result<(), Error> {
|
fn verify_block_final(&self, expected: &Header, got: &Header, receipts: u64) -> Result<(), Error> {
|
||||||
verification::verify_block_final(expected, got, receipts)
|
verification::verify_block_final(expected, got, receipts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ impl Verifier for NoopVerifier {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_final(&self, _expected: &Header, _got: &Header, _receipts: bool) -> Result<(), Error> {
|
fn verify_block_final(&self, _expected: &Header, _got: &Header, _receipts: u64) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 4 verification. Check block information against transaction enactment results,
|
/// Phase 4 verification. Check block information against transaction enactment results,
|
||||||
pub fn verify_block_final(expected: &Header, got: &Header, check_receipts: bool) -> Result<(), Error> {
|
pub fn verify_block_final(expected: &Header, got: &Header, check_receipts: u64) -> Result<(), Error> {
|
||||||
if expected.gas_used() != got.gas_used() {
|
if expected.gas_used() != got.gas_used() {
|
||||||
return Err(From::from(BlockError::InvalidGasUsed(Mismatch { expected: expected.gas_used().clone(), found: got.gas_used().clone() })))
|
return Err(From::from(BlockError::InvalidGasUsed(Mismatch { expected: expected.gas_used().clone(), found: got.gas_used().clone() })))
|
||||||
}
|
}
|
||||||
@ -188,7 +188,7 @@ pub fn verify_block_final(expected: &Header, got: &Header, check_receipts: bool)
|
|||||||
if expected.state_root() != got.state_root() {
|
if expected.state_root() != got.state_root() {
|
||||||
return Err(From::from(BlockError::InvalidStateRoot(Mismatch { expected: expected.state_root().clone(), found: got.state_root().clone() })))
|
return Err(From::from(BlockError::InvalidStateRoot(Mismatch { expected: expected.state_root().clone(), found: got.state_root().clone() })))
|
||||||
}
|
}
|
||||||
if check_receipts && expected.receipts_root() != got.receipts_root() {
|
if got.number() >= check_receipts && expected.receipts_root() != got.receipts_root() {
|
||||||
return Err(From::from(BlockError::InvalidReceiptsRoot(Mismatch { expected: expected.receipts_root().clone(), found: got.receipts_root().clone() })))
|
return Err(From::from(BlockError::InvalidReceiptsRoot(Mismatch { expected: expected.receipts_root().clone(), found: got.receipts_root().clone() })))
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -26,5 +26,5 @@ pub trait Verifier: Send + Sync {
|
|||||||
/// Verify a block relative to its parent and uncles.
|
/// Verify a block relative to its parent and uncles.
|
||||||
fn verify_block_family(&self, header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error>;
|
fn verify_block_family(&self, header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error>;
|
||||||
/// Do a final verification check for an enacted header vs its expected counterpart.
|
/// Do a final verification check for an enacted header vs its expected counterpart.
|
||||||
fn verify_block_final(&self, expected: &Header, got: &Header, receipts: bool) -> Result<(), Error>;
|
fn verify_block_final(&self, expected: &Header, got: &Header, receipts: u64) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,9 @@ pub struct AuthorityRoundParams {
|
|||||||
/// To be used for testing only.
|
/// To be used for testing only.
|
||||||
#[serde(rename="startStep")]
|
#[serde(rename="startStep")]
|
||||||
pub start_step: Option<Uint>,
|
pub start_step: Option<Uint>,
|
||||||
|
/// Block at which score validation should start.
|
||||||
|
#[serde(rename="validateScoreTransition")]
|
||||||
|
pub validate_score_transition: Option<Uint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authority engine deserialization.
|
/// Authority engine deserialization.
|
||||||
|
@ -54,8 +54,8 @@ pub struct Params {
|
|||||||
#[serde(rename="eip98Transition")]
|
#[serde(rename="eip98Transition")]
|
||||||
pub eip98_transition: Option<Uint>,
|
pub eip98_transition: Option<Uint>,
|
||||||
/// See `CommonParams` docs.
|
/// See `CommonParams` docs.
|
||||||
#[serde(rename="validateReceipts")]
|
#[serde(rename="validateReceiptsTransition")]
|
||||||
pub validate_receipts: Option<bool>,
|
pub validate_receipts_transition: Option<Uint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
Reference in New Issue
Block a user