Skip to content

test: improve the data generation for the consensus simulation#510

Merged
etorreborre merged 16 commits into
mainfrom
etorreborre/test/run-simulation-tests-with-several-peers
Oct 20, 2025
Merged

test: improve the data generation for the consensus simulation#510
etorreborre merged 16 commits into
mainfrom
etorreborre/test/run-simulation-tests-with-several-peers

Conversation

@etorreborre

@etorreborre etorreborre commented Oct 17, 2025

Copy link
Copy Markdown
Contributor

This PR uses the data generation support testing the HeadersTree in the simulation runs:

  • New arguments have been added to control the data generation (rollback ratio, branching ratio).
  • A bug is fixed to allow the simulation to run with several downstream peers.
  • Validation errors now don't terminate the node (only processing errors, like not being able to write in the database, do).
  • The whole downstream chain is now tested instead of just its tip.

Summary by CodeRabbit

  • New Features

    • Configurable chain generation with per-peer branching and rollback ratios; CLI accepts ratio strings.
    • Message debug output now includes parent-hash for easier troubleshooting.
    • Exposed parent-hash accessor for header inspection.
  • Bug Fixes

    • Added round-trip header serialization test to catch decode regressions.
    • Validation errors are logged instead of aborting execution.
  • Refactoring

    • Switched from file-based to generated chain inputs and consolidated simulator config around ratio-based generation.

@etorreborre

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 17, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Replaces file-based chain and ledger generation with an action-based generator and proptest strategies; makes Chain pub, adds Ratio Display/FromStr, expands headers-tree generators to return best-chain spines, removes legacy chain/ledger modules, updates simulator APIs to use Entry<T> (no Reverse), and wires downstream-based chain validation.

Changes

Cohort / File(s) Summary
Consensus Ratio & Actions
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs
Add Display and FromStr for Ratio (validated "num/den"); make Chain public; update any_select_chains and generate_random_walks to accept peers_nb and branching_ratio and to return (Vec<Action>, Chain).
Headers Tree Generators
crates/amaru-consensus/src/consensus/headers_tree/data_generation/data_generation.rs
Add any_tree_of_headers_and_best_chain and generate_header_tree_and_best_chain returning (Tree<BlockHeader>, Chain); keep any_tree_of_headers delegating to the pair generator.
Headers Tree Tests
crates/amaru-consensus/src/consensus/headers_tree/headers_tree.rs
Add BRANCHING_RATIO constant and update proptest calls to the new any_select_chains parameter order.
Header Accessor
crates/amaru-ouroboros-traits/src/is_header/mod.rs
Add pub fn parent_hash(&self) -> Option<HeaderHash> on BlockHeader.
Test Runner Helper
crates/amaru-ouroboros-traits/src/is_header/tests.rs
Add run_with_rng<T, RNG: Rng>(rng: &mut RNG, s: impl Strategy<Value = T>) -> T to run proptest strategies with a fixed RNG seed.
Stage & Graph Tests
crates/amaru-consensus/src/consensus/stages/receive_header.rs, crates/amaru/src/stages/build_stage_graph.rs
Add decode_header round-trip test and TODOs in receive_header; change validation error handler to only log (no termination) and rename closure param to _eff.
Simulator Cargo Changes
simulation/amaru-sim/Cargo.toml
Make amaru-consensus dependency explicit with features = ["test-utils"]; add amaru-ouroboros-traits dependency with test-utils.
Simulator Args & NodeConfig
simulation/amaru-sim/src/simulator/args.rs, simulation/amaru-sim/src/simulator/node_config.rs
Remove file/path fields; add generated_chain_depth: u64, generated_chain_rollback_ratio: Ratio, generated_chain_branching_ratio: Ratio; parse Ratio via FromStr; add NodeConfig builder helpers and defaults.
Removed Legacy Chain & Ledger
simulation/amaru-sim/src/simulator/data_generation/chain.rs, simulation/amaru-sim/src/simulator/ledger.rs, simulation/amaru-sim/src/simulator/mod.rs, simulation/amaru-sim/src/simulator/data_generation/mod.rs
Delete chain-file parsing, Chain/Block structs and methods, fake stake/ledger population, tests, and module re-exports.
Data Generation Refactor
simulation/amaru-sim/src/simulator/data_generation/generate.rs
Replace file-based generation with action-based generator using any_select_chains + run_with_rng; generate_entries now returns a closure producing (Vec<Entry<ChainSyncMessage>>, Chain); add make_entry helper; build ChainSyncMessage Fwd/Bck from Actions.
Entry/Reverse Removal across Simulator
simulation/amaru-sim/src/echo/simulate.rs, simulation/amaru-sim/src/simulator/simulate.rs, simulation/amaru-sim/src/simulator/world/world.rs
Remove Reverse usage: generators return Vec<Entry<Msg>>; update simulate, test_nodes, create_failure_message, World::new, property callbacks, and History debug handling accordingly.
Run / Chain Validation Helpers
simulation/amaru-sim/src/simulator/run.rs
Add make_best_chain_from_downstream_messages(history) -> Chain; refactor validation to compare expected built chain with downstream-derived chain and adjust channel sizing; remove chain store population step.
ChainSync Message Enhancements
simulation/amaru-sim/src/sync/chain_sync_message.rs
Add decode_block_header() and header_hash() helpers; change Bck hash type to Bytes; enhance Debug output to include parent hash and abbreviated header.
Tests / Traces / Simulation args
simulation/amaru-sim/tests/simulation.rs, simulation/amaru-sim/tests/traces.rs
Update tests to use new Args fields (generated_chain_*), initialize Ratio values, adapt generator/property arity, and extend is_true truthy parsing.

Sequence Diagram(s)

sequenceDiagram
    %% Styling: subtle colored rects for clarity (renders in supporting viewers)
    participant Test
    participant Sim as Simulate
    participant Gen as Generator (closure)
    participant RNG as run_with_rng
    participant Select as any_select_chains
    participant MakeEntries as generate_entries (make_entry)
    participant World
    participant Property

    Test->>Sim: start simulate(...)
    Sim->>Gen: call generator(rng)
    Gen->>RNG: run_with_rng(rng, any_select_chains(peers_nb,...))
    RNG->>Select: request actions (peers_nb, depth, rollback/branching ratios, seed)
    Select-->>RNG: (Vec<Action>, Chain)  %% new: actions plus best-chain spine
    RNG-->>Gen: (Vec<Action>, Chain)
    Gen->>MakeEntries: translate Actions -> Vec<Entry<ChainSyncMessage>>
    MakeEntries-->>Gen: (Vec<Entry<ChainSyncMessage>>, Chain)  %% generator returns entries + context (Chain)
    Gen-->>Sim: (entries, generation_context)
    Sim->>World: feed entries
    World->>Property: property(&history, &generation_context)
    Property->>Property: derive actual chain from downstream messages
    Property->>Property: compare to generation_context (expected chain)
    Property-->>World: pass/fail
    World-->>Sim: result
    Sim-->>Test: pass/fail
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • abailly
  • stevana

Poem

🍀 A little refactor struts down the lane, Ratio hums its two-note song,
Actions march, entries smile — Reverse is gone, right where they belong.
Tests keep time like old arcade beats, headers spin a jaunty tune,
Merge it in, let CI nod — we’ll celebrate with tea and rune.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed Right, mate, let's break this down properly. The title "test: improve the data generation for the consensus simulation" is bang-on related to the main thrust of this PR—it's all about leveling up how chains are generated for testing. You've got the new Ratio parameters for branching and rollback, the whole action-based generator replacing the old file-based approach, and a completely reworked simulation pipeline. The title captures the core architectural shift without getting bogged down in the weeds, which is exactly what you want. It's concise, specific about the domain (data generation for consensus simulation), and doesn't throw around vague nonsense like "misc updates" or "stuff"—it's like a well-directed cutscene that gets you exactly where you need to be.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch etorreborre/test/run-simulation-tests-with-several-peers

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ee84b2 and 7e451ea.

