Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/relayer tests #395

Open
wants to merge 9 commits into
base: dev
Choose a base branch
from
Open

Feat/relayer tests #395

wants to merge 9 commits into from

Conversation

mani99brar
Copy link
Contributor

@mani99brar mani99brar commented Jan 15, 2025

PR-Codex overview

This PR introduces event-driven logging for the relayer, updates dependencies, and enhances the proof handling logic. It also restructures the relayer's initialization and state management processes, ensuring better event emission and handling.

Detailed summary

  • Added BotEvents enum for event handling.
  • Updated web3 version in package.json.
  • Refactored initialize and updateStateFile functions to accept an EventEmitter.
  • Enhanced logging with event emissions for relayer state changes.
  • Added tests for getProofIndices and relayBatch functions.
  • Improved error handling in relayBatch and getMessageDataToRelay.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced event-driven logging and notification system for relayer operations.
    • Introduced a new configuration file for the testnet environment.
  • Bug Fixes

    • Updated web3 library version to improve compatibility.
  • Chores

    • Refactored utility functions to support more flexible dependency injection.
    • Added comprehensive test coverage for relayer components.
  • Documentation

    • Added detailed JSDoc comments for key functions.
    • Improved code documentation and clarity.

Copy link
Contributor

coderabbitai bot commented Jan 15, 2025

Walkthrough

The pull request introduces significant modifications to the relayer CLI project, focusing on enhancing modularity and adopting an event-driven architecture. Key changes include the introduction of an EventEmitter for event management, updates to the web3 dependency version, and refactoring of function signatures to support dependency injection. Additional improvements include enhanced logging capabilities and the addition of a new state file for testnet configuration.

Changes

File Change Summary
relayer-cli/package.json Updated web3 package version from ^4.16.0 to ^1.10.4
relayer-cli/src/devnetRelayExample.ts Added EventEmitter parameter to start function
relayer-cli/src/testnetRelayer.ts Refactored start function to use RelayerConfig interface, added event emitter handling
relayer-cli/src/utils/botEvents.ts Introduced BotEvents enum for standardized event types
relayer-cli/src/utils/ethers.ts Updated import path for getBridgeConfig
relayer-cli/src/utils/logger.ts Added event logging functions for EventEmitter
relayer-cli/src/utils/proof.ts Enhanced function signatures, added JSDoc comments, exported getProofIndices
relayer-cli/src/utils/relay.ts Refactored relayBatch with RelayBatchDeps interface, improved error handling
relayer-cli/src/utils/relayerHelpers.ts Updated functions to support event emission and dependency injection
relayer-cli/state/testnet_11155111.json New state file added with timestamp and nonce

Sequence Diagram

sequenceDiagram
    participant Relayer
    participant EventEmitter
    participant Logger
    participant StateManager

    Relayer->>EventEmitter: Initialize
    EventEmitter-->>Logger: Register Event Listeners
    Relayer->>StateManager: Start Relaying
    StateManager-->>EventEmitter: Emit STARTED Event
    EventEmitter-->>Logger: Log Start Event
    Relayer->>Relayer: Relay Batches
    alt Waiting
        EventEmitter->>Logger: Emit WAITING Event
    end
    alt Exit
        EventEmitter->>Logger: Emit EXIT Event
    end
Loading

Possibly related PRs

  • Hardhat ether version update #379: The main PR updates the web3 dependency from ^4.16.0 to ^1.10.4, which is directly related to the changes in the package.json file in this PR.

Suggested labels

Type: Maintenance :construction:, Type: Feature🗿

Suggested reviewers

  • alcercu
  • jaybuidl

Poem

🐰 A Relayer's Tale of Change

With events that dance and flow,
Web3 upgraded, modularity's glow
Emitters sing their gentle song
Logging whispers where logs belong
A rabbit's code, now light and free! 🌈

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

netlify bot commented Jan 15, 2025

Deploy Preview for veascan failed. Why did it fail? →

Name Link
🔨 Latest commit 1609300
🔍 Latest deploy log https://app.netlify.com/sites/veascan/deploys/67977a30156e4e0008abe505

Copy link
Contributor

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

🔭 Outside diff range comments (4)
relayer-cli/src/utils/proof.ts (3)

Line range hint 10-31: Improve error handling in getMessageDataToRelay

The function has several issues that need attention:

  1. The error is only logged, not propagated
  2. No validation for empty results
  3. Potential undefined return if error occurs
 const getMessageDataToRelay = async (chainId: number, nonce: number, requestGraph: typeof request = request) => {
   try {
     const subgraph = getInboxSubgraph(chainId);
 
     const result = await requestGraph(
       `https://api.studio.thegraph.com/query/${subgraph}`,
       `{
                 messageSents(first: 5, where: {nonce: ${nonce}}) {
                 nonce
                 to {
                     id
                 }
                 data
                 }
             }`
     );
+    if (!result?.messageSents?.[0]) {
+      throw new Error(`No message found for nonce ${nonce}`);
+    }
 
     return [result[`messageSents`][0].to.id, result[`messageSents`][0].data];
   } catch (e) {
-    console.log(e);
+    throw new Error(`Failed to get message data: ${e.message}`);
   }
 };

Line range hint 40-71: Improve error handling and query construction in getProofAtCount

