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: add onchain delegation #24

Closed
wants to merge 1 commit into from
Closed

feat: add onchain delegation #24

wants to merge 1 commit into from

Conversation

zsluedem
Copy link
Collaborator

@zsluedem zsluedem commented Nov 5, 2024

Summary by CodeRabbit

  • New Features

    • Introduced contract delegation functionality for interacting with the TaiyiCore smart contract on Ethereum.
    • Added new configuration options for execution clients and on-chain delegation in the RelayConfig.
    • Enhanced PreconferElection struct with a proposer public key field.
    • Added a mock implementation for delegation to facilitate testing.
    • Integrated new delegation capabilities into the ProposerApi and related components.
    • Updated the API service to utilize the new delegation contract.
  • Bug Fixes

    • Commented out the inactive MAX_GATEWAY_ELECTION_SIZE constant and the /elect_preconfer API endpoint.
  • Documentation

    • Updated tests to reflect new delegation capabilities and ensure compatibility with existing functionalities.

Copy link

coderabbitai bot commented Nov 5, 2024

Walkthrough

The pull request introduces several changes to the helix-api package, primarily focusing on the integration of the Alloy framework and enhancements to the delegation mechanism. New dependencies related to Alloy are added in Cargo.toml, while a contract delegation mechanism is implemented in contract_delegation.rs. Additionally, modifications are made to existing files, including the commenting out of a constant in api.rs, updates to the ProposerApi struct, and the introduction of new error handling in error.rs. The overall structure is reorganized to improve modularity and functionality.

Changes

File Path Change Summary
crates/api/Cargo.toml Added dependencies: alloy-sol-types = "0.8.8", alloy-contract = "0.5.2", alloy-provider = { version = "0.5.2", features = ["reqwest"], default-features = false }, alloy-transport = "0.5.2".
crates/api/src/constraints/api.rs Commented out constant: pub(crate) const MAX_GATEWAY_ELECTION_SIZE: usize = 1024 * 1024;.
crates/api/src/delegation/contract_delegation.rs Introduced PreconferElectionRes struct, TaiyiCore contract, and methods for contract delegation, including get_preconfer_election.
crates/api/src/delegation/error.rs Added new error handling enum: pub enum Error with variants for handling specific errors related to preconfer elections and BLS public keys.
crates/api/src/delegation/mock_delegation.rs Introduced MockDelegation struct implementing DelegationTrait, with a method returning Ok(None).
crates/api/src/delegation/mod.rs Added new public modules: contract_delegation, error, mock_delegation, and traits. Exported ContractDelegation and MockDelegation.
crates/api/src/delegation/traits.rs Added DelegationTrait with an asynchronous method for fetching preconfer election data.
crates/api/src/lib.rs Introduced new public module: delegation.
crates/api/src/proposer/api.rs Updated ProposerApi struct to include a new generic type parameter D, reflecting changes in method signatures and constructor. Commented out elect_preconfer method.
crates/api/src/proposer/tests.rs Integrated MockDelegation into tests, updating ProposerApi instantiation and related methods.
crates/api/src/router.rs Updated ProposerApiProd type to include ContractDelegation and commented out Route::ElectPreconfer.
crates/api/src/service.rs Added imports for ProviderBuilder and ContractDelegation, modified run method to instantiate a provider and delegation contract.
crates/api/src/test_utils.rs Updated ProposerApi instantiation to include MockDelegation in various functions.
crates/common/src/api/constraints_api.rs Added new field proposer_pubkey to PreconferElection struct. Updated from_proposer_duty method accordingly.
crates/common/src/api/mod.rs Commented out constant PATH_ELECT_PRECONFER, affecting the availability of the /elect_preconfer endpoint.
crates/common/src/config.rs Added new structures ExecutionClientConfig and OnchainDelegationConfig to RelayConfig, updated route handling to comment out ElectPreconfer.
crates/utils/src/signing.rs Enhanced verification functions to handle fork_version more explicitly and updated test data structure.

Possibly related PRs

  • Use cb domain to sign preconfer api #6: The changes in this PR involve modifications to the ProposerApi related to the signature verification process for SignedPreconferElection, which aligns with the integration of new dependencies in the main PR that enhance functionality related to Ethereum development.

Suggested reviewers

  • chirag-bgh

🐇 In the code we hop and play,
With Alloy's charms, we pave the way.
Delegation's dance, a new delight,
In the API's heart, we take flight.
Constants fade, new paths unfold,
In this realm of code, our tale is told! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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 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 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

@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

🧹 Outside diff range and nitpick comments (17)
crates/api/src/delegation/error.rs (1)

3-6: Consider using more specific error types.

Instead of using String for error details, consider creating more specific error types or using underlying error types directly. This would provide better type safety and more structured error handling.

