Skip to content

Conversation

@fbac
Copy link
Collaborator

@fbac fbac commented May 6, 2025

Restructure contract configuration to support separate application and settlement chain configurations in the blockchain client

Reorganizes contract configuration by introducing a nested structure with AppChain and SettlementChain properties in options.go. The changes include:

  • Creates new AppChainOptions and SettlementChainOptions structs to separate chain-specific configurations
  • Renames contract addresses to be more descriptive (e.g., MessagesContractAddress to GroupMessageBroadcasterAddress)
  • Updates all blockchain client components to use the new configuration structure
  • Modifies validation logic in validation.go to handle the new nested configuration format
  • Updates test utilities and configuration generators to support the new structure

📍Where to Start

Start with the configuration structure changes in options.go which defines the new AppChainOptions and SettlementChainOptions structs that form the foundation for all other changes.


Macroscope summarized 384b3a8.

Summary by CodeRabbit

  • Refactor
    • Separated blockchain settings into distinct "AppChain" and "SettlementChain" configuration sections.
    • Reorganized contract addresses, chain IDs, RPC URLs, and refresh intervals under nested configuration fields.
    • Updated environment variables and scripts to support the new multi-chain configuration structure.
  • Bug Fixes
    • Enhanced validation and initialization to correctly handle the distinct AppChain and SettlementChain configurations.
  • Documentation
    • Revised onboarding and deployment guides to reflect local development environment setup and updated CLI usage.
  • Tests
    • Updated all tests to align with the new nested configuration format for blockchain settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 6, 2025

Warning

Rate limit exceeded

@fbac has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 19 minutes and 16 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 8bcb993 and 299498f.

📒 Files selected for processing (28)
  • cmd/cli/main.go (14 hunks)
  • cmd/replication/main.go (2 hunks)
  • dev/local.env (1 hunks)
  • dev/up (1 hunks)
  • doc/deploy.md (1 hunks)
  • doc/onboarding.md (2 hunks)
  • pkg/blockchain/blockchainPublisher.go (2 hunks)
  • pkg/blockchain/blockchainPublisher_test.go (1 hunks)
  • pkg/blockchain/migrator/migrator_test.go (1 hunks)
  • pkg/blockchain/ratesAdmin.go (1 hunks)
  • pkg/blockchain/ratesAdmin_test.go (1 hunks)
  • pkg/blockchain/registryAdmin.go (1 hunks)
  • pkg/blockchain/registryAdmin_test.go (1 hunks)
  • pkg/blockchain/registryCaller.go (1 hunks)
  • pkg/config/options.go (2 hunks)
  • pkg/config/validation.go (2 hunks)
  • pkg/fees/contractRates.go (2 hunks)
  • pkg/indexer/e2e_test.go (2 hunks)
  • pkg/indexer/indexer.go (8 hunks)
  • pkg/indexer/storer/groupMessage_test.go (1 hunks)
  • pkg/indexer/storer/identityUpdate_test.go (1 hunks)
  • pkg/registry/contractRegistry.go (2 hunks)
  • pkg/registry/contractRegistry_test.go (3 hunks)
  • pkg/server/server.go (2 hunks)
  • pkg/server/server_test.go (1 hunks)
  • pkg/testutils/config.go (1 hunks)
  • pkg/upgrade/scripts/load_env.sh (1 hunks)
  • pkg/utils/namespace.go (1 hunks)
## Walkthrough

The changes restructure contract and blockchain configuration throughout the codebase by introducing nested `AppChain` and `SettlementChain` structs within `ContractsOptions`. All references to contract addresses, chain IDs, RPC URLs, and refresh intervals are updated to use these new nested fields. Associated test and validation logic are also adjusted accordingly.

## Changes

| Files/Groups                                                                                 | Change Summary                                                                                                                                                                                                                                                                                                                                                       |
|---------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `pkg/config/options.go`                                                                     | Refactored `ContractsOptions` from a flat structure to include nested `AppChainOptions` and `SettlementChainOptions` for clearer separation of configuration parameters for two chains.                                                                                                                                        |
| `pkg/config/validation.go`                                                                  | Updated validation logic to separately validate nested `AppChain` and `SettlementChain` fields, replacing previous flat field checks.                                                                                                                                                                                        |
| `cmd/cli/main.go`, `cmd/replication/main.go`, `pkg/server/server.go`                        | Updated blockchain client and signer initialization to use nested `AppChain` or `SettlementChain` fields for RPC URLs and chain IDs. Variable names updated for clarity.                                                                                                               |
| `pkg/blockchain/blockchainPublisher.go`, `pkg/blockchain/blockchainPublisher_test.go`       | Changed contract address and chain ID references from flat to nested `AppChain`/`SettlementChain` fields in publisher logic and tests.                                                                                                                                                |
| `pkg/blockchain/migrator/migrator_test.go`, `pkg/blockchain/registryAdmin_test.go`          | Updated test setup to use nested `SettlementChain` fields for node registry contract addresses, chain IDs, and RPC URLs.                                                                                                                                                              |
| `pkg/blockchain/ratesAdmin.go`, `pkg/blockchain/ratesAdmin_test.go`, `pkg/fees/contractRates.go` | Changed rate registry contract address and refresh interval references to use `SettlementChain` nested fields in both implementation and tests.                                                                                                                                               |
| `pkg/blockchain/registryAdmin.go`, `pkg/blockchain/registryCaller.go`                       | Updated node registry contract address references to use nested `SettlementChain` fields in admin/caller constructors.                                                                                                                                                                 |
| `pkg/indexer/indexer.go`, `pkg/indexer/e2e_test.go`, `pkg/indexer/storer/groupMessage_test.go`, `pkg/indexer/storer/identityUpdate_test.go` | Updated all contract address, chain ID, and RPC URL references to use `AppChain` nested fields in indexer logic and tests.                                                                                                                     |
| `pkg/registry/contractRegistry.go`, `pkg/registry/contractRegistry_test.go`                 | Changed node registry address and refresh interval configuration to use nested `SettlementChain` fields in registry logic and tests.                                                                                                                                                  |
| `pkg/server/server_test.go`                                                                 | Modified test server configuration to use nested `AppChain` fields for RPC URL and disconnect time.                                                                                                                                            |
| `pkg/testutils/config.go`                                                                   | Changed utility function to return `ContractsOptions` with nested `AppChain` and `SettlementChain` fields instead of flat fields.                                                                                                              |
| `pkg/utils/namespace.go`                                                                    | Updated namespace derivation to use `SettlementChain.NodeRegistryAddress` instead of flat contract address.                                                                                                                                    |
| `dev/local.env`, `pkg/upgrade/scripts/load_env.sh`                                          | Updated environment variables and script to replace single RPC URL variable with separate `APP_CHAIN` and `SETTLEMENT_CHAIN` RPC URL variables; renamed contract address variables to reflect new nested configuration structure.                                                                  |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Config as ContractsOptions
    participant AppChain as AppChainOptions
    participant SettlementChain as SettlementChainOptions
    participant Client as Blockchain Client
    participant Contract as Smart Contract

    Config->>AppChain: Access AppChain fields (e.g. RpcURL, ChainID)
    Config->>SettlementChain: Access SettlementChain fields (e.g. RpcURL, NodeRegistryAddress)
    AppChain->>Client: Initialize client with AppChain.RpcURL
    SettlementChain->>Client: Initialize client with SettlementChain.RpcURL
    Client->>Contract: Instantiate contract with address from AppChain/SettlementChain