Several improvements needed:

  1. Error handling only returns empty array
  2. Query string construction could be vulnerable to injection
  3. No validation for subgraph response
 const getProofAtCount = async (
   chainId: number,
   nonce: number,
   count: number,
   requestGraph: typeof request = request,
   calculateProofIndices: typeof getProofIndices = getProofIndices,
   fetchInboxSubgraph: typeof getInboxSubgraph = getInboxSubgraph
 ): Promise<string[]> => {
   const proofIndices = calculateProofIndices(nonce, count);
   if (proofIndices.length == 0) return [];
 
-  let query = "{";
-  for (let i = 0; i < proofIndices.length; i++) {
-    query += `layer${i}: nodes(first: 1, where: {id: "${proofIndices[i]}"}) {
-              hash
-            }`;
-  }
-  query += "}";
+  const query = `{
+    ${proofIndices.map((index, i) => `
+      layer${i}: nodes(first: 1, where: {id: ${JSON.stringify(index)}}) {
+        hash
+      }
+    `).join('')}
+  }`;

   try {
     const subgraph = fetchInboxSubgraph(chainId);
     const result = await requestGraph(`https://api.studio.thegraph.com/query/${subgraph}`, query);
 
+    if (!result) {
+      throw new Error('No result from subgraph');
+    }
+
     const proof = [];
     for (let i = 0; i < proofIndices.length; i++) {
+      if (!result[`layer${i}`]?.[0]?.hash) {
+        throw new Error(`Missing hash for layer ${i}`);
+      }
       proof.push(result[`layer${i}`][0].hash);
     }
     return proof;
   } catch (e) {
-    console.log(e);
-    return [];
+    throw new Error(`Failed to get proof: ${e.message}`);
   }
 };

Line range hint 81-100: Add input validation to getProofIndices