Example improvement:

 pub enum Error {
-    #[error("error getting preconfer election: {0}")]
-    GetPreconferElection(String),
+    #[error("error getting preconfer election: {0}")]
+    GetPreconferElection(#[from] ContractError),
-    #[error("error parsing bls public key: {0}")]
-    BlsPublicKey(String),
+    #[error("error parsing bls public key: {0}")]
+    BlsPublicKey(#[from] BlsError),
 }
crates/api/src/delegation/traits.rs (2)

7-11: Add documentation for the trait and method.

While the implementation looks solid, it would benefit from documentation explaining:

  • The purpose and responsibility of the DelegationTrait
  • The expected behavior of get_preconfer_election
  • The meaning of a None result vs Some result
  • The conditions under which errors might occur

Consider adding documentation like this:

 #[async_trait]
 #[auto_impl::auto_impl(Arc)]
+/// Trait for handling delegation-related operations, particularly pre-conference election data.
 pub trait DelegationTrait: Send + Sync + Clone {
+    /// Retrieves the pre-conference election data for a validator at a specific slot.
+    /// 
+    /// # Arguments
+    /// * `validator_pubkey` - The BLS public key of the validator
+    /// * `slot` - The slot number to query
+    /// 
+    /// # Returns
+    /// * `Ok(Some(election))` - If election data exists for the validator at the slot
+    /// * `Ok(None)` - If no election data exists
+    /// * `Err(Error)` - If there was an error fetching the data
     async fn get_preconfer_election(&self, validator_pubkey: &BlsPublicKey, slot: u64) -> Result<Option<SignedPreconferElection>, Error>;

7-11: Consider caching for performance optimization.

Since this trait will be used for blockchain interactions:

  1. Consider implementing a caching layer to reduce blockchain calls
  2. Think about cache invalidation strategy based on slot numbers
  3. Consider adding a bulk query method if multiple validators need to be checked frequently

This would help optimize performance, especially if the same validator/slot combinations are queried repeatedly.

crates/api/src/delegation/mock_delegation.rs (2)

7-8: Add documentation comments to explain the mock's purpose.

Consider adding documentation comments to explain that this is a mock implementation for testing purposes and how it should be used.

+/// A mock implementation of the DelegationTrait for testing purposes.
+/// This implementation always returns None for get_preconfer_election queries.
 #[derive(Clone, Default)]
 pub struct MockDelegation {}

10-15: Consider enhancing the mock implementation for better testing capabilities.

While the current implementation is sufficient for basic testing, consider these improvements:

  1. Add test coverage for the mock itself
  2. Make the mock configurable to return different results for different test scenarios

Here's a suggested enhancement:

 #[derive(Clone, Default)]
-pub struct MockDelegation {}
+pub struct MockDelegation {
+    // Allow configuring responses for specific validator keys and slots
+    responses: std::collections::HashMap<(BlsPublicKey, u64), SignedPreconferElection>,
+}
 
 #[async_trait]
 impl DelegationTrait for MockDelegation {
     async fn get_preconfer_election(&self, _validator_pubkey: &BlsPublicKey, _slot: u64) -> Result<Option<SignedPreconferElection>, Error> {
-        Ok(None)
+        Ok(self.responses.get(&(_validator_pubkey.clone(), _slot)).cloned())
     }
 }
+
+impl MockDelegation {
+    /// Sets the response for a specific validator and slot
+    pub fn set_response(&mut self, validator: BlsPublicKey, slot: u64, election: SignedPreconferElection) {
+        self.responses.insert((validator, slot), election);
+    }
+}

This enhancement would allow tests to configure specific responses for different scenarios.

crates/api/Cargo.toml (2)

43-46: Consider using version ranges for Alloy dependencies.

The dependencies are correctly added and use recent versions. However, consider using version ranges to allow for non-breaking updates:

-alloy-sol-types = "0.8.8"
-alloy-contract ="0.5.2"
-alloy-provider = { version = "0.5.2", features = ["reqwest"], default-features = false }
-alloy-transport = "0.5.2"
+alloy-sol-types = "^0.8.8"
+alloy-contract ="^0.5.2"
+alloy-provider = { version = "^0.5.2", features = ["reqwest"], default-features = false }
+alloy-transport = "^0.5.2"

45-45: Document the rationale for feature flag choices.

For alloy-provider, you've disabled default features and only enabled reqwest. Consider adding a comment explaining why this specific configuration was chosen to help future maintainers understand the decision.

-alloy-provider = { version = "0.5.2", features = ["reqwest"], default-features = false }
+# Only reqwest transport is needed for our use case, excluding other transport options
+alloy-provider = { version = "0.5.2", features = ["reqwest"], default-features = false }
crates/utils/src/signing.rs (3)

117-117: Remove commented-out code.

Instead of commenting out the unused constant, it should be removed entirely. Commented-out code can lead to confusion and maintenance overhead.

-    // const SLOT_NUMBER: u64 = 836343;

130-134: LGTM! Consider adding more test cases.

The test initialization is well structured with proper field assignments and real-world test data. However, consider adding more test cases to cover:

  • Invalid signatures
  • Different chain IDs
  • Edge cases for gas limits

Line range hint 1-142: Consider adding documentation for delegation-related security implications.

Since this code handles cryptographic signing for the new onchain delegation feature:

  1. Consider adding documentation explaining the security model and trust assumptions for delegation message signing.
  2. Document how the domain computation relates to the delegation mechanism to help future maintainers understand the security boundaries.
crates/api/src/service.rs (1)

Line range hint 145-163: Consider operational aspects of execution client dependency.

The addition of an execution client dependency introduces a new critical component to the system. Consider:

  1. Adding metrics/monitoring for execution client connectivity
  2. Implementing retry logic for temporary connection issues
  3. Documenting fallback procedures for execution client outages
  4. Adding health checks for the delegation contract
crates/common/src/api/constraints_api.rs (1)

48-49: LGTM! Consider adding a getter method for consistency.

The addition of proposer_pubkey field is well-documented and aligns with the onchain delegation feature. However, for consistency with other fields that have getter methods (preconfer_public_key(), slot(), etc.), consider adding a getter method for proposer_pubkey.

Add this getter method to the PreconferElection impl block:

+ pub fn proposer_public_key(&self) -> &BlsPublicKey {
+     &self.proposer_pubkey
+ }
crates/api/src/delegation/contract_delegation.rs (4)

56-56: Optimize conversion by avoiding unnecessary allocation

The current code converts validator_pubkey to a Vec<u8>, which may incur an unnecessary allocation. Consider passing the slice directly to Bytes::from to improve performance.

Apply this diff to optimize the conversion:

-let pubkey = Bytes::from(validator_pubkey.as_ref().to_vec());
+let pubkey = Bytes::from(validator_pubkey.as_ref());

57-57: Remove unnecessary use of Arc when creating the contract instance

Since taiyi_core_contract is only used within this function and not shared across threads, wrapping it in an Arc is unnecessary. Removing Arc simplifies the code without affecting functionality.

Apply this diff to remove Arc:

-let taiyi_core_contract = Arc::new(TaiyiCoreInstance::new(self.delegation_contract_address.clone(), self.provider.clone()));
+let taiyi_core_contract = TaiyiCoreInstance::new(self.delegation_contract_address.clone(), self.provider.clone());

59-70: Improve readability by destructuring the contract call result

Currently, you're accessing fields using preconfer_election._0, which can be less readable. Consider destructuring the result to access the fields directly, enhancing code clarity.

Apply this diff to destructure the result:

-let preconfer_election =
-    taiyi_core_contract.getPreconferElection(pubkey).call().await.map_err(|e| Error::GetPreconferElection(e.to_string()))?;
-if preconfer_election._0.preconferAddress.is_zero() {
+let election_res =
+    taiyi_core_contract
+        .getPreconferElection(pubkey)
+        .call()
+        .await
+        .map_err(|e| Error::GetPreconferElection(e.to_string()))?;
+if election_res.preconferAddress.is_zero() {

This allows you to access the fields directly without the _0 prefix.


67-69: Provide more descriptive error context when parsing BLS public keys

When converting bytes to BlsPublicKey, adding context to the error messages can aid in debugging.

Apply this diff to enhance error messages:

-.map_err(|e| Error::BlsPublicKey(e.to_string()))?,
+.map_err(|e| Error::BlsPublicKey(format!("Failed to parse preconfer_pubkey: {}", e)))?,

Repeat a similar change for proposer_pubkey.

crates/api/src/proposer/api.rs (1)

794-830: Consider removing the commented out code.

The elect_preconfer function has been commented out, indicating that it is no longer in use. Consider removing the commented out code to improve code clarity and maintainability.

Apply this diff to remove the commented out code:

-    // pub async fn elect_preconfer(
-    //     Extension(proposer_api): Extension<Arc<ProposerApi<A, DB, M, G>>>,
-    //     req: Request<Body>,
-    // ) -> Result<StatusCode, ProposerApiError> {
-    //     let request_id = Uuid::new_v4();
-    //     let mut trace = ElectGatewayTrace { receive: get_nanos_timestamp()?, ..Default::default() };
-
-    //     // Deserialise request
-    //     let mut election_req: SignedPreconferElection = deserialize_json_request_bytes(req, MAX_GATEWAY_ELECTION_SIZE).await?;
-    //     trace.deserialize = get_nanos_timestamp()?;
-
-    //     let slot_info = proposer_api.curr_slot_info.read().await;
-    //     info!(
-    //         request_id = %request_id,
-    //         event = "elect_gateway",
-    //         head_slot = slot_info.slot,
-    //         request_ts = trace.receive,
-    //         slot = %election_req.slot(),
-    //         preconfer_public_key = ?election_req.preconfer_public_key(),
-    //         gas_limit = election_req.gas_limit(),
-    //         chain_id = election_req.chain_id(),
-    //     );
-
-    //     if let Err(err) = proposer_api.validate_election_request(&mut election_req, slot_info.slot).await {
-    //         warn!(request_id = %request_id, ?err, "validation failed");
-    //         return Err(err);
-    //     }
-    //     trace.validation_complete = get_nanos_timestamp()?;
-
-    //     // Save to constraints datastore
-    //     // TODO: database
-    //     proposer_api.auctioneer.save_new_gateway_election(&election_req, election_req.slot()).await?;
-    //     trace.gateway_election_saved = get_nanos_timestamp()?;
-
-    //     info!(%request_id, ?trace, "gateway elected");
-    //     Ok(StatusCode::OK)
-    // }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between da1d87c and c17ceb6.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • crates/api/Cargo.toml (1 hunks)
  • crates/api/src/constraints/api.rs (1 hunks)
  • crates/api/src/delegation/contract_delegation.rs (1 hunks)
  • crates/api/src/delegation/error.rs (1 hunks)
  • crates/api/src/delegation/mock_delegation.rs (1 hunks)
  • crates/api/src/delegation/mod.rs (1 hunks)
  • crates/api/src/delegation/traits.rs (1 hunks)
  • crates/api/src/lib.rs (1 hunks)
  • crates/api/src/proposer/api.rs (15 hunks)
  • crates/api/src/proposer/tests.rs (4 hunks)
  • crates/api/src/router.rs (3 hunks)
  • crates/api/src/service.rs (4 hunks)
  • crates/api/src/test_utils.rs (4 hunks)
  • crates/common/src/api/constraints_api.rs (2 hunks)
  • crates/common/src/api/mod.rs (1 hunks)
  • crates/common/src/config.rs (7 hunks)
  • crates/utils/src/signing.rs (2 hunks)
✅ Files skipped from review due to trivial changes (3)
  • crates/api/src/constraints/api.rs
  • crates/api/src/delegation/mod.rs
  • crates/common/src/api/mod.rs
🔇 Additional comments (33)
crates/api/src/delegation/error.rs (2)

1-7: LGTM! The error handling structure is well-organized.

The error enum is well-designed with clear error messages and appropriate trait derivations.


1-7: Review error message content for security.

Ensure that the string error messages passed to these variants don't contain sensitive information like private keys, internal states, or implementation details that could be exploited.

✅ Verification successful

Let me analyze the usage of these error variants to verify if any sensitive information is being exposed.


Error handling appears secure - no sensitive data exposure

The error handling implementation is secure:

  • GetPreconferElection only wraps contract call errors using e.to_string(), which provides standard error messages from the contract interaction
  • BlsPublicKey errors come from public key parsing/validation failures using try_from, containing only validation error messages
  • Neither error variant exposes private keys, internal states or implementation details that could be exploited
  • The error messages are appropriately generic while still being useful for debugging
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for potential sensitive information in error messages
rg -g '!target/' -g '!*.lock' -A 3 'GetPreconferElection\(|BlsPublicKey\(' 

Length of output: 1452


Script:

#!/bin/bash
# Look for the actual error sources being passed to these variants
ast-grep --pattern 'Error::GetPreconferElection($_)'
ast-grep --pattern 'Error::BlsPublicKey($_)'

# Also check the contract call to see full context
ast-grep --pattern 'getPreconferElection($_)'

Length of output: 579

crates/api/src/lib.rs (1)

5-5: LGTM! Module declaration follows good practices.

The new delegation module is properly declared and follows the existing module organization pattern.

Let's verify the module structure is complete:

✅ Verification successful

Module structure is complete and well-organized

All expected files are present in the delegation module:

  • contract_delegation.rs: Main contract delegation implementation
  • error.rs: Error handling
  • mock_delegation.rs: Mock implementations
  • traits.rs: Trait definitions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the delegation module structure matches the AI summary
# Expected files: contract_delegation.rs, error.rs, mock_delegation.rs, traits.rs

# Check if all expected files exist in the delegation module
echo "Verifying delegation module structure..."
fd --type f "^(contract_delegation|error|mock_delegation|traits)\.rs$" "crates/api/src/delegation"

Length of output: 354

crates/api/src/delegation/traits.rs (1)

1-5: LGTM! Well-organized imports with clear dependencies.

The imports are properly organized and show good separation of concerns, particularly with error handling in a separate module.

crates/api/src/delegation/mock_delegation.rs (2)

1-5: LGTM! Imports are well-organized and necessary.

The imports are properly organized following Rust conventions, with external crates first followed by local imports.


1-15: Verify test coverage using this mock implementation.

Let's verify how this mock is being used in tests across the codebase.

✅ Verification successful

MockDelegation is properly integrated and used in tests

The mock implementation is well integrated into the codebase:

  • Used in test utilities (test_utils.rs) for setting up test API servers
  • Properly integrated in proposer API tests (proposer/tests.rs)
  • Returns None by default which is a safe mock behavior for testing
  • Implements the required DelegationTrait correctly

The mock is used consistently across test scenarios, particularly in:

  • API server initialization for testing
  • Proposer API validation tests
  • Integration with other mock components (MockAuctioneer, MockDatabaseService, etc.)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find test files using MockDelegation
# Expected: Test files showing usage of this mock

# Search for test modules using MockDelegation
rg -l "use.*MockDelegation" --type rust | grep "_test\|test_\|tests"

# Search for direct usage in test functions
rg "fn.*test.*MockDelegation" --type rust

Length of output: 114


Script:

#!/bin/bash
# Let's try a broader search to find any references to MockDelegation
rg "MockDelegation" -A 5 -B 5 --type rust

# Also search for test files in the delegation module
fd "test.*\.rs$" -p "crates/api/src/delegation/"

# Look for any test modules in the same file
rg "mod test" "crates/api/src/delegation/mock_delegation.rs"

Length of output: 12514

crates/api/src/router.rs (2)

34-35: LGTM: Clean integration of ContractDelegation

The addition of ContractDelegation as a type parameter to ProposerApiProd aligns with the PR's objective of implementing on-chain delegation.


96-98: Verify the impact of removing ElectPreconfer route

The ElectPreconfer route has been commented out. This could potentially break API consumers who depend on this endpoint.

Let's verify if this endpoint is still in use:

Please ensure:

  1. API consumers are notified of this breaking change
  2. Documentation is updated to reflect the removal
  3. Consider adding a deprecation notice if this needs to be phased out gradually
crates/api/src/test_utils.rs (6)

24-24: LGTM: Import added correctly.

The MockDelegation import follows the established pattern for mock implementations.


56-68: LGTM: Route handlers updated consistently.

All ProposerApi route handlers have been properly updated to include the MockDelegation type parameter while maintaining the original functionality.


117-117: LGTM: ProposerApi type and instantiation updated correctly in proposer_api_app().

The changes maintain consistency with the updates in the app() function:

  • Return type properly includes MockDelegation
  • All parameters are correctly wrapped in Arc
  • Parameter ordering and initialization remain consistent

Also applies to: 124-137


142-151: LGTM: Route handlers in proposer_api_app() updated consistently.

The route handlers are properly updated to include MockDelegation while maintaining consistency with the changes in the app() function.


Line range hint 1-179: Verify test coverage for delegation functionality.

While the mock setup is complete, it would be beneficial to verify that the test coverage adequately exercises the new delegation functionality.

Let's check the test coverage:

#!/bin/bash
# Description: Find and analyze test cases for delegation functionality
# Expected: Locate test files and verify coverage of delegation features

# Search for test files that might contain delegation tests
rg -l "test.*delegation" --type rust

# Search for delegation-related test cases
rg "fn.*test.*delegation" -A 5 --type rust

Line range hint 37-48: LGTM: ProposerApi instantiation updated correctly.

The MockDelegation is properly integrated with thread-safe Arc wrapper and follows the pattern of other mock objects.

Let's verify the MockDelegation implementation:

✅ Verification successful

MockDelegation implementation is suitable for testing purposes

The implementation is correct and appropriate for testing:

  • It implements the required DelegationTrait with the single method get_preconfer_election
  • The mock returns Ok(None) which is a valid default behavior for testing scenarios where delegation is not needed
  • The implementation follows Rust's async trait patterns with proper error handling
  • It maintains consistency with other mock objects in the codebase by implementing default()
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify MockDelegation's default implementation
# Expected: Find the MockDelegation implementation to ensure it provides necessary test functionality

# Search for MockDelegation implementation
rg -A 10 "impl.*MockDelegation"

Length of output: 83


Script:

#!/bin/bash
# Let's try different search patterns to locate MockDelegation
# First, find the direct definition
rg "struct MockDelegation" --type rust -A 5

# Also search for the mock module where it might be defined
rg "mod mock" --type rust -A 10

# Search for any delegation-related mocks
rg "Mock.*Delegation" --type rust -A 5

# Try finding test files that might contain the mock
fd "test" --type f --extension rs --exec rg "MockDelegation" {}

Length of output: 14309


Script:

#!/bin/bash
# Let's examine the DelegationTrait to understand what the mock should implement
rg "trait DelegationTrait" -A 10 --type rust

# Also check if there are any tests using MockDelegation to verify its behavior
rg "fn.*test.*delegation" -A 10 --type rust

Length of output: 389

crates/api/src/service.rs (2)

3-3: LGTM: Import changes align with onchain delegation feature.

The new imports for ProviderBuilder and ContractDelegation are appropriately placed and support the onchain delegation functionality.

Also applies to: 22-22


163-163: LGTM: ProposerApi correctly initialized with delegation contract.

The delegation contract is properly passed to the ProposerApi constructor.

crates/common/src/config.rs (2)

181-181: Consider cleaning up the commented ElectPreconfer route.

The ElectPreconfer route is commented out in multiple places. If this route is being permanently removed:

  1. We should remove the commented code rather than leaving it
  2. This change might affect existing functionality

If this is a temporary change, please add a TODO comment explaining why it's commented out and when it will be re-enabled.

Let's check for any remaining references to this route:

#!/bin/bash
# Description: Check for any remaining references to ElectPreconfer
# Test: Look for any usage of ElectPreconfer that might be affected
rg "ElectPreconfer|elect_preconfer" --type rust

Also applies to: 190-190, 261-261, 280-280


109-118: ⚠️ Potential issue

Review the safety of using Address::default() for delegation contract.

The OnchainDelegationConfig derives Default, which means delegation_contract_address will be initialized to the zero address (0x0000...0000). This could be dangerous if the code doesn't properly handle this case.

Consider:

  1. Explicitly implementing Default with a more appropriate default value
  2. Adding runtime validation to ensure a non-zero address is provided

Let's verify how the contract address is used:

#!/bin/bash
# Description: Check how the delegation contract address is used
# Test: Look for usage of delegation_contract_address to ensure proper validation
rg "delegation_contract_address" --type rust -A 5
crates/api/src/delegation/contract_delegation.rs (1)

74-74: Confirm if using a default signature is appropriate

The signature field is set to BlsSignature::default(). Verify whether this is intentional or if the signature should be obtained from a valid source.

crates/api/src/proposer/tests.rs (3)

73-73: Addition of MockDelegation Import

The import delegation::mock_delegation::MockDelegation is correctly added to support mock delegation in tests.


Line range hint 208-212: Update Return Type to Include MockDelegation

The return type of start_api_server now incorporates MockDelegation within the ProposerApi generic parameters. This change seamlessly integrates delegation functionality into the test API server.


Line range hint 829-840: Initialization of ProposerApi with MockDelegation

ProposerApi is instantiated with MockDelegation, ensuring that delegation logic is included in the tests. The initialization appears correct and follows the expected pattern.

crates/api/src/proposer/api.rs (11)

34-34: LGTM!

The import statement for traces::constraints_api::SetConstraintsTrace is valid and necessary for the set_constraints function.


42-42: LGTM!

The import statement for signing::{verify_signed_builder_message, verify_signed_consensus_message} is valid and necessary for signature verification.


54-55: LGTM!

The import statements for constraints::{api::MAX_SET_CONSTRAINTS_SIZE, SET_CONSTRAINTS_CUTOFF_NS} and delegation::traits::DelegationTrait are valid and necessary for the set_constraints function and the new DelegationTrait generic parameter.


Line range hint 156-173: LGTM!

The changes to the status, register_validators, get_header, get_payload, and set_constraints functions to include the new generic parameter D in the Extension type are valid and consistent with the updated ProposerApi struct.


455-455: LGTM!

The change to the get_payload function to include the new generic parameter D in the Extension type is valid and consistent with the updated ProposerApi struct.


734-734: LGTM!

The change to the set_constraints function to include the new generic parameter D in the Extension type is valid and consistent with the updated ProposerApi struct.


878-884: LGTM!

The changes to the helper functions to include the new generic parameter D constrained by the DelegationTrait are valid and consistent with the updated ProposerApi struct.


1236-1242: LGTM!

The changes to the state sync functions to include the new generic parameter D constrained by the DelegationTrait are valid and consistent with the updated ProposerApi struct.


1276-1298: Verify the integration of the DelegationTrait in the codebase.

The handle_new_slot function has been updated to integrate the DelegationTrait for retrieving preconfer elections. This change is valid and allows for the integration of delegation functionality.

Run the following script to verify the usage of the DelegationTrait:

#!/bin/bash
# Description: Verify the usage of the `DelegationTrait` in the `handle_new_slot` function.

# Test: Search for the `get_preconfer_election` function usage. 
# Expect: The function should be called on the `delegation_contract` field to retrieve preconfer elections.
rg -A 10 $'self.delegation_contract.get_preconfer_election'

74-80: Verify the new generic parameter D in the codebase.

The ProposerApi struct has been updated to include a new generic parameter D constrained by the DelegationTrait. This change is valid and allows for the integration of delegation functionality.

Run the following script to verify the usage of the new generic parameter:

Also applies to: 97-97

✅ Verification successful

The new generic parameter D is properly integrated throughout the codebase

The verification shows that the new generic parameter D with DelegationTrait constraint is:

  • Correctly used in the production code with ContractDelegation implementation (crates/api/src/router.rs)
  • Properly handled in test code with MockDelegation implementation (crates/api/src/test_utils.rs, crates/api/src/proposer/tests.rs)
  • Consistently used across all ProposerApi implementations and method signatures in crates/api/src/proposer/api.rs
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of the new generic parameter `D` in the `ProposerApi` struct.

# Test: Search for the `ProposerApi` struct definition and instantiation. 
# Expect: The struct definition and instantiation should include the new generic parameter `D`.
rg -A 5 $'pub struct ProposerApi'
rg -A 5 $'ProposerApi::new'

Length of output: 427


Script:

#!/bin/bash
# Let's search for more comprehensive information about ProposerApi usage

# Search for any implementation blocks for ProposerApi
ast-grep --pattern 'impl$$$ProposerApi<$$$>$$$'

# Search for any struct fields or method parameters using ProposerApi
rg -l "ProposerApi"

# Search for where ProposerApi is instantiated or type parameters are specified
rg "ProposerApi\s*<" -A 3

Length of output: 4323


100-106: Verify the new delegation_contract field in the codebase.

The ProposerApi struct has been updated to include a new field delegation_contract of type Arc<D>. This change is valid and allows for the integration of delegation functionality.

Run the following script to verify the usage of the new field:

Also applies to: 119-119, 132-132

✅ Verification successful

Let me gather more information about the delegation contract field to verify its complete implementation.


Let me search for more specific implementation details of the delegation contract usage.


The delegation_contract field is properly integrated and used in the codebase

The verification shows that:

  • The field is correctly declared in the ProposerApi struct
  • It's properly initialized in the new constructor method
  • It's actively used in the codebase to get preconfer election data via get_preconfer_election method
  • The implementation follows the expected pattern with proper error handling and logging
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of the new `delegation_contract` field in the `ProposerApi` struct.

# Test: Search for the `delegation_contract` field usage. 
# Expect: The field should be initialized in the `ProposerApi::new` function and used in other parts of the codebase.
rg -A 5 $'delegation_contract'

Length of output: 1137


Script:

#!/bin/bash
# Search for the ProposerApi struct definition and its new method
ast-grep --pattern 'struct ProposerApi {
  $$$
}'

# Search for the initialization of delegation_contract in new method
ast-grep --pattern 'impl$$ ProposerApi$$ {
    $$$
    pub fn new($$$) -> Self {
        $$$
    }
    $$$
}'

# Search for any other usages of delegation_contract
rg -A 3 "delegation_contract:"

Length of output: 632


Script:

#!/bin/bash
# Search for the DelegationTrait implementation and interface
ast-grep --pattern 'trait DelegationTrait {
    $$$
}'

# Search for any async functions using delegation_contract
rg -A 5 "self.delegation_contract" --type rust

# Search for the complete new method implementation
rg -A 15 "pub fn new\(" --type rust crates/api/src/proposer/api.rs

Length of output: 2107

crates/api/src/service.rs Show resolved Hide resolved
crates/common/src/api/constraints_api.rs Show resolved Hide resolved
crates/common/src/config.rs Show resolved Hide resolved
@zsluedem zsluedem force-pushed the onchain-delegation branch 2 times, most recently from bf84d3f to d39396f Compare November 5, 2024 16:37
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (10)
crates/api/src/test_utils.rs (2)

117-137: Consider extracting common test configuration

The ProposerApi initialization contains a lot of mock setup code that's duplicated from the app() function. Consider extracting this into a helper function to reduce duplication and improve maintainability.

+fn create_test_proposer_api(
+    auctioneer: Arc<MockAuctioneer>,
+    slot_update_sender: Sender<Sender<ChainUpdate>>,
+    gossip_receiver: Receiver<GossipedMessage>,
+) -> Arc<ProposerApi<MockAuctioneer, MockDatabaseService, MockMultiBeaconClient, MockGossiper, MockDelegation>> {
+    Arc::new(ProposerApi::new(
+        auctioneer,
+        Arc::new(MockDatabaseService::default()),
+        Arc::new(MockGossiper::new().unwrap()),
+        vec![Arc::new(BlockBroadcaster::Mock(MockBlockBroadcaster::default()))],
+        Arc::new(MockMultiBeaconClient::default()),
+        Arc::new(ChainInfo::for_mainnet()),
+        slot_update_sender,
+        Arc::new(ValidatorPreferences::default()),
+        0,
+        gossip_receiver,
+        Arc::new(MockDelegation::default()),
+    ))
+}

Missing test coverage for MockDelegation implementation

The codebase analysis reveals:

  • MockDelegation is a mock implementation of DelegationTrait with a single method get_preconfer_election
  • There are no dedicated test modules or test cases in the delegation directory
  • The mock is only used as a dependency in ProposerApi tests without verifying its behavior

The following areas need test coverage:

  • Test module for mock_delegation.rs to verify the default behavior
  • Test cases for get_preconfer_election method returning None
  • Integration tests verifying MockDelegation's interaction with ProposerApi
🔗 Analysis chain

Line range hint 1-179: Verify test coverage for delegation functionality

Since this is a test utilities file, we should ensure that the mock delegation functionality is properly tested.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Look for test modules that exercise the delegation functionality
rg -p "mod tests" -A 10 "use.*MockDelegation"

# Look for actual test cases
rg -p "#\[test\]" -A 20 "MockDelegation"

Length of output: 203


Script:

#!/bin/bash
# First, let's find where MockDelegation is defined
rg -p "struct MockDelegation"

# Then look for any tests involving MockDelegation
rg -p "MockDelegation" --type rust -C 5

# Look for any test files that might use MockDelegation
fd -e rs "test" --exec grep -l "MockDelegation" {}

Length of output: 8232


Script:

#!/bin/bash
# Let's examine the DelegationTrait implementation and its test coverage
rg -p "impl.*DelegationTrait" -A 10

# Look for any test modules in the delegation directory
rg -p "mod tests" --type rust ./crates/api/src/delegation/

# Check if there are any test functions that verify the delegation functionality
ast-grep --pattern 'async fn test_$_() {
  $$$
  MockDelegation
  $$$
}'

Length of output: 1285

crates/common/src/config.rs (1)

103-113: Consider extracting the default URL into a constant

The default URL http://localhost:8545 should be extracted into a constant for better maintainability and reusability.

+const DEFAULT_EXECUTION_CLIENT_URL: &str = "http://localhost:8545";

 impl Default for ExecutionClientConfig {
     fn default() -> Self {
-        Self { url: Url::parse("http://localhost:8545").unwrap() }
+        Self { url: Url::parse(DEFAULT_EXECUTION_CLIENT_URL).unwrap() }
     }
 }
crates/api/src/proposer/tests.rs (1)

Line range hint 829-840: Consider adding test coverage for delegation functionality.

While the MockDelegation is properly integrated into the ProposerApi constructor, there are no specific test cases validating the delegation behavior.

Would you like me to help generate test cases to cover the delegation functionality?

crates/api/src/delegation/contract_delegation.rs (4)

56-56: Optimize conversion of validator_pubkey to Bytes

The conversion of validator_pubkey to Bytes can be simplified to avoid unnecessary allocations.

Apply this diff to optimize the conversion:

-let pubkey = Bytes::from(validator_pubkey.as_ref().to_vec());
+let pubkey = Bytes::copy_from_slice(validator_pubkey.as_ref());

This change uses Bytes::copy_from_slice, which is more efficient than creating an intermediate Vec<u8>.


44-44: Avoid unnecessary cloning of provider

Cloning the provider may be unnecessary if it's already reference-counted or cheaply clonable.

Consider passing the provider by reference or using an Arc to avoid unnecessary clones.

-        provider: RecommendProvider,
+        provider: Arc<RecommendProvider>,

Update the constructor accordingly:

-pub fn new(delegation_contract_address: Address, provider: RecommendProvider) -> Self {
+pub fn new(delegation_contract_address: Address, provider: Arc<RecommendProvider>) -> Self {

64-73: Improve error context in try_from conversions

When handling errors from BlsPublicKey::try_from, include contextual information to aid debugging.

Apply this diff to enhance error messages:

 .map_err(|e| Error::BlsPublicKey(format!("Failed to parse preconfer_pubkey: {}", e)))?,

Repeat for the proposer_pubkey.


17-17: Consider making DEFAULT_GAS_LIMIT a configurable parameter

Making DEFAULT_GAS_LIMIT configurable enhances flexibility and allows adjustment without code changes.

crates/api/src/proposer/api.rs (2)

1276-1298: Enhance error handling when fetching preconfer elections

In the handle_new_slot method, while fetching preconfer elections from the delegation contract, consider the following improvements:

  • Retry Mechanism: Implement a retry mechanism for transient errors when calling get_preconfer_election and save_new_gateway_election to handle temporary network issues or timeouts.
  • Error Classification: Differentiate between recoverable and unrecoverable errors to decide when to retry or fail gracefully.
  • Logging Enhancements: Include additional context in log messages, such as the error type or code, to facilitate easier debugging and monitoring.

794-830: Remove or document commented-out code in elect_preconfer function

The elect_preconfer function is commented out entirely. If this code is deprecated or no longer needed, consider removing it to clean up the codebase. If it's intended for future implementation, add a comment explaining its purpose and any pending dependencies or reasons for its current state.

🛑 Comments failed to post (4)
crates/common/src/config.rs (2)

181-181: 🛠️ Refactor suggestion

Consider removing commented-out route instead of commenting

The ElectPreconfer route is commented out in multiple places. If this route is no longer needed, it should be removed entirely rather than commented out. If it's temporary, please add a comment explaining why it's disabled and when it might be re-enabled.

-            // Route::ElectPreconfer,

If this is truly temporary, add a TODO comment explaining why:

+            // TODO: ElectPreconfer route temporarily disabled due to [reason]
+            // Expected to be re-enabled in [timeline/condition]
             // Route::ElectPreconfer,

Also applies to: 190-190, 261-261, 280-280


115-118: ⚠️ Potential issue

Verify the safety of Address default value

The #[derive(Default)] for OnchainDelegationConfig will use Address::default() (likely 0x0) for delegation_contract_address. This might not be a valid contract address in practice.

Consider either:

  1. Removing Default and requiring explicit configuration
  2. Implementing a custom Default that panics with a clear message
-#[derive(Serialize, Deserialize, Clone, Debug, Default)]
+#[derive(Serialize, Deserialize, Clone, Debug)]
 pub struct OnchainDelegationConfig {
     pub delegation_contract_address: Address,
 }
+
+impl Default for OnchainDelegationConfig {
+    fn default() -> Self {
+        panic!("OnchainDelegationConfig requires explicit configuration of delegation_contract_address")
+    }
+}
📝 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.

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct OnchainDelegationConfig {
    pub delegation_contract_address: Address,
}

impl Default for OnchainDelegationConfig {
    fn default() -> Self {
        panic!("OnchainDelegationConfig requires explicit configuration of delegation_contract_address")
    }
}
crates/api/src/delegation/contract_delegation.rs (2)

60-62: 🛠️ Refactor suggestion

Clarify the field access of preconfer_election

Accessing fields using ._0 suggests that preconfer_election contains unnamed fields. Ensure that the fields are being accessed correctly and consider naming the fields for clarity.

Modify the Solidity struct to name the return parameter, which allows for direct field access:

 #[sol(rpc)]
 contract TaiyiCore {
     #[derive(Debug)]
-    function getPreconferElection(bytes calldata validatorPubKey) external view returns (PreconferElectionRes memory);
+    function getPreconferElection(bytes calldata validatorPubKey) external view returns (PreconferElectionRes memory result);
 }

Then, you can access the fields directly:

-if preconfer_election._0.preconferAddress.is_zero() {
+if preconfer_election.preconferAddress.is_zero() {

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


70-70: ⚠️ Potential issue

Properly convert chainId to the expected integer type

The method .to() on preconfer_election.chainId may not perform the desired conversion. Ensure that chainId is converted to the correct Rust integer type, handling potential overflows.

Apply this diff to explicitly convert chainId:

-chain_id: preconfer_election.chainId.to(),
+chain_id: preconfer_election.chainId.as_u64(),

If chainId exceeds u64::MAX, handle the error appropriately.

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (7)
crates/api/src/delegation/contract_delegation.rs (4)

17-17: Consider making the gas limit configurable.

The hardcoded DEFAULT_GAS_LIMIT might not be suitable for all network conditions or contract interactions. Consider making it configurable through environment variables or configuration files.

-const DEFAULT_GAS_LIMIT: u64 = 100_000;
+const DEFAULT_GAS_LIMIT: u64 = std::env::var("DELEGATION_GAS_LIMIT")
+    .ok()
+    .and_then(|s| s.parse().ok())
+    .unwrap_or(100_000);

19-24: Consider adding documentation for the RecommendProvider type.

The complex provider type combines multiple fillers for transaction handling. Adding documentation would help explain its purpose and components.

+/// Provider type that combines multiple fillers for complete transaction handling:
+/// - Identity: For authentication
+/// - GasFiller: For gas price estimation
+/// - BlobGasFiller: For blob gas estimation
+/// - NonceFiller: For transaction nonce management
+/// - ChainIdFiller: For network identification
 type RecommendProvider = FillProvider<
     JoinFill<Identity, JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>>,
     RootProvider<BoxTransport>,
     BoxTransport,
     Ethereum,
 >;

25-39: Add documentation for the contract interfaces.

The smart contract definitions would benefit from documentation explaining their purpose and field meanings.

 sol! {
+    /// Represents the result of a preconfer election query from the TaiyiCore contract
     #[derive(Debug)]
     struct PreconferElectionRes {
+        /// The public key of the validator
         bytes validatorPubkey;
+        /// The public key of the preconfer
         bytes preconferPubkey;
+        /// The chain ID where this election is valid
         uint256 chainId;
+        /// The Ethereum address of the preconfer
         address preconferAddress;
     }

+    /// TaiyiCore contract interface for delegation management
     #[sol(rpc)]
     contract TaiyiCore {
         #[derive(Debug)]
+        /// Retrieves preconfer election data for a given validator
+        /// @param validatorPubKey The public key of the validator
+        /// @return PreconferElectionRes containing the election details
         function getPreconferElection(bytes calldata validatorPubKey) external view returns (PreconferElectionRes memory);
     }
 }

57-57: Unnecessary Arc wrapping.

The Arc::new() wrapping seems unnecessary as the contract instance is only used for a single async call and not shared between threads.

-        let taiyi_core_contract = Arc::new(TaiyiCoreInstance::new(self.delegation_contract_address, self.provider.clone()));
+        let taiyi_core_contract = TaiyiCoreInstance::new(self.delegation_contract_address, self.provider.clone());
crates/api/src/router.rs (1)

96-98: Consider removing commented code if the route is permanently disabled.

Instead of commenting out the ElectPreconfer route, consider removing it entirely if it's no longer needed. If this is a temporary change, please add a TODO comment explaining the reason and when it might be re-enabled.

-            // Route::ElectPreconfer => {
-            //     router = router.route(&route.path(), post(ProposerApiProd::elect_preconfer));
-            // }
crates/api/src/proposer/api.rs (2)

35-35: Nitpick: Consider renaming constraints_api to constraints_trace for clarity.

The module name constraints_api is a bit misleading since it contains a trace struct. Renaming it to constraints_trace would better convey its purpose.

-use helix_common::traces::constraints_api::SetConstraintsTrace;
+use helix_common::traces::constraints_trace::SetConstraintsTrace;

793-831: Refactor: Remove the commented out elect_preconfer function.

The elect_preconfer function has been commented out, indicating that it is no longer in use. To improve code clarity and maintainability, it is recommended to remove the commented out code entirely.

-// /// Elects a gateway to perform pre-confirmations for a validator. The request must be signed by the validator
-// /// and must be for the next epoch.
-// pub async fn elect_preconfer(
-//     Extension(proposer_api): Extension<Arc<ProposerApi<A, DB, M, G>>>,
-//     req: Request<Body>,
-// ) -> Result<StatusCode, ProposerApiError> {
-//     let request_id = Uuid::new_v4();
-//     let mut trace = ElectGatewayTrace { receive: get_nanos_timestamp()?, ..Default::default() };
-//
-//     // Deserialise request
-//     let mut election_req: SignedPreconferElection = deserialize_json_request_bytes(req, MAX_GATEWAY_ELECTION_SIZE).await?;
-//     trace.deserialize = get_nanos_timestamp()?;
-//
-//     let slot_info = proposer_api.curr_slot_info.read().await;
-//     info!(
-//         request_id = %request_id,
-//         event = "elect_gateway",
-//         head_slot = slot_info.slot,
-//         request_ts = trace.receive,
-//         slot = %election_req.slot(),
-//         preconfer_public_key = ?election_req.preconfer_public_key(),
-//         gas_limit = election_req.gas_limit(),
-//         chain_id = election_req.chain_id(),
-//     );
-//
-//     if let Err(err) = proposer_api.validate_election_request(&mut election_req, slot_info.slot).await {
-//         warn!(request_id = %request_id, ?err, "validation failed");
-//         return Err(err);
-//     }
-//     trace.validation_complete = get_nanos_timestamp()?;
-//
-//     // Save to constraints datastore
-//     // TODO: database
-//     proposer_api.auctioneer.save_new_gateway_election(&election_req, election_req.slot()).await?;
-//     trace.gateway_election_saved = get_nanos_timestamp()?;
-//
-//     info!(%request_id, ?trace, "gateway elected");
-//     Ok(StatusCode::OK)
-// }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c17ceb6 and d39396f.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • crates/api/Cargo.toml (1 hunks)
  • crates/api/src/constraints/api.rs (1 hunks)
  • crates/api/src/delegation/contract_delegation.rs (1 hunks)
  • crates/api/src/delegation/error.rs (1 hunks)
  • crates/api/src/delegation/mock_delegation.rs (1 hunks)
  • crates/api/src/delegation/mod.rs (1 hunks)
  • crates/api/src/delegation/traits.rs (1 hunks)
  • crates/api/src/lib.rs (1 hunks)
  • crates/api/src/proposer/api.rs (16 hunks)
  • crates/api/src/proposer/tests.rs (4 hunks)
  • crates/api/src/router.rs (3 hunks)
  • crates/api/src/service.rs (4 hunks)
  • crates/api/src/test_utils.rs (4 hunks)
  • crates/common/src/api/constraints_api.rs (2 hunks)
  • crates/common/src/api/mod.rs (1 hunks)
  • crates/common/src/config.rs (7 hunks)
  • crates/utils/src/signing.rs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • crates/api/src/delegation/error.rs
🚧 Files skipped from review as they are similar to previous changes (11)
  • crates/api/Cargo.toml
  • crates/api/src/constraints/api.rs
  • crates/api/src/delegation/mock_delegation.rs
  • crates/api/src/delegation/mod.rs
  • crates/api/src/delegation/traits.rs
  • crates/api/src/lib.rs
  • crates/api/src/proposer/tests.rs
  • crates/api/src/test_utils.rs
  • crates/common/src/api/constraints_api.rs
  • crates/common/src/api/mod.rs
  • crates/utils/src/signing.rs
🔇 Additional comments (23)
crates/api/src/router.rs (2)

23-23: LGTM!

The import is correctly placed and necessary for the type definition changes.


34-35: Verify type definition usage across the codebase.

The addition of ContractDelegation as a new type parameter is correct, but we should verify that all instantiations of ProposerApiProd have been updated accordingly.

✅ Verification successful

Let me check the content of service.rs to verify the instantiation is correct.


Let me check the actual implementation of ProposerApi::new to verify the parameter order matches the type definition.


Let me try a different approach to find the ProposerApi implementation.


Let me check the complete constructor implementation to verify all parameters.


The type definition and its usage are correctly aligned

Based on the verification:

  1. The ProposerApiProd type definition in router.rs correctly includes ContractDelegation as the fifth type parameter
  2. The only instantiation in service.rs shows delegation_contract is properly created and passed as the last parameter to ProposerApiProd::new
  3. The constructor implementation in proposer/api.rs confirms the parameter order matches the type definition, with delegation_contract: Arc<D> as the last parameter
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for ProposerApiProd instantiations to ensure they've been updated
rg -l "ProposerApiProd::new|: ProposerApiProd = " --type rust

# Search for any direct uses of ProposerApi that might need the new parameter
ast-grep --pattern 'ProposerApi<$$$>'

Length of output: 129


Script:

#!/bin/bash
# Check the content of service.rs focusing on ProposerApiProd usage
rg "ProposerApiProd" -A 5 -B 5 crates/api/src/service.rs

Length of output: 1090


Script:

#!/bin/bash
# Search for ProposerApi implementation to verify constructor parameters
ast-grep --pattern 'impl$_ ProposerApi<$$$> {
  $$$
  fn new($$$) {
    $$$
  }
  $$$
}'

Length of output: 90


Script:

#!/bin/bash
# Search for ProposerApi implementation with ripgrep
rg "impl.*ProposerApi" -A 10 --type rust

Length of output: 6170


Script:

#!/bin/bash
# Get the complete new function implementation
rg "pub fn new" -A 15 crates/api/src/proposer/api.rs

Length of output: 616

crates/api/src/service.rs (3)

145-149: Previous review comment about provider initialization is still applicable.

The current implementation using expect for error handling needs improvement. Please refer to the previous review comment that suggested adding proper error handling, timeout configuration, and connection testing.


Line range hint 152-163: Verify ProposerApiProd constructor usage.

The addition of the delegation_contract parameter looks correct. Let's ensure all call sites are updated.

#!/bin/bash
# Description: Verify all ProposerApiProd constructor calls are updated

# Test: Search for ProposerApiProd::new calls
ast-grep --pattern 'ProposerApiProd::new($$$)'

150-151: ⚠️ Potential issue

Add validation and error handling for delegation contract initialization.

The current implementation should include:

  1. Validation of the contract address format
  2. Verification that the contract exists at the given address
  3. Error handling for contract initialization failures

Consider this approach:

-let delegation_contract = Arc::new(ContractDelegation::new(config.onchain_delegation.delegation_contract_address, provider));
+let delegation_contract = match ContractDelegation::new(config.onchain_delegation.delegation_contract_address, provider.clone()).await {
+    Ok(contract) => {
+        // Verify contract exists at the address
+        if provider.get_code(config.onchain_delegation.delegation_contract_address, None).await?.is_empty() {
+            error!("No contract found at configured address");
+            return;
+        }
+        Arc::new(contract)
+    },
+    Err(e) => {
+        error!("Failed to initialize delegation contract: {}", e);
+        return;
+    }
+};
crates/common/src/config.rs (2)

25-28: LGTM! New configuration fields are properly structured.

The new fields follow good practices with proper #[serde(default)] attributes for backward compatibility.


103-113: LGTM! ExecutionClientConfig is well-implemented.

The implementation follows best practices:

  • Proper URL serialization/deserialization
  • Sensible default implementation using the standard Ethereum node port
crates/api/src/proposer/api.rs (16)

1-1: LGTM!

The #![allow(clippy::type_complexity)] attribute is appropriate here to suppress the Clippy warning about the complexity of the type definitions in this file.


43-43: LGTM!

The usage of helix_utils::signing functions for verifying signed builder and consensus messages is appropriate.


55-56: LGTM!

The usage of constants MAX_SET_CONSTRAINTS_SIZE and the new DelegationTrait import are appropriate.


97-98: LGTM!

The addition of the delegation_contract field of type Arc<D> to the ProposerApi struct is appropriate, given the new generic parameter D constrained by DelegationTrait.


120-120: LGTM!

The addition of the delegation_contract parameter of type Arc<D> to the ProposerApi::new function is appropriate and consistent with the new generic parameter D and the delegation_contract field in the struct.


133-133: LGTM!

The initialization of the delegation_contract field with the provided delegation_contract parameter in the ProposerApi::new function is correct.


157-157: LGTM!

The addition of the new generic parameter D to the ProposerApi type in the status function signature is appropriate and consistent with the changes made to the ProposerApi struct.


174-174: LGTM!

The addition of the new generic parameter D to the ProposerApi type in the register_validators function signature is appropriate and consistent with the changes made to the ProposerApi struct.


375-375: LGTM!

The addition of the new generic parameter D to the ProposerApi type in the get_header function signature is appropriate and consistent with the changes made to the ProposerApi struct.


456-456: LGTM!

The addition of the new generic parameter D to the ProposerApi type in the get_payload function signature is appropriate and consistent with the changes made to the ProposerApi struct.


735-735: LGTM!

The addition of the new generic parameter D to the ProposerApi type in the set_constraints function signature is appropriate and consistent with the changes made to the ProposerApi struct.


879-885: LGTM!

The addition of the new generic parameter D constrained by DelegationTrait to the impl block for the helper functions of ProposerApi is appropriate and consistent with the changes made to the ProposerApi struct.


1237-1243: LGTM!

The addition of the new generic parameter D constrained by DelegationTrait to the impl block for the state sync functions of ProposerApi is appropriate and consistent with the changes made to the ProposerApi struct.


1277-1299: Verify the usage of delegation_contract in the handle_new_slot function.

The handle_new_slot function now includes logic to retrieve the preconfer election using the delegation_contract and save it to the auctioneer. This change looks good, but please ensure that:

  1. The get_preconfer_election method of delegation_contract returns the expected result.
  2. The error handling for get_preconfer_election and save_new_gateway_election is appropriate.
  3. The logging statements provide sufficient information for debugging and monitoring.
#!/bin/bash
# Description: Verify the usage of `delegation_contract` in `handle_new_slot`.

# Test 1: Check if `get_preconfer_election` method exists in `DelegationTrait`.
rg 'fn get_preconfer_election' $(fd DelegationTrait)

# Test 2: Check if `get_preconfer_election` returns a `Result<Option<_>, _>`.
rg 'get_preconfer_election(.+)\.await' -A 1 | rg 'Ok\(Some\(.+\)\)'
rg 'get_preconfer_election(.+)\.await' -A 1 | rg 'Ok\(None\)'
rg 'get_preconfer_election(.+)\.await' -A 1 | rg 'Err\(.+\)'

# Test 3: Check if the error handling for `get_preconfer_election` and `save_new_gateway_election` includes logging.
rg 'get_preconfer_election(.+)\.await' -A 5 | rg 'error!'
rg 'save_new_gateway_election(.+)\.await' -A 5 | rg 'error!'

101-107: Verify the new generic parameter D is properly constrained.

The new generic parameter D has been added to the impl block for ProposerApi, which is good. However, please ensure that the DelegationTrait bound is sufficient and appropriate for all the use cases of D within the ProposerApi implementation.

✅ Verification successful

The DelegationTrait bound is appropriate and sufficient for the generic parameter D

The verification shows that:

  • DelegationTrait is properly defined with the required get_preconfer_election method
  • Within ProposerApi, the generic parameter D is used correctly through self.delegation_contract.get_preconfer_election() call
  • The trait includes necessary bounds (Send + Sync + Clone) for concurrent usage
  • No additional trait bounds are required based on its usage
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of the generic parameter `D` within `ProposerApi` implementation.

# Test: Check if `D` is used with any other traits besides `DelegationTrait`.
rg 'impl<.+> ProposerApi<.+, D>' -A 10 | rg 'D: (?!DelegationTrait)'

Length of output: 1091


Script:

#!/bin/bash
# Let's check how D is used within ProposerApi implementation
ast-grep --pattern 'impl<$_> ProposerApi<$_> {
  $$$
}'

# Also check for any direct usage of D or DelegationTrait
rg "D::" crates/api/src/proposer/api.rs
rg "self\.delegation" crates/api/src/proposer/api.rs

# Check the trait definition to understand required functionality
cat crates/api/src/delegation/traits.rs

Length of output: 733


75-81: Verify the new generic parameter D is properly constrained and used.

The new generic parameter D constrained by DelegationTrait has been added to the ProposerApi struct. This change looks good, but please ensure that:

  1. The DelegationTrait is properly defined and implemented.
  2. The delegation_contract field of type Arc<D> is properly initialized and used throughout the code.
  3. All the necessary changes have been made in the codebase to accommodate this new generic parameter.
✅ Verification successful

Let me gather more information about the DelegationTrait definition and its implementations to ensure it's properly constrained and used.


Let me check one more thing to see the complete initialization of ProposerApi and its fields.


The new generic parameter D is properly constrained and used

The verification shows that:

  1. DelegationTrait is properly defined in traits.rs with required bounds (Send + Sync + Clone) and a clear async method signature
  2. The trait is correctly implemented by both MockDelegation and ContractDelegation
  3. delegation_contract field is properly initialized in ProposerApi as Arc<D>
  4. The field is actively used in the codebase, specifically in duty updates to get preconfer elections
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of the new generic parameter `D` and `DelegationTrait`.

# Test 1: Check if `DelegationTrait` is defined.
rg 'pub trait DelegationTrait'

# Test 2: Check if `DelegationTrait` is implemented.
rg 'impl DelegationTrait for'

# Test 3: Check if `delegation_contract` field is initialized in `ProposerApi::new`.
rg 'delegation_contract: Arc<D>'

# Test 4: Check if `delegation_contract` field is used.
rg 'self\.delegation_contract'

Length of output: 870


Script:

#!/bin/bash
# Check the definition of DelegationTrait and its methods
rg -A 10 'pub trait DelegationTrait' crates/api/src/delegation/traits.rs

# Check the implementation in MockDelegation
rg -A 10 'impl DelegationTrait for MockDelegation' crates/api/src/delegation/mock_delegation.rs

# Check the implementation in ContractDelegation
rg -A 10 'impl DelegationTrait for ContractDelegation' crates/api/src/delegation/contract_delegation.rs

# Check the initialization of ProposerApi with the delegation_contract
rg -A 5 'pub fn new\(' crates/api/src/proposer/api.rs

Length of output: 1662


Script:

#!/bin/bash
# Search for ProposerApi struct definition and initialization
ast-grep --pattern 'struct ProposerApi {
  $$$
}'

# Check for any other usages of delegation_contract in ProposerApi
rg -B 5 -A 5 'delegation_contract' crates/api/src/proposer/api.rs

Length of output: 1884

crates/common/src/config.rs Show resolved Hide resolved
crates/common/src/config.rs Show resolved Hide resolved
@Akagi201
Copy link
Member

Akagi201 commented Nov 6, 2024

We need to create a new branch offchain-delegation to backup the offchain version

@Akagi201
Copy link
Member

Akagi201 commented Nov 6, 2024

We may use a indexer to index delegation event on the contract to reduce the need to query contract on every slot.

crates/api/Cargo.toml Outdated Show resolved Hide resolved
@zsluedem
Copy link
Collaborator Author

zsluedem commented Nov 8, 2024

We need to create a new branch offchain-delegation to backup the offchain version

https://github.com/lu-bann/helix/tree/offchain-delegation

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (6)
Cargo.toml (1)

70-74: Consider adding documentation for new dependencies.

To improve maintainability, consider adding comments explaining why these Alloy dependencies are needed and their role in the onchain delegation feature. This will help future contributors understand the purpose of these dependencies.

Example documentation:

 # Alloy rust types
+# The following dependencies are required for onchain delegation:
+# - alloy-sol-types: Solidity type definitions for contract interactions
+# - alloy-contract: Smart contract interaction utilities
+# - alloy-provider: Blockchain provider interface with HTTP support
+# - alloy-transport: Network transport layer for blockchain communication
 alloy-sol-types = "0.8.8"
 alloy-contract ="0.5.2"
 alloy-provider = { version = "0.5.2", features = ["reqwest"], default-features = false }
 alloy-transport = "0.5.2"
crates/api/src/delegation/contract_delegation.rs (3)

29-34: Add documentation for PreconferElectionRes fields.

While the struct matches the Solidity contract, it would be helpful to document the purpose of each field, especially since this is a public interface.


59-61: Improve error context for contract call failures.

The error handling for contract calls could provide more context about what failed:

-        let taiyi_core_contract = Arc::new(TaiyiCoreInstance::new(self.delegation_contract_address, self.provider.clone()));
-        let preconfer_election =
-            taiyi_core_contract.getPreconferElection(pubkey).call().await.map_err(|e| Error::GetPreconferElection(e.to_string()))?;
+        let taiyi_core_contract = TaiyiCoreInstance::new(self.delegation_contract_address, self.provider.clone());
+        let preconfer_election = taiyi_core_contract
+            .getPreconferElection(pubkey)
+            .call()
+            .await
+            .map_err(|e| Error::GetPreconferElection(
+                format!("Failed to get preconfer election for validator {:?}: {}", validator_pubkey, e)
+            ))?;

59-59: Remove unnecessary Arc wrapping.

The Arc wrapping of the contract instance appears unnecessary as it's only used locally within the function.

crates/api/src/service.rs (1)

150-150: Consider implementing an indexer for delegation events.

The current implementation might need to query the contract frequently, which could impact performance. As suggested in the PR comments, implementing an indexer for delegation events would:

  • Reduce the load on the execution client
  • Improve response times by caching delegation relationships
  • Minimize RPC calls by only tracking changes through events

Consider these steps:

  1. Create an indexer service that subscribes to delegation events
  2. Store indexed data in your existing PostgreSQL database
  3. Update ContractDelegation to first check the indexed data before falling back to direct contract queries

Would you like help designing the indexer service architecture?

Also applies to: 163-163

crates/api/src/proposer/tests.rs (1)

Line range hint 829-840: Consider adding specific test cases for delegation functionality.

While the MockDelegation integration looks correct, there should be dedicated test cases to verify the delegation behavior. This would help ensure the new functionality works as expected.

Would you like me to help generate test cases for the delegation functionality?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d39396f and ca7daf2.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (18)
  • Cargo.toml (1 hunks)
  • crates/api/Cargo.toml (1 hunks)
  • crates/api/src/constraints/api.rs (1 hunks)
  • crates/api/src/delegation/contract_delegation.rs (1 hunks)
  • crates/api/src/delegation/error.rs (1 hunks)
  • crates/api/src/delegation/mock_delegation.rs (1 hunks)
  • crates/api/src/delegation/mod.rs (1 hunks)
  • crates/api/src/delegation/traits.rs (1 hunks)
  • crates/api/src/lib.rs (1 hunks)
  • crates/api/src/proposer/api.rs (16 hunks)
  • crates/api/src/proposer/tests.rs (4 hunks)
  • crates/api/src/router.rs (3 hunks)
  • crates/api/src/service.rs (4 hunks)
  • crates/api/src/test_utils.rs (4 hunks)
  • crates/common/src/api/constraints_api.rs (2 hunks)
  • crates/common/src/api/mod.rs (1 hunks)
  • crates/common/src/config.rs (7 hunks)
  • crates/utils/src/signing.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (13)
  • crates/api/Cargo.toml
  • crates/api/src/constraints/api.rs
  • crates/api/src/delegation/error.rs
  • crates/api/src/delegation/mock_delegation.rs
  • crates/api/src/delegation/mod.rs
  • crates/api/src/delegation/traits.rs
  • crates/api/src/lib.rs
  • crates/api/src/router.rs
  • crates/api/src/test_utils.rs
  • crates/common/src/api/constraints_api.rs
  • crates/common/src/api/mod.rs
  • crates/common/src/config.rs
  • crates/utils/src/signing.rs
🔇 Additional comments (6)
crates/api/src/service.rs (2)

3-3: LGTM: Imports are correctly placed.

The new imports for ProviderBuilder and ContractDelegation are appropriately placed and necessary for the onchain delegation feature.

Also applies to: 22-22


145-149: Refer to previous review comment about provider initialization robustness.

crates/api/src/proposer/tests.rs (2)

73-73: LGTM: Mock delegation import added correctly.

The import is properly placed and follows the existing import structure.


208-208: LGTM: Function signature updated to support delegation.

The return type has been properly updated to include the new MockDelegation type parameter.

crates/api/src/proposer/api.rs (2)

75-81: LGTM: Generic type parameter and field addition.

The addition of the generic type parameter D with DelegationTrait constraint and the corresponding delegation_contract field is well-structured and properly thread-safe using Arc.

Also applies to: 97-98


1277-1299: Consider potential race conditions in preconfer election handling.

While the code properly handles error cases and includes appropriate logging, there's a potential race condition when saving preconfer elections for multiple duties concurrently. Consider:

  1. Multiple duties could attempt to save the same preconfer election simultaneously
  2. The save_new_gateway_election call might need synchronization or deduplication

Note: A related issue about checking if the elected_preconfer has changed is being tracked in #25.

Consider implementing one of these solutions:

  1. Add a mutex/lock around the save operation
  2. Implement optimistic concurrency control
  3. Use a queue to process elections sequentially

Cargo.toml Show resolved Hide resolved
crates/api/src/proposer/api.rs Show resolved Hide resolved
@zsluedem
Copy link
Collaborator Author

zsluedem commented Nov 8, 2024

close it since onchain delegation is not our goal now

@zsluedem zsluedem closed this Nov 8, 2024
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