Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Strict validation transitions #4988

Merged
merged 5 commits into from
Mar 28, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions ethcore/res/ethereum/kovan.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@

"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de"
]
}
},
"validateScoreTransition": 1000000
}
}
},
"params": {
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2A",
"validateReceipts" : false
"validateReceiptsTransition" : 1000000
},
"genesis": {
"seal": {
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ impl Client {
})?;

// 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);
return Err(());
}
Expand Down
16 changes: 13 additions & 3 deletions ethcore/src/engines/authority_round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub struct AuthorityRoundParams {
pub start_step: Option<u64>,
/// Valid validators.
pub validators: ethjson::spec::ValidatorSet,
/// Chain score validation transition block.
pub validate_score_transition: u64,
}

impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
Expand All @@ -64,6 +66,7 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
block_reward: p.block_reward.map_or_else(U256::zero, Into::into),
registrar: p.registrar.map_or_else(Address::new, Into::into),
start_step: p.start_step.map(Into::into),
validate_score_transition: p.validate_score_transition.map_or(0, Into::into),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the default at 0 break compatibility with existing PoA chains?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only ones started with 1.5, but the default eip98 transition breaks them anyway.

}
}
}
Expand All @@ -83,8 +86,9 @@ pub struct AuthorityRound {
client: RwLock<Option<Weak<EngineClient>>>,
signer: EngineSigner,
validators: Box<ValidatorSet + Send + Sync>,
/// Is this Engine just for testing (prevents step calibration).
/// Is this Engine not used for testing and should be calibrated.
calibrate_step: bool,
validate_score_transition: u64,
}

fn header_step(header: &Header) -> Result<usize, ::rlp::DecoderError> {
Expand Down Expand Up @@ -125,6 +129,7 @@ impl AuthorityRound {
signer: Default::default(),
validators: new_validator_set(our_params.validators),
calibrate_step: our_params.start_step.is_none(),
validate_score_transition: our_params.validate_score_transition,
});
// Do not initialize timeouts for tests.
if should_timeout {
Expand Down Expand Up @@ -295,13 +300,17 @@ impl Engine for AuthorityRound {
Err(From::from(BlockError::InvalidSealArity(
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 {
Ok(())
}
}

fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
Ok(())
Ok(())
}

/// Do the validator and gas limit validation.
Expand All @@ -327,7 +336,8 @@ impl Engine for AuthorityRound {
}

// 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);
self.validators.report_malicious(header.author());
Err(EngineError::DoubleVote(header.author().clone()))?;
Expand Down
4 changes: 2 additions & 2 deletions ethcore/src/spec/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub struct CommonParams {
/// Number of first block where EIP-98 rules begin.
pub eip98_transition: BlockNumber,
/// Validate block receipts root.
pub validate_receipts: bool,
pub validate_receipts_transition: u64,
}

impl From<ethjson::spec::Params> for CommonParams {
Expand All @@ -70,7 +70,7 @@ impl From<ethjson::spec::Params> for CommonParams {
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 },
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),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/verification/canon_verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl Verifier for CanonVerifier {
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)
}
}
2 changes: 1 addition & 1 deletion ethcore/src/verification/noop_verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl Verifier for NoopVerifier {
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(())
}
}
4 changes: 2 additions & 2 deletions ethcore/src/verification/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
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() {
return Err(From::from(BlockError::InvalidGasUsed(Mismatch { expected: expected.gas_used().clone(), found: got.gas_used().clone() })))
}
Expand All @@ -188,7 +188,7 @@ pub fn verify_block_final(expected: &Header, got: &Header, check_receipts: bool)
if expected.state_root() != got.state_root() {
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() })))
}
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/verification/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ pub trait Verifier: Send + Sync {
/// Verify a block relative to its parent and uncles.
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.
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>;
}
3 changes: 3 additions & 0 deletions json/src/spec/authority_round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ pub struct AuthorityRoundParams {
/// To be used for testing only.
#[serde(rename="startStep")]
pub start_step: Option<Uint>,
/// Block at which score validation should start.
#[serde(rename="validateScoreTransition")]
pub validate_score_transition: Option<Uint>,
}

/// Authority engine deserialization.
Expand Down
4 changes: 2 additions & 2 deletions json/src/spec/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ pub struct Params {
#[serde(rename="eip98Transition")]
pub eip98_transition: Option<Uint>,
/// See `CommonParams` docs.
#[serde(rename="validateReceipts")]
pub validate_receipts: Option<bool>,
#[serde(rename="validateReceiptsTransition")]
pub validate_receipts_transition: Option<Uint>,
}

#[cfg(test)]
Expand Down