Skip to content

Conversation

@MuncleUscles
Copy link
Member

@MuncleUscles MuncleUscles commented Dec 18, 2025

Summary

  • Add --debug flag to validator-info to show raw unfiltered pending deposits
  • Use tree traversal to fetch ALL validators (including unprimed) for validators command
  • Add separate "Primed" column with color-coded urgency (green/yellow/red)
  • Add prime-all command to prime all validators that need priming

Changes

  • validator-info --debug: Shows current epoch and all pending deposits (including activated ones)
  • validators: Now uses validatorsRoot tree traversal to find all validators, adds Primed column
  • prime-all: Iterates all validators and attempts to prime each, skipping on failure

Test plan

  • genlayer staking validator-info 0x... --debug shows currentEpoch and raw deposits
  • genlayer staking validators shows Primed column with correct colors
  • genlayer staking prime-all primes validators and shows results

Summary by CodeRabbit

Release Notes

New Features

  • Added validator-prime and prime-all CLI commands to prime validators each epoch
  • Added --debug flag to validator-info command to display raw unfiltered data
  • Added priming status column (Green/Yellow/Red indicators) to validator listing

Documentation

  • Updated CLI help with new priming commands and usage examples
  • Expanded validator guide with priming instructions and validator set viewing guidance

✏️ Tip: You can customize this high-level summary in your review settings.

Shows raw unfiltered pending deposits/withdrawals and current epoch
for debugging stake visibility issues.
- Traverse validatorsRoot tree to find ALL validators (including unprimed)
- Add separate Primed column showing epoch and needs-priming status
- Remove prime! from Status column (now in dedicated column)
Iterates through validator tree and attempts to prime each validator
that needs priming. Continues on failure for max resilience.
@coderabbitai
Copy link

coderabbitai bot commented Dec 18, 2025

Walkthrough

This PR adds validator priming capabilities to the staking CLI. New commands validator-prime and prime-all enable bulk validator priming. Core changes include tree-based validator discovery in StakingAction, extended validator listing with priming status indicators, an optional debug mode for detailed information, and updated documentation.

Changes

Cohort / File(s) Summary
Documentation & Guides
README.md, docs/validator-guide.md
Added new CLI command examples for validator priming (validator-prime, prime-all). Extended validator-guide with sections on priming workflow, priming status indicators, and validator set viewing. Updated command descriptions to reflect debug and priming capabilities.
Staking Command Interface
src/commands/staking/index.ts
Added new prime-all subcommand with --account, --network, --rpc, and --staking-address options. Added --debug flag to validator-info command.
Validator Discovery & Infrastructure
src/commands/staking/StakingAction.ts
Added STAKING_TREE_ABI constant with validatorsRoot function. Introduced getAllValidatorsFromTree() method to traverse validator tree structure and collect all validator addresses using recursive left/right node traversal. Updated ethers import to include ZeroAddress.
Validator Information & Listing
src/commands/staking/stakingInfo.ts
Added debug option to StakingInfoOptions. Modified getValidatorInfo() to include currentEpoch in debug mode and alter pending deposits filtering logic. Integrated tree-based validator discovery into listing flows. Extended validator table with new Primed column displaying color-coded priming status (Green/Yellow/Red). Updated spinner text and result summaries.
Validator Priming Action
src/commands/staking/validatorPrime.ts
Added primeAll() method to iterate through all discovered validators and attempt priming each via client.validatorPrime(). Implements logging of successes (with transaction hash) and failures (with error summary). Tracks and reports final priming statistics.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as CLI Handler
    participant VAP as ValidatorPrimeAction
    participant SA as StakingAction
    participant Tree as Validator Tree Contract
    participant Client as Staking Client

    User->>CLI: prime-all
    CLI->>VAP: primeAll(options)
    activate VAP
    VAP->>SA: getAllValidatorsFromTree(config)
    activate SA
    SA->>Tree: read validatorsRoot
    loop Tree Traversal
        SA->>Tree: read validatorView(node)
        Tree-->>SA: left/right children
    end
    SA-->>VAP: all validator addresses
    deactivate SA
    
    loop For Each Validator
        VAP->>Client: validatorPrime(address)
        alt Success
            Client-->>VAP: transactionHash
            VAP->>User: ✓ Primed (green)
        else Failure
            Client-->>VAP: error
            VAP->>User: ✗ Skipped (gray)
        end
    end
    
    VAP-->>User: Summary (N primed, M skipped)
    deactivate VAP
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • src/commands/staking/StakingAction.ts: Tree traversal logic requires careful verification of recursive node handling, ZeroAddress checks, and proper termination conditions.
  • src/commands/staking/stakingInfo.ts: Significant refactoring with new conditional debug logic, integration of tree-based discovery, and priming status computation across multiple methods. Changes to pending deposit filtering and validator list rendering require thorough validation.
  • src/commands/staking/validatorPrime.ts: Verify error handling, logging accuracy, and transaction tracking across batch priming operations.
  • Integration across files: Ensure new getAllValidatorsFromTree() is correctly invoked and results properly propagated through stakingInfo flows.

