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

Multi-spork client access support #230

Merged
merged 61 commits into from May 20, 2024
Merged

Multi-spork client access support #230

merged 61 commits into from May 20, 2024

Conversation

sideninja
Copy link
Member

@sideninja sideninja commented May 6, 2024

Closes: #229

Description

This PR adds support for connecting to multiple AN hosts configured by the height boundary, which can be used to support multi-spork access.

We can use the new --access-node-spork-hosts flag to configure multiple hosts. This is optional, for the current spork we still use the --access-node-grpc-host flag.


For contributor use:

  • Targeted PR against master branch
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the standards mentioned here.
  • Updated relevant documentation
  • Re-reviewed Files changed in the Github PR explorer
  • Added appropriate labels

Summary by CodeRabbit

  • New Features

    • Introduced support for cross-spork client initialization, allowing seamless access to different spork APIs based on height boundaries.
  • Enhancements

    • Improved event subscription by backfilling events from previous sporks before subscribing to live data.
  • Configuration Changes

    • Renamed AccessNodeGRPCHost to AccessNodeHost.
    • Added new configuration field AccessNodePreviousSporkHosts to manage spork hosts.
  • Bug Fixes

    • Enhanced client initialization to handle multiple spork hosts, ensuring robust connectivity and data retrieval.

@sideninja sideninja self-assigned this May 6, 2024
Copy link

coderabbitai bot commented May 6, 2024

Walkthrough

The recent changes enhance the system to handle cross-spork access by implementing a multi-spork client in the requester package. This update enables seamless switching between hosts based on spork heights, facilitating access to historical data. The configuration and subscriber components were also adjusted to support this new functionality effectively.

Changes

Files Change Summary
bootstrap/bootstrap.go Updated client initialization to use requester.NewCrossSporkClient instead of grpc.NewClient and added support for managing previous spork hosts.
config/config.go Introduced AccessNodePreviousSporkHosts field, renamed AccessNodeGRPCHost to AccessNodeHost, and incorporated a new flag for spork hosts parsing.
services/ingestion/subscriber.go Modified client type, added logger field, adjusted Subscribe method, and included blocksFilter method.
services/requester/cross-spork_client.go Added CrossSporkClient struct and methods for handling spork clients and cross-spork access.
tests/integration_test.go Renamed AccessNodeGRPCHost field to AccessNodeHost.

Assessment against linked issues

