Skip to content

feat(exit-certificate): F05 - use same targetBlock between multiples runs#1627

Open
joanestebanr wants to merge 1 commit into
feat/exit_certificate_f01_token_sclockedfrom
feat/exit_certificate_f05_target_block
Open

feat(exit-certificate): F05 - use same targetBlock between multiples runs#1627
joanestebanr wants to merge 1 commit into
feat/exit_certificate_f01_token_sclockedfrom
feat/exit_certificate_f05_target_block

Conversation

@joanestebanr
Copy link
Copy Markdown
Collaborator

🔄 Changes Summary

  • Changed cfg.TargetBlock type from string to aggkittypes.BlockNumberFinality, enabling finality keywords (latest, finalized, safe, pending), decimal/hex block numbers, and offset notation (e.g. LatestBlock/-10).
  • Added Step0Result.TargetBlock uint64 — the concrete resolved block number is now part of the Step 0 output and persisted to step-0-l2_target_block.json.
  • Removed ResolvedTargetBlock from Config; the resolved block number is passed as an explicit targetBlock uint64 parameter to RunStepA, RunStepB, and RunStepG.
  • Single-step runners (runSingleA/B/G) load the block from step-0-l2_target_block.json via a new loadTargetBlock helper.
  • Renamed intermediate file step-0-result.jsonstep-0-l2_target_block.json.
  • Updated README with target-block resolution table and updated Step 0 output list.
  • Added output-directory cleanup hint at the end of the kurtosis configuration script.

⚠️ Breaking Changes

  • 🛠️ Config: targetBlock in parameters.json now accepts finality keywords and offset notation in addition to decimal/hex block numbers. The default (empty string) resolves to latest. Existing decimal/hex values continue to work.
  • 🗑️ Deprecated Features: step-0-result.json renamed to step-0-l2_target_block.json; any tooling reading the old filename must be updated.

📋 Config Updates

// Before
"targetBlock": "12345678"

// After — still works, plus new forms:
"targetBlock": "latest"          // or "finalized", "safe", "pending"
"targetBlock": "LatestBlock/-10" // latest minus 10 blocks
"targetBlock": "12345678"        // decimal (unchanged)
"targetBlock": "0xBCDE34"        // hex (unchanged)

✅ Testing

  • 🖱️ Manual: Run full pipeline with targetBlock: "latest" and verify step-0-l2_target_block.json is written with a valid block number; subsequent single-step runs for A, B, and G should pick it up automatically.

🐞 Issues

🔗 Related PRs

  • Base branch: feat/exit_certificate_f01_token_sclocked

…n Step 0

- Change `cfg.TargetBlock` type from `string` to `aggkittypes.BlockNumberFinality`,
  supporting finality keywords (latest/finalized/safe/pending), decimal/hex block
  numbers, and offset notation (e.g. "LatestBlock/-10").
- Resolve the concrete block number at the start of `RunStep0` via
  `BlockNumberFinality.BlockNumber()` using a minimal `ethClientAdapter`; result
  stored in `Step0Result.TargetBlock` (new field) and persisted as
  `step-0-l2_target_block.json`.
- Remove `ResolvedTargetBlock` from `Config`; pass the resolved `uint64` as an
  explicit parameter to `RunStepA`, `RunStepB`, and `RunStepG`.
- Single-step runners (`runSingleA/B/G`) load the block from
  `step-0-l2_target_block.json` via `loadTargetBlock`.
- Rename intermediate file `step-0-result.json` → `step-0-l2_target_block.json`.
- Update README with target-block resolution table and updated Step 0 outputs.
- Add output-directory cleanup hint at end of kurtosis configuration script.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude Bot commented May 22, 2026

Claude finished @joanestebanr's task in 1m 53s —— View job


PR Review Complete ✅

Reviewed PR #1627: feat(exit-certificate): resolve targetBlock via BlockNumberFinality in Step 0


🚀 What's New

This PR refactors target block handling in the exit certificate tool by replacing the string-based targetBlock configuration with the type-safe aggkittypes.BlockNumberFinality. The resolved concrete block number is now output from Step 0 and persisted to step-0-l2_target_block.json, eliminating the need for ResolvedTargetBlock in the config. Single-step runners load this value automatically, improving consistency across the pipeline.

🐛 Bug Fixes

None.

📋 Config Updates

// Before
"targetBlock": "12345678"

// After — still works, plus new forms:
"targetBlock": "latest"          // or "finalized", "safe", "pending"
"targetBlock": "LatestBlock/-10" // latest minus 10 blocks
"targetBlock": "12345678"        // decimal (unchanged)
"targetBlock": "0xBCDE34"        // hex (unchanged)

⚠️ Breaking Changes

  • Config: targetBlock type changed from string to BlockNumberFinality, but backward compatible (existing decimal/hex values still work)
  • Output: step-0-result.json renamed to step-0-l2_target_block.json
  • API: RunStep0 now returns *Step0Result instead of []LBTEntry (includes resolved target block)
  • API: RunStepA, RunStepB, RunStepG now accept targetBlock uint64 parameter instead of reading from config

Code Review Feedback

🔴 Required Changes

1. Error handling in parseTargetBlock silently falls back to default (config.go:148-157)

The parseTargetBlock function swallows errors from NewBlockNumberFinality and returns LatestBlock as a fallback:

func parseTargetBlock(s string) aggkittypes.BlockNumberFinality {
	if s == "" {
		return aggkittypes.LatestBlock
	}
	tb, err := aggkittypes.NewBlockNumberFinality(s)
	if err != nil {
		return aggkittypes.LatestBlock  // ⚠️ Silent fallback
	}
	return *tb
}