📒 Files selected for processing (8)
  • crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (7 hunks)
  • crates/amaru-consensus/src/consensus/headers_tree/data_generation/data_generation.rs (4 hunks)
  • crates/amaru-consensus/src/consensus/headers_tree/headers_tree.rs (1 hunks)
  • simulation/amaru-sim/src/echo/simulate.rs (1 hunks)
  • simulation/amaru-sim/src/simulator/data_generation/generate.rs (1 hunks)
  • simulation/amaru-sim/src/simulator/run.rs (6 hunks)
  • simulation/amaru-sim/src/simulator/simulate.rs (7 hunks)
  • simulation/amaru-sim/tests/traces.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/amaru-consensus/src/consensus/headers_tree/headers_tree.rs
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-02-03T11:15:22.640Z
Learnt from: abailly
PR: pragma-org/amaru#75
File: crates/amaru/src/consensus/mod.rs:164-165
Timestamp: 2025-02-03T11:15:22.640Z
Learning: In the Amaru project, chain selection operations (roll_forward and rollback) should use separate result types to leverage the type system for preventing impossible states, rather than using runtime checks or panics.

Applied to files:

  • simulation/amaru-sim/src/simulator/run.rs
📚 Learning: 2025-08-12T12:28:24.027Z
Learnt from: etorreborre
PR: pragma-org/amaru#372
File: simulation/amaru-sim/src/simulator/mod.rs:410-412
Timestamp: 2025-08-12T12:28:24.027Z
Learning: In the Amaru project, panic statements are acceptable in simulation/test code (like amaru-sim crate) as they help identify configuration issues quickly during development, rather than needing proper error handling like production code.

Applied to files:

  • simulation/amaru-sim/src/simulator/run.rs
🧬 Code graph analysis (6)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/data_generation.rs (1)
crates/amaru-consensus/src/consensus/headers_tree/tree.rs (1)
  • make_leaf (53-61)
simulation/amaru-sim/src/echo/simulate.rs (2)
crates/pure-stage/src/time.rs (1)
  • at_offset (112-114)
simulation/amaru-sim/src/simulator/data_generation/base_generators.rs (3)
  • generate_zip_with (51-63)
  • generate_vec (23-33)
  • generate_arrival_times (67-84)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (1)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/data_generation.rs (1)
  • any_tree_of_headers_and_best_chain (38-44)
simulation/amaru-sim/tests/traces.rs (1)
simulation/amaru-sim/src/simulator/data_generation/generate.rs (1)
  • generate_entries (29-72)
simulation/amaru-sim/src/simulator/data_generation/generate.rs (8)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (2)
  • any_select_chains (392-408)
  • peer (191-196)
crates/amaru-ouroboros-traits/src/is_header/tests.rs (1)
  • run_with_rng (123-130)
simulation/amaru-sim/src/simulator/simulate_config.rs (2)
  • rand (31-31)
  • from (39-47)
simulation/amaru-sim/src/simulator/run.rs (3)
  • node_config (208-210)
  • new (314-325)
  • message (331-351)
simulation/amaru-sim/src/simulator/data_generation/base_generators.rs (1)
  • generate_arrival_times (67-84)
simulation/amaru-sim/src/echo/message.rs (1)
  • new (25-27)
simulation/amaru-sim/src/simulator/bytes.rs (3)
  • new (25-27)
  • from (57-59)
  • from (73-75)
simulation/amaru-sim/src/simulator/node_config.rs (1)
  • from (41-49)
simulation/amaru-sim/src/simulator/run.rs (2)
simulation/amaru-sim/src/simulator/data_generation/generate.rs (1)
  • generate_entries (29-72)
