diff --git a/Cargo.lock b/Cargo.lock index 42b1e99a4da..23116f4a54f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4710,6 +4710,7 @@ dependencies = [ "indexmap 2.6.0", "log", "parity-scale-codec", + "rand", "tokio", ] @@ -4756,6 +4757,7 @@ dependencies = [ "gprimitives", "log", "parity-scale-codec", + "rand", "static_init", ] diff --git a/ethexe/cli/src/service.rs b/ethexe/cli/src/service.rs index 2b4d039ed3e..245806ffa71 100644 --- a/ethexe/cli/src/service.rs +++ b/ethexe/cli/src/service.rs @@ -357,7 +357,9 @@ impl Service { db.set_block_header(block_data.hash, block_data.header); let mut commitments = vec![]; + let last_committed_chain = query.get_last_committed_chain(block_data.hash).await?; + for block_hash in last_committed_chain.into_iter().rev() { let transitions = Self::process_one_block(db, query, processor, block_hash).await?; @@ -366,8 +368,13 @@ impl Service { continue; } + let header = db + .block_header(block_hash) + .ok_or_else(|| anyhow!("header not found, but most exist"))?; + commitments.push(BlockCommitment { block_hash, + block_timestamp: header.timestamp, pred_block_hash: block_data.hash, prev_commitment_hash: db .block_prev_commitment(block_hash) diff --git a/ethexe/sequencer/Cargo.toml b/ethexe/sequencer/Cargo.toml index 4e0c9a18285..ceb3258c3d7 100644 --- a/ethexe/sequencer/Cargo.toml +++ b/ethexe/sequencer/Cargo.toml @@ -24,3 +24,6 @@ anyhow.workspace = true futures.workspace = true tokio.workspace = true indexmap.workspace = true + +[dev-dependencies] +rand.workspace = true diff --git a/ethexe/sequencer/src/lib.rs b/ethexe/sequencer/src/lib.rs index bc48fdb32e4..db21eb3bb12 100644 --- a/ethexe/sequencer/src/lib.rs +++ b/ethexe/sequencer/src/lib.rs @@ -683,18 +683,21 @@ mod tests { let commitment1 = BlockCommitment { block_hash: H256::random(), + block_timestamp: rand::random(), prev_commitment_hash: H256::random(), pred_block_hash: H256::random(), transitions: Default::default(), }; let commitment2 = BlockCommitment { block_hash: H256::random(), + block_timestamp: rand::random(), prev_commitment_hash: commitment1.block_hash, pred_block_hash: H256::random(), transitions: Default::default(), }; let commitment3 = BlockCommitment { block_hash: H256::random(), + block_timestamp: rand::random(), prev_commitment_hash: commitment1.block_hash, pred_block_hash: H256::random(), transitions: Default::default(), diff --git a/ethexe/signer/src/digest.rs b/ethexe/signer/src/digest.rs index 9eee8f61053..902377bcd46 100644 --- a/ethexe/signer/src/digest.rs +++ b/ethexe/signer/src/digest.rs @@ -179,12 +179,14 @@ impl ToDigest for BlockCommitment { // To avoid missing incorrect hashing while developing. let Self { block_hash, + block_timestamp, prev_commitment_hash, pred_block_hash, transitions, } = self; hasher.update(block_hash.as_bytes()); + hasher.update(ethexe_common::u64_into_uint48_be_bytes_lossy(*block_timestamp).as_slice()); hasher.update(prev_commitment_hash.as_bytes()); hasher.update(pred_block_hash.as_bytes()); hasher.update(transitions.to_digest().as_ref()); @@ -225,6 +227,7 @@ mod tests { let block_commitment = BlockCommitment { block_hash: H256::from([0; 32]), + block_timestamp: 0, pred_block_hash: H256::from([1; 32]), prev_commitment_hash: H256::from([2; 32]), transitions: transitions.clone(), diff --git a/ethexe/validator/Cargo.toml b/ethexe/validator/Cargo.toml index d6b62de06dc..57bde0c03cb 100644 --- a/ethexe/validator/Cargo.toml +++ b/ethexe/validator/Cargo.toml @@ -24,3 +24,4 @@ static_init = "1.0.3" [dev-dependencies] ethexe-db.workspace = true +rand.workspace = true diff --git a/ethexe/validator/src/lib.rs b/ethexe/validator/src/lib.rs index 9dff3c15565..dda37fd1254 100644 --- a/ethexe/validator/src/lib.rs +++ b/ethexe/validator/src/lib.rs @@ -16,13 +16,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, ensure, Result}; use ethexe_common::{ db::{BlockMetaStorage, CodesStorage}, router::{BlockCommitment, CodeCommitment}, }; use ethexe_sequencer::agro::{self, AggregatedCommitments}; -use ethexe_signer::{sha3, Address, Digest, PublicKey, Signature, Signer, ToDigest}; +use ethexe_signer::{ + sha3::{self, Digest as _}, + Address, Digest, PublicKey, Signature, Signer, ToDigest, +}; use gprimitives::H256; use parity_scale_codec::{Decode, Encode}; @@ -40,6 +43,7 @@ pub struct Config { #[derive(Debug, Clone, Encode, Decode)] pub struct BlockCommitmentValidationRequest { pub block_hash: H256, + pub block_timestamp: u64, pub prev_commitment_hash: H256, pub pred_block_hash: H256, pub transitions_digest: Digest, @@ -47,21 +51,41 @@ pub struct BlockCommitmentValidationRequest { impl From<&BlockCommitment> for BlockCommitmentValidationRequest { fn from(commitment: &BlockCommitment) -> Self { + // To avoid missing incorrect hashing while developing. + let BlockCommitment { + block_hash, + block_timestamp, + prev_commitment_hash, + pred_block_hash, + transitions, + } = commitment; + Self { - block_hash: commitment.block_hash, - prev_commitment_hash: commitment.prev_commitment_hash, - pred_block_hash: commitment.pred_block_hash, - transitions_digest: commitment.transitions.to_digest(), + block_hash: *block_hash, + block_timestamp: *block_timestamp, + prev_commitment_hash: *prev_commitment_hash, + pred_block_hash: *pred_block_hash, + transitions_digest: transitions.to_digest(), } } } impl ToDigest for BlockCommitmentValidationRequest { fn update_hasher(&self, hasher: &mut sha3::Keccak256) { - sha3::Digest::update(hasher, self.block_hash.as_bytes()); - sha3::Digest::update(hasher, self.prev_commitment_hash.as_bytes()); - sha3::Digest::update(hasher, self.pred_block_hash.as_bytes()); - sha3::Digest::update(hasher, self.transitions_digest.as_ref()); + // To avoid missing incorrect hashing while developing. + let Self { + block_hash, + block_timestamp, + prev_commitment_hash, + pred_block_hash, + transitions_digest, + } = self; + + hasher.update(block_hash.as_bytes()); + hasher.update(ethexe_common::u64_into_uint48_be_bytes_lossy(*block_timestamp).as_slice()); + hasher.update(prev_commitment_hash.as_bytes()); + hasher.update(pred_block_hash.as_bytes()); + hasher.update(transitions_digest.as_ref()); } } @@ -155,6 +179,7 @@ impl Validator { ) -> Result<()> { let BlockCommitmentValidationRequest { block_hash, + block_timestamp, pred_block_hash: allowed_pred_block_hash, prev_commitment_hash: allowed_prev_commitment_hash, transitions_digest, @@ -166,6 +191,12 @@ impl Validator { )); } + let header = db.block_header(block_hash).ok_or_else(|| { + anyhow!("Requested block {block_hash} header wasn't found in storage") + })?; + + ensure!(header.timestamp == block_timestamp, "Timestamps mismatch"); + if db .block_outcome(block_hash) .ok_or_else(|| anyhow!("Cannot get from db outcome for block {block_hash}"))? @@ -258,6 +289,7 @@ mod tests { let commitment = BlockCommitment { block_hash: H256::random(), + block_timestamp: rand::random(), prev_commitment_hash: H256::random(), pred_block_hash: H256::random(), transitions: vec![transition.clone(), transition], @@ -309,6 +341,7 @@ mod tests { let db = ethexe_db::Database::from_one(ðexe_db::MemDb::default(), [0; 20]); let block_hash = H256::random(); + let block_timestamp = rand::random::() as u64; let pred_block_hash = H256::random(); let prev_commitment_hash = H256::random(); let transitions = vec![]; @@ -321,7 +354,7 @@ mod tests { block_hash, BlockHeader { height: 100, - timestamp: 100, + timestamp: block_timestamp, parent_hash: pred_block_hash, }, ); @@ -330,6 +363,7 @@ mod tests { &db, BlockCommitmentValidationRequest { block_hash, + block_timestamp, pred_block_hash: block_hash, prev_commitment_hash, transitions_digest, @@ -341,6 +375,19 @@ mod tests { &db, BlockCommitmentValidationRequest { block_hash, + block_timestamp: block_timestamp + 1, + pred_block_hash: block_hash, + prev_commitment_hash, + transitions_digest, + }, + ) + .expect_err("Timestamps mismatch"); + + Validator::validate_block_commitment( + &db, + BlockCommitmentValidationRequest { + block_hash, + block_timestamp, pred_block_hash: H256::random(), prev_commitment_hash, transitions_digest, @@ -352,6 +399,7 @@ mod tests { &db, BlockCommitmentValidationRequest { block_hash, + block_timestamp, pred_block_hash: block_hash, prev_commitment_hash: H256::random(), transitions_digest, @@ -363,6 +411,7 @@ mod tests { &db, BlockCommitmentValidationRequest { block_hash, + block_timestamp, pred_block_hash: block_hash, prev_commitment_hash, transitions_digest: Digest::from([2; 32]), @@ -374,6 +423,7 @@ mod tests { &db, BlockCommitmentValidationRequest { block_hash: H256::random(), + block_timestamp, pred_block_hash: block_hash, prev_commitment_hash, transitions_digest,