Issue: If a user provides an invalid targetBlock value (e.g., malformed offset notation), the error is silently ignored and the tool uses LatestBlock instead. This can lead to unexpected behavior where the wrong block is processed.

Recommendation: Return an error from parseTargetBlock and propagate it through LoadConfig:

func parseTargetBlock(s string) (aggkittypes.BlockNumberFinality, error) {
	if s == "" {
		return aggkittypes.LatestBlock, nil
	}
	tb, err := aggkittypes.NewBlockNumberFinality(s)
	if err != nil {
		return aggkittypes.BlockNumberFinality{}, fmt.Errorf("invalid targetBlock %q: %w", s, err)
	}
	return *tb, nil
}

Fix this →

2. Missing test coverage for resolveTargetBlockNumber (step_0.go:548-587)

The new resolveTargetBlockNumber function and its ethClientAdapter implementation lack unit tests. This is critical functionality that determines which block the entire pipeline operates on.

Recommendation: Add test coverage for:

  • Constant finality (should return Specific directly)
  • Named finalities (latest, finalized, safe, pending)
  • Offset notation (e.g., LatestBlock/-10)
  • Error cases (invalid RPC URL, offset calculation failures)

Fix this →

🟡 Suggested Improvements

3. Test removal without explanation (run_test.go)

The PR removes 20 lines from run_test.go with no explanation in the PR description. Looking at the test names and file changes, it appears tests related to ResolvedTargetBlock were removed (since that field no longer exists).

Recommendation: Document this in the PR description under "Breaking Changes" or add a note explaining which tests were removed and why. If the test logic is still relevant, consider adapting it to the new API rather than deleting it entirely.

4. Potential confusion in logging (step_0.go:44-46)

if !cfg.TargetBlock.IsConstant() {
	log.Infof("Resolved targetBlock=%q → %d", cfg.TargetBlock.String(), blockNum)
}

The conditional logging only shows resolution for non-constant finalities. This is correct behavior, but users might be confused when they specify a concrete block number and don't see the "Resolved" message.

Recommendation: Consider always logging the target block with clearer messaging:

if cfg.TargetBlock.IsConstant() {
	log.Infof("Using target block: %d", blockNum)
} else {
	log.Infof("Resolved %s → block %d", cfg.TargetBlock.String(), blockNum)
}

5. Inconsistent parameter ordering (run.go:230-234, 247-249, 297-302)

The new targetBlock uint64 parameter is added in different positions across functions:

  • RunStepA(ctx, cfg, targetBlock) — third position
  • RunStepB(ctx, cfg, targetBlock, stepAResult) — third position (before stepAResult)
  • RunStepG(ctx, cfg, targetBlock, certificate, lbtEntries) — third position

Recommendation: This is actually consistent—good! Consider documenting this pattern in CLAUDE.md if it's not already there.

6. README could clarify resolution timing (README.md:259-269)

The README explains target block resolution but could be clearer about when it happens:

The resolved number is written to step-0-l2_target_block.json and used as a fixed reference by all subsequent steps

Suggestion: Add a note about the resolution timing:

The target block is resolved at the start of Step 0 (before LBT generation begins) and written to step-0-l2_target_block.json. All subsequent steps (A, B, G) use this fixed number—even if you later run individual steps, they will use the block number from the most recent Step 0 run.

🟢 Optional Improvements

7. Consider caching ethclient.Client for repeated resolution

The resolveTargetBlockNumber function dials a new ethclient for each call. Since Step 0 is only called once per pipeline run, this isn't a performance issue. However, if this function is ever called more frequently (e.g., in a loop or for validation), consider caching the client.

Not urgent—just something to keep in mind for future refactoring.

8. Type alias for targetBlock uint64 parameter

Several functions now take a targetBlock uint64 parameter. Consider defining a type alias for clarity:

type ResolvedBlockNumber uint64

This would make the API self-documenting and distinguish it from other uint64 values (like network IDs).

This is a style preference—not necessary for correctness.


Summary

Overall this is a solid refactoring that improves type safety and makes the target block resolution more explicit. The architecture is sound and the implementation follows Go best practices.

Must Fix (🔴):

  1. Error handling in parseTargetBlock should not silently fall back
  2. Add test coverage for resolveTargetBlockNumber and ethClientAdapter

Should Fix (🟡):

  1. Document test removal in PR description
  2. Improve logging clarity for constant vs. resolved blocks
  3. (Already consistent—good job!)
  4. Clarify resolution timing in README

Nice to Have (🟢):

  1. Consider client caching (not urgent)
  2. Consider type alias for ResolvedBlockNumber (style preference)

@joanestebanr joanestebanr changed the title feat(exit-certificate): resolve targetBlock via BlockNumberFinality in Step 0 feat(exit-certificate): F05 - use same targetBlock between multiples runs May 22, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1d0983418b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +153 to +154
if err != nil {
return aggkittypes.LatestBlock
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject invalid targetBlock instead of defaulting to latest

parseTargetBlock silently falls back to LatestBlock whenever NewBlockNumberFinality returns an error, so typos or malformed values (for example "FinalizedBock" or "0xZZ") are accepted and the run proceeds against a different block than configured. This can produce incorrect LBT/balance/certificate outputs without any user-visible configuration error, which is a regression from the previous behavior that rejected invalid block values.

Useful? React with 👍 / 👎.

@joanestebanr joanestebanr requested a review from web3security May 22, 2026 19:46
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