simulation/amaru-sim/src/sync/chain_sync_message.rs (1)
  • header_hash (68-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: clippy
  • GitHub Check: Benches
  • GitHub Check: Build wasm32
  • GitHub Check: Build riscv32
  • GitHub Check: Build x86_64/windows
  • GitHub Check: Test the CLI
  • GitHub Check: Build aarch64/macos
  • GitHub Check: Build x86_64/linux
  • GitHub Check: Build aarch64/linux
  • GitHub Check: End-to-end snapshot tests (preprod, 1, 10.1.4)
  • GitHub Check: Test coverage
  • GitHub Check: Analyze (rust)
🔇 Additional comments (22)
simulation/amaru-sim/src/echo/simulate.rs (2)

72-92: LGTM! Clean API alignment.

The shift from Vec<Reverse<Entry<...>>> to (Vec<Entry<...>>, ()) is spot on—removes the wrapper and sets up the generator API for downstream context propagation. The unit () as the second tuple element keeps things tidy for now while matching the new signature pattern across the codebase.


97-100: LGTM! Signature consistency maintained.

Adding the unused _generation_context parameter keeps echo_property aligned with the new callback interface across the simulation framework. The underscore prefix makes it crystal clear it's a placeholder.

simulation/amaru-sim/src/simulator/data_generation/generate.rs (1)

29-72: LGTM! Solid action-based generation flow.

The refactor from file-based to action-based generation is mint—using any_select_chains with run_with_rng gives you reproducible, property-driven data. The mapping from Action variants to ChainSyncMessage is straightforward, and returning the best_chain alongside entries sets up downstream validation nicely.

simulation/amaru-sim/tests/traces.rs (3)

34-36: LGTM! Test config updated correctly.

The new generated_chain_* fields align with the shifted generation model—using Ratio(1, 2) gives you 50% rollback and branching probabilities, which is a fair middle ground for testing.


52-58: LGTM! Generator wiring updated.

The destructuring of (entries, best_chain) from generate_entries is spot on, and limiting to .take(1) keeps the trace test minimal. The best_chain is propagated correctly for downstream validation.


67-67: LGTM! Property signature updated.

The property callback now accepts &Chain to match the new simulate API. Since this test is just validating trace structure (not chain correctness), leaving both params unused is fair enough.

crates/amaru-consensus/src/consensus/headers_tree/data_generation/data_generation.rs (5)

38-44: LGTM! Clean proptest strategy addition.

The new any_tree_of_headers_and_best_chain gives you a proper strategy that yields both the tree and its spine. Mapping over seed values to generate deterministic outputs is the right pattern for property testing.


47-52: LGTM! Backward compatibility maintained.

Updating any_tree_of_headers to delegate to the new _and_best_chain variant and then discard the chain keeps existing call sites happy—nice non-breaking evolution of the API.


58-70: LGTM! Spine construction is solid.

Generating the subtree spine and then inserting the root at the front (line 68) gives you the complete best chain—straightforward and correct.


74-76: LGTM! Clean delegation.

Refactoring generate_header_tree to call generate_header_tree_and_best_chain and return just the tree (.0) keeps existing callers working—tidy backward compatibility.


87-117: LGTM! Spine tracking implemented correctly.

Returning spine at line 116 after building it through the chain generation is spot on. The recursive calls at line 113 for branches correctly discard their spines—you only track the main spine, not the side branches.

simulation/amaru-sim/src/simulator/run.rs (2)

164-167: LGTM! Channel sizing adjusted appropriately.

Sizing the channel to 10 * number_of_downstream_peers makes sense—each forward event gets duplicated per peer, so you need headroom proportional to the peer count. The comment explains the rationale clearly.


237-251: LGTM! Chain validation property updated.

The property now validates that the downstream-derived chain matches the expected best chain from generation—solid integration. The assertion at lines 244-248 includes helpful context (both chains plus history) for debugging failures.

crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (6)

319-323: LGTM! Clean Display impl.

Simple and correct—formats as "numerator/denominator", which aligns with the FromStr parsing.


325-351: LGTM! All validation from past review implemented.

The FromStr impl includes all the guards suggested in the previous review:

  • Format validation (line 330-331)
  • Denominator > 0 check (line 340-341)
  • Numerator ≤ denominator check (line 343-347)

Descriptive error messages for each case make debugging parse failures straightforward. Past review concern fully addressed.


392-408: LGTM! Strategy expanded to return best chain.

Adding peers_nb and branching_ratio params and returning (Vec<Action>, Chain) sets up the generation flow to provide the expected best chain for validation. The integration with any_tree_of_headers_and_best_chain is clean.


523-523: LGTM! Type alias promoted to public.

Making Chain public is necessary for the new APIs that return it (any_select_chains, generate_header_tree_and_best_chain, etc.). Clean type alias.


656-666: LGTM! Good coverage of valid cases.

Testing "3/4", "0/1", and "1/1" covers typical and boundary-valid ratios. Nice one.


668-684: LGTM! Comprehensive error validation.

Testing all the failure modes—bad format, non-numeric parts, zero denominator, and ratio > 1.0—gives you solid confidence that invalid inputs are caught with clear messages. Ripper testing coverage!

simulation/amaru-sim/src/simulator/simulate.rs (3)

49-75: LGTM! Clean context propagation through pipeline.

Adding GenerationContext as a generic and threading it from generator → test_nodes → property is spot on. The destructuring at line 64 and propagation at lines 67-72 keep the flow clear. Log statements at lines 65 and 74 add useful visibility into test execution.


116-145: LGTM! test_nodes wired up correctly.

The GenerationContext parameter and updated property signature are consistent with the simulate changes. Passing generation_context to the property at line 139 completes the pipeline.


149-200: LGTM! Entry type cleanup.

Switching from Vec<Reverse<Entry<Msg>>> to Vec<Entry<Msg>> and updating the access pattern from entry.0.envelope to entry.envelope (line 161) simplifies the code. The Reverse wrapper is well gone!


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai

coderabbitai Bot commented Oct 17, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@etorreborre etorreborre force-pushed the etorreborre/test/run-simulation-tests-with-several-peers branch 3 times, most recently from 190584b to 0fc993c Compare October 17, 2025 08:27
@etorreborre etorreborre marked this pull request as ready for review October 17, 2025 08:40
@etorreborre etorreborre self-assigned this Oct 17, 2025
@etorreborre etorreborre requested a review from abailly October 17, 2025 08:41

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
simulation/amaru-sim/src/simulator/world/world.rs (1)

46-65: Critical: Ord/PartialEq/Eq inconsistency on Entry can corrupt heap ordering.

cmp only uses arrival_time, but PartialEq (derived) compares arrival_time + envelope. If two different envelopes share the same time, cmp == Equal while eq == false. That breaks the Ord/Eq contract and can trigger weird BinaryHeap behaviour. Like trying to do a photo finish with two Marios but only timing one.

Minimal fix: make equality match ordering (arrival_time-only). Example patch:

-#[derive(Debug, Clone, PartialEq, Serialize)]
+#[derive(Debug, Clone, Serialize)]
 pub struct Entry<Msg> {
   pub arrival_time: Instant,
   pub envelope: Envelope<Msg>,
 }
 
-impl<Msg: PartialEq> PartialOrd for Entry<Msg> {
+impl<Msg> PartialOrd for Entry<Msg> {
   fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
     Some(self.cmp(other))
   }
 }
 
-impl<Msg: PartialEq> Ord for Entry<Msg> {
+impl<Msg> Ord for Entry<Msg> {
   fn cmp(&self, other: &Self) -> Ordering {
     self.arrival_time.cmp(&other.arrival_time)
   }
 }
 
-impl<Msg: PartialEq> Eq for Entry<Msg> {}
+impl<Msg> PartialEq for Entry<Msg> {
+  fn eq(&self, other: &Self) -> bool {
+    self.arrival_time == other.arrival_time
+  }
+}
+
+impl<Msg> Eq for Entry<Msg> {}

If you need stable tie‑breaks, consider adding a monotonic seq field and ordering by (arrival_time, seq).

crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (1)

107-112: decode_hash panics on invalid length; return an error instead

copy_from_slice will panic if the decoded hex isn’t exactly HEADER_HASH_SIZE bytes. That’s a sneaky footgun when deserializing JSON. Let’s fail gracefully.

Apply:

 fn decode_hash(s: &str) -> Result<HeaderHash, FromHexError> {
     let bytes = hex::decode(s)?;
-    let mut arr = [0u8; HEADER_HASH_SIZE];
-    arr.copy_from_slice(&bytes);
-    Ok(Hash::from(arr))
+    if bytes.len() != HEADER_HASH_SIZE {
+        return Err(FromHexError::InvalidStringLength);
+    }
+    let mut arr = [0u8; HEADER_HASH_SIZE];
+    arr.copy_from_slice(&bytes);
+    Ok(Hash::from(arr))
 }
🧹 Nitpick comments (14)
crates/amaru-ouroboros-traits/src/is_header/mod.rs (1)

138-140: G'day mate! Spotted a bit of déjà vu here – like seeing the same NPC twice in an open world game.

This new parent_hash() method is doing the exact same thing as the parent() method down on lines 183-185, both pulling from self.header.header_body.prev_hash. Now, I reckon there might be a solid reason for this – maybe you want folks to access the parent hash without needing the IsHeader trait in scope, which is fair dinkum for ergonomics. Or perhaps parent_hash just reads clearer than parent in the API, like how "The Fellowship of the Ring" is more specific than just "The Fellowship", yeah?

But if there's no specific reason for the duplication, you might wanna consider either:

  • Using parent_hash() as the canonical accessor and having parent() delegate to it, or
  • Sticking with just the trait method if that's sufficient

Just flagging it so the API stays clean and future maintainers don't scratch their heads wondering which one to use!

crates/amaru/src/stages/build_stage_graph.rs (1)

60-66: Ripper change, mate! Validation errors now take the 'catch and release' approach.

This shift from termination to log-and-continue for validation errors is spot-on with your PR goals. Like a good bouncer at a pub, you're now letting the node stay up while just noting the troublemakers in the logbook. The distinction between validation failures (log it) and processing failures (nuke the whole graph) is clearer than a Sydney summer day.

However, that TODO on line 64 is a bit of a ticking time bomb, innit? Without disconnecting dodgy peers, you've basically got a 'Dark Souls' situation where the same enemy keeps respawning and having a go at you. A malicious peer could spam validation errors and fill your logs faster than a cafe hipster fills their Instagram feed with latte art.

Suggested follow-ups:

  1. Track the peer disconnection work: That TODO needs to be actioned soon to prevent bad actors from exploiting the lack of consequences. Want me to open an issue to track this as priority work, or do you already have it sorted?

  2. Consider adding observability (optional/nice-to-have): Right now you're just logging, but adding a counter or metric for validation errors would be ace for monitoring. Something like:

async |_, error: ValidationFailed, _eff| {
    tracing::error!(%error, "stage error");
    // Optional: track validation error metrics
    // metrics::counter!("consensus.validation_errors").increment(1);
    // TODO: disconnect bad behaving peers
}

This would give you that sweet, sweet Prometheus data to catch issues before they become proper dramas.

crates/amaru-ouroboros-traits/src/is_header/tests.rs (1)

120-130: Nice little helper function here, but could use a touch more clarity in the docs!

The implementation looks solid as—mirrors the existing run pattern and uses proptest's fixed seed API correctly. Love that it keeps RNG-driven tests deterministic, like quicksaving before a boss fight.

Just one tiny thing: the doc comment says "seed provided by a random generator", which might confuse folks into thinkin' the RNG drives generation directly. What's actually happenin' is you're usin' the RNG to generate one seed value, then proptest's TestRunner uses that fixed seed internally. Might be worth clarifying that in the docs, or even tossin' in a wee usage example.

Optional doc improvement:

-/// Run a strategy with a seed provided by a random generator
-/// and return the generated value, panicking if generation fails.
+/// Run a strategy with a fixed seed derived from the given RNG.
+/// The RNG is used to generate a deterministic seed for proptest's TestRunner,
+/// ensuring reproducible test data generation. Panics if generation fails.
+///
+/// # Example
+/// ```ignore
+/// let mut rng = rand::thread_rng();
+/// let header = run_with_rng(&mut rng, any_header());
+/// ```
simulation/amaru-sim/Cargo.toml (1)

38-39: Bold move flipping on test-utils for consensus and traits. Looks good for the sim binary, but mind the cargo feature avalanche, mate.

  • If these helpers aren’t needed at runtime, consider gating behind a sim-only feature to keep compile times lean when building other bins.
  • Also, you’ve got rand in both dependencies (Line 25) and dev-dependencies (Line 46); consider consolidating later.
simulation/amaru-sim/src/simulator/world/world.rs (2)

72-79: Custom Debug for History prints one message per line. Sweet for eyeballing, but a bit spartan for log parsers.

Optional: prefix with History(len = N): and wrap in brackets to make it grep‑friendly.


128-130: Heap dump at debug level can be chonky as a Morrowind mod list.

Suggest: move heap = ?self.heap to trace or gate behind a verbose flag.

simulation/amaru-sim/tests/simulation.rs (2)

83-86: is_true accepting "true" is a nice touch. Consider case-insensitive and more truthy tokens ("yes", "on") for friendlier DX.

Example:

-fn is_true(var_name: &str) -> bool {
-    env::var(var_name).is_ok_and(|v| v == "1" || v == "true")
-}
+fn is_true(var_name: &str) -> bool {
+    env::var(var_name)
+        .map(|v| v.trim().to_ascii_lowercase())
+        .map(|v| v == "1" || v == "true" || v == "yes" || v == "on")
+        .unwrap_or(false)
+}

39-50: Spot on—whitespace handling and input robustness are the real MVPs here.

Your original review nailed it, mate. Here's what I found:

  1. Whitespace footgun is legit: get_env_var (line 71) calls parse() directly without trimming. If someone accidentally sets AMARU_GENERATED_CHAIN_ROLLBACK_RATIO=" 1/2 " (with spaces), it silently falls back to the default instead of erroring. Like a roguelike where you don't realise you've walked into a trap until it's too late.

  2. Ratio format needs docs: The FromStr impl (line 328–340) expects strict "numerator/denominator" format but it's nowhere documented. A quick README note would save future devs the head-scratching.

  3. is_true is case-sensitive: The function (line 84–86) only matches "1" or "true" exactly. Doesn't handle "True", "TRUE", or whitespace. Could be friendlier.

These aren't critical bugs, but they're solid quality-of-life wins—the difference between smooth UX and "why didn't my config work?"


Consider adding:

  • .trim() in get_env_var before parsing (line 72–74)
  • Similar trim in is_true and make it case-insensitive
  • Document Ratio format in test README
simulation/amaru-sim/src/sync/chain_sync_message.rs (1)

52-65: Decode fallback to plain Header for sturdier Debugging

Nice helper, mate. For robustness, try decoding a plain Header if MintedHeader decoding fails, so Debug still shows parent_hash when headers are serialized without the mint wrapper.

Apply this minimal fallback:

 pub fn decode_block_header(&self) -> Option<BlockHeader> {
     match self {
         ChainSyncMessage::Fwd { header, .. } => {
-            if let Ok(minted_header) = cbor::decode::<MintedHeader<'_>>(&header.bytes) {
-                Some(BlockHeader::from(Header::from(minted_header)))
-            } else {
-                None
-            }
+            if let Ok(minted_header) = cbor::decode::<MintedHeader<'_>>(&header.bytes) {
+                Some(BlockHeader::from(Header::from(minted_header)))
+            } else if let Ok(hdr) = cbor::decode::<Header>(&header.bytes) {
+                Some(BlockHeader::from(hdr))
+            } else {
+                None
+            }
         }
         _ => None,
     }
 }
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (2)