The function needs input validation to handle invalid inputs gracefully.

 const getProofIndices = (nonce: number, count: number) => {
+  if (nonce < 0 || count < 0) {
+    throw new Error('Nonce and count must be non-negative');
+  }
+
   let proof = [];
   if (nonce >= count) return proof;
 
   const treeDepth = Math.ceil(Math.log2(count));
relayer-cli/src/utils/relayerHelpers.ts (1)

Line range hint 73-76: [Critical Issue] Inconsistent use of lock file directory path.

In setupExitHandlers, lockFileName is constructed with a hard-coded "./state/" directory, whereas in other parts of the code, process.env.STATE_DIR is used. This inconsistency can cause the cleanup process to fail to remove the lock file from the correct directory.

Apply this diff to fix the inconsistency:

-    const lockFileName = "./state/" + network + "_" + chainId + ".pid";
+    const lockFileName = process.env.STATE_DIR + network + "_" + chainId + ".pid";
🧹 Nitpick comments (14)
relayer-cli/src/utils/proof.test.ts (2)

14-14: Fix typo in test description

There's a missing parenthesis in the test description.

-    it("should return the proof indices(for a large count", () => {
+    it("should return the proof indices (for a large count)", () => {

5-18: Enhance test coverage with edge cases

While the current tests cover basic scenarios, consider adding tests for:

  • Edge cases: count = 0, nonce = 0
  • Invalid inputs: negative numbers
  • Boundary conditions: nonce > count
relayer-cli/src/utils/proof.ts (1)

Line range hint 14-31: Extract GraphQL endpoint to configuration

The GraphQL endpoint URL is hardcoded in multiple places. Consider extracting it to a configuration constant.

+const GRAPH_API_ENDPOINT = 'https://api.studio.thegraph.com/query';
+
 const getMessageDataToRelay = async (...) => {
   try {
     const subgraph = getInboxSubgraph(chainId);
-    const result = await requestGraph(
-      `https://api.studio.thegraph.com/query/${subgraph}`,
+    const result = await requestGraph(
+      `${GRAPH_API_ENDPOINT}/${subgraph}`,

Also applies to: 62-62

relayer-cli/src/testnetRelayer.ts (1)

2-2: Ensure consistent import of EventEmitter

In this file, EventEmitter is imported from "node:events", whereas in other files it's imported from "events". Consider using the same import statement across all files for consistency. Using the standard "events" module is generally preferred unless you have a specific reason to import from "node:events".

Apply this diff to adjust the import statement:

- import { EventEmitter } from "node:events";
+ import { EventEmitter } from "events";
relayer-cli/src/utils/botEvents.ts (1)

1-15: Ensure consistent naming conventions for enum members

The BotEvents enum members use uppercase (e.g., STARTED, WAITING), but the assigned string values are lowercase with underscores (e.g., "started", "promise_rejection"). For consistency and clarity, consider using a consistent naming convention for enum members and their string values. For example, you could use uppercase with underscores for both enum keys and values, or use camelCase, depending on your project's style guide.

Apply this diff to adjust the enum values:

 export enum BotEvents {
   // Bridger state
-  STARTED = "started",
-  WAITING = "waiting",
-  EXIT = "exit",
+  STARTED = "STARTED",
+  WAITING = "WAITING",
+  EXIT = "EXIT",

   // Bot health
-  EXCEPTION = "exception",
-  PROMISE_REJECTION = "promise_rejection",
+  EXCEPTION = "EXCEPTION",
+  PROMISE_REJECTION = "PROMISE_REJECTION",

   // Lock file
-  LOCK_CLAIMED = "lock_claimed",
-  LOCK_DIRECTORY = "lock_directory",
-  LOCK_RELEASED = "lock_released",
+  LOCK_CLAIMED = "LOCK_CLAIMED",
+  LOCK_DIRECTORY = "LOCK_DIRECTORY",
+  LOCK_RELEASED = "LOCK_RELEASED",
 }
relayer-cli/src/devnetRelayExample.ts (2)

1-1: Ensure consistent import of EventEmitter

In this file, EventEmitter is imported from "events", whereas in other files it's imported from "node:events". Consider using the same import statement across all files for consistency. Using the standard "events" module is generally preferred unless there's a specific reason to import from "node:events".

Apply this diff to adjust the import statement:

- import { EventEmitter } from "events";
+ import { EventEmitter } from "node:events";

6-6: Add JSDoc comments to the start function

Consider adding JSDoc comments to the start function to document its purpose and parameters (shutdownManager, emitter). This enhances code readability and helps other developers understand how to use the function.

Apply this diff to add JSDoc comments:

+ /**
+  * Starts the devnet relayer example.
+  * @param shutdownManager Manages graceful shutdowns.
+  * @param emitter Event emitter for logging and event handling.
+  */
  export async function start(shutdownManager: ShutdownManager = new ShutdownManager(), emitter: EventEmitter) {
relayer-cli/src/utils/logger.ts (2)

15-18: Consider removing redundant initialize function.

The initialize function simply forwards to configurableInitialize without adding any value. Consider removing it and using configurableInitialize directly.

-export const initialize = (emitter: EventEmitter) => {
-  return configurableInitialize(emitter);
-};

31-37: Enhance error logging for uncaught exceptions.

The error logging for exceptions could be more detailed to aid in debugging. Consider including stack traces and error codes if available.

-  emitter.on(BotEvents.EXCEPTION, (err) => {
-    console.error("Uncaught Exception occurred", err);
-  });
+  emitter.on(BotEvents.EXCEPTION, (err) => {
+    console.error("Uncaught Exception occurred:", {
+      message: err.message,
+      stack: err.stack,
+      code: err.code
+    });
+  });
relayer-cli/src/utils/relayerHelpers.test.ts (1)

69-77: Add descriptions for TODO tests.

The setupExitHandlers test cases are marked as TODO without descriptions. Consider adding detailed descriptions of what each test should verify.

-    it.todo("should register signal handlers for SIGINT, SIGTERM, and SIGQUIT");
+    it.todo("should register signal handlers for SIGINT, SIGTERM, and SIGQUIT and verify they are properly attached to process.on()");

-    it.todo("should trigger shutdown and cleanup on SIGINT signal");
+    it.todo("should trigger shutdown and cleanup on SIGINT signal and verify all resources are properly released");
relayer-cli/src/utils/relay.test.ts (2)

186-229: Enhance error case testing.

The error handling test could be more comprehensive. Consider testing different types of errors and retry scenarios.

Add test cases for:

  • Network errors
  • Timeout errors
  • Invalid message format
  • Retry mechanism

96-120: Add memory usage tests for large batches.

Consider adding tests to verify memory usage remains stable with large batch sizes.

Add a test case that:

  • Processes a very large number of messages
  • Monitors memory usage
  • Verifies no memory leaks occur
relayer-cli/src/utils/relayerHelpers.ts (2)

59-59: Ensure the target directory exists before writing the state file.

When writing the state file, if the target directory does not exist, fileSystem.writeFileSync will throw an error. To prevent this, ensure that the directory exists before attempting to write the file.

Apply this diff to check and create the directory if necessary:

+  const dir = path.dirname(chain_state_file);
+  if (!fileSystem.existsSync(dir)) {
+    fileSystem.mkdirSync(dir, { recursive: true });
+  }
   fileSystem.writeFileSync(chain_state_file, JSON.stringify(json), { encoding: "utf8" });

Remember to import the path module:

+ import * as path from "path";

65-70: Inject fileSystem into setupExitHandlers for consistency and testability.

In other functions like initialize and updateStateFile, fileSystem is injected as a parameter to allow for easier mocking and testing. For consistency and improved testability, consider injecting fileSystem into setupExitHandlers as well, instead of directly importing and using fs within the function.

Apply this diff to update the function signature and usage:

 async function setupExitHandlers(
     chainId: number,
     shutdownManager: ShutdownManager,
     network: string,
     emitter: EventEmitter,
+    fileSystem: typeof fs = fs
 ) {

Update references to fs within the function to use fileSystem instead.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0adb33e and b6c735a.

📒 Files selected for processing (13)
  • relayer-cli/package.json (1 hunks)
  • relayer-cli/src/devnetRelayExample.ts (1 hunks)
  • relayer-cli/src/testnetRelayer.ts (1 hunks)
  • relayer-cli/src/utils/botEvents.ts (1 hunks)
  • relayer-cli/src/utils/ethers.ts (1 hunks)
  • relayer-cli/src/utils/logger.ts (1 hunks)
  • relayer-cli/src/utils/proof.test.ts (1 hunks)
  • relayer-cli/src/utils/proof.ts (4 hunks)
  • relayer-cli/src/utils/relay.test.ts (1 hunks)
  • relayer-cli/src/utils/relay.ts (7 hunks)
  • relayer-cli/src/utils/relayerHelpers.test.ts (1 hunks)
  • relayer-cli/src/utils/relayerHelpers.ts (3 hunks)
  • relayer-cli/state/testnet_11155111.json (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • relayer-cli/state/testnet_11155111.json
  • relayer-cli/src/utils/ethers.ts
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: test
  • GitHub Check: Scorecard analysis
  • GitHub Check: dependency-review
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
relayer-cli/src/utils/proof.ts (1)

4-9: Great job on JSDoc comments!

The JSDoc comments are well-written and provide clear documentation for the functions.

Also applies to: 33-39, 75-80

relayer-cli/src/utils/botEvents.ts (1)

1-15: Good addition of BotEvents enum

The introduction of the BotEvents enum provides a centralized and type-safe way to manage event strings, improving code maintainability and reducing the risk of typos in event names.

relayer-cli/package.json (1)

23-23: ⚠️ Potential issue

Significant downgrade of web3.js requires attention.

The change downgrades web3.js from v4.16.0 to v1.10.4, which is a major version downgrade that:

  • Removes access to newer Web3.js features and improvements
  • May impact security fixes available in v4.x.x
  • Could affect compatibility with Node.js 18+ requirement

Please run this script to check compatibility and security implications:

Could you please:

  1. Document the reason for this downgrade in the PR description?
  2. Verify if this is related to compatibility with [email protected]?
  3. Consider using a more recent version if possible, or create a tracking issue for future upgrade?
relayer-cli/src/utils/relayerHelpers.ts (1)

22-23: LGTM: Proper use of dependency injection and event emission.

The initialize function correctly uses dependency injection for setLock and emits the LOCK_CLAIMED event after acquiring the lock.

Comment on lines +59 to +61
chainId: Number(process.env.VEAOUTBOX_CHAIN_ID),
network: "testnet",
};
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 15, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Verify that VEAOUTBOX_CHAIN_ID environment variable is defined

You're using Number(process.env.VEAOUTBOX_CHAIN_ID) to set chainId. If VEAOUTBOX_CHAIN_ID is undefined, Number(undefined) results in NaN, which could cause issues downstream. Consider adding a check to ensure that process.env.VEAOUTBOX_CHAIN_ID is defined and handle the case where it is not.

Apply this diff to add a check for the environment variable:

+ if (!process.env.VEAOUTBOX_CHAIN_ID) {
+   throw new Error('VEAOUTBOX_CHAIN_ID environment variable is not defined');
+ }
  const testnetRelayerConfig: RelayerConfig = {
    shutdownManager,
    emitter,
    chainId: Number(process.env.VEAOUTBOX_CHAIN_ID),
    network: "testnet",
  };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
chainId: Number(process.env.VEAOUTBOX_CHAIN_ID),
network: "testnet",
};
if (!process.env.VEAOUTBOX_CHAIN_ID) {
throw new Error('VEAOUTBOX_CHAIN_ID environment variable is not defined');
}
const testnetRelayerConfig: RelayerConfig = {
shutdownManager,
emitter,
chainId: Number(process.env.VEAOUTBOX_CHAIN_ID),
network: "testnet",
};

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's already an issue created for env validation and it will be addressed there.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mani99brar Understood, thanks for letting me know that environment variable validation will be handled separately.

Comment on lines 22 to 28
/**
* Start the relayer
* @param chainId The chain id of the relayer
* @param network The network of the relayer
* @param shutdownManager The shutdown manager
* @param emitter The event emitter
*/
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 15, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Update JSDoc comments to reflect the new function signature

The start function now accepts a single RelayerConfig object as a parameter, but the JSDoc comments list individual parameters (chainId, network, shutdownManager, emitter). Please update the JSDoc to accurately describe the RelayerConfig parameter and its properties.

Apply this diff to update the JSDoc comments:

 /**
  * Start the relayer
-  * @param chainId The chain id of the relayer
-  * @param network The network of the relayer
-  * @param shutdownManager The shutdown manager
-  * @param emitter The event emitter
+  * @param config The relayer configuration
+  * @param config.chainId The chain id of the relayer
+  * @param config.network The network of the relayer
+  * @param config.shutdownManager The shutdown manager
+  * @param config.emitter The event emitter
  */
 export async function start({ chainId, network, shutdownManager, emitter }: RelayerConfig) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Start the relayer
* @param chainId The chain id of the relayer
* @param network The network of the relayer
* @param shutdownManager The shutdown manager
* @param emitter The event emitter
*/
/**
* Start the relayer
* @param config The relayer configuration
* @param config.chainId The chain id of the relayer
* @param config.network The network of the relayer
* @param config.shutdownManager The shutdown manager
* @param config.emitter The event emitter
*/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think its needed, the comments and implementation is clear enough.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mani99brar Understood, I'll retract the suggestion. The TypeScript types and current documentation are indeed clear enough.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mani99brar the bot is right, the correct way of documenting object properties is with the dot notation

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines 8 to 9
const epochPeriod = 1800; // 30 min
const network = "devnet";
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 15, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Verify environment variables are defined before use

You're using process.env.VEAOUTBOX_CHAIN_ID to set chainId. If this environment variable is undefined, parseInt(undefined) results in NaN, which could cause issues. Similarly, sender is set from process.env.DEVNET_SENDER. Consider adding checks to ensure these environment variables are defined and handle the case where they are not.

Apply this diff to add checks for the environment variables:

+ if (!process.env.VEAOUTBOX_CHAIN_ID) {
+   throw new Error('VEAOUTBOX_CHAIN_ID environment variable is not defined');
+ }
  const chainId = parseInt(process.env.VEAOUTBOX_CHAIN_ID);

  const epochPeriod = 1800; // 30 min
  const network = "devnet";

+ if (!process.env.DEVNET_SENDER) {
+   throw new Error('DEVNET_SENDER environment variable is not defined');
+ }
  const sender = process.env.DEVNET_SENDER;

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's already an issue created for env validation and it will be addressed there.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mani99brar Understood, I'll defer to that issue for environment variable validation.

⊙﹏⊙

Comment on lines +19 to +49
export const configurableInitialize = (emitter: EventEmitter) => {
// Relayer state logs
emitter.on(BotEvents.STARTED, (chainId, network) => {
console.log(`Relayer started for ${chainId} on ${network}`);
});
emitter.on(BotEvents.WAITING, (delayAmount) => {
console.log(`Waiting for next epoch: ${delayAmount} ms`);
});
emitter.on(BotEvents.EXIT, () => {
console.log("Exiting");
});

// Bot health logs
emitter.on(BotEvents.EXCEPTION, (err) => {
console.error("Uncaught Exception occurred", err);
});
emitter.on(BotEvents.PROMISE_REJECTION, (reason, promise) => {
console.error("Unhandled promise rejection:", reason, "at", promise);
});

// Lock file logs
emitter.on(BotEvents.LOCK_CLAIMED, () => {
console.log("Lock claimed");
});
emitter.on(BotEvents.LOCK_DIRECTORY, (pwd) => {
console.log(`Lock file directory: ${pwd}`);
});
emitter.on(BotEvents.LOCK_RELEASED, () => {
console.log("Lock released");
});
};
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 15, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling to event listeners.

The event listeners should include try-catch blocks to prevent crashes if event handling fails.

Here's an example for one event handler:

-  emitter.on(BotEvents.STARTED, (chainId, network) => {
-    console.log(`Relayer started for ${chainId} on ${network}`);
-  });
+  emitter.on(BotEvents.STARTED, (chainId, network) => {
+    try {
+      console.log(`Relayer started for ${chainId} on ${network}`);
+    } catch (error) {
+      console.error('Failed to handle STARTED event:', error);
+    }
+  });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const configurableInitialize = (emitter: EventEmitter) => {
// Relayer state logs
emitter.on(BotEvents.STARTED, (chainId, network) => {
console.log(`Relayer started for ${chainId} on ${network}`);
});
emitter.on(BotEvents.WAITING, (delayAmount) => {
console.log(`Waiting for next epoch: ${delayAmount} ms`);
});
emitter.on(BotEvents.EXIT, () => {
console.log("Exiting");
});
// Bot health logs
emitter.on(BotEvents.EXCEPTION, (err) => {
console.error("Uncaught Exception occurred", err);
});
emitter.on(BotEvents.PROMISE_REJECTION, (reason, promise) => {
console.error("Unhandled promise rejection:", reason, "at", promise);
});
// Lock file logs
emitter.on(BotEvents.LOCK_CLAIMED, () => {
console.log("Lock claimed");
});
emitter.on(BotEvents.LOCK_DIRECTORY, (pwd) => {
console.log(`Lock file directory: ${pwd}`);
});
emitter.on(BotEvents.LOCK_RELEASED, () => {
console.log("Lock released");
});
};
export const configurableInitialize = (emitter: EventEmitter) => {
// Relayer state logs
emitter.on(BotEvents.STARTED, (chainId, network) => {
try {
console.log(`Relayer started for ${chainId} on ${network}`);
} catch (error) {
console.error('Failed to handle STARTED event:', error);
}
});
emitter.on(BotEvents.WAITING, (delayAmount) => {
try {
console.log(`Waiting for next epoch: ${delayAmount} ms`);
} catch (error) {
console.error('Failed to handle WAITING event:', error);
}
});
emitter.on(BotEvents.EXIT, () => {
try {
console.log("Exiting");
} catch (error) {
console.error('Failed to handle EXIT event:', error);
}
});
// Bot health logs
emitter.on(BotEvents.EXCEPTION, (err) => {
try {
console.error("Uncaught Exception occurred", err);
} catch (error) {
console.error('Failed to handle EXCEPTION event:', error);
}
});
emitter.on(BotEvents.PROMISE_REJECTION, (reason, promise) => {
try {
console.error("Unhandled promise rejection:", reason, "at", promise);
} catch (error) {
console.error('Failed to handle PROMISE_REJECTION event:', error);
}
});
// Lock file logs
emitter.on(BotEvents.LOCK_CLAIMED, () => {
try {
console.log("Lock claimed");
} catch (error) {
console.error('Failed to handle LOCK_CLAIMED event:', error);
}
});
emitter.on(BotEvents.LOCK_DIRECTORY, (pwd) => {
try {
console.log(`Lock file directory: ${pwd}`);
} catch (error) {
console.error('Failed to handle LOCK_DIRECTORY event:', error);
}
});
emitter.on(BotEvents.LOCK_RELEASED, () => {
try {
console.log("Lock released");
} catch (error) {
console.error('Failed to handle LOCK_RELEASED event:', error);
}
});
};

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I dont see how this is necessary

Copy link
Contributor

Choose a reason for hiding this comment

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

@mani99brar You're right. The event listeners are just doing simple console logging, which is very unlikely to throw errors. Adding try-catch blocks would be unnecessary complexity. I'll retract this suggestion.


✏️ Learnings added
Learnt from: mani99brar
PR: kleros/vea#395
File: relayer-cli/src/utils/logger.ts:19-49
Timestamp: 2025-01-15T07:41:36.295Z
Learning: For simple logging operations using console.log/error, adding try-catch blocks is unnecessary as these operations are highly reliable and any errors would be caught by process-level error handlers.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +91 to +101
const batchedSend = setBatchedSend(web3Instance, routeParams.batcher, process.env.PRIVATE_KEY, 0);
const veaOutboxInstance = new web3Instance.eth.Contract(
routeParams.veaOutboxContract.abi,
routeParams.veaOutboxAddress
);
const veaOutbox = fetchVeaOutbox(
routeParams.veaOutboxAddress,
process.env.PRIVATE_KEY,
routeParams.rpcOutbox,
chainId
);
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 15, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Secure private key handling required.

The private key is being read directly from environment variables. Consider using a secure key management service or encrypted configuration.

Consider implementing a secure key provider interface:

interface KeyProvider {
  getPrivateKey(): Promise<string>;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The bot will be deployed in a private environment so I don't think this will be an issue, @fcanela wdyt, is this something to be concerned about?

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines +117 to +122
try {
await veaOutboxInstance.methods.sendMessage(proof, nonce, to, data).call();
} catch {
nonce++;
continue;
}
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 15, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling in batch processing.

The current implementation silently continues on errors. Consider logging the error and implementing a retry mechanism.

       try {
         await veaOutboxInstance.methods.sendMessage(proof, nonce, to, data).call();
       } catch (error) {
+        console.error(`Failed to process message ${nonce}:`, error);
+        if (shouldRetry(error)) {
+          await delay(1000);
+          continue;
+        }
         nonce++;
         continue;
       }

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

retry and restart mechanisms are not implemented across the repo, will consider it to use after monitoring testnet deployments.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mani99brar Understood, that's a sensible approach to wait for testnet monitoring data before implementing retry mechanisms.


✏️ Learnings added
Learnt from: mani99brar
PR: kleros/vea#395
File: relayer-cli/src/utils/relay.ts:117-122
Timestamp: 2025-01-15T07:41:35.455Z
Learning: Retry and restart mechanisms are not implemented across the repository. The team prefers to monitor testnet deployments first before considering implementing retry logic.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +95 to 97
emitter.emit(BotEvents.EXCEPTION, err);
await handleExit(1);
});
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 15, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

[Critical Issue] exitCode parameter in handleExit is unused.

The handleExit function accepts an exitCode parameter but does not utilize it when calling process.exit(). As a result, the application always exits with code 0, even in error scenarios where an exit code of 1 is intended.

Modify handleExit to use the exitCode parameter:

 const handleExit = async (exitCode: number = 0) => {
     shutdownManager.triggerShutdown();
     await cleanup();
-    process.exit(0);
+    process.exit(exitCode);
 };

Also applies to: 100-102

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will work on shutdownManager in a separate PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mani99brar Understood! Would you like me to create a GitHub issue to track the shutdown manager improvements for the follow-up PR?


✏️ Learnings added
Learnt from: mani99brar
PR: kleros/vea#395
File: relayer-cli/src/utils/relayerHelpers.ts:95-97
Timestamp: 2025-01-15T07:41:33.898Z
Learning: The shutdown manager improvements in relayer-cli/src/utils/relayerHelpers.ts, including proper exit code handling, will be addressed in a separate PR to keep the current changes focused.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

const chain_state_raw = fs.readFileSync(state_file, { encoding: "utf8" });
emitter.emit(BotEvents.LOCK_DIRECTORY, process.cwd());

const chain_state_raw = fileSystem.readFileSync(state_file, { encoding: "utf8" });
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 15, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for file read operation.

Reading the state file using fileSystem.readFileSync may throw an exception if the file cannot be read due to permissions issues or unexpected errors. It's recommended to wrap the file read operation in a try-catch block to handle any potential errors gracefully.

Apply this diff to include error handling:

-  const chain_state_raw = fileSystem.readFileSync(state_file, { encoding: "utf8" });
+  let chain_state_raw;
+  try {
+    chain_state_raw = fileSystem.readFileSync(state_file, { encoding: "utf8" });
+  } catch (err) {
+    emitter.emit(BotEvents.FILE_READ_ERROR, err);
+    throw new Error(`Failed to read state file: ${err.message}`);
+  }

Ensure that BotEvents includes a FILE_READ_ERROR event, or handle the error appropriately.

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The shutdownManager will handle any uncaught unexpected errors, so let it fail.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mani99brar Understood. I'll retract the suggestion since the shutdownManager is designed to handle such uncaught errors.


✏️ Learnings added
Learnt from: mani99brar
PR: kleros/vea#395
File: relayer-cli/src/utils/relayerHelpers.ts:35-35
Timestamp: 2025-01-15T07:41:33.722Z
Learning: In the VEA relayer, uncaught errors are intentionally allowed to propagate up to be handled by the shutdownManager, which has handlers for uncaughtException and unhandledRejection events, rather than adding explicit try-catch blocks.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Copy link
Contributor

Choose a reason for hiding this comment

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

@coderabbitai in general, try to avoid suggesting adding a try/catch for everything that may fail. We let the errors pop up to be handled by an upper layer or crash the process (that's fine). We are not pokemon trainers: our goal is not catch them all.

Copy link
Contributor

Choose a reason for hiding this comment

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

@fcanela Understood, I'll refrain from suggesting try/catch blocks for every potential failure point. Thank you for the clear guidance (and the Pokemon reference 😄).


✏️ Learnings added
Learnt from: fcanela
PR: kleros/vea#395
File: relayer-cli/src/utils/relayerHelpers.ts:35-35
Timestamp: 2025-01-15T12:37:24.802Z
Learning: Error handling philosophy: Avoid adding try/catch blocks for every potential failure. Let errors propagate up to be handled by upper layers or crash the process if necessary. The goal is not to catch every possible error ("we are not pokemon trainers").

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

emitter: EventEmitter,
fileSystem: typeof fs = fs,
removeLock: typeof releaseLock = releaseLock
) {
const chain_state_file = "./state/" + network + "_" + chainId + ".json";
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 15, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

[Critical Issue] Inconsistent use of state file directory path.

There is an inconsistency in how the state file path is constructed in updateStateFile compared to initialize. In initialize, state_file is built using process.env.STATE_DIR, while in updateStateFile, chain_state_file uses a hard-coded "./state/" path. This could lead to incorrect file paths if STATE_DIR is set to a different directory.

Apply this diff to fix the inconsistency:

-  const chain_state_file = "./state/" + network + "_" + chainId + ".json";
+  const chain_state_file = process.env.STATE_DIR + network + "_" + chainId + ".json";

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

@mani99brar Thanks for agreeing to fix the state file path inconsistency!

(^◕ᴥ◕^)

Copy link
Contributor

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

🧹 Nitpick comments (1)
relayer-cli/src/utils/relayerHelpers.ts (1)

14-21: LGTM! Consider enhancing function documentation.

The dependency injection pattern and event emission changes look good. Consider updating the JSDoc to document the new parameters and their purposes.

 /**
  * Initialize the relayer by claiming the lock and reading the nonce from the state file.
  * If the state file does not exist, it will be created with the current timestamp and nonce 0.
  *
  * @param chainId Chain ID of the relayer
  * @param network Network name of the relayer (e.g. "testnet")
+ * @param emitter EventEmitter instance for logging state changes
+ * @param setLock Optional function for claiming locks (defaults to claimLock)
+ * @param syncStateFile Optional function for state file updates (defaults to updateStateFile)
+ * @param fileSystem Optional filesystem interface (defaults to fs)
+ * @returns Promise<number> The current nonce
  */
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6c735a and 47900e9.

📒 Files selected for processing (1)
  • relayer-cli/src/utils/relayerHelpers.ts (3 hunks)
🧰 Additional context used
📓 Learnings (1)
relayer-cli/src/utils/relayerHelpers.ts (2)
Learnt from: mani99brar
PR: kleros/vea#395
File: relayer-cli/src/utils/relayerHelpers.ts:95-97
Timestamp: 2025-01-15T07:41:34.012Z
Learning: The shutdown manager improvements in relayer-cli/src/utils/relayerHelpers.ts, including proper exit code handling, will be addressed in a separate PR to keep the current changes focused.
Learnt from: mani99brar
PR: kleros/vea#395
File: relayer-cli/src/utils/relayerHelpers.ts:35-35
Timestamp: 2025-01-15T07:41:33.847Z
Learning: In the VEA relayer, uncaught errors are intentionally allowed to propagate up to be handled by the shutdownManager, which has handlers for uncaughtException and unhandledRejection events, rather than adding explicit try-catch blocks.
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: dependency-review
  • GitHub Check: Scorecard analysis
  • GitHub Check: test
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
relayer-cli/src/utils/relayerHelpers.ts (2)

45-62: LGTM! Path handling and event emission look good.

The function now consistently uses process.env.STATE_DIR and properly emits events for lock state changes.


Line range hint 65-102: Event-driven error handling looks good.

The replacement of console.error with event emissions improves observability. Note that the exit code handling improvements are intentionally deferred to a separate PR.

Let's verify that all error scenarios emit the appropriate events:

✅ Verification successful

Error handling and event emissions are properly implemented

The verification confirms that:

  • Uncaught exceptions emit BotEvents.EXCEPTION
  • Unhandled rejections emit BotEvents.PROMISE_REJECTION
  • Both events are properly handled by the logger
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all error handling code paths emit events
# Look for error handling code that might be missing event emissions
rg -U "catch.*\{(?:(?!emit).)*\}" 

Length of output: 276


Script:

#!/bin/bash
# Search for catch blocks and error handling patterns
echo "=== Searching for catch blocks ==="
rg "catch.*\{" -A 3

echo -e "\n=== Searching for error-related event emissions ==="
rg "emit.*(?:ERROR|EXCEPTION|PROMISE_REJECTION)" --pcre2

echo -e "\n=== Searching for BotEvents error-related constants ==="
rg "BotEvents\.[A-Z_]+" -l | xargs rg "ERROR|EXCEPTION|PROMISE_REJECTION"

Length of output: 5135

@mani99brar mani99brar marked this pull request as ready for review January 15, 2025 07:50
@mani99brar mani99brar requested a review from jaybuidl as a code owner January 15, 2025 07:50
@mani99brar mani99brar requested a review from fcanela January 15, 2025 07:51
fcanela
fcanela previously approved these changes Jan 15, 2025
Copy link
Contributor

@fcanela fcanela left a comment

Choose a reason for hiding this comment

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

I have no full control over the Vea logic, but code-wise it looks great. Good job!

Comment on lines 22 to 28
/**
* Start the relayer
* @param chainId The chain id of the relayer
* @param network The network of the relayer
* @param shutdownManager The shutdown manager
* @param emitter The event emitter
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

@mani99brar the bot is right, the correct way of documenting object properties is with the dot notation

for (let i = 0; i < proofIndices.length; i++) {
proof.push(result[`layer${i}`][0].hash);
}

return proof;
} catch (e) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not a change of the PR, so please don't address it within it... but this try/catch is unexpected for me. If it fails getting the hashes... it returns an empty array? not throw the error? the request failing should be unexpected, not a controlled error

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, you are right. It doesn't make any sense to return an empty array to me either. Creating an issue for it.

const chain_state_raw = fs.readFileSync(state_file, { encoding: "utf8" });
emitter.emit(BotEvents.LOCK_DIRECTORY, process.cwd());

const chain_state_raw = fileSystem.readFileSync(state_file, { encoding: "utf8" });
Copy link
Contributor

Choose a reason for hiding this comment

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

@coderabbitai in general, try to avoid suggesting adding a try/catch for everything that may fail. We let the errors pop up to be handled by an upper layer or crash the process (that's fine). We are not pokemon trainers: our goal is not catch them all.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is this file meant to be committed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's the state file which the bot starts from or initialises. Pushed it to create the state directory as I had to create the folder each time

Copy link

Copy link
Contributor

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

🧹 Nitpick comments (5)
relayer-cli/src/testnetRelayer.ts (3)

33-33: Consider making maxBatchSize configurable.

The batch size is hardcoded to 10 messages per batch. Consider making this configurable through the RelayerConfig interface to allow for different batch sizes based on network conditions or requirements.

 interface RelayerConfig {
   chainId: number;
   network: string;
   shutdownManager: ShutdownManager;
   emitter: EventEmitter;
+  maxBatchSize?: number;
 }

-  const maxBatchSize = 10; // 10 messages per batch
+  const maxBatchSize = config.maxBatchSize ?? 10; // Default to 10 messages per batch

46-49: Extract delay calculation logic for better readability.

The delay calculation logic could be extracted into a separate function to improve code readability and maintainability.

+ function calculateNextEpochDelay(epochPeriod: number): number {
+   const currentTS = Math.floor(Date.now() / 1000);
+   return (epochPeriod - (currentTS % epochPeriod)) * 1000 + 100 * 1000;
+ }

-    const currentTS = Math.floor(Date.now() / 1000);
-    const delayAmount = (epochPeriod - (currentTS % epochPeriod)) * 1000 + 100 * 1000;
+    const delayAmount = calculateNextEpochDelay(epochPeriod);
     emitter.emit(BotEvents.WAITING, delayAmount);
     await delay(delayAmount);

44-45: Add explicit null check for nonce.

The code assumes that a null nonce should skip state file updates. Consider making this more explicit with a clear condition check.

-    if (nonce != null) await updateStateFile(chainId, Math.floor(Date.now() / 1000), nonce, network, emitter);
+    if (nonce === null) {
+      emitter.emit(BotEvents.NONCE_UPDATE_SKIPPED);
+    } else {
+      await updateStateFile(chainId, Math.floor(Date.now() / 1000), nonce, network, emitter);
+    }
relayer-cli/src/utils/relayerHelpers.ts (2)

23-24: Consider adding debug logging for state file initialization.

While the event emission for lock claiming is good, it would be helpful to emit an event when initializing a new state file to aid in debugging.

   if (!fileSystem.existsSync(state_file)) {
     // No state file so initialize starting now
     const tsnow = Math.floor(Date.now() / 1000);
+    emitter.emit(BotEvents.STATE_FILE_INIT, { timestamp: tsnow, network, chainId });
     await syncStateFile(chainId, tsnow, 0, network, emitter);
   }

Also applies to: 28-32


46-56: Replace console.log with event emission.

Debug logging should use the event emitter for consistency with the rest of the codebase.

-  console.log(process.env.STATE_DIR);
+  emitter.emit(BotEvents.DEBUG, { type: 'state_dir', value: process.env.STATE_DIR });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47900e9 and 1609300.

📒 Files selected for processing (3)
  • relayer-cli/src/testnetRelayer.ts (1 hunks)
  • relayer-cli/src/utils/relayerHelpers.test.ts (1 hunks)
  • relayer-cli/src/utils/relayerHelpers.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • relayer-cli/src/utils/relayerHelpers.test.ts
🧰 Additional context used
📓 Learnings (1)
relayer-cli/src/utils/relayerHelpers.ts (3)
Learnt from: fcanela
PR: kleros/vea#395
File: relayer-cli/src/utils/relayerHelpers.ts:35-35
Timestamp: 2025-01-15T12:37:24.982Z
Learning: Error handling philosophy: Avoid adding try/catch blocks for every potential failure. Let errors propagate up to be handled by upper layers or crash the process if necessary. The goal is not to catch every possible error ("we are not pokemon trainers").
Learnt from: mani99brar
PR: kleros/vea#395
File: relayer-cli/src/utils/relayerHelpers.ts:95-97
Timestamp: 2025-01-15T07:41:34.012Z
Learning: The shutdown manager improvements in relayer-cli/src/utils/relayerHelpers.ts, including proper exit code handling, will be addressed in a separate PR to keep the current changes focused.
Learnt from: mani99brar
PR: kleros/vea#395
File: relayer-cli/src/utils/relayerHelpers.ts:35-35
Timestamp: 2025-01-15T07:41:33.847Z
Learning: In the VEA relayer, uncaught errors are intentionally allowed to propagate up to be handled by the shutdownManager, which has handlers for uncaughtException and unhandledRejection events, rather than adding explicit try-catch blocks.
🔇 Additional comments (5)
relayer-cli/src/testnetRelayer.ts (2)

2-20: LGTM! Well-structured imports and interface definition.

The introduction of EventEmitter and the well-defined RelayerConfig interface enhance the modularity and type safety of the code.


59-59: Environment variable validation remains to be addressed.

The usage of process.env.VEAOUTBOX_CHAIN_ID without validation was previously discussed, and it was noted that this will be addressed in a separate issue for environment variable validation.

relayer-cli/src/utils/relayerHelpers.ts (3)

2-6: LGTM! Clean import organization.

The new imports for EventEmitter and BotEvents are well-organized and align with the shift towards an event-driven architecture.


15-22: LGTM! Well-structured dependency injection pattern.

The function signature changes improve testability while maintaining backward compatibility through default parameters.


67-72: LGTM! Improved error handling with event emission.

The replacement of console logging with event emission provides better error tracking and aligns with the event-driven architecture. The exit code handling will be addressed in a separate PR focused on shutdown manager improvements.

Also applies to: 74-75, 97-97, 102-102

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