Possibly related PRs

Suggested reviewers

  • cristiam86
  • danielrc888

Poem

🐰 A fluffy validator hops with glee,
Each epoch primed, as prime can be!
Trees of validators, leaf by leaf,
Bulk priming brings our network relief!
Green status glows—oh what a sight,
Staking commands burning bright!

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 accurately summarizes the three main changes: validator tree traversal, adding a primed column, and the prime-all command.
✨ 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 feat/validator-debug-and-tree-traversal

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.

Copy link

@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: 1

🧹 Nitpick comments (3)
src/commands/staking/StakingAction.ts (1)

212-265: Consider adding error handling and potential batching for tree traversal.

The tree traversal logic is correct, but there are a few considerations:

  1. Sequential RPC calls: Each node requires an RPC call to fetch validatorView. For large validator sets, this could be slow and may hit rate limits.

  2. No error handling for individual node reads: If a single readContract call fails (e.g., network hiccup), the entire traversal fails. Consider catching errors per-node to improve resilience.

  3. Potential memory consideration: The visited set and validators array grow unbounded, though this is unlikely to be an issue for realistic validator counts.

🔎 Optional: Add per-node error handling for resilience
     while (stack.length > 0) {
       const addr = stack.pop()!;

       if (addr === ZeroAddress || visited.has(addr.toLowerCase())) continue;
       visited.add(addr.toLowerCase());

       validators.push(addr as Address);

+      try {
         const info = await publicClient.readContract({
           address: stakingAddress as `0x${string}`,
           abi: abi.STAKING_ABI,
           functionName: "validatorView",
           args: [addr as `0x${string}`],
         }) as {left: string; right: string};

         if (info.left !== ZeroAddress) {
           stack.push(info.left);
         }
         if (info.right !== ZeroAddress) {
           stack.push(info.right);
         }
+      } catch (error) {
+        // Log warning but continue traversal - node is already added to validators
+        console.warn(`Warning: Failed to read validator tree node ${addr}`);
+      }
     }
src/commands/staking/validatorPrime.ts (1)

53-65: Consider adding rate limiting for large validator sets.

When priming many validators, rapid sequential RPC calls could potentially hit rate limits on the RPC endpoint. This might be worth considering for production use with large validator sets.

🔎 Optional: Add a small delay between calls
       for (const addr of allValidators) {
         process.stdout.write(`  ${addr} ... `);

         try {
           const result = await client.validatorPrime({validator: addr});
           console.log(chalk.green(`primed ${result.transactionHash}`));
           succeeded++;
         } catch (error: any) {
           const msg = error.message || String(error);
           const shortErr = msg.length > 60 ? msg.slice(0, 57) + "..." : msg;
           console.log(chalk.gray(`skipped: ${shortErr}`));
           skipped++;
         }
+        // Optional: small delay to avoid rate limiting
+        // await new Promise(resolve => setTimeout(resolve, 100));
       }
src/commands/staking/stakingInfo.ts (1)

509-523: Minor: Missing semicolon on line 522.

The pending deposits/withdrawals logic is correct. Note the missing semicolon on line 522, though ASI handles it.

🔎 Apply this diff to add the missing semicolon:
         } else if (pendingWithdrawSum > 0n) {
-          pendingStr = chalk.red(`-${formatStake(`${Number(pendingWithdrawSum) / 1e18} GEN`)}`)
+          pendingStr = chalk.red(`-${formatStake(`${Number(pendingWithdrawSum) / 1e18} GEN`)}`);
         }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4229f98 and 4f915b1.

📒 Files selected for processing (6)
  • README.md (2 hunks)
  • docs/validator-guide.md (2 hunks)
  • src/commands/staking/StakingAction.ts (3 hunks)
  • src/commands/staking/index.ts (2 hunks)
  • src/commands/staking/stakingInfo.ts (9 hunks)
  • src/commands/staking/validatorPrime.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/commands/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

All CLI action classes must extend BaseAction from src/lib/actions/BaseAction.ts which provides GenLayer client initialization, keystore management, spinner/logging utilities, and user prompts

Files:

  • src/commands/staking/stakingInfo.ts
  • src/commands/staking/validatorPrime.ts
  • src/commands/staking/StakingAction.ts
  • src/commands/staking/index.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use @/* path alias to reference ./src/* and @@/tests/* path alias to reference ./tests/* in imports

Files:

  • src/commands/staking/stakingInfo.ts
  • src/commands/staking/validatorPrime.ts
  • src/commands/staking/StakingAction.ts
  • src/commands/staking/index.ts
src/commands/*/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Commands must be organized in src/commands/<domain>/index.ts with each file exporting an initialize*Commands(program) function

Files:

  • src/commands/staking/index.ts
🧠 Learnings (1)
📚 Learning: 2025-12-03T23:03:32.323Z
Learnt from: CR
Repo: genlayerlabs/genlayer-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T23:03:32.323Z
Learning: Applies to src/commands/**/*.ts : All CLI action classes must extend `BaseAction` from `src/lib/actions/BaseAction.ts` which provides GenLayer client initialization, keystore management, spinner/logging utilities, and user prompts