289-301: Defensive use of random_ratio

Even with input validation, a debug assert helps future refactors, and clamping avoids UB in tests.

Apply:

-        if rng.random_ratio(rollback_ratio.0, rollback_ratio.1)
+        debug_assert!(rollback_ratio.1 > 0, "Ratio denominator must be > 0");
+        let num = rollback_ratio.0.min(rollback_ratio.1);
+        if rng.random_ratio(num, rollback_ratio.1)
             && let Some(actions) = result.get_mut(peer)
         {

517-550: Indexing best_chains[0] is safe today; add a tiny guard

It’s currently safe because there’s always at least one chain, but an assert makes that invariant explicit and future‑proof.

Apply:

-        let best_chains = current_chains
+        let best_chains = current_chains
             .clone()
             .into_values()
             .filter(|c| c.len() == best_length)
             .collect::<Vec<Chain>>();
+        debug_assert!(!best_chains.is_empty());
         current_chains.insert(Me, best_chains[0].clone());
simulation/amaru-sim/src/simulator/data_generation/generate.rs (2)

48-69: Minor nits: avoid clone, use Bytes::from for consistency

Tidy ups: no behavior change, just smoother edges.

Apply:

-                Action::RollForward { header, .. } => ChainSyncMessage::Fwd {
+                Action::RollForward { header, .. } => ChainSyncMessage::Fwd {
                     msg_id,
                     slot: Slot::from(header.slot()),
-                    hash: Bytes {
-                        bytes: header.hash().to_vec(),
-                    },
-                    header: Bytes {
-                        bytes: to_cbor(&header),
-                    },
+                    hash: Bytes::from(header.hash().to_vec()),
+                    header: Bytes::from(to_cbor(&header)),
                 },
                 Action::RollBack { rollback_point, .. } => ChainSyncMessage::Bck {
                     msg_id,
                     slot: rollback_point.slot_or_default(),
-                    hash: Bytes::from(rollback_point.hash().to_vec()),
+                    hash: Bytes::from(rollback_point.hash().to_vec()),
                 },
             };
-            messages.push(make_entry(action.peer(), arrival_time, message));
+            messages.push(make_entry(action.peer(), arrival_time, message));

And:

-            src: format!("c{}", peer.name.clone()),
+            src: format!("c{}", peer.name),

74-83: Destination hard-coded to "n1"

If number_of_nodes > 1, this might route messages to the wrong node. Is the generator only used in single-node sims? If not, thread the NodeId or let caller set dest.

Happy to sketch a small patch to parameterize dest.

simulation/amaru-sim/src/simulator/run.rs (1)

284-286: Silent failures on decode could hide bugs.

When decode_block_header() or header_hash() return None, you're silently skipping those entries. In a test simulation, you probably want to know if decoding is failing - it could indicate data corruption or a bug in the generation logic.

Consider logging or counting decode failures:

             msg @ ChainSyncMessage::Fwd { .. } => {
-                // make sure to skip headers that cannot be decoded
-                if let Some(header) = msg.decode_block_header() {
+                match msg.decode_block_header() {
+                    Some(header) => {
                     chain.push(header);
+                    }
+                    None => {
+                        warn!("Failed to decode header from peer {}: {:?}", message.src, msg);
+                    }
                 }
             }

Also applies to: 290-295

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a9804a and 0fc993c.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (21)
  • crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (4 hunks)
  • crates/amaru-consensus/src/consensus/headers_tree/headers_tree.rs (1 hunks)
  • crates/amaru-consensus/src/consensus/stages/receive_header.rs (2 hunks)
  • crates/amaru-ouroboros-traits/src/is_header/mod.rs (1 hunks)
  • crates/amaru-ouroboros-traits/src/is_header/tests.rs (2 hunks)
  • crates/amaru/src/stages/build_stage_graph.rs (1 hunks)
  • simulation/amaru-sim/Cargo.toml (1 hunks)
  • simulation/amaru-sim/src/echo/simulate.rs (1 hunks)
  • simulation/amaru-sim/src/simulator/args.rs (2 hunks)
  • simulation/amaru-sim/src/simulator/data_generation/chain.rs (0 hunks)
  • simulation/amaru-sim/src/simulator/data_generation/generate.rs (1 hunks)
  • simulation/amaru-sim/src/simulator/data_generation/mod.rs (0 hunks)
  • simulation/amaru-sim/src/simulator/ledger.rs (0 hunks)
  • simulation/amaru-sim/src/simulator/mod.rs (0 hunks)
  • simulation/amaru-sim/src/simulator/node_config.rs (2 hunks)
  • simulation/amaru-sim/src/simulator/run.rs (6 hunks)
  • simulation/amaru-sim/src/simulator/simulate.rs (7 hunks)
  • simulation/amaru-sim/src/simulator/world/world.rs (3 hunks)
  • simulation/amaru-sim/src/sync/chain_sync_message.rs (3 hunks)
  • simulation/amaru-sim/tests/simulation.rs (2 hunks)
  • simulation/amaru-sim/tests/traces.rs (3 hunks)
💤 Files with no reviewable changes (4)
  • simulation/amaru-sim/src/simulator/data_generation/mod.rs
  • simulation/amaru-sim/src/simulator/mod.rs
  • simulation/amaru-sim/src/simulator/ledger.rs
  • simulation/amaru-sim/src/simulator/data_generation/chain.rs
🧰 Additional context used
🧬 Code graph analysis (11)
crates/amaru-consensus/src/consensus/stages/receive_header.rs (2)
crates/amaru-ouroboros-traits/src/is_header/mod.rs (2)
  • header (130-132)
  • point (37-39)
crates/amaru-ouroboros-traits/src/is_header/tests.rs (1)
  • any_header (77-86)
crates/amaru-consensus/src/consensus/headers_tree/headers_tree.rs (2)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/property_configuration.rs (4)
  • config_begin (55-64)
  • no_shrink (32-35)
  • with_cases (38-41)
  • end (50-52)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (1)
  • any_select_chains (382-392)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (1)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/data_generation.rs (1)
  • any_tree_of_headers (37-42)
simulation/amaru-sim/src/simulator/world/world.rs (1)
simulation/amaru-sim/src/simulator/world/node_handle.rs (1)
  • new (37-48)
simulation/amaru-sim/src/simulator/simulate.rs (2)
simulation/amaru-sim/src/simulator/world/world.rs (1)
  • fmt (73-78)
simulation/amaru-sim/src/simulator/run.rs (1)
  • entries (246-249)
simulation/amaru-sim/tests/simulation.rs (1)
simulation/amaru-sim/src/simulator/run.rs (1)
  • node_config (211-213)
simulation/amaru-sim/src/sync/chain_sync_message.rs (2)
crates/amaru-ouroboros-traits/src/is_header/mod.rs (8)
  • decode (158-161)
  • header (130-132)
  • from (165-170)
  • hash (34-34)
  • hash (111-113)
  • hash (179-181)
  • hash (201-203)
  • parent_hash (138-140)
simulation/amaru-sim/src/simulator/bytes.rs (2)
  • from (57-59)
  • from (73-75)
simulation/amaru-sim/src/echo/simulate.rs (2)
crates/pure-stage/src/time.rs (1)
  • at_offset (112-114)
simulation/amaru-sim/src/simulator/data_generation/base_generators.rs (3)
  • generate_zip_with (51-63)
  • generate_vec (23-33)
  • generate_arrival_times (67-84)
simulation/amaru-sim/src/simulator/args.rs (1)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (1)
  • from_str (328-340)
simulation/amaru-sim/src/simulator/data_generation/generate.rs (6)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (2)
  • any_select_chains (382-392)
  • peer (191-196)
crates/amaru-ouroboros-traits/src/is_header/tests.rs (1)
  • run_with_rng (123-130)
simulation/amaru-sim/src/simulator/run.rs (3)
  • node_config (211-213)
  • new (368-379)
  • message (385-405)
simulation/amaru-sim/src/simulator/data_generation/base_generators.rs (1)
  • generate_arrival_times (67-84)
simulation/amaru-sim/src/simulator/world/world.rs (1)
  • new (83-97)
simulation/amaru-sim/src/simulator/node_config.rs (1)
  • from (41-49)
simulation/amaru-sim/src/simulator/run.rs (2)
simulation/amaru-sim/src/simulator/data_generation/generate.rs (1)
  • generate_entries (29-72)
simulation/amaru-sim/src/sync/chain_sync_message.rs (1)
  • header_hash (68-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Test the CLI
  • GitHub Check: Benches
  • GitHub Check: Build x86_64/windows
  • GitHub Check: Build x86_64/linux
  • GitHub Check: Test coverage
  • GitHub Check: Build riscv32
  • GitHub Check: Build aarch64/macos
  • GitHub Check: Build aarch64/linux
  • GitHub Check: End-to-end snapshot tests (preprod, 1, 10.1.4)
🔇 Additional comments (18)
crates/amaru-consensus/src/consensus/stages/receive_header.rs (1)

246-253: Solid round-trip test, legend!

This test is dead simple and does exactly what's on the tin – generates a header, serializes it, deserializes it, and makes sure we get back what we started with. Perfect for catching any CBOR encoding gremlins that might sneak in. Aligns beautifully with the PR's vibe of beefing up the data generation testing.

Bonus XP opportunity: if you implement that TODO from lines 47-48, you could extend this test to also verify that decoded.point() == point to ensure the point extraction logic is consistent. But honestly, this test already does its job well, so no worries either way, cobber!

simulation/amaru-sim/src/echo/simulate.rs (2)

72-91: Spot on—verified and locked in, mate!

The verification came back clean as a whistle. No callers of echo_generator showed up in the search, which means this change is totally isolated and self-contained—like a perfectly crafted side quest that doesn't affect the main storyline. The Reverse wrapper isn't lurking anywhere else in the codebase either, so you've got no ripple effects to worry about.

This is exactly the kind of straightforward cleanup that makes code sing. The simplified signature plays nice with the rest of the system, and the direct Entry construction is chef's kiss for readability.

All good to merge, legend.


96-99: Add a comment explaining the _entries parameter or remove it if unnecessary.

The underscore prefix is intentional (Rust's standard marker for unused parameters), but there's no trait enforcing this signature across the codebase—unlike chain_property which actually uses its entries parameter. The TODO comment about response time suggests this might be reserved for future validation logic.

Either add a brief doc comment like // Reserved for response time validation to signal intent to future maintainers, or drop the parameter entirely if it's not part of any planned work. Right now it's like leaving a placeholder in a game level that never got populated.

crates/amaru-ouroboros-traits/src/is_header/tests.rs (1)

15-18: G'day, mate—false alarm on that Rng trait!

Ya see, line 16 already has use proptest::prelude::*; which pulls in the Rng trait from the rand crate through proptest's prelude. That's your golden ticket right there. The function signature and implementation at lines 123-130 are solid as—it's using the trait bound correctly with rng.random() and all that. No compilation drama here, legend.

Likely an incorrect or invalid review comment.

simulation/amaru-sim/src/simulator/world/world.rs (1)

84-93: Nice ergonomics: accepting Vec<Entry> and doing the Reverse wrap internally. Cleaner API, fewer call-site papercuts. LGTM.

simulation/amaru-sim/tests/traces.rs (1)

34-37: New generated_chain_* knobs and Ratio usage look tidy. Depth=1 keeps this as a quick smoke test; no objections.

crates/amaru-consensus/src/consensus/headers_tree/headers_tree.rs (1)

1287-1293: Now I'll search directly in the codebase to verify the argument order:The web searches aren't helping—I need to grep the actual codebase directly. Let me search for constants and all call sites in the repo.

Based on the script output provided initially, I now have what I need to verify the issue. Let me finalize my analysis:

From the script results:

  • Function signature: pub fn any_select_chains(peers_nb: usize, depth: usize, rollback_ratio: Ratio, branching_ratio: Ratio)
  • Call at line 1292: any_select_chains(DEPTH, 5, ROLLBACK_RATIO, BRANCHING_RATIO)

This means:

  • peers_nb is receiving DEPTH
  • depth is receiving 5

The review comment claims this is likely swapped. Without being able to directly access the DEPTH constant definition or other call sites to understand the intent, the review's concern is based on the semantic oddity that typically in blockchain testing, the "depth" parameter (chain depth) would be larger than the "peers" parameter. A depth of 5 seems shallow, while DEPTH (likely 10 based on the review's parenthetical) would be more typical for depth.

However, without definitive evidence from the codebase showing:

  1. The exact value of DEPTH
  2. Other correct usages of any_select_chains for comparison
  3. The semantic intent of the function

I cannot conclusively prove the arguments are swapped. This requires manual developer verification.


Fix the argument order in the proptest call.

The function signature is any_select_chains(peers_nb, depth, rollback_ratio, branching_ratio), but the call at line 1292 passes any_select_chains(DEPTH, 5, ROLLBACK_RATIO, BRANCHING_RATIO), which maps peers to DEPTH and depth to 5. This appears semantically inverted—chain depth testing typically uses a larger depth value. Swap to any_select_chains(5, DEPTH, ROLLBACK_RATIO, BRANCHING_RATIO) to align peers and depth logically.

simulation/amaru-sim/src/sync/chain_sync_message.rs (1)

67-74: Ensure hash byte length is always HEADER_HASH_SIZE

HeaderHash::from(hash.bytes.as_slice()) assumes the slice has the exact size. If any caller sends fewer/more bytes, you might get unexpected behavior. Please confirm all producers always supply 32 bytes; if not, gate this with a length check or TryFrom.

simulation/amaru-sim/src/simulator/node_config.rs (1)

23-36: Config surface looks good; builder API reads clean

Defaults and the new builder methods make it easy to tweak generation without carting around a kitchen sink. No blockers here.

Also applies to: 45-48, 61-74

simulation/amaru-sim/src/simulator/args.rs (1)

40-51: CLI ratios: confirm invalid inputs are rejected

value_parser = Ratio::from_str is spot on. With the suggested Ratio validation, “1/0” or “5/3” will cleanly error at parse time. Once you wire that in, we’re golden.

simulation/amaru-sim/src/simulator/run.rs (5)

18-20: Imports look solid, mate!

All the new imports are actually used in the code below. Nice and tidy - no orphaned imports hanging about like a dingo at a barbie.

Also applies to: 32-32, 43-43, 52-52


84-84: Good call using the new chain property!

This hooks up the new validation logic nicely. The function signature below matches what simulate expects.


167-170: Nice fix for the multi-peer scenario!

Scaling the channel by downstream peer count is spot-on. This directly addresses the "fixes a bug to allow simulation to run with multiple downstream peers" from the PR description. The comment explains it well too.


240-261: Righteous chain validation logic!

The property correctly builds the expected chain from upstream and compares it to the actual downstream chain. The error messages are comprehensive - you'll know exactly what went wrong if this fails. Like having a GPS and a paper map, just to be sure.


327-334: Detailed assertion message - good on ya!

The assertion provides excellent debugging context including the action number, hash, chain state, and full history. This will make failures much easier to diagnose. Much better than a generic "assertion failed" message.

simulation/amaru-sim/src/simulator/simulate.rs (3)

52-53: Clean removal of the Reverse wrapper!

The signature updates are spot-on:

  • Property now receives both entries and history for comparison (matching run.rs's chain_property)
  • Removed Reverse wrapper throughout - simpler is better
  • Added Serialize bound for message persistence
  • Bonus info log at line 65 for debugging

All consistent with the PR's goal to simplify entry handling.

Also applies to: 58-58, 64-65


68-71: Property plumbing is wired up correctly.

The flow from entriestest()property(entries, history) is consistent throughout. The signature updates all match, no loose ends. Like a proper cable management job - everything connected right.

Also applies to: 114-115, 133-133


146-146: Cleaner entry access - no more tuple unwrapping.

Accessing entry.envelope directly is more readable than the old entry.0.envelope pattern. The Reverse wrapper is fully gone, and the code reads better for it.

Also applies to: 155-155

Comment thread crates/amaru-consensus/src/consensus/stages/receive_header.rs
Comment thread simulation/amaru-sim/src/simulator/data_generation/generate.rs Outdated
Comment thread simulation/amaru-sim/src/simulator/run.rs Outdated
Comment thread simulation/amaru-sim/src/simulator/run.rs Outdated
Comment thread simulation/amaru-sim/src/simulator/run.rs
Comment thread simulation/amaru-sim/src/simulator/run.rs Outdated
@codecov

codecov Bot commented Oct 17, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.42857% with 38 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
simulation/amaru-sim/src/simulator/node_config.rs 33.33% 12 Missing ⚠️
simulation/amaru-sim/src/simulator/run.rs 76.31% 9 Missing ⚠️
...imulation/amaru-sim/src/sync/chain_sync_message.rs 77.14% 8 Missing ⚠️
simulation/amaru-sim/src/simulator/world/world.rs 64.28% 5 Missing ⚠️
.../consensus/headers_tree/data_generation/actions.rs 94.82% 3 Missing ⚠️
crates/amaru/src/stages/build_stage_graph.rs 0.00% 1 Missing ⚠️
Files with missing lines Coverage Δ
...us/headers_tree/data_generation/data_generation.rs 100.00% <100.00%> (ø)
...nsensus/src/consensus/headers_tree/headers_tree.rs 89.70% <ø> (ø)
...u-consensus/src/consensus/stages/receive_header.rs 97.61% <100.00%> (+0.10%) ⬆️
crates/amaru-ouroboros-traits/src/is_header/mod.rs 74.73% <100.00%> (+0.82%) ⬆️
...ates/amaru-ouroboros-traits/src/is_header/tests.rs 87.05% <100.00%> (+1.34%) ⬆️
simulation/amaru-sim/src/echo/simulate.rs 73.97% <100.00%> (+0.36%) ⬆️
...maru-sim/src/simulator/data_generation/generate.rs 100.00% <100.00%> (ø)
simulation/amaru-sim/src/simulator/simulate.rs 81.12% <100.00%> (+0.80%) ⬆️
crates/amaru/src/stages/build_stage_graph.rs 91.86% <0.00%> (+1.05%) ⬆️
.../consensus/headers_tree/data_generation/actions.rs 79.03% <94.82%> (+1.91%) ⬆️
... and 4 more

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Signed-off-by: etorreborre <etorreborre@yahoo.com>
…ny downstream peers

Signed-off-by: etorreborre <etorreborre@yahoo.com>
Signed-off-by: etorreborre <etorreborre@yahoo.com>
Signed-off-by: etorreborre <etorreborre@yahoo.com>
Signed-off-by: etorreborre <etorreborre@yahoo.com>

| Conflicts:
|	simulation/amaru-sim/src/simulator/run.rs
Signed-off-by: etorreborre <etorreborre@yahoo.com>
Signed-off-by: etorreborre <etorreborre@yahoo.com>
Signed-off-by: etorreborre <etorreborre@yahoo.com>
Signed-off-by: etorreborre <etorreborre@yahoo.com>
Signed-off-by: etorreborre <etorreborre@yahoo.com>

| Conflicts:
|	simulation/amaru-sim/src/simulator/args.rs
|	simulation/amaru-sim/src/simulator/ledger.rs
|	simulation/amaru-sim/src/simulator/node_config.rs
Signed-off-by: etorreborre <etorreborre@yahoo.com>
Signed-off-by: etorreborre <etorreborre@yahoo.com>
Signed-off-by: etorreborre <etorreborre@yahoo.com>
Signed-off-by: etorreborre <etorreborre@yahoo.com>
Signed-off-by: etorreborre <etorreborre@yahoo.com>
@etorreborre etorreborre force-pushed the etorreborre/test/run-simulation-tests-with-several-peers branch from 4c2603b to 7ee84b2 Compare October 17, 2025 16:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (3)
simulation/amaru-sim/src/simulator/run.rs (3)

273-275: Hardcoded peer prefix again.

src.starts_with("c") is brittle; centralise the predicate or make it configurable.


300-308: Deterministic tie-breaker for equally long chains.

Picking best_chain[0] after collecting into a Vec depends on map order. Use a stable min-by key (e.g., peer id) to keep runs reproducible.

-        let best_chain = current_chains
-            .clone()
-            .into_values()
-            .filter(|c| c.len() == best_length)
-            .collect::<Vec<Chain>>();
-        current_chains.insert(best_chain_tracker.clone(), best_chain[0].clone());
+        if let Some((_, chain)) = current_chains
+            .iter()
+            .filter(|(_, c)| c.len() == best_length)
+            .min_by_key(|(peer_id, _)| *peer_id)
+        {
+            current_chains.insert(best_chain_tracker.clone(), chain.clone());
+        }

317-319: “c1” special-casing is fragile.

Filtering on dest.starts_with("c1") assumes a naming convention. Pass the target downstream peer id via config or a predicate instead.

🧹 Nitpick comments (7)
simulation/amaru-sim/src/simulator/world/world.rs (3)

72-79: Use debug_list() for cleaner, faster History formatting.

Current impl writes each line manually; fmt::Debug idiomatically uses f.debug_list(). Simpler and avoids an extra trailing newline.

 impl<Msg: Debug> Debug for History<Msg> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        for message in &self.0 {
-            writeln!(f, "{message:?}")?;
-        }
-        Ok(())
-    }
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        f.debug_list().entries(&self.0).finish()
+    }
 }

128-130: Dial back heap logging; it’s a lot of bytes for a debug line.

Dumping the entire BinaryHeap each step can be hefty and noisy. Log the size instead, or gate behind trace.

-                debug!(msg = ?envelope, arrival = ?arrival_time, heap = ?self.heap, "stepping");
+                debug!(msg = ?envelope, arrival = ?arrival_time, heap_len = self.heap.len(), "stepping");

135-154: Centralise “client” detection to avoid drift.

Here you use dest.starts_with("c"), elsewhere is_client_message(). Pull this into a single helper (e.g., Envelope::is_client_dest()), or reuse the same predicate in both spots for consistency.

simulation/amaru-sim/src/simulator/args.rs (1)

45-50: Make CLI help explicit about Ratio format.

Add “format: N/D (e.g., 1/2)” so folks don’t guess the syntax.

-    /// Ratio of rollbacks in the generated chain for a given peer
+    /// Ratio of rollbacks in the generated chain for a given peer (format: N/D, e.g., 1/2)
@@
-    /// Ratio of branches generated from a central chain that can be explored by peers during input generation
+    /// Ratio of branches generated from a central chain that can be explored by peers during input generation (format: N/D, e.g., 1/2)
simulation/amaru-sim/src/sync/chain_sync_message.rs (1)

94-120: Debug fmt does CBOR decode per log – keep it cheap.

It’s fine for occasional logs, but if Fwd messages are spammy, this decode can add up. Consider:

  • Only computing parent_hash under trace!, or
  • Using a shorter path (e.g., pre-parsed field if available).
simulation/amaru-sim/src/simulator/run.rs (1)

327-339: Prefer typed error over panic for rollback mismatch.

Great assertion message, but panicking in the helper makes reuse harder. Consider returning a Result and letting the property assert, aligning with our past approach to model impossible states with types.

Based on learnings

simulation/amaru-sim/src/simulator/simulate.rs (1)

64-71: Smooth operator! Efficiency gains and better visibility.

The changes here are spot on:

  • Ditching the .to_vec() call is a nice efficiency win – no need to clone when you've already got the goods
  • The info logs give good breadcrumbs through the test execution

Minor thought: those info logs might get a bit chatty during a marathon test session. Could consider debug! level instead, but given this is a testing harness, having the visibility at info is fair dinkum useful.

If you want to keep things quieter for bulk test runs, consider using debug! instead:

-        info!("Test data generated. Now executing the tests");
+        debug!("Test data generated. Now executing the tests");
         
         let test = test_nodes(config.number_of_nodes, &spawn, &property);
         let result = test(&entries);
-        info!("Test run executed. Now checking results");
+        debug!("Test run executed. Now checking results");
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c2603b and 7ee84b2.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (21)
  • crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (6 hunks)
  • crates/amaru-consensus/src/consensus/headers_tree/headers_tree.rs (1 hunks)
  • crates/amaru-consensus/src/consensus/stages/receive_header.rs (2 hunks)
  • crates/amaru-ouroboros-traits/src/is_header/mod.rs (1 hunks)
  • crates/amaru-ouroboros-traits/src/is_header/tests.rs (2 hunks)
  • crates/amaru/src/stages/build_stage_graph.rs (1 hunks)
  • simulation/amaru-sim/Cargo.toml (1 hunks)
  • simulation/amaru-sim/src/echo/simulate.rs (1 hunks)
  • simulation/amaru-sim/src/simulator/args.rs (2 hunks)
  • simulation/amaru-sim/src/simulator/data_generation/chain.rs (0 hunks)
  • simulation/amaru-sim/src/simulator/data_generation/generate.rs (1 hunks)
  • simulation/amaru-sim/src/simulator/data_generation/mod.rs (0 hunks)
  • simulation/amaru-sim/src/simulator/ledger.rs (0 hunks)
  • simulation/amaru-sim/src/simulator/mod.rs (0 hunks)
  • simulation/amaru-sim/src/simulator/node_config.rs (2 hunks)
  • simulation/amaru-sim/src/simulator/run.rs (6 hunks)
  • simulation/amaru-sim/src/simulator/simulate.rs (7 hunks)
  • simulation/amaru-sim/src/simulator/world/world.rs (3 hunks)
  • simulation/amaru-sim/src/sync/chain_sync_message.rs (3 hunks)
  • simulation/amaru-sim/tests/simulation.rs (2 hunks)
  • simulation/amaru-sim/tests/traces.rs (3 hunks)
💤 Files with no reviewable changes (4)
  • simulation/amaru-sim/src/simulator/data_generation/mod.rs
  • simulation/amaru-sim/src/simulator/mod.rs
  • simulation/amaru-sim/src/simulator/ledger.rs
  • simulation/amaru-sim/src/simulator/data_generation/chain.rs
🚧 Files skipped from review as they are similar to previous changes (9)
  • crates/amaru-ouroboros-traits/src/is_header/mod.rs
  • crates/amaru-ouroboros-traits/src/is_header/tests.rs
  • simulation/amaru-sim/src/simulator/node_config.rs
  • simulation/amaru-sim/Cargo.toml
  • simulation/amaru-sim/src/echo/simulate.rs
  • simulation/amaru-sim/tests/simulation.rs
  • simulation/amaru-sim/tests/traces.rs
  • crates/amaru-consensus/src/consensus/stages/receive_header.rs
  • crates/amaru-consensus/src/consensus/headers_tree/headers_tree.rs
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-02-03T11:15:22.640Z
Learnt from: abailly
PR: pragma-org/amaru#75
File: crates/amaru/src/consensus/mod.rs:164-165
Timestamp: 2025-02-03T11:15:22.640Z
Learning: In the Amaru project, chain selection operations (roll_forward and rollback) should use separate result types to leverage the type system for preventing impossible states, rather than using runtime checks or panics.

Applied to files:

  • simulation/amaru-sim/src/simulator/run.rs
🧬 Code graph analysis (7)
simulation/amaru-sim/src/simulator/world/world.rs (1)
simulation/amaru-sim/src/simulator/world/node_handle.rs (1)
  • new (37-48)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (2)
crates/amaru/src/stages/mod.rs (1)
  • from_str (143-153)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/data_generation.rs (1)
  • any_tree_of_headers (37-42)
simulation/amaru-sim/src/simulator/args.rs (1)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (1)
  • from_str (328-350)
simulation/amaru-sim/src/simulator/run.rs (3)
simulation/amaru-sim/src/simulator/data_generation/generate.rs (1)
  • generate_entries (29-72)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (1)
  • current_chains (550-554)
simulation/amaru-sim/src/sync/chain_sync_message.rs (1)
  • header_hash (68-74)
simulation/amaru-sim/src/simulator/data_generation/generate.rs (5)
crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (2)
  • any_select_chains (392-402)
  • peer (191-196)
crates/amaru-ouroboros-traits/src/is_header/tests.rs (1)
  • run_with_rng (123-130)
simulation/amaru-sim/src/simulator/data_generation/base_generators.rs (1)
  • generate_arrival_times (67-84)
simulation/amaru-sim/src/simulator/bytes.rs (3)
  • new (25-27)
  • from (57-59)
  • from (73-75)
simulation/amaru-sim/src/simulator/node_config.rs (1)
  • from (41-49)
simulation/amaru-sim/src/simulator/simulate.rs (1)
simulation/amaru-sim/src/simulator/run.rs (1)
  • entries (246-249)
simulation/amaru-sim/src/sync/chain_sync_message.rs (2)
crates/amaru-ouroboros-traits/src/is_header/mod.rs (12)
  • decode (157-160)
  • header (129-131)
  • from (164-169)
  • hash (36-36)
  • hash (110-112)
  • hash (178-180)
  • hash (200-202)
  • parent_hash (137-139)
  • slot (51-51)
  • slot (190-192)
  • slot (212-214)
  • encode (147-153)
crates/amaru-kernel/src/point.rs (5)
  • decode (114-131)
  • from (62-64)
  • hash (37-43)
  • s (83-83)
  • encode (99-110)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Build x86_64/windows
  • GitHub Check: Test the CLI
  • GitHub Check: Build riscv32
  • GitHub Check: Benches
  • GitHub Check: Build aarch64/macos
  • GitHub Check: Build aarch64/linux
  • GitHub Check: End-to-end snapshot tests (preprod, 1, 10.1.4)
  • GitHub Check: Test coverage
  • GitHub Check: Analyze (rust)
🔇 Additional comments (19)
crates/amaru/src/stages/build_stage_graph.rs (1)

62-62: Noice choice using the underscore prefix, mate!

Renaming eff to _eff is spot-on Rust convention for an unused parameter. Makes it crystal clear you're not calling .terminate() here anymore, which is exactly what the PR objectives ordered. The node stays alive even when peers send dodgy headers - proper resilient architecture, that!

crates/amaru-consensus/src/consensus/headers_tree/data_generation/actions.rs (8)

47-47: Nice one, mate!

Spot on with the import – needed for the FromStr trait implementation below.


319-323: Beauty! Display impl looks mint.

Clean formatting that pairs perfectly with your FromStr parser. Solid work!


325-351: Bonzer work addressing the previous feedback!

You've nailed the validation checks that were flagged before – zero denominator rejection (line 340) and the numerator-must-be-≤-denominator guard (line 343) are both in place. Error messages are clear as day, and this'll prevent those gnarly "1/0" panics or >100% ratios from sneaking through. Top stuff!

Based on learnings


393-401: Ripper refactor, mate!

The new peers_nb and branching_ratio parameters slot in perfectly with the downstream functions. Your closure wiring is spot-on – passing the right values to any_tree_of_headers and generate_random_walks. No dramas here!


517-517: Good call making Chain public!

Exposing this type alias makes sense for the broader API, especially with the testing extensions mentioned in the PR objectives. Sweet as!


522-526: Documentation clarity FTW!

The updated doc comment explaining the nested list structure is much clearer now. Nice improvement for the next dev who dives into this code!


628-629: Standard test module setup – no worries!

Classic Rust test pattern with the use super::*; import. All good here.


650-679: Absolute ripper test coverage!

Your tests nail all the happy paths (valid ratios including edge cases like "0/1" and "1/1") and every error scenario – wrong format, non-numeric parts, zero denominator, and the >1.0 ratio. This is exactly the kind of thorough testing that prevents regressions. Legend!

simulation/amaru-sim/src/simulator/data_generation/generate.rs (1)

29-35: Closure factory looks good.

Returning impl Fn(&mut R) -> Vec<_> with elided lifetime is fine here; nice cleanup from the earlier invalid bound.

simulation/amaru-sim/src/sync/chain_sync_message.rs (1)

52-75: Handy helpers.

decode_block_header() and header_hash() are tidy and reduce duplication. Nice one.

simulation/amaru-sim/src/simulator/run.rs (2)

166-171: Channel capacity scaled with downstream fan-out — good call.

Preemptively avoids backpressure when events are duplicated.


240-261: Property wiring reads well.

Clear expected vs actual, nice list_to_string for diffs.

simulation/amaru-sim/src/simulator/simulate.rs (6)

39-39: Righto, imports looking clean!

All three additions are put to good use throughout the file. No dead weight here, mate.


114-115: Internal consistency FTW!

The signature updates here match perfectly with the public API changes upstream. It's like watching a well-choreographed fight scene in The Matrix – everything flows together.


133-133: Property callback wired up correctly!

Passing both entries and history to the property gives it the full story for validation. This aligns perfectly with the PR goal of testing the entire downstream chain rather than just the tip.


146-146: Type signature keeping up with the times!

The removal of Reverse wrapper here is consistent with the broader refactor. Clean and simple.


155-155: Direct access to the envelope – no more wrapper taxes!

Now that Reverse is gone, accessing entry.envelope directly is the way to go. This matches the pattern used elsewhere in the codebase (as seen in run.rs).


52-53: All call sites properly updated—the breaking changes landed clean.

You were spot on about the ripple effects, mate. Ran the sweep and found both places where simulate() gets called:

  1. traces.rs (line 65): Property closure |_, _| Ok(()) correctly takes two params
  2. run.rs (line 76): chain_property() returns a proper closure with signature impl Fn(&[Entry<ChainSyncMessage>], &History<ChainSyncMessage>) -> Result<(), String>

Both are dialed in for the new API. No orphaned call sites lurking in the shadows. The Serialize bound addition and the new property signature have been stitched through the entire codebase—it's like everyone got the memo before the band started playing.

Comment thread crates/amaru/src/stages/build_stage_graph.rs
Comment thread simulation/amaru-sim/src/simulator/data_generation/generate.rs

@abailly abailly left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's great we can finally explore varied chains in the simulator, however I have questions about the property verification/data generation logic.


/// Generate some input echo messages at different arrival times.
pub fn echo_generator(rng: &mut StdRng) -> Vec<Reverse<Entry<EchoMessage>>> {
pub fn echo_generator(rng: &mut StdRng) -> Vec<Entry<EchoMessage>> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this stage I wonder if we should not get rid of the Echo stuff

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used to test the simulation framework on a simple system but I also can't tell how useful this is by now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep it for now, and remove it in a later version.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@abailly Would you rather suppress it now?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your call!

Comment thread simulation/amaru-sim/src/simulator/run.rs Outdated
…rite assertions

Signed-off-by: etorreborre <etorreborre@yahoo.com>
@etorreborre etorreborre requested a review from abailly October 20, 2025 10:23

@abailly abailly left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a next step on the simulation, I think we'll need some kind of summary report on what's being run

@etorreborre

Copy link
Copy Markdown
Contributor Author

@abailly already working on it :-)

@etorreborre etorreborre merged commit 0918356 into main Oct 20, 2025
20 checks passed
@etorreborre etorreborre deleted the etorreborre/test/run-simulation-tests-with-several-peers branch October 20, 2025 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants