feat!(ethexe): malachite#5419
Conversation
…oundation) Restores the foundational types from commit 4138374: - ReplyInfo::to_hash() in gear-core - PromiseEmissionMode in ethexe-common primitives - CompactPromise / SignedCompactPromise + helpers in ethexe-common - Mock impls for Promise - InjectedStorage{RO,RW} extended with promise/compact_promise getters and setters - Database/RawDatabase impls for the new storage methods This is the foundation that downstream pieces (processor BoundPromiseSink, compute PromisePolicy wiring, modular RPC injected API, gossipsub compact-promise topic) build on. The marker comments for those follow-ups remain. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Apply +_+_+ rename markers across Rust + Solidity sources:
- `AnnouncesCommitted{,Event}` → `MBCommitted{,Event}` (Rust struct, enum variant, Solidity event)
- `LastAdvancedEthBlockCommitted{,Event}` → `EBCommitted{,Event}` (Rust struct, enum variant, Solidity event)
- `ANNOUNCES_COMMITTED` → `MB_COMMITTED`, `LAST_ADVANCED_ETH_BLOCK_COMMITTED` → `EB_COMMITTED` (constants)
- `announces_committed` → `mb_committed`, `last_advanced_eth_block_committed` → `eb_committed` (methods)
- `last_committed_advanced_eth_block` → `last_committed_eb` (field in BlockMeta / PreparedBlockData)
- `last_advanced_block` → `last_advanced_eb` (field in MbMeta)
- `latest_synced_block` → `latest_synced_eb`, `latest_prepared_block_hash` → `latest_prepared_eb_hash` (DBGlobals)
- `CompactBlock` → `CompactMB` (struct)
- camelCase counterparts in Solidity
Forge build regenerated ABI JSON for Router/Mirror/Middleware/POAMiddleware/WrappedVara.
`ensure_types_unchanged` hash bumped to reflect the type-name changes (SCALE encoding unchanged).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The module owns Malachite-sequencer application types (`Transaction`, `Transactions`, etc.) so `malachite` is the more accurate name. Updates all import paths and the `ensure_types_unchanged` hash for the new module path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The validator state more accurately is the "idle" state (waiting for chain head, then sync, then prepare before electing a role). Renames: - module `wait_for_eth_block` → `idle` - struct `WaitForEthBlock` → `Idle` - display tag `WAIT_FOR_ETH_BLOCK` → `IDLE` Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The rate-stepping promise-latency experiment runner lives on a separate branch now; drop it from the main branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a `Migration` trait and `migrate()` driver that walks ascending schema versions in `migrations()`. The vector is empty for now — the old v1/v2/... entries had no live consumers and were removed earlier. Wire `migrate()` into `initialize_db()` so an on-disk version below `LATEST_VERSION` runs the framework instead of bailing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The handler now reads `mb_program_states(at)` and returns the set of `ActorId`s present there, instead of warning and returning an empty response. Added `MbStorageRO` to the `DbSyncDatabase` trait so the network layer can reach the MB stores. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The MB-driven path has no active consumers of db_sync responses: every incoming response was being logged-and-dropped, and every failure was just re-issued forever. Drop the `network_fetcher` future, the `Event::Fetching` variant, and their imports. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renumbers the test list to mirror master's ordering for tests common to both branches; new MB-specific tests (`multiple_validators_ping`, `reorg_within_quarantine`, `reorg_deeper_than_quarantine`) slot in where their thematic neighbors live. Also drop the now-stale `Event::Fetching` variant from the `TestingEvent` mirror — it was already gone from the runtime enum. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`MalachiteService::new` now takes `Option<PublicKey>`: - `Some(pk)` → `NodeRole::Validator`, validator key extracted from the signer. - `None` → `NodeRole::FullNode`, ephemeral secret used only as the libp2p peer identity. The service's call site no longer skips Malachite when no validator key is configured, so connect/full nodes also join the gossip mesh and receive proposals + sync responses. Test harness call sites updated to pass `Some(pub_key)`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move `db.set_injected_transaction(tx)` into `InjectedTxMempool::insert` so the network and RPC handlers don't have to remember to do it themselves. The two service-side call sites lose the duplicated persistence calls. Persistence happens before pool insertion so a producer that picks the tx on the very next round is guaranteed to find it via `injected_getTransactions`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`ethexe check --computation` now walks `latest_finalized_mb_hash`
back through `CompactMB.parent` and asserts that every MB has its
cached `mb_program_states` / `mb_outcome` / `mb_schedule` records
plus `MbMeta { computed: true }`.
Re-execution through the processor (asserting cached records match
fresh execution) is intentionally left out — it requires loading
every code blob and reconstructing the runtime, which the CLI doesn't
have the context for.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…k entry points Add `StateDump::collect_from_mb_storage(storage, mb_hash, block_hash)` as the malachite-native entry point — state lives per-MB, so callers that already know which MB to dump shouldn't have to round-trip through `BlockMeta::last_committed_mb`. The existing `collect_from_storage(block_hash)` becomes a thin wrapper that derives the MB and forwards. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`WaitForUploadCode`, `WaitForProgramCreation`, and `WaitForReplyTo`
each had an inline `select! { sleep => evm_mine, … = wait => break }`
loop that duplicated the `KickingStream::find_map` kick mechanism.
Each `wait_for` now hands the `(provider, block_time*3)` kick to the
receiver via `set_kicks` before consuming it with
`filter_map_block_synced`; the resulting `KickingStream` triggers
`evm_mine` on idle automatically.
`KickExt` retains its `EventReceiver` impl so `WaitFor*` can mutate
kicks pre-conversion. Replaced the marker on `extend_malachite_endpoints`
with a TODO note — pulling endpoint setup forward into `TestEnv::new`
needs a wider tests refactor and is left for a follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Promotes `apis/injected.rs` to `apis/injected/` and splits it into: - `mod.rs` — module entry, public re-exports - `trait.rs` — JSON-RPC trait definition (`Injected`) - `promise_manager.rs` — `PromiseSubscriptionManager` owns the `tx_hash → oneshot::Sender` map plus `try_register_subscriber`, `cancel_registration`, and `dispatch_promise` - `relay.rs` — `TransactionsRelayer` does the per-validator fan-out and the single-recipient fallback when the era's validator vector isn't known yet - `spawner.rs` — `spawn_pending_subscriber` bridges a registered subscriber to a jsonrpsee subscription sink with timeout / cleanup - `server.rs` — `InjectedApi` orchestrates all of the above Adds the `injected_getTransactionPromise` method that reads `db.promise(tx_hash)` and `db.compact_promise(tx_hash)` and reconstructs the `SignedPromise` via `SignedCompactPromise::restore`. This is the user-facing payoff of the CompactPromise primitives added in the foundation commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces every `Option<mpsc::UnboundedSender<Promise>>` field / parameter in the processor with `Option<BoundPromiseSink>`. The sink wraps an `UnboundedSender<(H256, Promise)>` and pre-binds each send to the MB hash the executor is currently working on, so worker threads no longer have to thread the binding through manually. Ripples: - `host::threads::ThreadParams.promise_out_tx` → `promise_sink` - `clear_promise_out_tx` → `clear_promise_sink` - `CommonRunContext.promise_out_tx` → `promise_sink` - compute's per-MB channel now carries `(H256, Promise)`; the `MbPromisesStream` reads the hash from each message instead of storing it in a field - compute constructs `BoundPromiseSink::new(sender, target_hash)` for the target MB and passes `None` for predecessor MBs (unchanged semantics) - processor unit tests upgrade their channel to `(H256, Promise)` and wrap senders in `BoundPromiseSink::new(_, H256::zero())` Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…h compute_mb Closes the remaining `+_+_+` marker on `MbComputeRequest`: - `MbComputeRequest` gains a `promise_policy: PromisePolicy` field - `ComputeSubService::receive_mb(mb_hash, policy)` records it - `compute()` constructs a `BoundPromiseSink` for the target MB only when `policy == Enabled`, preserving the rule that ancestor MBs always replay with promises disabled - `ComputeService` carries a `PromiseEmissionMode` (default `ConsensusDriven`) and offers `with_promise_mode(...)`. In `AlwaysEmit` it overrides the per-call policy to `Enabled` - service-side `compute_mb` call passes `PromisePolicy::Enabled` for `MalachiteEvent::BlockProposal` (consensus may still narrow it via the emission mode) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- `cargo fmt --all` across all touched files (line-wrap reorganisation only). - `Migration::from_version` → `source_version` (clippy: `wrong_self_convention`). - ProgramIds db-sync handler uses `BTreeMap::into_keys()` instead of `into_iter().map(|(k, _)| k)` (clippy: `iter_kv_map`). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…IONS
Splits the migrations module back into the historical shape:
- `migration.rs` — `Migration` trait (now `Sync` so the slice can be
`&'static`). `migrate(&InitConfig, &RawDatabase)` returns a pinned
boxed future so `&dyn Migration` is dyn-compatible.
- `v5.rs` — schema-version anchor. Holds `pub const VERSION: u32 = 5;`
and nothing else. Future schema bumps add `v6.rs`, `v7.rs`, … each
with their own `VERSION` and (where applicable) a
`migration_from_v(N-1)` function.
- `mod.rs` — re-introduces the user-requested constants:
pub const OLDEST_SUPPORTED_VERSION: u32 = v5::VERSION;
pub const LATEST_VERSION: u32 = v5::VERSION;
pub const MIGRATIONS: &[&dyn Migration] = &[];
const _: () = assert!(
(LATEST_VERSION - OLDEST_SUPPORTED_VERSION) as usize == MIGRATIONS.len(),
"Wrong number of migrations available"
);
The const-assert guarantees every step in the supported version
range has a corresponding migration entry — adding a new schema
version without a migration step (or vice versa) now fails to
compile. Both anchor constants point at `v5::VERSION` for now;
splits into distinct OLDEST/LATEST anchors when the next migration
lands.
- `init.rs` — `migrate(&config, &db).await` (was `migrate(&db)`).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`EventReceiver<T>` no longer carries a `kicks: Option<…>` field nor implements `KickExt`. Kicks live exclusively on the `KickingStream<S>` wrapper, and `TestingEventReceiver` / `ObserverEventReceiver` are now type aliases for `KickingStream<EventReceiver<…>>`. Side effects: - `channel<T>(db, kicks)` returns `(EventSender, KickingStream<EventReceiver<T>>)`. - `KickingStream` gains `Debug + Clone` derives (the inner `EventReceiver` is `Debug + Clone`) and forwards `FusedStream` from its inner stream. - `TestingEventReceiver::find_map_with_db` and `ObserverEventReceiver:: filter_map_*` switch from `self.db`/`self.kicks` field access to `self.db()`/`self.take_kicks()` helpers on the wrapper. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…s builder `WaitForUploadCode`, `WaitForProgramCreation`, and `WaitForReplyTo` no longer carry an `Option<(RootProvider, Duration)> hack` field — the receiver itself is now a `KickingStream`, so the kick lives there. Each waiter gains a public `fn with_kicks(self, kicks: Option<(Duration, RootProvider)>) -> Self` builder that forwards into `receiver.set_kicks` / `clear_kicks`. `force_mine_hack` is renamed to `default_wait_kicks` and produces the `(block_time * 3, provider)` tuple in the shape the kick consumes directly — no more in-call `* 3` math inside `wait_for`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
200 corner-case / hack tests exercised the public APIs of `ethexe-malachite-core`, `ethexe-malachite`, `ethexe-consensus`, and `ethexe-service`. Every iteration ran a fresh test; passing tests are listed here so future iterations don't repeat coverage. All 200 passed; no test code remains in the working tree. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The black-box test log lives alongside the working tree; no need to ship it through git. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`ethexe check --computation` now re-executes every persisted MB through a fresh `Processor` and asserts the cached `mb_program_states` / `mb_outcome` / `mb_schedule` match the fresh run — instead of just asserting the cached records exist. To avoid duplicating the live-pipeline's parent-state lookup, expose `ethexe_compute::prepare_executable_for_mb(db, mb_hash)`. It resolves the parent MB's program states / schedule / `last_advanced_eb`, reads the MB's `Transactions` blob, and assembles the same `ExecutableData` the `compute_mb` sub-service feeds to the processor. The CLI runs it over `processor.clone().overlaid()` so re-execution writes don't touch on-disk state. Adds `--chunk-size` (default 2) for the verification `Processor`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restores the wiring from #5377: when this node carries an RPC server, force `ComputeService` into `PromiseEmissionMode::AlwaysEmit` so the RPC subscribers see promises regardless of the per-MB consensus decision. Pure validator/peer nodes stay on the default `ConsensusDriven` and let the consensus layer pick the policy per MB. Without this, an RPC node running alongside a non-emitting validator role would drop replies on the floor. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The service-level wiring (`ComputeService::with_promise_mode`) translated the per-MB policy for the *target* but the SubService still silenced every walked predecessor unconditionally. An RPC node catching up in `AlwaysEmit` therefore missed the replies for every ancestor MB it had to re-execute. - `ComputeSubService` gains a `promise_emission_mode` field plus a `with_promise_mode(db, processor, mode)` constructor; `new` keeps defaulting to `ConsensusDriven` - `ComputeService::with_promise_mode` forwards the mode through - `compute()` builds a `BoundPromiseSink` per predecessor when the mode is `AlwaysEmit`; under `ConsensusDriven` predecessors stay silent as before (their promises were already gossiped) The target MB still follows `req.promise_policy` (already translated to `Enabled` for `AlwaysEmit` at the service layer), so the behaviour of pure-validator nodes is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop the empty doc-comment line that broke rustfmt between the `post_quarantine_delay` doc comment and its `TODO: #5478` follow-up. - Remove `rand`, `rand_chacha`, `nonempty` from `ethexe-consensus` Cargo.toml — none are referenced by the crate's source.
`receive_eb_prepared` is `pub`; linking to `pub(crate)` items from its doc-comment triggers rustdoc's `private_intra_doc_links` lint under `-D warnings`. Replace the link with prose.
`crates-io` publish-verify swaps the default feature from `server` to `client` before publishing, so the `pub trait Block` body is exposed to the compiler without `feature = "server"` active. Move `BlockHeader` and `BlockRequestEvent` imports out from under that cfg gate — they're used in the trait method signatures regardless of which side (server/client) the rpc macro generates.
|
@claude opus review |
|
Claude finished @grishasobol's task in 4m 13s —— View job Opus Review (2nd pass) —
|
| # | Prior finding | Status |
|---|---|---|
| 1 | Silent Ok(()) in try_include_checkpoint_chain_commitment |
partially fixed: last_committed_eb missing now hard-errors (utils.rs:301); block_header(advanced) missing and "didn't fit" path still silent — see below |
| 2 | SignedMagnitude::add_assign panic on overflow |
unresolved (utils.rs:451) |
| 3 | unreachable! in update_inner Err path |
unresolved (validator/mod.rs:171) |
| 4 | prepare_one_block non-atomic 2-write sequence |
unresolved (prepare.rs:355-366) |
| 5 | Streaming reaper / PartStreamsMap unbounded |
tracked: TODO #5473 with ignored regression test — acceptable |
| 6 | Checkpoint walk over-trusts peer-supplied last_advanced_eth_block |
unresolved (same code path as #1) |
| 7 | Codex: regression of last_advanced_eb in validator path |
fixed: is_strict_descendant_of enforced (externalities.rs:484-508) ✓ |
Also resolved during this revision: shape+ordering+gas-allowance check in validate_block_above, propose-timeout hang in app.rs (now drops reply sender on process_get_value error), checkpoint commitment loss on chain progress (cf45922), and the O(n²) batch-pack pass (5a90bb1).
severity: high — update_inner leaves inner = None on Err path
File: ethexe/consensus/src/validator/mod.rs:164-176
fn update_inner(&mut self, update: impl FnOnce(ValidatorState) -> Result<ValidatorState>) -> Result<()> {
let inner = self.inner.take().unwrap_or_else(|| unreachable!("inner must be Some"));
update(inner).map(|inner| { self.inner = Some(inner); })
}take() consumes inner. When update(...) returns Err, the closure's .map is never invoked and self.inner stays None. The next context() / context_mut() call (e.g. lines 153, 160 or via role() at 181) hits unreachable!.
Every ConsensusService method (receive_new_chain_head, receive_synced_block, receive_prepared_block, receive_validation_request, receive_validation_reply) routes through update_inner with closures that propagate ? from DB and protocol code — any of those errors poisons the validator. The first error bubbles up cleanly; the second event the consumer dispatches panics in unreachable! instead of returning a clean error.
Either restore inner on the Err path (mem::replace with a sentinel Faulted state) or refactor the closure to (ValidatorState, Result<()>) so the state is always restored. The TODO note in Idle already hints that a permanently-faulted state is expected.
severity: high — SignedMagnitude::add_assign panics on adversarial transition aggregation
File: ethexe/consensus/src/validator/batch/utils.rs:447-452
fn add_assign(&mut self, other: Self, actor_id: ActorId) {
match self.negative == other.negative {
true => {
self.value = self.value.checked_add(other.value).unwrap_or_else(|| {
panic!("squashed transition value overflow for actor {actor_id:?}")
});
}Reachable via squash_transitions_by_actor over StateTransitions sourced from MB payloads that the coordinator did not author. The current unit test test_squash_value_overflow_panics documents the panic — in production code path this means every honest participant crashes on the same input. Convert to Result and reject the offending commitment instead of crashing the validator process.
severity: medium — silent Ok(()) on missing block_header(advanced)
File: ethexe/consensus/src/validator/batch/utils.rs:291-297
let advanced = db.mb_meta(mb_head).last_advanced_eb;
if advanced.is_zero() { return Ok(()); }
let Some(advanced_header) = db.block_header(advanced) else {
return Ok(()); // silent skip
};Inconsistent with the new hard-error at 301-303 (last_committed_eb missing despite prepared==true). By construction, if mb_meta(mb_head).last_advanced_eb is non-zero, the MB observed that EB during proposal/finalize (see EthexeExternalities::process_mb_proposal setting meta.last_advanced_eb = last_advanced), so the header must be locally present. A None here is the same invariant violation class — hard-error to surface real bugs.
Separately at lines 327-330, when the chain commitment doesn't fit:
if let Err(err) = batch_filler.include_chain_commitment(commitment) {
tracing::trace!("checkpoint chain commitment didn't fit (...)");
}If uncommitted_chain_len_threshold is later breached for this reason, validators will reject the next coordinator's batches and the network stalls with only a trace! to debug from. At minimum warn!, and consider surfacing as a BatchFillerError variant so the coordinator can choose a smaller payload.
severity: medium — prepare_one_block writes block-meta and globals non-atomically
File: ethexe/compute/src/prepare.rs:355-366
db.mutate_block_meta(block.hash, |meta| {
meta.prepared = true;
/* ... */
});
db.globals_mutate(|globals| {
globals.latest_prepared_eb_hash = block.hash;
});Two separate RocksDB writes. If the process dies between them, block_meta(at).prepared == true but globals.latest_prepared_eb_hash lags. Downstream code (Idle::process_prepared_block, the validator's coordinator selection at idle.rs:99-on) keys off prepared, so a recovery walk seeing prepared==true could pick a block ahead of latest_prepared_eb_hash. Use a single batch-write or document the recovery contract.
severity: low — TxValidityChecker::check_tx_validity bails on local-state miss inside producer loop
File: ethexe/malachite/service/src/tx_validity.rs:173-179
let Some(state) = self.db.program_state(destination_state_hash.hash) else {
anyhow::bail!("program state not found for actor({}) by valid hash({})", ...);
};In build_block_above (externalities.rs:270) this ? propagates and the proposer fails to produce a block for this round. The hash came from latest_states which the checker just loaded, so the only way to hit this is a transient lookup race (or DB corruption). The current behavior — abort the round, let the engine rotate — is probably fine, but worth a comment noting that bail is intentional and the alternative (skip the tx) was rejected.
severity: low — eb_touched_programs walk is intentionally unbounded but lacks a soft cap
File: ethexe/malachite/service/src/tx_validity.rs:328-346
The comment is candid: "The walk is intentionally unbounded ... bailing at start_block_hash is the safe fallback." Under a reorg deeper than canonical_quarantine, the walk runs from advanced_eb back to start_block_hash accumulating into chain: Vec<H256>. That's a one-shot O(chain_depth) allocation, not a persistent leak, but it's worth a defense-in-depth MAX_EB_WALK_DEPTH that errors rather than silently allocating an enormous Vec. Especially given this runs inside both validate_block_above and build_block_above per proposal.
Verified clean
is_strict_descendant_ofis now enforced on the validator path forAdvanceTillEthereumBlock(externalities.rs:484-508) — closes Codex's previous concern.- Genesis parent_hash sentinel (
H256::zero()for height 1) is consistent —app.rs:376-388only consults the store whenheight > 1, andstore.rs/externalities.rsconsistently treat zero as "pre-genesis". - TODOs marked
+_+_+are now linked to tracking issues (ethexe-malachite: PartStreamsMap has no caps, single peer can exhaust memory #5473, ethexe-malachite: add per-peer rate limit on ReceivedProposalPart #5475, ethexe-malachite: verify ProposalFin signature before buffering future-height parts #5476, ethexe-malachite: extract shared helper for producer/validator EB-advance check #5477, ethexe-malachite: emit metrics for validate_block_above abstains #5479, ethexe-malachite: gate ReceivedProposalPart on validator peer-id allowlist #5480) — good follow-up hygiene. - Test coverage for the previously-flagged corner cases (
validate_rejects_advance_that_regresses_last_advanced_eb,part_streams_map_grows_unbounded_under_fin_sequence_attack,buffered_future_proposal_is_saved_on_promotion, the empty-checkpoint regression) is present in the right places.
Spot-checks worth adding before merge
- A state-machine test that drives
update_innerthrough anErrclosure and then dispatches a follow-up event — currently panics withunreachable!. - A property test on
SignedMagnitude::add_assignwith adversarial inputs; assert no panic. - A test where
mb_meta(mb_head).last_advanced_ebis set but the correspondingblock_headeris purged — current behavior emits no checkpoint and reports success.
- Re-fetch branch & survey changes since last opus review
- Verify status of prior opus findings
- Read malachite/core + consensus/validator/batch in detail
- Check new findings (atomicity, streaming reaper, EB regression)
- Post final review
· branchgsobol/ethexe/malachite-new
…hite-new # Conflicts: # ethexe/consensus/src/announces.rs # ethexe/consensus/src/connect/mod.rs # ethexe/consensus/src/mock.rs # ethexe/consensus/src/tx_validation.rs # ethexe/consensus/src/validator/initial.rs # ethexe/consensus/src/validator/mock.rs # ethexe/consensus/src/validator/producer.rs # ethexe/consensus/src/validator/subordinate.rs # ethexe/consensus/src/validator/tx_pool.rs # ethexe/db/src/migrations/v1.rs # ethexe/db/src/migrations/v2.rs # ethexe/db/src/migrations/v3.rs # ethexe/db/src/migrations/v4.rs
The merge re-introduced stale `rand`/`rand_chacha`/`nonempty` entries for `ethexe-consensus` in Cargo.lock that were already removed from its Cargo.toml (commit 8cad9f4). Re-sync.
Files added unintentionally via `git add -A` in the previous merge commit and now ignored to prevent re-adding: - `ok.md` (local scratch notes — was already untracked in 6610c5b) - `.claude/` (Claude Code internal state) - `**/proptest-regressions/` (locally-generated proptest seed cache) - `ethexe/contracts/broadcast/*/*/` (Foundry deployment logs for any chain-id; the existing 31337 carve-out is widened to all chain dirs, since broadcast records belong in deliberate deployment commits, not general merges). Files stay on disk; only their git-tracking is removed.
The promise-emission match guard `if mb_hash == head_mb_hash` applied to both `|` arms, so AlwaysEmit never emitted promises for parent-walked predecessor MBs — an RPC node catching up silently dropped replies for those MBs. Split the arms: AlwaysEmit now emits for every walked MB; ConsensusDriven still emits only for the requested head. Adds two compute-level emission-mode tests (real Processor + demo-ping). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Conflict in ethexe/processor/src/handling/run/mod.rs (imports only) resolved by keeping master's expanded imports — they're required by the lazy instrumentation flow introduced in #5396. Also adapted the new `process_programs_instruments_valid_code_missing_current_runtime_instrumentation` test in ethexe/processor/src/tests.rs to use malachite-new's `setup_handler(db, height: u32)` and the 5-arg `process_queues(transitions, height, timestamp, gas_allowance, None)` signatures.
| @@ -1066,6 +1048,8 @@ mod tests { | |||
| } | |||
|
|
|||
| #[tokio::test] | |||
| #[ignore = "test setup populates the requester's data provider rather than the responder's; \ | |||
| } | ||
|
|
||
| /// Buckets a message era can fall into relative to the snapshot era. |
There was a problem hiding this comment.
This literally has nothing to do with buckets
| } | ||
|
|
||
| fn signer_with_pubkey() -> (PublicKey, Signer) { | ||
| fn signed_promise() -> SignedCompactPromise { |
There was a problem hiding this comment.
mock(()) or arb_value::<T>() should be used instead
| @@ -38,7 +38,8 @@ use std::{ | |||
| pin::Pin, | |||
| task::{Context, Poll, ready}, | |||
| }; | |||
| use sync::ChainSync; | |||
| pub use sync::SyncError; | |||
There was a problem hiding this comment.
pub use and use must not be mixed in imports
| let attempt = self.subscription_retry_attempt.saturating_add(1); | ||
| self.subscription_retry_attempt = attempt; | ||
| let backoff = std::time::Duration::from_millis( | ||
| (500u64.saturating_mul(1u64 << attempt.min(6))).min(30_000), |
There was a problem hiding this comment.
<< is rudimentary way to calculate power of 2. Use pow instead.
| }; | ||
|
|
||
| fn init_tracing() { | ||
| static ONCE: Once = Once::new(); |
| use parity_scale_codec::{Decode, Encode}; | ||
| use proptest::prelude::*; | ||
| use tempfile::TempDir; | ||
| use tokio::time::sleep; |
| idx: usize, | ||
| } | ||
|
|
||
| fn arb_churn_events( |
There was a problem hiding this comment.
| fn arb_churn_events( | |
| fn churn_events_strategy( |
The strategy has nothing to do with aribtrary crate
| let Some(msg) = self.channels.consensus.recv().await else { | ||
| return Err(anyhow!("consensus channel closed")); | ||
| }; |
There was a problem hiding this comment.
| let Some(msg) = self.channels.consensus.recv().await else { | |
| return Err(anyhow!("consensus channel closed")); | |
| }; | |
| let msg = self.channels.consensus.recv().await.context("consensus channel closed")?; |
| externalities: Arc<EXT>, | ||
| } | ||
|
|
||
| impl<P, EXT> AppMsgHandler<P, EXT> |
There was a problem hiding this comment.
https://rust-lang.github.io/api-guidelines/naming.html
Type parameters: concise UpperCamelCase, usually single uppercase letter: T
| impl<P, EXT> AppMsgHandler<P, EXT> | |
| impl<P, Ext> AppMsgHandler<P, Ext> |
Closes #5434