Objective (Issue #229) Addressed Explanation
Introduce a wrapper for switching hosts based on height ranges
Allow indexing from previous spork before continuing with new spork data
Provide an emergency flag for overwriting new heights in non-production environments The introduction of an emergency flag for local networks is not explicitly mentioned in the changes.

Poem

In the land of sporks and heights,
A rabbit codes through days and nights.
With cross-spork clients, data flows,
Through past and present, knowledge grows.
🐰✨


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>.
    • 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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @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.

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 as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration 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: 6

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between 8fa4dbc and cf5e6ed.
Files selected for processing (5)
  • bootstrap/bootstrap.go (2 hunks)
  • config/config.go (4 hunks)
  • models/cross-spork_client.go (1 hunks)
  • tests/helpers.go (1 hunks)
  • tests/integration_test.go (1 hunks)
Files skipped from review due to trivial changes (1)
  • tests/helpers.go
Additional comments not posted (1)
tests/integration_test.go (1)

58-70: Ensure that the AccessNodeHost field is correctly utilized in all relevant parts of the test setup.

models/cross-spork_client.go Outdated Show resolved Hide resolved
models/cross-spork_client.go Outdated Show resolved Hide resolved
models/cross-spork_client.go Outdated Show resolved Hide resolved
bootstrap/bootstrap.go Outdated Show resolved Hide resolved
bootstrap/bootstrap.go Show resolved Hide resolved
config/config.go Outdated Show resolved Hide resolved
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

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between cf5e6ed and 21ced97.
Files selected for processing (3)
  • bootstrap/bootstrap.go (2 hunks)
  • models/cross-spork_client.go (1 hunks)
  • models/cross-spork_client_test.go (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • bootstrap/bootstrap.go
Additional comments not posted (6)
models/cross-spork_client_test.go (6)

13-14: Ensure proper error handling in NewCrossSporkClient initialization.

Verification successful

The error handling in the initialization of NewCrossSporkClient appears to be robust. The function is designed to return an error, which is appropriately checked in the test file using require.NoError(t, err). This ensures that the test will fail if an error occurs during the client initialization. Additionally, the usage in bootstrap.go also captures the error, allowing for proper handling or propagation in the application logic.

  • models/cross-spork_client_test.go: Error checked with require.NoError(t, err)
  • bootstrap/bootstrap.go: Error captured and needs to be handled or propagated

Overall, the implementation and usage of NewCrossSporkClient align with good practices in Go for error handling.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that error handling is robust during the initialization of `CrossSporkClient`.

# Test: Search for error handling patterns in `NewCrossSporkClient` usage.
rg --type go $'NewCrossSporkClient'

Length of output: 465


16-20: Check the logic for adding sporks in AddSpork method.

Verification successful

The AddSpork method in the CrossSporkClient class has been successfully located and reviewed. The method checks if a spork with the given lastHeight already exists in the sporkHosts map. If it does, an error is returned, indicating that the provided last height already exists. This effectively handles the edge case of duplicate heights. If the height does not exist, a new client is created for the given host, and it is added to the sporkHosts map.

Given this implementation, the method does handle the specific edge case of duplicate heights appropriately by preventing the addition of a spork with a height that is already registered.

Conclusion:
The AddSpork method correctly handles the edge case of duplicate heights as per the implementation in the CrossSporkClient class. No issues were found regarding this specific edge case handling.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that the logic for adding sporks handles edge cases correctly.

# Test: Search for `AddSpork` method usage and ensure it handles duplicate heights and other edge cases.
rg --type go $'AddSpork'

Length of output: 363



Script:

#!/bin/bash
# Extract the implementation of `AddSpork` method to verify edge case handling
rg --type go -A 10 'func (c \*CrossSporkClient) AddSpork' models/cross-spork_client.go

Length of output: 88



Script:

#!/bin/bash
# Confirm the presence of the `AddSpork` method in the expected file
cat models/cross-spork_client.go

Length of output: 3849


22-23: Validate the client retrieval logic in getClientForHeight.


28-29: Ensure error messages are informative and helpful in GetBlockByHeight.

Verification successful

The error handling associated with the GetBlockByHeight method across various files in the codebase appears to be adequately informative and context-specific. Here are the findings:

  • In models/cross-spork_client_test.go, the error messages include specific client hosts, which can be very useful for identifying issues related to specific network nodes or configurations.
  • In bootstrap/bootstrap.go, the error is enhanced with a clear message indicating a failure to retrieve a block at a specified height, which is crucial for debugging issues related to blockchain state or height mismatches.
  • In services/ingestion/subscriber.go, the error message explicitly includes the block height that could not be retrieved, directly pointing out the potential data availability issue.

These implementations suggest that the error messages are designed to provide the necessary context to diagnose issues effectively. Therefore, the original review comment concerning the informativeness of the error messages in GetBlockByHeight is addressed satisfactorily in the codebase.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that error messages in `GetBlockByHeight` provide enough context to be useful.

# Test: Search for `GetBlockByHeight` usage and check the associated error handling.
rg --type go $'GetBlockByHeight'

Length of output: 660



Script:

#!/bin/bash
# Extract the implementation of GetBlockByHeight and its error handling
rg --type go -C 10 'func (.*CrossSporkClient.*GetBlockByHeight' models/cross-spork_client.go
rg --type go -C 5 'GetBlockByHeight' services/ingestion/subscriber.go models/cross-spork_client_test.go bootstrap/bootstrap.go

Length of output: 2830


32-33: Check that the client selection logic for specific heights is accurate in GetBlockByHeight.

Verification successful

The implementation of GetBlockByHeight in the CrossSporkClient class reveals a clear mechanism for client selection based on the block height. The function getClientForHeight is used to determine the appropriate client for a given height. This function iterates through sorted height boundaries and selects the client corresponding to the last upper height limit that is greater than or equal to the requested height. This logic ensures that the correct client is used based on the block height, aligning with the expectations set in the review comment.

Given this information, the client selection logic for specific heights in GetBlockByHeight is accurately implemented as per the requirements.

  • The logic is implemented in models/cross-spork_client.go within the getClientForHeight method, which is called by GetBlockByHeight.
Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that the client selection logic for specific heights in `GetBlockByHeight` is accurate.

# Test: Search for `GetBlockByHeight` usage and ensure it selects the correct client based on height.
rg --type go $'GetBlockByHeight'

Length of output: 660



Script:

#!/bin/bash
# Description: Extract the implementation of `GetBlockByHeight` to verify client selection logic based on height.

# Extract the function implementation from `cross-spork_client.go`
rg --type go --context 20 'func \(c \*CrossSporkClient\) GetBlockByHeight' models/cross-spork_client.go

Length of output: 1188


36-37: Verify that the client selection for lower heights is handled correctly in GetBlockByHeight.

Verification successful

The review comment asked to verify the handling of client selection for lower heights in the GetBlockByHeight method. From the provided script outputs, we can see the implementation details in cross-spork_client.go and the test cases in cross-spork_client_test.go.

Analysis of Implementation:

The CrossSporkClient class in cross-spork_client.go has a method getClientForHeight which determines the appropriate client based on the block height. It iterates through the spork boundaries in descending order and selects the client that matches the height criteria. This method is used in GetBlockByHeight to fetch the block from the correct spork client based on the height.

Analysis of Test Cases:

The test cases in cross-spork_client_test.go specifically check the client selection logic:

  • For height 300, it expects to use the current spork client (test1.com).
  • For height 150, it expects to use the client from the second spork (test2.com).
  • For height 50, it expects to use the client from the third spork (test3.com).
  • It also tests the boundary condition at height 200, expecting to use the client from the third spork (test3.com).

These tests align with the implementation logic in cross-spork_client.go, confirming that the client selection for lower heights (and other heights) is handled as expected.

Conclusion:

The implementation and tests confirm that the client selection for lower heights in GetBlockByHeight is handled correctly. The test cases cover various scenarios including lower heights, ensuring that the correct client is selected based on the spork boundaries.

Final Response:

The verification of the client selection for lower heights in GetBlockByHeight confirms that the method correctly handles different heights according to the spork boundaries. The associated test cases in cross-spork_client_test.go adequately test this functionality, ensuring the correct client is used based on the block height.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that the client selection for lower heights in `GetBlockByHeight` is handled correctly.

# Test: Search for `GetBlockByHeight` usage and ensure it handles lower heights appropriately.
rg --type go $'GetBlockByHeight'

Length of output: 660



Script:

#!/bin/bash
# Inspect the implementation of GetBlockByHeight in cross-spork_client.go
cat models/cross-spork_client.go

# Check for any specific logic in cross-spork_client_test.go related to client selection based on height
cat models/cross-spork_client_test.go

Length of output: 4975

models/cross-spork_client.go Outdated Show resolved Hide resolved
models/cross-spork_client.go Outdated Show resolved Hide resolved
models/cross-spork_client.go Outdated Show resolved Hide resolved
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: 0

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between 21ced97 and cbb71e4.
Files selected for processing (1)
  • models/cross-spork_client_test.go (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • models/cross-spork_client_test.go

config/config.go Outdated
var streamTimeout int
var initHeight uint64

// parse from flags
flag.StringVar(&cfg.DatabaseDir, "database-dir", "./db", "Path to the directory for the database")
flag.StringVar(&cfg.RPCHost, "rpc-host", "", "Host for the RPC API server")
flag.IntVar(&cfg.RPCPort, "rpc-port", 8545, "Port for the RPC API server")
flag.StringVar(&cfg.AccessNodeGRPCHost, "access-node-grpc-host", "localhost:3569", "Host to the flow access node gRPC API")
flag.StringVar(&cfg.AccessNodeHost, "access-node-grpc-host", "localhost:3569", "Host to the flow access node gRPC API")
flag.StringVar(&accessSporkHosts, "access-node-spork-hosts", "", `Previous spork AN hosts, defined following the schema: {latest height}@{host} as comma separated list (e.g. "200@host-1.com,300@host2.com")`)

Choose a reason for hiding this comment

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

does latest height mean last height? is it sealed or finalized? It may make sense to define this as the first height in the spork since that's available in the sporks.json file as well as via the API.

Copy link
Member Author

Choose a reason for hiding this comment

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

I can make it that way yeah

Copy link
Member Author

Choose a reason for hiding this comment

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

actually on the second thought, I'm not sure it makes sense to do it that way, since then I cannot know if a height is in the current spork or previous, let me show with an example, if I provide one previous spork that starts at height 100, and I want to check for height 150, I can not know whether thats from previous spork or current spork, this would then require for current spork client to also be defined with starting height, which I wanted to to avoid. We could just subtract 1 from whats in sporks.json no?

Choose a reason for hiding this comment

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

it seems like there are 2 modes for the clients:

  • current
  • historic

In both cases, you can lookup the first block available using GetNodeVersionInfo().
In the historic case, you can lookup the last block available using GetLatestBlockHeader(). In some cases (infra bugs) this does not match [next spork start height] - 1 because the AN is missing some blocks. We always backfill when this happens, but something to be aware of.

When I originally wrote this comment, I was thinking the first block would be easier for the operator to get, but I think you're right that they can just derive it from to next spork. Another benefit of using the last height is you could validate that the height matches the response from GetLatestBlockHeader()

config/config.go Outdated Show resolved Hide resolved
return err
}

c.sporkHosts[lastHeight] = client

Choose a reason for hiding this comment

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

it's a good idea to validate the range to make sure there is a contiguous range of blocks. You can use GetNodeVersionInfo() to get the first block (NodeRootBlockHeight is the first block the node has):
https://github.com/onflow/flow-go/blob/1d581d472b7dcc40cd8952da497422c910ebd99b/access/api.go#L259-L266

GetLatestBlockHeader() to get the latest sealed block.

Then you can search all nodes to check for gaps

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a good idea, didn't know it exists. In my mind if you wrongly configured it would err out when accessing, but this is better for sure.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't have access to this method through the SDK

Copy link
Member Author

Choose a reason for hiding this comment

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

I can issue this up as a follow up PR since I believe it will require updating Go SDK first and then updating here.

Copy link
Member Author

Choose a reason for hiding this comment

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

models/cross-spork_client.go Outdated Show resolved Hide resolved
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: 2

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between 6e4dca5 and db9f8d7.
Files ignored due to path filters (4)
  • go.mod is excluded by !**/*.mod
  • go.sum is excluded by !**/*.sum
  • tests/go.mod is excluded by !**/*.mod
  • tests/go.sum is excluded by !**/*.sum
Files selected for processing (1)
  • services/ingestion/subscriber_test.go (1 hunks)

Comment on lines 37 to 49
client.
On("SubscribeEventsByBlockHeight", mock.Anything, mock.Anything, mock.Anything).
Return(func() (<-chan flowGo.BlockEvents, <-chan error, error) {
events := make(chan flowGo.BlockEvents)

for i := startHeight; i <= endHeight; i++ {
events <- flowGo.BlockEvents{
BlockHeight: i,
}
}

return events, make(chan error), nil
})
Copy link

Choose a reason for hiding this comment

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

Consider adding a close operation for the events channel to prevent potential resource leaks.

+			close(events)

This change ensures that the channel is properly closed after all events have been sent, preventing goroutines from hanging indefinitely.


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.

Suggested change
client.
On("SubscribeEventsByBlockHeight", mock.Anything, mock.Anything, mock.Anything).
Return(func() (<-chan flowGo.BlockEvents, <-chan error, error) {
events := make(chan flowGo.BlockEvents)
for i := startHeight; i <= endHeight; i++ {
events <- flowGo.BlockEvents{
BlockHeight: i,
}
}
return events, make(chan error), nil
})
client.
On("SubscribeEventsByBlockHeight", mock.Anything, mock.Anything, mock.Anything).
Return(func() (<-chan flowGo.BlockEvents, <-chan error, error) {
events := make(chan flowGo.BlockEvents)
for i := startHeight; i <= endHeight; i++ {
events <- flowGo.BlockEvents{
BlockHeight: i,
}
}
close(events)
return events, make(chan error), nil
})

Comment on lines 82 to 89
for ev := range events {
require.NoError(t, ev.Err)

// this makes sure all the event heights are sequential
eventHeight := ev.Events.CadenceHeight()
require.Equal(t, prevHeight+1, eventHeight)
prevHeight = eventHeight
}
Copy link

Choose a reason for hiding this comment

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

Consider handling potential errors from the event channel directly within the loop.

+		if ev.Err != nil {
+			t.Errorf("Error processing event: %v", ev.Err)
+			break
+		}
-		require.NoError(t, ev.Err)

This change improves the robustness of the test by handling errors immediately when they occur, allowing for cleaner error reporting and the ability to stop processing upon encountering an error.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
for ev := range events {
require.NoError(t, ev.Err)
// this makes sure all the event heights are sequential
eventHeight := ev.Events.CadenceHeight()
require.Equal(t, prevHeight+1, eventHeight)
prevHeight = eventHeight
}
for ev := range events {
if ev.Err != nil {
t.Errorf("Error processing event: %v", ev.Err)
break
}
// this makes sure all the event heights are sequential
eventHeight := ev.Events.CadenceHeight()
require.Equal(t, prevHeight+1, eventHeight)
prevHeight = eventHeight
}

@sideninja sideninja requested a review from peterargue May 9, 2024 12:13
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: 2

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between db9f8d7 and 3f910aa.
Files selected for processing (1)
  • services/ingestion/subscriber_test.go (1 hunks)
Additional comments not posted (2)
services/ingestion/subscriber_test.go (2)

43-80: LGTM! The mock client setup function is well-structured and effectively simulates different block heights.


83-125: LGTM! The test function effectively simulates the behavior of the blockchain client across different sporks and checks for sequential event heights.

}
}()

