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,