Possibly related PRs

  • xmtp/xmtpd#575: Introduces the RatesAdmin struct and methods for managing rates; related as both PRs touch rate management, but this PR focuses on configuration restructuring.

Suggested reviewers

  • neekolas
  • mkysel

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=xmtp/xmtpd&utm_content=755):

- 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.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

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](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@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` 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](https://docs.coderabbit.ai/guides/configure-coderabbit) 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](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1aa706b and 384b3a8.

📒 Files selected for processing (23)
  • cmd/cli/main.go (14 hunks)
  • cmd/replication/main.go (1 hunks)
  • pkg/blockchain/blockchainPublisher.go (2 hunks)
  • pkg/blockchain/blockchainPublisher_test.go (1 hunks)
  • pkg/blockchain/migrator/migrator_test.go (1 hunks)
  • pkg/blockchain/ratesAdmin.go (1 hunks)
  • pkg/blockchain/ratesAdmin_test.go (1 hunks)
  • pkg/blockchain/registryAdmin.go (1 hunks)
  • pkg/blockchain/registryAdmin_test.go (1 hunks)
  • pkg/blockchain/registryCaller.go (1 hunks)
  • pkg/config/options.go (1 hunks)
  • pkg/config/validation.go (1 hunks)
  • pkg/fees/contractRates.go (2 hunks)
  • pkg/indexer/e2e_test.go (2 hunks)
  • pkg/indexer/indexer.go (8 hunks)
  • pkg/indexer/storer/groupMessage_test.go (1 hunks)
  • pkg/indexer/storer/identityUpdate_test.go (1 hunks)
  • pkg/registry/contractRegistry.go (2 hunks)
  • pkg/registry/contractRegistry_test.go (3 hunks)
  • pkg/server/server.go (2 hunks)
  • pkg/server/server_test.go (1 hunks)
  • pkg/testutils/config.go (1 hunks)
  • pkg/utils/namespace.go (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (12)
cmd/replication/main.go (2)
pkg/blockchain/client.go (1)
  • NewClient (17-19)
pkg/registry/contractRegistry.go (1)
  • NewSmartContractRegistry (53-79)
pkg/blockchain/blockchainPublisher_test.go (4)
pkg/testutils/contracts.go (3)
  • DeployNodesContract (178-180)
  • DeployGroupMessagesContract (182-184)
  • DeployIdentityUpdatesContract (186-188)
pkg/blockchain/signer.go (1)
  • NewPrivateKeySigner (26-52)
pkg/testutils/config.go (1)
  • GetPayerOptions (32-36)
pkg/blockchain/client.go (1)
  • NewClient (17-19)
cmd/cli/main.go (2)
pkg/blockchain/client.go (1)
  • NewClient (17-19)
pkg/blockchain/signer.go (1)
  • NewPrivateKeySigner (26-52)
pkg/blockchain/ratesAdmin_test.go (3)
pkg/testutils/contracts.go (2)
  • DeployRatesRegistryContract (190-192)
  • LOCAL_PRIVATE_KEY (26-26)
pkg/blockchain/signer.go (1)
  • NewPrivateKeySigner (26-52)
pkg/blockchain/client.go (1)
  • NewClient (17-19)
pkg/server/server_test.go (1)
pkg/config/options.go (1)
  • AppChainOptions (17-25)
pkg/testutils/config.go (1)
pkg/config/options.go (2)
  • AppChainOptions (17-25)
  • SettlementChainOptions (27-32)
pkg/indexer/e2e_test.go (3)
pkg/testutils/contracts.go (2)
  • DeployGroupMessagesContract (182-184)
  • DeployIdentityUpdatesContract (186-188)
pkg/blockchain/signer.go (1)
  • NewPrivateKeySigner (26-52)
pkg/blockchain/client.go (1)
  • NewClient (17-19)
pkg/blockchain/registryAdmin_test.go (4)
pkg/testutils/contracts.go (1)
  • DeployNodesContract (178-180)
pkg/blockchain/signer.go (1)
  • NewPrivateKeySigner (26-52)
pkg/testutils/config.go (1)
  • GetPayerOptions (32-36)
pkg/blockchain/client.go (1)
  • NewClient (17-19)
pkg/blockchain/migrator/migrator_test.go (4)
pkg/testutils/contracts.go (1)
  • DeployNodesContract (178-180)
pkg/blockchain/signer.go (1)
  • NewPrivateKeySigner (26-52)
pkg/testutils/config.go (1)
  • GetPayerOptions (32-36)
pkg/blockchain/client.go (1)
  • NewClient (17-19)
pkg/server/server.go (1)
pkg/blockchain/client.go (1)
  • NewClient (17-19)
pkg/blockchain/blockchainPublisher.go (1)
pkg/abi/identityupdatebroadcaster/IdentityUpdateBroadcaster.go (1)
  • NewIdentityUpdateBroadcaster (123-129)
pkg/registry/contractRegistry_test.go (1)
pkg/config/options.go (2)
  • ContractsOptions (12-15)
  • SettlementChainOptions (27-32)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Code Review
  • GitHub Check: Push Docker Images to GitHub Packages (xmtpd-cli)
  • GitHub Check: Upgrade Tests
  • GitHub Check: Push Docker Images to GitHub Packages (xmtpd)
  • GitHub Check: Test (Node)
🔇 Additional comments (60)
pkg/blockchain/registryCaller.go (1)

33-33: LGTM: Address reference updated for multi-chain support

The contract address reference has been correctly updated to use the nested SettlementChain.NodeRegistryAddress field instead of a top-level field, which aligns with the multi-chain support objective of this PR.

cmd/replication/main.go (2)

102-105: LGTM: Client initialization updated for settlement chain

The blockchain client is now properly initialized with the settlement chain's RPC URL and renamed to settlementChainClient, making it clear which chain this client is connected to.


112-112: LGTM: Chain-specific client reference

The renamed client is correctly passed to the smart contract registry, maintaining consistency with the multi-chain architecture.

pkg/utils/namespace.go (1)

13-13: LGTM: Updated namespace generation for multi-chain support

The namespace generation correctly uses the settlement chain's node registry address, maintaining namespace consistency while supporting the new multi-chain structure.

pkg/blockchain/registryAdmin.go (1)

52-52: LGTM: Contract address reference updated for multi-chain support

The node registry contract address is now correctly sourced from the nested SettlementChain structure, consistent with the overall refactoring pattern in this PR.

pkg/blockchain/ratesAdmin.go (1)

34-34: LGTM: Correctly updated to use nested AppChain configuration

The change properly updates the contract address reference to use the new nested AppChain struct, which is consistent with the multi-chain support refactoring.

pkg/blockchain/blockchainPublisher.go (3)

52-54: LGTM: Properly updated contract address reference

The GroupMessageBroadcaster address is now correctly accessed from the nested AppChain configuration.


59-61: LGTM: Properly updated contract address reference

The IdentityUpdateBroadcaster address is now correctly accessed from the nested AppChain configuration.


83-83: LGTM: Updated logger context with new configuration path

Logger field updated to use the new nested path to the GroupMessageBroadcasterAddress.

pkg/registry/contractRegistry_test.go (3)

40-44: LGTM: Test configuration updated to use nested SettlementChain structure

The test is properly updated to use the new configuration structure, with the NodeRegistryRefreshInterval now under the nested SettlementChain options.


93-97: LGTM: Test configuration updated to use nested SettlementChain structure

This test case correctly uses the nested configuration structure with the refresh interval in the appropriate location.


155-159: LGTM: Test configuration updated to use nested SettlementChain structure

The TestStopOnContextCancel test has been properly updated to use the new nested configuration pattern.

pkg/indexer/storer/groupMessage_test.go (3)

27-30: LGTM: Test setup updated to use nested AppChain configuration

The contract address is now correctly assigned to the nested AppChain structure.


32-32: LGTM: Updated client initialization to use AppChain RPC URL

The blockchain client is now properly initialized using the RPC URL from the nested AppChain configuration.


35-35: LGTM: Updated contract address reference

Contract initialization correctly uses the address from the nested AppChain configuration.

pkg/blockchain/migrator/migrator_test.go (3)

24-24: Node registry contract is now properly associated with the settlement chain.

The code correctly updates the contract address storage to use the new nested SettlementChain structure. This aligns with the multi-chain support being added in this PR, where node registry functionality is consistently placed under the settlement chain.


28-28: Signer's chain ID now references settlement chain.

The signer configuration correctly uses the settlement chain's ID for transaction signing. This ensures transactions to the node registry contract are properly signed for the correct blockchain.


32-32: Blockchain client now connects to settlement chain.

The client instantiation properly uses the settlement chain's RPC URL, ensuring the test connects to the correct blockchain network for node registry operations.

pkg/blockchain/ratesAdmin_test.go (3)

24-27: Rate registry contract is now properly associated with the app chain.

The code correctly updates the rate registry contract address to be under the AppChain struct. This is consistent with the architectural changes in this PR that separate app chain and settlement chain functionality.


31-31: Signer's chain ID now references app chain.

The private key signer is correctly configured to use the app chain's ID, ensuring that transactions related to rates are signed for the appropriate blockchain.


35-35: Blockchain client now connects to app chain.

The client initialization properly uses the app chain's RPC URL, ensuring the test connects to the correct blockchain network for rate registry operations.

pkg/server/server_test.go (1)

45-48: Test server configuration updated to use nested AppChain options.

The server configuration for testing has been properly updated to use the new nested structure, with RPC URL and max disconnect time now correctly placed under the AppChain options. This aligns with the multi-chain support being implemented across the codebase.

pkg/blockchain/registryAdmin_test.go (3)

23-23: Node registry contract is now properly associated with the settlement chain.

The code correctly updates the node registry contract address to use the new nested SettlementChain structure. This is consistent with the changes in other files that place node registry functionality under the settlement chain.


27-27: Signer's chain ID now references settlement chain.

The private key signer is correctly configured to use the settlement chain's ID, ensuring that transactions to the node registry contract are signed for the appropriate blockchain.


31-31: Blockchain client now connects to settlement chain.

The client instantiation properly uses the settlement chain's RPC URL, ensuring the test connects to the correct blockchain network for node registry operations.

pkg/server/server.go (3)

241-241: Chain ID source updated to use AppChain struct.

The code now correctly uses the new nested AppChain configuration, making the chain distinction explicit.


247-247: Renamed variable and updated RPC URL source to use AppChain.

Good change that improves clarity by:

  1. Renaming ethclient to appChainClient to better indicate its purpose
  2. Using the new nested AppChain configuration structure

This makes it clear which chain this client is connecting to.


257-257: Updated blockchain publisher to use appChainClient.

This correctly ensures the blockchain publisher uses the renamed client that's connected to the application chain.

pkg/indexer/e2e_test.go (3)

33-40: Updated contract address assignment to use AppChain nested structure.

The test now correctly uses the restructured configuration, assigning the deployed contract addresses to the appropriate nested fields in the AppChain structure.


65-65: Updated chain ID reference to use AppChain nested field.

Properly uses the new configuration structure for the blockchain signer setup.


69-69: Updated RPC URL reference to use AppChain nested field.

Correctly uses the new configuration structure for client instantiation.

cmd/cli/main.go (5)

220-221: Updated to use SettlementChain's ChainID for registry admin setup.

The code now correctly references the chain ID from the settlement chain configuration.


251-254: Updated RPC URL to use SettlementChain's configuration.

The code now correctly creates a chain client using the settlement chain's RPC URL.


288-288: Updated chain ID references to use SettlementChain consistently.

The code consistently references the settlement chain's chain ID across multiple administrative functions.

Also applies to: 315-315, 342-342, 361-361, 383-383, 409-409, 484-484, 507-507


402-402: Updated RPC URL references to use SettlementChain consistently.

The code consistently references the settlement chain's RPC URL across blockchain client initialization points.

Also applies to: 445-445, 536-536, 571-571


725-728: Updated setupRegistryAdmin to use SettlementChain's RPC URL.

The helper function correctly uses the settlement chain configuration for blockchain client setup.

pkg/indexer/storer/identityUpdate_test.go (3)

31-34: Updated contract address assignment to use AppChain configuration.

The test now correctly deploys and assigns the contract address to the nested AppChain field.


36-36: Updated client initialization to use AppChain's RPC URL.

Correctly references the AppChain's RPC URL for blockchain client creation.


39-39: Updated contract address reference to use AppChain configuration.

The contract initialization now correctly uses the nested AppChain field for the contract address.

pkg/registry/contractRegistry.go (2)

60-60: Configuration path updated to use nested structure.

The node registry contract address is now accessed through the SettlementChain struct, aligning with the multi-chain support architecture.


72-72: Refresh interval now accessed through nested SettlementChain struct.

The refresh interval for the node registry is consistently updated to use the nested structure, maintaining alignment with the contract address change above.

pkg/indexer/indexer.go (9)

73-73: RPC URL now accessed through AppChain struct.

The blockchain client initialization now correctly uses the AppChain's RPC URL, supporting the multi-chain architecture.


97-97: Contract address logging uses AppChain structure.

The logger now consistently references the contract address through the AppChain struct, enhancing clarity about which chain this contract belongs to.

Also applies to: 108-108


123-123: Identity update broadcaster contract address updated to use AppChain.

Similar to the group message broadcaster, the identity update broadcaster contract address is now properly referenced through the AppChain struct.

Also applies to: 138-138


170-172: Block tracker initialization updated for multi-chain support.

The message tracker initialization now correctly uses the contract address from the AppChain struct, maintaining consistency with other changes.


180-183: ListenForContractEvent parameters updated for multi-chain architecture.

The contract address and max disconnect time are now accessed through the AppChain struct, ensuring consistency across the codebase.


190-194: Identity updates tracker initialization updated.

Similar to the messages tracker, the identity updates tracker now uses the appropriate contract address from the AppChain struct.


202-204: Identity update contract event parameters updated.

The contract address and max disconnect time for identity updates are now consistently accessed through the AppChain struct.


410-411: Contract instantiation updated for multi-chain support.

The message contract instantiation function now correctly references the contract address through the AppChain struct.


420-421: Identity update contract instantiation uses AppChain struct.

Similarly to the message contract, the identity update contract instantiation now correctly uses the AppChain nested field.

pkg/fees/contractRates.go (2)

60-61: Rate registry contract address now accessed through AppChain struct.

The rate registry contract address is now accessed through the AppChain nested structure, properly categorizing this contract as part of the application chain rather than the settlement chain.


71-71: Rates refresh interval accessed through AppChain struct.

The refresh interval is consistently accessed through the same nested structure as the contract address, maintaining a clear architecture.

pkg/blockchain/blockchainPublisher_test.go (3)

21-29: Test contract deployments updated for multi-chain support.

The test setup now correctly assigns contract addresses to the appropriate chain structures:

  • Node registry to the SettlementChain
  • Message broadcasters to the AppChain

This change ensures tests properly reflect the production code's multi-chain architecture.


33-33: Signer creation uses chain ID from AppChain struct.

The signer is now correctly initialized with the chain ID from the AppChain, ensuring transactions are signed with the appropriate chain parameters.


37-37: Blockchain client uses RPC URL from SettlementChain.

The client is now initialized with the RPC URL from the SettlementChain struct, which is correctly aligned with the test's use of the node registry on the settlement chain.

pkg/testutils/config.go (1)

18-28: Configuration refactored to support multi-chain - LGTM!

The NewContractsOptions function has been correctly updated to use the new nested structure with AppChain and SettlementChain fields. Both chains share the same RPC URL and chain ID for testing purposes, which makes sense since most tests likely run against a single local blockchain instance.

The test configuration provides reasonable defaults for both chains while maintaining the expected behavior of existing tests.

pkg/config/validation.go (2)

13-40: Validation logic split for AppChain fields - LGTM!

The validation logic has been properly updated to check all required fields and constraints for the Application Chain configuration. Error messages correctly reference the new nested structure with appropriate field paths.


42-57: Validation logic for SettlementChain fields - LGTM!

The validation logic properly checks all required fields for the Settlement Chain configuration, including RPC URL, chain ID, node registry address, and refresh interval. Error messages are clear and correctly reference the nested structure.

pkg/config/options.go (2)

13-15: ContractsOptions split into two chain-specific structs - LGTM!

The ContractsOptions struct has been restructured to contain two separate chain configurations, which better organizes the contract-related settings and provides clearer separation of concerns between application and settlement chains.


17-25: New AppChainOptions struct looks good!

The AppChainOptions struct properly encapsulates all application chain related configuration including RPC URL, chain ID, contract addresses, and intervals.

@fbac fbac force-pushed the 05-06-support_multi_chain branch from 0d4b1ca to 8f4b43b Compare May 6, 2025 14:54
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: 3

🧹 Nitpick comments (4)
doc/onboarding.md (1)

45-46: Disable MD034 lint for RPC URLs in code block
The bare RPC URL in the shell snippet triggers MD034. To suppress this for the entire block, add:

<!-- markdownlint-disable MD034 -->

immediately before the code fence.

doc/deploy.md (3)

15-19: Convert bare URLs in the DNS table to markdown links
Raw endpoints (e.g., https://grpc.testnet.xmtp.network) should be wrapped in link syntax for clarity and to satisfy markdownlint (MD034).

Example diff:

-| https://grpc.testnet.xmtp.network  | US-EAST-2  | 0x03e... |
+| [grpc.testnet.xmtp.network](https://grpc.testnet.xmtp.network) | US-EAST-2 | 0x03e... |
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

17-17: Bare URL used
null

(MD034, no-bare-urls)


18-18: Bare URL used
null

(MD034, no-bare-urls)


72-75: Mirror registry variable naming in verification section
Similar to registration, the verification example still references XMTPD_CONTRACTS_NODE_REGISTRY_ADDRESS. Update to:

export XMTPD_SETTLEMENT_CHAIN_NODE_REGISTRY_ADDRESS="0xDEADBEEF"

85-106: Replace hard tabs in JSON sample
The JSON output block contains hard tabs, violating MD010. Convert tabs to spaces (e.g., 2 spaces per indent) for proper formatting.

Example diff for the first few lines:

-	"level": "INFO",
-	"time": "2025-05-06T16:39:35.737+0200",
-	"message": "got nodes",
+  "level": "INFO",
+  "time": "2025-05-06T16:39:35.737+0200",
+  "message": "got nodes",
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

85-85: Hard tabs
Column: 1

(MD010, no-hard-tabs)


86-86: Hard tabs
Column: 1

(MD010, no-hard-tabs)


87-87: Hard tabs
Column: 1

(MD010, no-hard-tabs)


88-88: Hard tabs
Column: 1

(MD010, no-hard-tabs)


89-89: Hard tabs
Column: 1

(MD010, no-hard-tabs)


90-90: Hard tabs
Column: 1

(MD010, no-hard-tabs)


91-91: Hard tabs
Column: 1

(MD010, no-hard-tabs)


92-92: Hard tabs
Column: 1

(MD010, no-hard-tabs)


93-93: Hard tabs
Column: 1

(MD010, no-hard-tabs)


94-94: Hard tabs
Column: 1

(MD010, no-hard-tabs)


95-95: Hard tabs
Column: 1

(MD010, no-hard-tabs)


96-96: Hard tabs
Column: 1

(MD010, no-hard-tabs)


97-97: Hard tabs
Column: 1

(MD010, no-hard-tabs)


98-98: Hard tabs
Column: 1

(MD010, no-hard-tabs)


99-99: Hard tabs
Column: 1

(MD010, no-hard-tabs)


100-100: Hard tabs
Column: 1

(MD010, no-hard-tabs)


101-101: Hard tabs
Column: 1

(MD010, no-hard-tabs)


102-102: Hard tabs
Column: 1

(MD010, no-hard-tabs)


103-103: Hard tabs
Column: 1

(MD010, no-hard-tabs)


104-104: Hard tabs
Column: 1

(MD010, no-hard-tabs)


105-105: Hard tabs
Column: 1

(MD010, no-hard-tabs)


106-106: Hard tabs
Column: 1

(MD010, no-hard-tabs)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 611321e and 8f4b43b.

📒 Files selected for processing (8)
  • doc/deploy.md (1 hunks)
  • doc/onboarding.md (2 hunks)
  • pkg/blockchain/ratesAdmin.go (1 hunks)
  • pkg/blockchain/ratesAdmin_test.go (1 hunks)
  • pkg/config/options.go (1 hunks)
  • pkg/config/validation.go (1 hunks)
  • pkg/fees/contractRates.go (2 hunks)
  • pkg/testutils/config.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • pkg/blockchain/ratesAdmin_test.go
  • pkg/blockchain/ratesAdmin.go
  • pkg/testutils/config.go
  • pkg/fees/contractRates.go
  • pkg/config/validation.go
  • pkg/config/options.go
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
doc/deploy.md

17-17: Bare URL used
null

(MD034, no-bare-urls)


18-18: Bare URL used
null

(MD034, no-bare-urls)


85-85: Hard tabs
Column: 1

(MD010, no-hard-tabs)


86-86: Hard tabs
Column: 1

(MD010, no-hard-tabs)


87-87: Hard tabs
Column: 1

(MD010, no-hard-tabs)


88-88: Hard tabs
Column: 1

(MD010, no-hard-tabs)


89-89: Hard tabs
Column: 1

(MD010, no-hard-tabs)


90-90: Hard tabs
Column: 1

(MD010, no-hard-tabs)


91-91: Hard tabs
Column: 1

(MD010, no-hard-tabs)


92-92: Hard tabs
Column: 1

(MD010, no-hard-tabs)


93-93: Hard tabs
Column: 1

(MD010, no-hard-tabs)


94-94: Hard tabs
Column: 1

(MD010, no-hard-tabs)


95-95: Hard tabs
Column: 1

(MD010, no-hard-tabs)


96-96: Hard tabs
Column: 1

(MD010, no-hard-tabs)


97-97: Hard tabs
Column: 1

(MD010, no-hard-tabs)


98-98: Hard tabs
Column: 1

(MD010, no-hard-tabs)


99-99: Hard tabs
Column: 1

(MD010, no-hard-tabs)


100-100: Hard tabs
Column: 1

(MD010, no-hard-tabs)


101-101: Hard tabs
Column: 1

(MD010, no-hard-tabs)


102-102: Hard tabs
Column: 1

(MD010, no-hard-tabs)


103-103: Hard tabs
Column: 1

(MD010, no-hard-tabs)


104-104: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Code Review

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

♻️ Duplicate comments (1)
doc/deploy.md (1)

78-79: ⚠️ Potential issue

Inconsistent private key environment variable usage
The get-all-nodes command still references $PRIVATE_KEY, whereas the registration step uses ${ADMIN_PRIVATE_KEY} (or XMTPD_ADMIN_PRIVATE_KEY if renamed). Update it to:

dev/cmd/get-all-nodes \
    --admin.private-key=${ADMIN_PRIVATE_KEY}
🧹 Nitpick comments (4)
doc/deploy.md (4)

17-18: Convert bare URLs to markdown links
Markdownlint flags bare URLs in the table header (lines 17–18). Wrapping them in link syntax improves readability and compliance:

-| https://grpc.testnet.xmtp.network  | US-EAST-2  | ...
-| https://grpc2.testnet.xmtp.network | EU-NORTH-1 | ...
+| [grpc.testnet.xmtp.network](https://grpc.testnet.xmtp.network)  | US-EAST-2  | ...
+| [grpc2.testnet.xmtp.network](https://grpc2.testnet.xmtp.network) | EU-NORTH-1 | ...
🧰 Tools
🪛 Gitleaks (8.21.2)

17-17: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 markdownlint-cli2 (0.17.2)

17-17: Bare URL used
null

(MD034, no-bare-urls)


18-18: Bare URL used
null

(MD034, no-bare-urls)


49-52: Add AppChain environment variables
With the new multi-chain support, we should document the corresponding XMTPD_APP_CHAIN_* settings alongside the settlement-chain vars. For example:

+export XMTPD_APP_CHAIN_RPC_URL="http://localhost:7546/"
+export XMTPD_APP_CHAIN_CHAIN_ID=31338

This ensures users can configure both chains explicitly.


50-56: Namespace environment variables consistently
The variables ADMIN_PRIVATE_KEY, NODE_HTTP_ADDRESS, NODE_OWNER_ADDRESS, and NODE_SIGNING_KEY_PUB lack the XMTPD_ prefix used elsewhere. To avoid collisions and improve clarity, consider renaming them:

-export ADMIN_PRIVATE_KEY="0xDEADBEEF"
+export XMTPD_ADMIN_PRIVATE_KEY="0xDEADBEEF"

-export NODE_HTTP_ADDRESS="https://grpc.example.com"
+export XMTPD_NODE_HTTP_ADDRESS="https://grpc.example.com"

-export NODE_OWNER_ADDRESS="0xDEADBEEF"
+export XMTPD_NODE_OWNER_ADDRESS="0xDEADBEEF"

-export NODE_SIGNING_KEY_PUB="0xDEADBEEF"
+export XMTPD_NODE_SIGNING_KEY_PUB="0xDEADBEEF"

85-104: Replace hard tabs with spaces in JSON example
The JSON code block uses hard tabs for indentation (lines 85–104), which can render inconsistently. Replace tabs with a consistent number of spaces (e.g., two spaces per level):

-	"level": "INFO",
-	"time": "2025-05-06T16:39:35.737+0200",
-	"message": "got nodes",
+  "level": "INFO",
+  "time": "2025-05-06T16:39:35.737+0200",
+  "message": "got nodes",
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

85-85: Hard tabs
Column: 1

(MD010, no-hard-tabs)


86-86: Hard tabs
Column: 1

(MD010, no-hard-tabs)


87-87: Hard tabs
Column: 1

(MD010, no-hard-tabs)


88-88: Hard tabs
Column: 1

(MD010, no-hard-tabs)


89-89: Hard tabs
Column: 1

(MD010, no-hard-tabs)


90-90: Hard tabs
Column: 1

(MD010, no-hard-tabs)


91-91: Hard tabs
Column: 1

(MD010, no-hard-tabs)


92-92: Hard tabs
Column: 1

(MD010, no-hard-tabs)


93-93: Hard tabs
Column: 1

(MD010, no-hard-tabs)


94-94: Hard tabs
Column: 1

(MD010, no-hard-tabs)


95-95: Hard tabs
Column: 1

(MD010, no-hard-tabs)


96-96: Hard tabs
Column: 1

(MD010, no-hard-tabs)


97-97: Hard tabs
Column: 1

(MD010, no-hard-tabs)


98-98: Hard tabs
Column: 1

(MD010, no-hard-tabs)


99-99: Hard tabs
Column: 1

(MD010, no-hard-tabs)


100-100: Hard tabs
Column: 1

(MD010, no-hard-tabs)


101-101: Hard tabs
Column: 1

(MD010, no-hard-tabs)


102-102: Hard tabs
Column: 1

(MD010, no-hard-tabs)


103-103: Hard tabs
Column: 1

(MD010, no-hard-tabs)


104-104: Hard tabs
Column: 1

(MD010, no-hard-tabs)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 8f4b43b and 786a8ff.

📒 Files selected for processing (5)
  • dev/local.env (1 hunks)
  • dev/up (1 hunks)
  • doc/deploy.md (1 hunks)
  • doc/onboarding.md (2 hunks)
  • pkg/config/options.go (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • dev/up
🚧 Files skipped from review as they are similar to previous changes (3)
  • doc/onboarding.md
  • pkg/config/options.go
  • dev/local.env
🧰 Additional context used
🪛 Gitleaks (8.21.2)
doc/deploy.md

17-17: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


31-31: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 markdownlint-cli2 (0.17.2)
doc/deploy.md

17-17: Bare URL used
null

(MD034, no-bare-urls)


18-18: Bare URL used
null

(MD034, no-bare-urls)


85-85: Hard tabs
Column: 1

(MD010, no-hard-tabs)


86-86: Hard tabs
Column: 1

(MD010, no-hard-tabs)


87-87: Hard tabs
Column: 1

(MD010, no-hard-tabs)


88-88: Hard tabs
Column: 1

(MD010, no-hard-tabs)


89-89: Hard tabs
Column: 1

(MD010, no-hard-tabs)


90-90: Hard tabs
Column: 1

(MD010, no-hard-tabs)


91-91: Hard tabs
Column: 1

(MD010, no-hard-tabs)


92-92: Hard tabs
Column: 1

(MD010, no-hard-tabs)


93-93: Hard tabs
Column: 1

(MD010, no-hard-tabs)


94-94: Hard tabs
Column: 1

(MD010, no-hard-tabs)


95-95: Hard tabs
Column: 1

(MD010, no-hard-tabs)


96-96: Hard tabs
Column: 1

(MD010, no-hard-tabs)


97-97: Hard tabs
Column: 1

(MD010, no-hard-tabs)


98-98: Hard tabs
Column: 1

(MD010, no-hard-tabs)


99-99: Hard tabs
Column: 1

(MD010, no-hard-tabs)


100-100: Hard tabs
Column: 1

(MD010, no-hard-tabs)


101-101: Hard tabs
Column: 1

(MD010, no-hard-tabs)


102-102: Hard tabs
Column: 1

(MD010, no-hard-tabs)


103-103: Hard tabs
Column: 1

(MD010, no-hard-tabs)


104-104: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: Push Docker Images to GitHub Packages (xmtpd-cli)
  • GitHub Check: Upgrade Tests
  • GitHub Check: Lint-Go
  • GitHub Check: Test (Node)
  • GitHub Check: Push Docker Images to GitHub Packages (xmtpd)
  • GitHub Check: Code Review

@fbac fbac changed the title Add multi-chain support breaking: Add multi-chain support May 7, 2025
@fbac fbac marked this pull request as ready for review May 7, 2025 15:08
@fbac fbac requested review from a team as code owners May 7, 2025 15:08
@macroscopeapp
Copy link

macroscopeapp bot commented May 7, 2025

Restructure contract configuration to support separate application and settlement chain deployments

The changes introduce a new multi-chain architecture by restructuring the contract configuration into separate application chain and settlement chain components. Key changes include:

  • Refactors ContractsOptions in options.go to add nested AppChainOptions and SettlementChainOptions structures while maintaining backward compatibility
  • Updates configuration validation in validation.go to handle multi-chain deployments and normalize legacy configurations
  • Modifies contract address references across the codebase to use chain-specific paths (e.g. AppChain.GroupMessageBroadcasterAddress and SettlementChain.NodeRegistryAddress)
  • Updates environment variable structure in local.env to separate chain configurations with new XMTPD_SETTLEMENT_CHAIN_ and XMTPD_APP_CHAIN_ prefixes

📍Where to Start

Start with the configuration structure changes in options.go which defines the new multi-chain architecture, followed by validation.go which implements the validation logic for the new structure.


Macroscope summarized 299498f.

@fbac
Copy link
Collaborator Author

fbac commented May 7, 2025

After merging this there's a need to:

  • Use the newly generated xmtpd-cli after this PR in the docker compose which register nodes.
  • Update terraform infra to the new env vars.

Copy link
Collaborator

@mkysel mkysel left a comment

Choose a reason for hiding this comment

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

LGTM. Can we still accept the old XMTPD variables and deprecate them instead? It won't break anyone and it will be easier to deploy

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

♻️ Duplicate comments (2)
pkg/config/validation.go (2)

23-24: Error key inconsistency persists in validation messages.

The error key --contracts.app-chain.messages-address mentioned in the past review comment has been changed to --contracts.app-chain.group-message-broadcaster-address, which is correct for the new nested structure. However, other inconsistencies with error key formatting remain throughout the validation code.


120-133: Inconsistent error key formatting needs to be addressed.

The error keys for fields such as DB.WriterConnectionString, payer.PrivateKey, and Signer.PrivateKey use a different format than the kebab-case style used for contract option fields. This inconsistency was noted in a previous review and should be standardized.

Apply this diff to make error keys consistent:

-			missingSet["--DB.WriterConnectionString"] = struct{}{}
+			missingSet["--db.writer-connection-string"] = struct{}{}
-			missingSet["--payer.PrivateKey"] = struct{}{}
+			missingSet["--payer.private-key"] = struct{}{}
-			missingSet["--Signer.PrivateKey"] = struct{}{}
+			missingSet["--signer.private-key"] = struct{}{}
🧹 Nitpick comments (1)
pkg/config/validation.go (1)

9-169: Consider adding a function comment to document in-place modification behavior.

The function now modifies the input options directly, particularly when copying values from flat fields to the nested structure in single-chain mode. This behavior should be documented in a function comment.

Add a function comment like this:

+// ValidateServerOptions validates the ServerOptions and, for backward compatibility,
+// copies values from legacy flat fields to the new nested AppChain and SettlementChain 
+// structure when in single-chain mode.
 func ValidateServerOptions(options *ServerOptions) error {
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 786a8ff and 2d73f67.

📒 Files selected for processing (4)
  • cmd/replication/main.go (2 hunks)
  • dev/local.env (1 hunks)
  • pkg/config/options.go (2 hunks)
  • pkg/config/validation.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • cmd/replication/main.go
  • pkg/config/options.go
  • dev/local.env
🧰 Additional context used
🧬 Code Graph Analysis (1)
pkg/config/validation.go (1)
pkg/config/options.go (1)
  • ServerOptions (105-120)
🔇 Additional comments (4)
pkg/config/validation.go (4)

9-9: Function signature updated to allow in-place modification of options.

The signature change from value to pointer parameter allows the function to modify the options in-place, particularly for copying values from legacy fields to the new nested structure. This is appropriate for enabling backward compatibility while supporting the new multi-chain configuration.


13-115: Multi-chain support structure looks good with proper validation.

The code now correctly differentiates between multi-chain and single-chain deployments, with comprehensive validation for both scenarios. For backward compatibility, legacy field values are properly copied to the new nested structure.


171-174: Helper function effectively determines multi-chain deployment.

The isMultiChainDeployment function provides a clear way to determine if a multi-chain deployment is configured by checking if both App Chain and Settlement Chain RPC URLs are specified. This is a good approach for detecting the deployment type.


117-117: Good separation of common validations with clear comment.

Adding a comment to clearly separate common validations from chain-specific validations improves code readability and maintainability.

@fbac fbac force-pushed the 05-06-support_multi_chain branch 2 times, most recently from 963b25a to 7045ccc Compare May 9, 2025 12:22
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 (3)
pkg/config/validation.go (3)

142-145: Consider enhancing multi-chain detection logic

The isMultiChainDeployment function currently only checks if both RPC URLs are set. You might want to consider additional conditions for more robust detection, such as verifying other required fields for multi-chain deployments are properly configured.

func isMultiChainDeployment(options ServerOptions) bool {
-	return options.Contracts.AppChain.RpcURL != "" &&
-		options.Contracts.SettlementChain.RpcURL != ""
+	return options.Contracts.AppChain.RpcURL != "" && 
+		options.Contracts.SettlementChain.RpcURL != "" &&
+		// Consider adding additional checks if appropriate
+		(options.Contracts.AppChain.GroupMessageBroadcasterAddress != "" || 
+		 options.Contracts.SettlementChain.NodeRegistryAddress != "")
}

85-117: Reduce duplication in WriterConnectionString validation

The validation for DB.WriterConnectionString is repeated in multiple places. Consider refactoring to check this field once and then check which features are enabled.

-	if options.Payer.Enable {
-		validateField(
-			options.DB.WriterConnectionString,
-			"db.writer-connection-string",
-			missingSet,
-		)
-		validateField(options.Payer.PrivateKey, "payer.private-key", missingSet)
-	}
-
-	if options.Replication.Enable {
-		validateField(
-			options.DB.WriterConnectionString,
-			"db.writer-connection-string",
-			missingSet,
-		)
-		validateField(options.Signer.PrivateKey, "signer.private-key", missingSet)
-	}
-
-	if options.Sync.Enable {
-		validateField(
-			options.DB.WriterConnectionString,
-			"db.writer-connection-string",
-			missingSet,
-		)
-	}
-
-	if options.Indexer.Enable {
-		validateField(
-			options.DB.WriterConnectionString,
-			"db.writer-connection-string",
-			missingSet,
-		)
-	}
+	// Check if any feature requiring DB writer connection is enabled
+	if options.Payer.Enable || options.Replication.Enable || options.Sync.Enable || options.Indexer.Enable {
+		validateField(
+			options.DB.WriterConnectionString,
+			"db.writer-connection-string",
+			missingSet,
+		)
+	}
+
+	// Check feature-specific required fields
+	if options.Payer.Enable {
+		validateField(options.Payer.PrivateKey, "payer.private-key", missingSet)
+	}
+
+	if options.Replication.Enable {
+		validateField(options.Signer.PrivateKey, "signer.private-key", missingSet)
+	}

180-196: Enhance type safety in validateField function

The current implementation doesn't handle unexpected types. Consider adding a default case to catch unexpected types that might be passed to this function in the future.

func validateField(value interface{}, fieldName string, set map[string]struct{}) {
	switch v := value.(type) {
	case string:
		if v == "" {
			set[fmt.Sprintf("--%s", fieldName)] = struct{}{}
		}
	case int:
		if v <= 0 {
			set[fmt.Sprintf("--%s must be greater than 0", fieldName)] = struct{}{}
		}
	case time.Duration:
		if v <= 0 {
			set[fmt.Sprintf("--%s must be greater than 0", fieldName)] = struct{}{}
		}
+	default:
+		// Log or handle unexpected types
+		set[fmt.Sprintf("--%s has unsupported type for validation", fieldName)] = struct{}{}
	}
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2d73f67 and 963b25a.

📒 Files selected for processing (4)
  • cmd/replication/main.go (2 hunks)
  • dev/local.env (1 hunks)
  • pkg/config/options.go (2 hunks)
  • pkg/config/validation.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • cmd/replication/main.go
  • dev/local.env
  • pkg/config/options.go
🔇 Additional comments (4)
pkg/config/validation.go (4)

26-29: Correctly using struct field naming in error messages

The error key now correctly references group-message-broadcaster-address instead of messages-address, addressing the issue from previous reviews.


31-34: Correctly using struct field naming in error messages

The error key now correctly references identity-update-broadcaster-address instead of the previous incorrect naming, addressing the issue from previous reviews.


10-140: Well-structured validation logic for multi-chain support

The refactored ValidateServerOptions function cleanly handles both multi-chain and single-chain deployments, with appropriate validation for each case. The use of a pointer parameter is also a good performance improvement.


147-178: Good backward compatibility with normalization function

The normalizeSingleChainConfig function provides excellent backward compatibility by copying values from deprecated fields to the new nested structure. This ensures a smooth transition for existing configurations.

@fbac fbac changed the title breaking: Add multi-chain support Add multi-chain support May 9, 2025
@fbac fbac force-pushed the 05-06-support_multi_chain branch from 8bcb993 to ef0e77b Compare May 9, 2025 12:31
@fbac fbac merged commit a64dc80 into main May 13, 2025
10 checks passed
@fbac fbac deleted the 05-06-support_multi_chain branch May 13, 2025 13:18
fbac pushed a commit that referenced this pull request May 13, 2025
### Restructure contract configuration to support separate application
and settlement chain configurations in the blockchain client
Reorganizes contract configuration by introducing a nested structure
with `AppChain` and `SettlementChain` properties in
[options.go](https://github.com/xmtp/xmtpd/pull/755/files#diff-6731fb6f709392ce3e37d3b0c42074cddbce566dad2bab86af24ba7585eeb57c).
The changes include:

* Creates new `AppChainOptions` and `SettlementChainOptions` structs to
separate chain-specific configurations
* Renames contract addresses to be more descriptive (e.g.,
`MessagesContractAddress` to `GroupMessageBroadcasterAddress`)
* Updates all blockchain client components to use the new configuration
structure
* Modifies validation logic in
[validation.go](https://github.com/xmtp/xmtpd/pull/755/files#diff-3e0b3707cc5d712d06d1eeb6a67c10b45a7ba0b27e972924d71df3c8e539f23b)
to handle the new nested configuration format
* Updates test utilities and configuration generators to support the new
structure

#### 📍Where to Start
Start with the configuration structure changes in
[options.go](https://github.com/xmtp/xmtpd/pull/755/files#diff-6731fb6f709392ce3e37d3b0c42074cddbce566dad2bab86af24ba7585eeb57c)
which defines the new `AppChainOptions` and `SettlementChainOptions`
structs that form the foundation for all other changes.

----

_[Macroscope](https://app.macroscope.com) summarized 384b3a8._

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Refactor**
- Separated blockchain settings into distinct "AppChain" and
"SettlementChain" configuration sections.
- Reorganized contract addresses, chain IDs, RPC URLs, and refresh
intervals under nested configuration fields.
- Updated environment variables and scripts to support the new
multi-chain configuration structure.
- **Bug Fixes**
- Enhanced validation and initialization to correctly handle the
distinct AppChain and SettlementChain configurations.
- **Documentation**
- Revised onboarding and deployment guides to reflect local development
environment setup and updated CLI usage.
- **Tests**
- Updated all tests to align with the new nested configuration format
for blockchain settings.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@coderabbitai coderabbitai bot mentioned this pull request May 13, 2025
@coderabbitai coderabbitai bot mentioned this pull request May 27, 2025
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.

3 participants