Applied to files:

  • src/commands/staking/StakingAction.ts
🧬 Code graph analysis (3)
src/commands/staking/validatorPrime.ts (1)
src/commands/staking/StakingAction.ts (1)
  • StakingConfig (23-28)
src/commands/staking/StakingAction.ts (1)
templates/default/tools/types.py (1)
  • Address (11-83)
src/commands/staking/index.ts (2)
src/commands/staking/StakingAction.ts (1)
  • StakingConfig (23-28)
src/commands/staking/validatorPrime.ts (1)
  • ValidatorPrimeAction (9-73)
🔇 Additional comments (13)
src/commands/staking/StakingAction.ts (2)

9-18: LGTM on the extended ABI definition.

The STAKING_TREE_ABI constant is correctly defined with proper TypeScript const assertion for type safety with viem's contract reads.


146-146: Minor UX improvement noted.

The spinner text change from "Continuing..." to "Unlocking account..." provides clearer feedback to users about what's happening.

docs/validator-guide.md (2)

238-254: Documentation looks good.

The priming section clearly explains the concept and provides practical examples with the new commands. The color-coded status indicators are well-documented.


267-275: LGTM on the View Validator Set section.

Clear and concise documentation for the validators command with the --all flag option.

README.md (2)

309-310: LGTM on new command documentation.

The new validator-prime and prime-all commands are properly documented in the command list.


421-426: Examples are clear and helpful.

The examples for the new priming commands follow the established documentation pattern.

src/commands/staking/index.ts (1)

243-243: LGTM on the --debug flag addition.

The debug flag is properly added and follows the existing option pattern.

src/commands/staking/validatorPrime.ts (1)

37-72: Good implementation of batch priming with graceful error handling.

The primeAll method correctly:

  • Fetches all validators from the tree
  • Handles individual validator priming failures without stopping the entire operation
  • Provides clear progress feedback with color-coded output
  • Summarizes results at the end

One minor consideration: if getStakingClient or getAllValidatorsFromTree fails, the spinner is properly handled by the catch block. However, after stopSpinner() on line 47, if any console operation fails before the loop, there's no cleanup needed since spinner is already stopped.

src/commands/staking/stakingInfo.ts (5)

10-13: LGTM!

The debug option is correctly added as an optional boolean field.


56-78: LGTM!

The debug mode logic correctly differentiates between showing all deposits vs. only truly pending ones. The status indicators ("ACTIVATED" vs. pending epochs) provide useful context in debug mode.


372-393: LGTM!

Good use of parallel fetching and Set for O(1) membership lookups. The tree traversal approach correctly discovers all validators including unprimed ones.


544-552: LGTM!

The primed status color coding provides clear visual feedback: green for current, yellow for one epoch behind, and red with "!" for validators needing attention. The BigInt comparisons are handled correctly.


488-500: LGTM!

The table structure is consistent with headers matching row data order. The new "Primed" column integrates well with the existing table layout.

Also applies to: 562-571

Comment on lines +119 to +129
staking
.command("prime-all")
.description("Prime all validators that need priming")
.option("--account <name>", "Account to use (pays gas)")
.option("--network <network>", "Network to use (localnet, testnet-asimov)")
.option("--rpc <rpcUrl>", "RPC URL for the network")
.option("--staking-address <address>", "Staking contract address (overrides chain config)")
.action(async (options: StakingConfig) => {
const action = new ValidatorPrimeAction();
await action.primeAll(options);
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the imports and content of the staking index.ts file
echo "=== Checking imports in src/commands/staking/index.ts ==="
head -30 src/commands/staking/index.ts

echo -e "\n=== Checking lines 119-129 for prime-all action ==="
sed -n '119,129p' src/commands/staking/index.ts

echo -e "\n=== Checking if StakingConfig exists ==="
rg "StakingConfig" src/commands/staking/ -A 2 -B 2

Repository: genlayerlabs/genlayer-cli

Length of output: 14314


Add missing import for StakingConfig type.

The prime-all action uses StakingConfig type annotation (line 126), but this type is not imported at the top of the file. Add the import from ./StakingAction:

 import {Command} from "commander";
 import {ValidatorJoinAction, ValidatorJoinOptions} from "./validatorJoin";
 import {ValidatorDepositAction, ValidatorDepositOptions} from "./validatorDeposit";
 import {ValidatorExitAction, ValidatorExitOptions} from "./validatorExit";
 import {ValidatorClaimAction, ValidatorClaimOptions} from "./validatorClaim";
 import {ValidatorPrimeAction, ValidatorPrimeOptions} from "./validatorPrime";
+import {StakingConfig} from "./StakingAction";
 import {SetOperatorAction, SetOperatorOptions} from "./setOperator";

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/commands/staking/index.ts around lines 119 to 129, the StakingConfig type
used to type the options parameter in the prime-all action is not imported; add
an import for StakingConfig from ./StakingAction at the top of the file (e.g.
import { StakingConfig } from "./StakingAction") so the type reference is
resolved and TypeScript compiles cleanly.

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