From 289e9bddcc2c8222983496fc8fe4639c32d20dd0 Mon Sep 17 00:00:00 2001 From: playX18 Date: Tue, 9 Jun 2026 07:21:21 +0700 Subject: [PATCH 1/3] feat(ethexe/processor): exclude zero balance programs from processing --- ethexe/processor/src/handling/overlaid.rs | 6 +- ethexe/processor/src/handling/run/mod.rs | 96 ++++++++++++++++++++++- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/ethexe/processor/src/handling/overlaid.rs b/ethexe/processor/src/handling/overlaid.rs index ce07d2b7ad4..9b6d607ac96 100644 --- a/ethexe/processor/src/handling/overlaid.rs +++ b/ethexe/processor/src/handling/overlaid.rs @@ -186,7 +186,11 @@ impl RunContext for OverlaidRunContext { } fn states(&self, processing_queue_type: MessageType) -> Vec { - run::states(&self.inner.transitions, processing_queue_type) + run::states( + &self.inner.db, + &self.inner.transitions, + processing_queue_type, + ) } fn handle_chunk_data( diff --git a/ethexe/processor/src/handling/run/mod.rs b/ethexe/processor/src/handling/run/mod.rs index 6ae53c2edf7..e0247ea5364 100644 --- a/ethexe/processor/src/handling/run/mod.rs +++ b/ethexe/processor/src/handling/run/mod.rs @@ -112,6 +112,7 @@ use ethexe_common::{ use ethexe_db::{CASDatabase, Database}; use ethexe_runtime_common::{ BlockInfo, InBlockTransitions, JournalHandler, ProgramJournals, TransitionController, + state::Storage as _, }; use futures::prelude::*; use gear_core::{ @@ -438,7 +439,7 @@ impl RunContext for CommonRunContext { } fn states(&self, processing_queue_type: MessageType) -> Vec { - states(&self.transitions, processing_queue_type) + states(&self.db, &self.transitions, processing_queue_type) } fn inner(&self) -> &CommonRunContext { @@ -526,6 +527,7 @@ pub(super) fn instrumented_code_and_metadata( } pub(super) fn states( + db: &Database, in_block_transitions: &InBlockTransitions, processing_queue_type: MessageType, ) -> Vec { @@ -540,6 +542,14 @@ pub(super) fn states( if queue_size == 0 { return None; } + + let program_state = db + .program_state(state.hash) + .expect("program state from transitions must exist in storage"); + if program_state.executable_balance == 0 { + return None; + } + let actor_state = ActorStateHashWithQueueSize::new(actor_id, state); Some(actor_state) @@ -564,13 +574,17 @@ mod tests { const CHUNK_PROCESSING_THREADS: usize = 16; const MAX_QUEUE_SIZE: u8 = 20; + let db = Database::memory(); let mut i = 0; let mut states_to_queue_size = HashMap::new(); let states = std::iter::repeat_with(|| { i += 1; - let hash = H256::from_low_u64_le(i); let canonical_queue_size = rand::random::() % MAX_QUEUE_SIZE + 1; + let mut program_state = ProgramState::zero(); + program_state.balance = i as u128; + program_state.executable_balance = 1; + let hash = db.write_program_state(program_state); states_to_queue_size.insert(hash, canonical_queue_size as usize); ( @@ -586,7 +600,6 @@ mod tests { .collect(); let transitions = InBlockTransitions::new(0, states, Default::default()); - let db = Database::memory(); let mut ctx = CommonRunContext::new( db.clone(), InstanceCreator::new(db.clone(), host::runtime()).unwrap(), @@ -623,6 +636,83 @@ mod tests { } } + #[test] + fn chunk_partitioning_skips_zero_executable_balance_programs() { + let db = Database::memory(); + let skipped = ActorId::from(1); + let executable_without_owned_balance = ActorId::from(2); + let executable_with_owned_balance = ActorId::from(3); + + let write_program_state = |balance, executable_balance| { + let mut state = ProgramState::zero(); + state.balance = balance; + state.executable_balance = executable_balance; + db.write_program_state(state) + }; + + let skipped_hash = write_program_state(1_000, 0); + let executable_without_owned_balance_hash = write_program_state(0, 1_000); + let executable_with_owned_balance_hash = write_program_state(1_000, 1_000); + + let states = BTreeMap::from([ + ( + skipped, + StateHashWithQueueSize { + hash: skipped_hash, + canonical_queue_size: 1, + injected_queue_size: 0, + }, + ), + ( + executable_without_owned_balance, + StateHashWithQueueSize { + hash: executable_without_owned_balance_hash, + canonical_queue_size: 1, + injected_queue_size: 0, + }, + ), + ( + executable_with_owned_balance, + StateHashWithQueueSize { + hash: executable_with_owned_balance_hash, + canonical_queue_size: 1, + injected_queue_size: 0, + }, + ), + ]); + let transitions = InBlockTransitions::new(0, states, Default::default()); + let mut ctx = CommonRunContext::new( + db.clone(), + InstanceCreator::new(db.clone(), host::runtime()).unwrap(), + transitions, + 1_000_000, + 2, + 3, + 3, + None, + ); + + let chunks = chunks_splitting::prepare_execution_chunks(&mut ctx, MessageType::Canonical); + + assert_eq!(chunks.len(), 1); + let chunk = chunks.first().expect("one chunk must be prepared"); + assert_eq!(chunk.len(), 2); + assert!( + !chunk + .iter() + .any(|(program_id, state_hash)| *program_id == skipped + && *state_hash == skipped_hash) + ); + assert!(chunk.iter().any(|(program_id, state_hash)| { + *program_id == executable_without_owned_balance + && *state_hash == executable_without_owned_balance_hash + })); + assert!(chunk.iter().any(|(program_id, state_hash)| { + *program_id == executable_with_owned_balance + && *state_hash == executable_with_owned_balance_hash + })); + } + #[test] fn nullification() { let db = Database::memory(); From 36915475672f851c972664989fbdf46012bf29c9 Mon Sep 17 00:00:00 2001 From: playX18 Date: Tue, 9 Jun 2026 12:14:50 +0700 Subject: [PATCH 2/3] test(ethexe/processor): cover injected queue zero-balance skip Add test for MessageType::Injected filtering and simplify chunk assertions per review. --- ethexe/processor/src/handling/run/mod.rs | 64 +++++++++++++++++++++--- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/ethexe/processor/src/handling/run/mod.rs b/ethexe/processor/src/handling/run/mod.rs index e0247ea5364..9a928142b14 100644 --- a/ethexe/processor/src/handling/run/mod.rs +++ b/ethexe/processor/src/handling/run/mod.rs @@ -697,12 +697,7 @@ mod tests { assert_eq!(chunks.len(), 1); let chunk = chunks.first().expect("one chunk must be prepared"); assert_eq!(chunk.len(), 2); - assert!( - !chunk - .iter() - .any(|(program_id, state_hash)| *program_id == skipped - && *state_hash == skipped_hash) - ); + assert!(chunk.iter().all(|(program_id, _)| *program_id != skipped)); assert!(chunk.iter().any(|(program_id, state_hash)| { *program_id == executable_without_owned_balance && *state_hash == executable_without_owned_balance_hash @@ -713,6 +708,63 @@ mod tests { })); } + #[test] + fn chunk_partitioning_skips_zero_executable_balance_programs_injected_queue() { + let db = Database::memory(); + let skipped = ActorId::from(1); + let executable = ActorId::from(2); + + let write_program_state = |balance, executable_balance| { + let mut state = ProgramState::zero(); + state.balance = balance; + state.executable_balance = executable_balance; + db.write_program_state(state) + }; + + let skipped_hash = write_program_state(1_000, 0); + let executable_hash = write_program_state(1_000, 1_000); + + let states = BTreeMap::from([ + ( + skipped, + StateHashWithQueueSize { + hash: skipped_hash, + canonical_queue_size: 0, + injected_queue_size: 1, + }, + ), + ( + executable, + StateHashWithQueueSize { + hash: executable_hash, + canonical_queue_size: 0, + injected_queue_size: 1, + }, + ), + ]); + let transitions = InBlockTransitions::new(0, states, Default::default()); + let mut ctx = CommonRunContext::new( + db.clone(), + InstanceCreator::new(db.clone(), host::runtime()).unwrap(), + transitions, + 1_000_000, + 2, + 3, + 3, + None, + ); + + let chunks = chunks_splitting::prepare_execution_chunks(&mut ctx, MessageType::Injected); + + assert_eq!(chunks.len(), 1); + let chunk = chunks.first().expect("one chunk must be prepared"); + assert_eq!(chunk.len(), 1); + assert!(chunk.iter().all(|(program_id, _)| *program_id != skipped)); + assert!(chunk.iter().any(|(program_id, state_hash)| { + *program_id == executable && *state_hash == executable_hash + })); + } + #[test] fn nullification() { let db = Database::memory(); From a30e4aa9885c36f53500810a130bea31b746f7ca Mon Sep 17 00:00:00 2001 From: playX18 Date: Wed, 24 Jun 2026 13:42:22 +0700 Subject: [PATCH 3/3] clippy --- ethexe/processor/src/handling/run/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ethexe/processor/src/handling/run/mod.rs b/ethexe/processor/src/handling/run/mod.rs index 3931f893567..293b02bba91 100644 --- a/ethexe/processor/src/handling/run/mod.rs +++ b/ethexe/processor/src/handling/run/mod.rs @@ -688,7 +688,8 @@ mod tests { }, ), ]); - let transitions = InBlockTransitions::new(0, states, Default::default()); + let transitions = + InBlockTransitions::new(TransitionsConfig::default(), states, Default::default()); let mut ctx = CommonRunContext::new( db.clone(), InstanceCreator::new(db.clone(), host::runtime()).unwrap(), @@ -750,7 +751,8 @@ mod tests { }, ), ]); - let transitions = InBlockTransitions::new(0, states, Default::default()); + let transitions = + InBlockTransitions::new(TransitionsConfig::default(), states, Default::default()); let mut ctx = CommonRunContext::new( db.clone(), InstanceCreator::new(db.clone(), host::runtime()).unwrap(),