return events, make(chan error), nil
Copy link

Choose a reason for hiding this comment

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

Consider closing the error channel to prevent potential resource leaks.

+			close(errChan)

This change ensures that the error channel is properly closed after all events have been sent, preventing goroutines from hanging indefinitely.


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.

Suggested change
return events, make(chan error), nil
return events, make(chan error), nil
close(errChan)

Comment on lines +109 to +113
for ev := range events {
if prevHeight == endHeight {
require.ErrorIs(t, ev.Err, models.ErrDisconnected)
break
}
Copy link

Choose a reason for hiding this comment

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

Consider handling potential errors from the event channel directly within the loop.

+		if ev.Err != nil {
+			t.Errorf("Error processing event: %v", ev.Err)
+			break
+		}
-		require.NoError(t, ev.Err)

This change improves the robustness of the test by handling errors immediately when they occur, allowing for cleaner error reporting and the ability to stop processing upon encountering an error.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
for ev := range events {
if prevHeight == endHeight {
require.ErrorIs(t, ev.Err, models.ErrDisconnected)
break
}
for ev := range events {
if ev.Err != nil {
t.Errorf("Error processing event: %v", ev.Err)
break
}
if prevHeight == endHeight {
require.ErrorIs(t, ev.Err, models.ErrDisconnected)
break
}

return fmt.Errorf("failed to create client connection for host: %s, with error: %w", cfg.AccessNodeHost, err)
}

client, err := models.NewCrossSporkClient(grpcClient, logger)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe we could encapsulate the instantiation logic for CrossSporkClient, with a method that accepts cfg.AccessNodeHost & cfg.AccessNodePreviousSporkHosts and does the necessary creation of clients.
Maybe not something addressable in this PR, but a note to consider.


// NewCrossSporkClient creates a new instance of the client, it accepts the
// host to the current spork AN API.
func NewCrossSporkClient(currentSporkClient access.Client, logger zerolog.Logger) (*CrossSporkClient, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

There isn't any statement in this methods' body that can cause an error. If we choose to move the instantiation of current spork client and past sport clients in this method, then it makes sense to keep it.

@@ -0,0 +1,142 @@
package models
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor: Can we rename the file to cross_spork_client.go. Right now there's mixed - & _.
Another note: The functionality of this CrossSporkClient doesn't make me feel like it belongs to the models package, but rather the services package. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm using - and _ mixed because the _ is instead of a space, whereas - is actually how you write "cross-spork" in english.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, I see. This didn't even cross my mind 😇

Copy link
Collaborator

@m-Peter m-Peter left a comment

Choose a reason for hiding this comment

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

Nice 👏
Left a few comments that we can consider adding in a follow-up PR.

@sideninja
Copy link
Member Author

@m-Peter changed the factory like you said in this PR.

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

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between 3f910aa and e2b9adb.
Files ignored due to path filters (4)
  • go.mod is excluded by !**/*.mod
  • go.sum is excluded by !**/*.sum
  • tests/go.mod is excluded by !**/*.mod
  • tests/go.sum is excluded by !**/*.sum
Files selected for processing (5)
  • bootstrap/bootstrap.go (6 hunks)
  • config/config.go (4 hunks)
  • services/ingestion/subscriber.go (1 hunks)
  • services/ingestion/subscriber_test.go (1 hunks)
  • services/requester/cross-spork_client.go (1 hunks)
Files skipped from review as they are similar to previous changes (3)
  • bootstrap/bootstrap.go
  • config/config.go
  • services/ingestion/subscriber_test.go
Additional comments not posted (17)
services/requester/cross-spork_client.go (10)

23-28: Struct definition looks good.


30-50: Function definition looks good.


52-72: Function definition looks good.


74-77: Function definition looks good.


79-103: Function definition looks good.


105-111: Function definition looks good.


113-124: Function definition looks good.


126-133: Function definition looks good.


135-144: Function definition looks good.


146-155: Function definition looks good.

services/ingestion/subscriber.go (7)

29-34: Struct definition looks good.


37-39: Function definition looks good.


42-92: Function definition looks good.


94-156: Function definition looks good.


158-215: Function definition looks good.


217-240: Function definition looks good.


21-26: Interface definition looks good.

}

// getSporkBoundaries will return descending order of spork height boundaries
func (c *CrossSporkClient) getSporkBoundariesDesc() []uint64 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor: We can move this to NewCrossSporkClient and cache it, as it is not expected to change after initialization.

Copy link
Member Author

Choose a reason for hiding this comment

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

good point, I moved it into factory.

@m-Peter
Copy link
Collaborator

m-Peter commented May 16, 2024

@sideninja Looks good 👏
Left only a minor comment.

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

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between e2b9adb and e600315.
Files selected for processing (2)
  • services/requester/cross-spork_client.go (1 hunks)
  • tests/integration_test.go (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • tests/integration_test.go
Additional comments not posted (7)
services/requester/cross-spork_client.go (7)

31-57: Initialization of CrossSporkClient looks robust and well-structured.


60-80: Method addSpork correctly handles adding new spork clients and checks for duplicates.


82-85: Method IsPastSpork efficiently checks if a height is within past sporks.


87-110: Method getClientForHeight correctly selects the appropriate client based on the given height.


113-124: Method GetLatestHeightForSpork correctly retrieves the latest block height for a given spork.


126-133: Method GetBlockHeaderByHeight correctly fetches the block header for a specific height.


146-155: Method SubscribeEventsByBlockHeight correctly subscribes to events based on the start height.

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

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between e600315 and 14d972f.
Files selected for processing (1)
  • config/config.go (4 hunks)
Files skipped from review as they are similar to previous changes (1)
  • config/config.go

@sideninja sideninja merged commit 21099e0 into main May 20, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: ✅ Done
Development

Successfully merging this pull request may close these issues.

Handle cross-spork access
3 participants