Skip to content

feat: replay txs from file#12

Merged
kakysha merged 2 commits intov2from
feat/replay-from-file
Apr 13, 2026
Merged

feat: replay txs from file#12
kakysha merged 2 commits intov2from
feat/replay-from-file

Conversation

@kakysha
Copy link
Copy Markdown
Contributor

@kakysha kakysha commented Apr 3, 2026

Adds two more flags to tx-replay command:

--from-file filepath to read sniffed txs from. If omitted, will sniff txs from RPC in realtime.
--to-file filepath to store sniffed txs into. If omitted, will replay sniffed txs in realtime.

When replaying from file, we batch txs into blocks by 100 tx each.

Summary by CodeRabbit

  • New Features

    • Added CLI options to read transactions from files for offline replay and to write sniffed transactions to files for recording.
    • CLI now enforces valid flag combinations and mutually exclusive modes (file vs realtime) to avoid misconfiguration.
  • Bug Fixes

    • Fixed variable scope handling in the transaction broadcast phase to prevent concurrency issues.

+ sniff into file
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 3, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 16f64109-48b8-4f57-b712-b8f047830cfb

📥 Commits

Reviewing files that changed from the base of the PR and between d30be55 and 8ba14ac.

📒 Files selected for processing (1)
  • cmd/chain-stresser/main.go

📝 Walkthrough

Walkthrough

Adds file-based transaction sourcing and dumping to the chain-stresser: new --from-file and --to-file options, validation to enforce allowed flag combinations, sniffer support for length-prefixed tx file read/write, and control-flow changes to skip replay initialization when dumping to file.

Changes

Cohort / File(s) Summary
CLI Configuration
cmd/chain-stresser/main.go
Added --from-file and --to-file flags; updated PreRunE to require either RPC or --from-file, forbid simultaneous --from-file/--to-file, and disallow sniffer height flags when reading from file. Adjusted RunE to skip chain client/stress provider when dumping to file.
Configuration Struct
replay/replay.go
Extended TxReplayConfig with FromFile string and ToFile string (YAML/arg tags) to control file-based sourcing/dumping.
Sniffer Implementation
replay/sniffer.go
Conditional RPC client creation; open FromFile for reading and ToFile for writing. run() now branches: build virtual blocks from file (batch size controlled by new constant) or fetch real blocks via RPC. Added processBlock() to write length-prefixed txs and readTxFromFile() to parse them. Introduced BlockFromFileTxNum = 100.
Broadcast Loop Closure
stresser.go
Removed per-iteration local copies of loop variables before spawning goroutines, restoring correct capture semantics for per-account broadcast goroutines.

Sequence Diagram(s)

sequenceDiagram
participant CLI
participant Sniffer
participant File
participant RPC
participant Stresser

CLI->>Sniffer: start (cfg: FromFile/ToFile/RPC)
alt FromFile set (replay from file)
  Sniffer->>File: open FromFile (read)
  loop read batches
    Sniffer->>File: read length-prefixed txs
    Sniffer->>Stresser: emit virtual block (txs)
  end
  Sniffer->>CLI: Done / EOF
else ToFile set (dump to file)
  Sniffer->>RPC: poll blocks
  loop for each block
    RPC->>Sniffer: block with txs
    Sniffer->>File: write length-prefixed txs (processBlock)
  end
  Sniffer->>CLI: Done / stopped
else Realtime replay (no files)
  Sniffer->>RPC: poll blocks
  loop for each block
    RPC->>Sniffer: block with txs
    Sniffer->>Stresser: emit block for replay
  end
end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hop through files, I sniff and write,
Little length-prefixed bytes take flight,
FromFile or ToFile — pick your quest,
Goroutines now capture what’s best,
A rabbit cheers for replay done right! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: replay txs from file' directly summarizes the main change: adding file-based transaction replay capability with --from-file and --to-file flags.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/replay-from-file

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/chain-stresser/main.go`:
- Around line 572-575: The dump-only branch currently waits for <-sniffer.Done()
and returns nil, which masks sniffer failures; after waiting on sniffer.Done()
check sniffer.Errors() and if it returns a non-nil error return that error
instead of nil so failures (e.g., exhausted RPC retries) propagate; update the
branch that checks replayCfg.ToFile and uses sniffer.Done() to inspect
sniffer.Errors() and return it when present.

In `@replay/sniffer.go`:
- Around line 125-140: The code that builds a virtual block from s.cfg.FromFile
uses a nil block sentinel when no txs are read, but because EndHeight==0 the
outer loop never exits; instead of setting block = nil when len(block.Txs) == 0,
stop the producer loop immediately: when readTxFromFile yields no txs (len==0),
break out of the surrounding production loop or return from the producing method
so Done() can close cleanly; adjust the logic around
BlockFromFileTxNum/readTxFromFile to return/terminate rather than relying on a
nil block sentinel.
- Around line 207-229: In readTxFromFile (method on Sniffer) replace the two raw
s.txsFile.Read calls with io.ReadFull to ensure buffers are completely filled
and check the returned error; treat a zero-byte length read as io.EOF and
propagate other read errors; validate the decoded uint64 length against a
reasonable maximum (e.g., a configured MaxTxSize or a constant) before
allocating txnBuf to avoid unbounded allocations, then use io.ReadFull to read
the txnBuf and return any read errors instead of ignoring them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 80f96cc8-f627-4421-8e5c-3433dd5d9602

📥 Commits

Reviewing files that changed from the base of the PR and between dcbbecb and d30be55.

📒 Files selected for processing (4)
  • cmd/chain-stresser/main.go
  • replay/replay.go
  • replay/sniffer.go
  • stresser.go
💤 Files with no reviewable changes (1)
  • stresser.go

Comment thread cmd/chain-stresser/main.go
Comment thread replay/sniffer.go
Comment thread replay/sniffer.go
@kakysha kakysha merged commit 774a834 into v2 Apr 13, 2026
2 checks passed
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.

1 participant