Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
444f858
refactor(db): move announces from BlockMeta to AnnounceStorage
playX18 Jan 7, 2026
9a042d4
refactor(ethexe/compute): use AnnounceStorage
playX18 Jan 7, 2026
4a06652
refactor(ethexe/common): use AnnounceStorage for block announces
playX18 Jan 7, 2026
8236477
refactor(ethexe/consensus): use AnnounceStorage for block announces
playX18 Jan 7, 2026
642dd9d
refactor(ethexe/db): use AnnounceStorage for block announces
playX18 Jan 7, 2026
587480a
refactor(ethexe/network): use AnnounceStorage for block announces
playX18 Jan 7, 2026
98b9839
refactor(ethexe/processor): use AnnounceStorage for block announces
playX18 Jan 7, 2026
0551255
refactor(ethexe/processor): use AnnounceStorage for block announces
playX18 Jan 7, 2026
096c614
refactor(ethexe/service/tests): use AnnounceStorage for block announces
playX18 Jan 7, 2026
a96428e
Merge branch 'master' into ap-move-anounces
playX18 Jan 7, 2026
48dc70b
update tests.rs
playX18 Jan 8, 2026
9c61733
feat(ethexe/db): add take_block_announces
playX18 Jan 8, 2026
7a9c824
fix(ethexe/mock): take block announces in setup if there are any
playX18 Jan 8, 2026
6b85d24
Merge branch 'master' into ap-move-anounces
playX18 Jan 15, 2026
8b62bee
Merge branch 'master' into ap-move-anounces
playX18 Feb 4, 2026
63427f6
typos fix
playX18 Feb 4, 2026
d604972
Merge remote-tracking branch 'origin/master' into ap-move-anounces
playX18 Mar 24, 2026
d5ace9c
fix after merge
playX18 Mar 24, 2026
e159986
remove take_block_announces
playX18 Mar 24, 2026
55a6c03
fmt
playX18 Mar 24, 2026
a8dceb2
clean db in process_announces_response_rejected
playX18 Mar 24, 2026
e047fbc
Merge branch 'master' into ap-move-anounces
playX18 Mar 25, 2026
f8493ef
Change `Key::BlockAnnounces` variant position and discriminant
liferooter Mar 25, 2026
b538521
Add a migration
liferooter Mar 25, 2026
d0d9e8a
Slight adjustments
liferooter Mar 25, 2026
774939a
Update type info hash
liferooter Mar 25, 2026
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
13 changes: 9 additions & 4 deletions ethexe/common/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@ pub struct BlockMeta {
/// Block has been prepared, meaning:
/// all metadata is ready, all predecessors till start block are prepared too.
pub prepared: bool,
// TODO: #4945 remove announces from here
/// Set of announces included in the block.
pub announces: Option<BTreeSet<HashOf<Announce>>>,
/// Queue of code ids waiting for validation status commitment on-chain.
pub codes_queue: Option<VecDeque<CodeId>>,
/// Last committed on-chain batch hash.
Expand All @@ -57,7 +54,6 @@ impl BlockMeta {
pub fn default_prepared() -> Self {
Self {
prepared: true,
announces: Some(Default::default()),
codes_queue: Some(Default::default()),
last_committed_batch: Some(Default::default()),
last_committed_announce: Some(Default::default()),
Expand Down Expand Up @@ -157,11 +153,13 @@ pub trait AnnounceStorageRO {
fn announce_outcome(&self, announce_hash: HashOf<Announce>) -> Option<Vec<StateTransition>>;
fn announce_schedule(&self, announce_hash: HashOf<Announce>) -> Option<Schedule>;
fn announce_meta(&self, announce_hash: HashOf<Announce>) -> AnnounceMeta;
fn block_announces(&self, block_hash: H256) -> Option<BTreeSet<HashOf<Announce>>>;
}

#[auto_impl::auto_impl(&)]
pub trait AnnounceStorageRW: AnnounceStorageRO {
fn set_announce(&self, announce: Announce) -> HashOf<Announce>;
fn set_block_announces(&self, block_hash: H256, announces: BTreeSet<HashOf<Announce>>);
fn set_announce_program_states(
&self,
announce_hash: HashOf<Announce>,
Expand All @@ -175,6 +173,13 @@ pub trait AnnounceStorageRW: AnnounceStorageRO {
announce_hash: HashOf<Announce>,
f: impl FnOnce(&mut AnnounceMeta),
);
fn mutate_block_announces(
&self,
block_hash: H256,
f: impl FnOnce(&mut BTreeSet<HashOf<Announce>>),
);

fn take_block_announces(&self, block_hash: H256) -> Option<BTreeSet<HashOf<Announce>>>;
}

#[derive(Debug, Clone, Default, Encode, Decode, PartialEq, Eq)]
Expand Down
13 changes: 9 additions & 4 deletions ethexe/common/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,10 +409,16 @@ impl BlockChain {
});
}

if let Some(announces) = announces {
db.set_block_announces(hash, announces);
} else {
// take announces, might've been set-up by previous test.
db.take_block_announces(hash);
}

db.mutate_block_meta(hash, |meta| {
*meta = BlockMeta {
prepared: true,
announces,
codes_queue: Some(codes_queue),
last_committed_batch: Some(last_committed_batch),
last_committed_announce: Some(last_committed_announce),
Expand Down Expand Up @@ -544,7 +550,7 @@ pub trait DBMockExt {
fn top_announce_hash(&self, block: H256) -> HashOf<Announce>;
}

impl<DB: OnChainStorageRO + BlockMetaStorageRO> DBMockExt for DB {
impl<DB: OnChainStorageRO + BlockMetaStorageRO + AnnounceStorageRO> DBMockExt for DB {
#[track_caller]
fn simple_block_data(&self, block: H256) -> SimpleBlockData {
let header = self.block_header(block).expect("block header not found");
Expand All @@ -556,8 +562,7 @@ impl<DB: OnChainStorageRO + BlockMetaStorageRO> DBMockExt for DB {

#[track_caller]
fn top_announce_hash(&self, block: H256) -> HashOf<Announce> {
self.block_meta(block)
.announces
self.block_announces(block)
.expect("block announces not found")
.into_iter()
.next()
Expand Down
5 changes: 3 additions & 2 deletions ethexe/common/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ pub fn setup_genesis_in_db<
}
}

pub fn setup_block_in_db<DB: OnChainStorageRW + BlockMetaStorageRW>(
pub fn setup_block_in_db<DB: OnChainStorageRW + BlockMetaStorageRW + AnnounceStorageRW>(
db: &DB,
block_hash: H256,
block_data: FullBlockData,
Expand All @@ -158,10 +158,11 @@ pub fn setup_block_in_db<DB: OnChainStorageRW + BlockMetaStorageRW>(
db.set_block_events(block_hash, &block_data.events);
db.set_block_synced(block_hash);

db.set_block_announces(block_hash, block_data.announces);

db.mutate_block_meta(block_hash, |meta| {
*meta = BlockMeta {
prepared: true,
announces: Some(block_data.announces),
codes_queue: Some(block_data.codes_queue),
last_committed_batch: Some(block_data.last_committed_batch),
last_committed_announce: Some(block_data.last_committed_announce),
Expand Down
16 changes: 8 additions & 8 deletions ethexe/compute/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,10 @@ impl TestEnv {
let processed_announce = event.unwrap_announce_computed();
assert_eq!(processed_announce, announce_hash);

self.db.mutate_block_meta(announce.block_hash, |meta| {
meta.announces.get_or_insert_default().insert(announce_hash);
});
self.db
.mutate_block_announces(announce.block_hash, |announces| {
announces.insert(announce_hash);
});
}
}

Expand Down Expand Up @@ -251,11 +252,10 @@ async fn multiple_preparation_and_one_processing() -> Result<()> {
// append announces to prepared blocks, except the last one, so that it can be computed
for i in 1..3 {
let announce = new_announce(&env.db, env.chain.blocks[i].hash, Some(100));
env.db.mutate_block_meta(announce.block_hash, |meta| {
meta.announces
.get_or_insert_default()
.insert(announce.to_hash());
});
env.db
.mutate_block_announces(announce.block_hash, |announces| {
announces.insert(announce.to_hash());
});
env.db.set_announce(announce);
}

Expand Down
57 changes: 25 additions & 32 deletions ethexe/consensus/src/announces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ impl<
.block_header(current_block)
.ok_or_else(|| anyhow!("header not found for block({current_block})"))?;

if self.block_meta(current_block).announces.is_some() {
if self.block_announces(current_block).is_some() {
break;
}

Expand All @@ -168,11 +168,10 @@ impl<
let announce_hash = self.set_announce(announce);

let mut newly_included = None;
self.mutate_block_meta(block_hash, |meta| {
if let Some(announces) = &mut meta.announces {
newly_included = Some(announces.insert(announce_hash));
}
});
if let Some(mut announces) = self.block_announces(block_hash) {
newly_included = Some(announces.insert(announce_hash));
self.set_block_announces(block_hash, announces);
}

if let Some(newly_included) = newly_included {
Ok((announce_hash, newly_included))
Expand All @@ -190,7 +189,7 @@ impl<
}

self.announce(announce_hash)
.and_then(|announce| self.block_meta(announce.block_hash).announces)
.and_then(|announce| self.block_announces(announce.block_hash))
.map(|announces| announces.contains(&announce_hash))
.unwrap_or(false)
}
Expand Down Expand Up @@ -225,7 +224,7 @@ pub fn propagate_announces(
// iterate over the collected blocks from oldest to newest and propagate announces
for block in chain {
debug_assert!(
db.block_meta(block.hash).announces.is_none(),
db.block_announces(block.hash).is_none(),
"Block {} should not have announces propagated yet",
block.hash
);
Expand All @@ -249,15 +248,14 @@ pub fn propagate_announces(
)?;

let mut new_base_announces = BTreeSet::new();
for parent_announce_hash in db
.block_meta(block.header.parent_hash)
.announces
.ok_or_else(|| {
anyhow!(
"Parent block({}) announces are missing",
block.header.parent_hash
)
})?
for parent_announce_hash in
db.block_announces(block.header.parent_hash)
.ok_or_else(|| {
anyhow!(
"Parent block({}) announces are missing",
block.header.parent_hash
)
})?
{
if let Some(new_base_announce) = propagate_one_base_announce(
db,
Expand All @@ -278,14 +276,12 @@ pub fn propagate_announces(
block.hash
);

db.mutate_block_meta(block.hash, |meta| {
debug_assert!(
meta.announces.is_none(),
"block({}) announces must be None before propagation",
block.hash
);
meta.announces = Some(new_base_announces);
});
debug_assert!(
db.block_announces(block.hash).is_none(),
"block({}) announces must be None before propagation",
block.hash
);
db.set_block_announces(block.hash, new_base_announces);
}

Ok(())
Expand Down Expand Up @@ -446,8 +442,7 @@ fn propagate_one_base_announce(

// Check neighbor announces to be last committed announce
if db
.block_meta(current_announce.block_hash)
.announces
.block_announces(current_announce.block_hash)
.ok_or_else(|| {
anyhow!(
"announces are missing for block({})",
Expand Down Expand Up @@ -568,8 +563,7 @@ fn find_announces_common_predecessor(
.start_announce_hash;

let mut announces = db
.block_meta(block_hash)
.announces
.block_announces(block_hash)
.ok_or_else(|| anyhow!("announces not found for block {block_hash}"))?;

for _ in 0..commitment_delay_limit {
Expand Down Expand Up @@ -612,7 +606,7 @@ pub fn best_parent_announce(
// so we take parents of all announces from `block_hash`,
// to be sure that we take only not expired parent announces.
let parent_announces =
db.announces_parents(db.block_meta(block_hash).announces.into_iter().flatten())?;
db.announces_parents(db.block_announces(block_hash).into_iter().flatten())?;

best_announce(db, parent_announces, commitment_delay_limit)
}
Expand Down Expand Up @@ -800,8 +794,7 @@ mod tests {
) -> (H256, usize) {
let block_hash = chain.blocks[idx].hash;
let announces_amount = db
.block_meta(block_hash)
.announces
.block_announces(block_hash)
.unwrap_or_else(|| panic!("announces not found for block {block_hash}"))
.len();
(block_hash, announces_amount)
Expand Down
9 changes: 2 additions & 7 deletions ethexe/consensus/src/validator/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use async_trait::async_trait;
use ethexe_common::{
Address, Announce, Digest, HashOf, ProtocolTimelines, SimpleBlockData, ToDigest, ValidatorsVec,
consensus::BatchCommitmentValidationRequest,
db::{BlockMetaStorageRO, OnChainStorageRO},
db::{AnnounceStorageRO, BlockMetaStorageRO, OnChainStorageRO},
ecdsa::{ContractSignature, PublicKey},
gear::{
BatchCommitment, ChainCommitment, CodeCommitment, RewardsCommitment, ValidatorsCommitment,
Expand Down Expand Up @@ -262,12 +262,7 @@ impl ValidatorCore {
// TODO #4791: support commitment head from another block in chain,
// have to check head block is predecessor of current block

let candidates = self
.db
.block_meta(block.hash)
.announces
.into_iter()
.flatten();
let candidates = self.db.block_announces(block.hash).into_iter().flatten();

let best_announce_hash =
announces::best_announce(&self.db, candidates, self.commitment_delay_limit)?;
Expand Down
6 changes: 3 additions & 3 deletions ethexe/consensus/src/validator/initial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,11 +439,11 @@ mod tests {
let ctx = state.into_context();
assert_eq!(ctx.output, vec![]);
for i in last - 5..last - 5 + ctx.core.commitment_delay_limit as usize {
let announces = ctx.core.db.block_meta(chain.blocks[i].hash).announces;
let announces = ctx.core.db.block_announces(chain.blocks[i].hash);
assert_eq!(announces.unwrap().len(), 2);
}
for i in last - 5 + ctx.core.commitment_delay_limit as usize..=last {
let announces = ctx.core.db.block_meta(chain.blocks[i].hash).announces;
let announces = ctx.core.db.block_announces(chain.blocks[i].hash);
assert_eq!(announces.unwrap().len(), 1);
}
}
Expand Down Expand Up @@ -475,7 +475,7 @@ mod tests {
assert_eq!(ctx.output, vec![]);
(last - 9..=last).for_each(|idx| {
let block_hash = chain.blocks[idx].hash;
let announces = ctx.core.db.block_meta(block_hash).announces;
let announces = ctx.core.db.block_announces(block_hash);
assert!(
announces.is_some(),
"expected announces to be propagated for block {block_hash}"
Expand Down
43 changes: 43 additions & 0 deletions ethexe/db/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ enum Key {

// TODO kuzmindev: temporal solution - must move into block meta or something else.
LatestEraValidatorsCommitted(H256),

BlockAnnounces(H256) = 17,
}

impl Key {
Expand All @@ -93,6 +95,7 @@ impl Key {
match self {
Self::BlockSmallData(hash)
| Self::BlockEvents(hash)
| Self::BlockAnnounces(hash)
| Self::LatestEraValidatorsCommitted(hash) => [prefix.as_ref(), hash.as_ref()].concat(),

Self::ValidatorSet(era_index) => {
Expand Down Expand Up @@ -643,6 +646,15 @@ impl AnnounceStorageRO for Database {
})
.unwrap_or_default()
}

fn block_announces(&self, block_hash: H256) -> Option<BTreeSet<HashOf<Announce>>> {
self.kv
.get(&Key::BlockAnnounces(block_hash).to_bytes())
.map(|data| {
BTreeSet::<HashOf<Announce>>::decode(&mut data.as_slice())
.expect("Failed to decode data into `BTreeSet<HashOf<Announce>>`")
})
}
}

impl AnnounceStorageRW for Database {
Expand All @@ -652,6 +664,14 @@ impl AnnounceStorageRW for Database {
unsafe { HashOf::new(self.cas.write(&announce.encode())) }
}

fn set_block_announces(&self, block_hash: H256, announces: BTreeSet<HashOf<Announce>>) {
tracing::trace!("Set block {block_hash} announces: len {}", announces.len());
self.kv.put(
&Key::BlockAnnounces(block_hash).to_bytes(),
announces.encode(),
);
}

fn set_announce_program_states(
&self,
announce_hash: HashOf<Announce>,
Expand Down Expand Up @@ -700,6 +720,29 @@ impl AnnounceStorageRW for Database {
self.kv
.put(&Key::AnnounceMeta(announce_hash).to_bytes(), meta.encode());
}

fn mutate_block_announces(
&self,
block_hash: H256,
f: impl FnOnce(&mut BTreeSet<HashOf<Announce>>),
) {
tracing::trace!("For block {block_hash} mutate announces");
let mut announces = self.block_announces(block_hash).unwrap_or_default();
f(&mut announces);
self.kv.put(
&Key::BlockAnnounces(block_hash).to_bytes(),
announces.encode(),
);
}

fn take_block_announces(&self, block_hash: H256) -> Option<BTreeSet<HashOf<Announce>>> {
self.kv
.take(&Key::BlockAnnounces(block_hash).to_bytes())
.map(|data| {
BTreeSet::<HashOf<Announce>>::decode(&mut data.as_slice())
.expect("Failed to decode data into `BTreeSet<HashOf<Announce>>`")
})
}
}

impl LatestDataStorageRO for Database {
Expand Down
Loading