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

Use flow-go Components for composing #682

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

janezpodhostnik
Copy link
Contributor

@janezpodhostnik janezpodhostnik commented Nov 27, 2024

Closes: onflow/flow-go#6776
Depends on: onflow/flow-go#6769

Description

Use flow-go component model and node framework to compose the Gatway and handle shutdown.

Main advantage is that the re-use of the component management system from flow-go automatically gives us nicer error handling an resource closing on error. To use the error handling, just make sure to use irrecoverable.SignalerContext.Throw(err) for any unexpected error. This will start the shutdown procedure and properly release all resources.

Changes:

  • api/profiler.go is now a component
  • api/server.go is now a component
  • bootstrap/bootstrap.go is changed a lot and is modeled after flow-go ExecutionNodeBuilder
  • bootstrap/utils.go were moved into services/requester/key_store_component.go which is a component that handles the keystore. It should have a Close for the KMS client, but the KMS client is currently not a io.Closer (which should be addresses)
  • cmd/run/cmd.go was simplified because the startup logic is now actually in flow-go
  • models/engine.go was removed because its no longer needed
  • models/stream.go was converted into a component. This lets it force shutdown the gateway in case of an error in Notify
  • services/ingestion/engine.go is now component. In case of errors in events processing it shuts down the node.

This depends on onflow/flow-go#6769


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

Release Notes

  • Architecture Refactoring

    • Introduced a new component-based architecture for improved modularity.
    • Streamlined server and engine lifecycle management.
    • Enhanced error handling and context management.
  • Dependency Updates

    • Updated Flow Go dependency to v0.38.0-preview.0.4.0.20250102180624-72adf9e522c4.
    • Added multiple AWS SDK and utility library dependencies.
    • Refined dependency management.
  • Performance Improvements

    • Optimized publisher and subscriber mechanisms.
    • Improved concurrent event processing.
    • Enhanced startup and shutdown procedures for services.
  • Testing Enhancements

    • Updated integration test infrastructure.
    • Simplified gateway startup process in tests.
    • Improved error tracking and synchronization mechanisms.
  • Cleanup

    • Removed deprecated mock generation for Engine.
    • Simplified key store and signer management.
    • Removed unused utility functions.

@janezpodhostnik janezpodhostnik self-assigned this Nov 27, 2024
Copy link
Contributor

coderabbitai bot commented Nov 27, 2024

Walkthrough

This pull request introduces a comprehensive refactoring of the EVM Gateway's architecture, focusing on component-based design, improved error handling, and streamlined lifecycle management. The changes span multiple files, including bootstrap, services, models, and tests. Key modifications include replacing the EngineStatus with a component-based approach, enhancing context management, and simplifying error propagation mechanisms across different parts of the system.

Changes

File Change Summary
Makefile Removed mock generation line for Engine type
api/profiler.go Refactored ProfileServer to use component interface, updated logging and server management
api/server.go Enhanced server lifecycle management, added startup completion channel
api/stream.go Simplified error handling in newSubscription, removed error-checking loop
bootstrap/bootstrap.go Introduced EVMGatewayNodeImp and EVMGatewayNodeBuilder, modularized initialization process
bootstrap/utils.go Removed createSigner function
models/engine.go Removed Engine interface and EngineStatus struct
models/mocks/Engine.go Removed mock implementation of Engine interface
models/stream.go Enhanced Publisher with new fields and refactored Publish method
services/ingestion/engine.go Replaced EngineStatus with component-based architecture, modified error handling
services/requester/key_store_component.go New component for key store management
Multiple files Updated dependency versions in go.mod

Assessment against linked issues

Objective Addressed Explanation
Identify stability edge-cases (6776) Refactoring introduces more robust component lifecycle management
Improve error handling (6776) Enhanced error propagation through context and component interfaces
Simplify system architecture (6776) Modular design with clear component boundaries

Poem

🐰 A Gateway's Tale of Refactor's Grace
Components dance, errors embrace
Channels close, contexts align
Code flows smooth, like vintage wine
Stability's rabbit hops with glee! 🚀

Finishing Touches

  • 📝 Generate Docstrings

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 generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai 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.

Base automatically changed from janez/config-instance to janez/switch-to-flow-go-metrics-server November 29, 2024 14:28
@janezpodhostnik janezpodhostnik changed the base branch from janez/switch-to-flow-go-metrics-server to janez/config-instance-2 November 29, 2024 14:36
@janezpodhostnik janezpodhostnik changed the base branch from janez/config-instance-2 to feature/local-tx-reexecution December 2, 2024 13:22
@janezpodhostnik janezpodhostnik force-pushed the janez/use-flow-go-components branch from 33d6278 to 67136f9 Compare December 2, 2024 15:11
@janezpodhostnik janezpodhostnik force-pushed the janez/use-flow-go-components branch 4 times, most recently from 9e3947b to 50d77d2 Compare December 16, 2024 15:17
@janezpodhostnik janezpodhostnik marked this pull request as ready for review December 16, 2024 15:17
@m-Peter m-Peter force-pushed the feature/local-tx-reexecution branch from 2121836 to a746c82 Compare December 18, 2024 11:30
bootstrap/bootstrap.go Outdated Show resolved Hide resolved
bootstrap/bootstrap.go Outdated Show resolved Hide resolved
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 👏 👏 👏

@janezpodhostnik janezpodhostnik force-pushed the janez/use-flow-go-components branch from 87a1102 to 453f201 Compare December 18, 2024 17:01
Copy link
Contributor

@peterargue peterargue left a comment

Choose a reason for hiding this comment

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

thanks for making this consistent with flow-go. will make it much easier to reason with.

a general comment about the component usage. In some places you used a component manager, and in others you wrote your own. I'm OK with custom handling where it's easier, but I think we should avoid non-idempotent Ready/Done methods

api/profiler.go Outdated Show resolved Hide resolved
tests/integration_test.go Show resolved Hide resolved
cmd/run/cmd.go Outdated Show resolved Hide resolved
cmd/run/cmd.go Outdated Show resolved Hide resolved
bootstrap/bootstrap.go Outdated Show resolved Hide resolved
bootstrap/bootstrap.go Outdated Show resolved Hide resolved
bootstrap/bootstrap.go Outdated Show resolved Hide resolved
bootstrap/bootstrap.go Outdated Show resolved Hide resolved
services/ingestion/engine.go Show resolved Hide resolved
Base automatically changed from feature/local-tx-reexecution to main December 19, 2024 09:12
@janezpodhostnik janezpodhostnik force-pushed the janez/use-flow-go-components branch from 050ab5f to 93ee75c Compare January 3, 2025 15:11
@janezpodhostnik janezpodhostnik force-pushed the janez/use-flow-go-components branch from 93ee75c to e9e537f Compare January 3, 2025 15:25
l.Info().Msg("bootstrap starting event ingestion")

// get latest cadence block from the network and the database
gatewayLatestBlock, err := fnb.Client.GetLatestBlock(context.Background(), true)
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 this should be chainLatestBlock.


func (b *Bootstrap) StartMetricsServer(ctx context.Context) error {
b.logger.Info().Msg("bootstrap starting metrics server")
chainLatestHeight, err := fnb.Storages.Blocks.LatestCadenceHeight()
Copy link
Collaborator

Choose a reason for hiding this comment

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

And this should be gatewayLatestHeight.

return
}
for _, key := range account.Keys {
accountKeys = append(accountKeys, &AccountKey{
Copy link
Collaborator

Choose a reason for hiding this comment

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

We are missing this piece of code: https://github.com/onflow/flow-evm-gateway/blob/main/bootstrap/bootstrap.go#L217-L221, from this loop here. This is quite important for the setup that we have now on testnet & mainnet.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🔭 Outside diff range comments (1)
api/server.go (1)

Line range hint 192-219: Avoid signaling readiness when the server fails to start

The startupCompleted channel is closed regardless of whether the server starts successfully or not. This could cause Ready() to signal that the server is ready even if it failed to start due to an error or misconfiguration.

Apply this diff to close startupCompleted only after the server has started successfully:

 func (h *Server) Start(ctx irrecoverable.SignalerContext) {
-	defer close(h.startupCompleted)
 	if h.endpoint == "" || h.listener != nil {
 		return // already running or not configured
 	}
+	defer func() {
+		if err == nil {
+			close(h.startupCompleted)
+		}
+	}()
 
 	// Initialize the server.
🧹 Nitpick comments (7)
api/profiler.go (1)

80-100: Refine Shutdown Logic in shutdownOnContextDone

The shutdownOnContextDone method may log errors even when there is no error (i.e., err == nil). Adjust the error handling to log messages appropriately based on the presence of an error.

Consider modifying the error handling as follows:

     err := s.server.Shutdown(ctx)
     if err == nil {
         s.log.Info().Msg("Profiler server graceful shutdown completed")
+        return
     }

-    if errors.Is(err, ctx.Err()) {
+    if errors.Is(err, context.DeadlineExceeded) {
         s.log.Warn().Msg("Profiler server graceful shutdown timed out")
         err := s.server.Close()
         if err != nil {
             s.log.Err(err).Msg("error closing profiler server")
         }
     } else {
         s.log.Err(err).Msg("error shutting down profiler server")
     }
services/requester/key_store_component.go (1)

78-102: Simplify Ready and Done Methods Using Sync Mechanisms

The Ready and Done methods use additional goroutines and channels to signal readiness and completion. Consider using synchronization primitives like sync.Once or leveraging existing component patterns to simplify this logic.

Refactor the methods to reduce complexity and potential overhead from unnecessary goroutines.

api/server.go (1)

245-253: Simplify the Ready method

Consider simplifying the Ready method by returning the startupCompleted channel directly, as it's already a channel that signals readiness.

Apply this diff to simplify the method:

 func (h *Server) Ready() <-chan struct{} {
-	ready := make(chan struct{})
-
-	go func() {
-		<-h.startupCompleted
-		close(ready)
-	}()
-
-	return ready
+	return h.startupCompleted
 }
bootstrap/bootstrap.go (3)

54-56: Consider renaming EVMGatewayNodeImp to EVMGatewayNodeImpl for consistency

It's standard practice in Go to use Impl as a suffix for implementation structs. Renaming EVMGatewayNodeImp to EVMGatewayNodeImpl would improve clarity and adhere to conventions.


369-371: Wrap the error with context for better error handling

Currently, the error returned from fnb.Storages.Blocks.LatestCadenceHeight() is returned directly. Consider wrapping it with additional context to aid in debugging.

Apply this diff:

	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to get latest cadence height: %w", err)
	}

402-403: Wrap the error with context for better error handling

Instead of returning the error directly from replayer.NewCallTracerCollector, wrap it with context to improve debuggability.

Apply this diff:

	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to create CallTracerCollector: %w", err)
	}
tests/helpers.go (1)

187-199: Well-structured gateway initialization function.

The function follows a clear sequence of steps and properly manages the node lifecycle. Consider adding a function comment to document its purpose and behavior.

Add a function comment:

+// startGateway initializes and starts the EVM gateway node.
+// It blocks until the node is ready to accept requests.
 func startGateway(t *testing.T, ctx context.Context, cfg config.Config) {
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 08d369b and 4a8ccb2.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • tests/go.sum is excluded by !**/*.sum
📒 Files selected for processing (18)
  • Makefile (0 hunks)
  • api/profiler.go (1 hunks)
  • api/server.go (8 hunks)
  • api/stream.go (2 hunks)
  • bootstrap/bootstrap.go (3 hunks)
  • bootstrap/utils.go (0 hunks)
  • cmd/run/cmd.go (1 hunks)
  • go.mod (6 hunks)
  • models/engine.go (0 hunks)
  • models/mocks/Engine.go (0 hunks)
  • models/stream.go (2 hunks)
  • models/stream_test.go (5 hunks)
  • services/ingestion/engine.go (5 hunks)
  • services/ingestion/engine_test.go (17 hunks)
  • services/requester/key_store_component.go (1 hunks)
  • tests/go.mod (13 hunks)
  • tests/helpers.go (1 hunks)
  • tests/integration_test.go (4 hunks)
💤 Files with no reviewable changes (4)
  • bootstrap/utils.go
  • Makefile
  • models/mocks/Engine.go
  • models/engine.go
🔇 Additional comments (20)
models/stream.go (2)

25-41: Properly Build and Assign the Component Manager

In the NewPublisher function, the ComponentManager is built and assigned to both p.cm and p.Component. Confirm that this dual assignment is necessary and doesn't lead to redundant references or potential confusion in managing the component's lifecycle.

Please confirm if assigning both p.cm and p.Component is required or if one reference suffices.


67-98: ⚠️ Potential issue

Ensure Proper Error Propagation in publishWorker

Within publishWorker, when an error occurs during s.Notify(data), ctx.Throw(err) is called. Since ctx.Throw(err) signals an irrecoverable error, it's important to ensure that the goroutine exits immediately after throwing the error to prevent further execution.

Consider adding a return statement after ctx.Throw(err) to ensure the worker exits:

                     if err != nil {
                         p.log.Error().Err(err).Msg("failed to notify subscriber")
                         ctx.Throw(err)
+                        return true
                     }

Likely invalid or redundant comment.

api/profiler.go (1)

51-77: ⚠️ Potential issue

Handle Errors Appropriately in the serve Method

In the serve method, after calling ctx.Throw(err), the function should return immediately to prevent further execution. Continuing after throwing an error might lead to unintended behavior.

Apply this diff to ensure the function exits after throwing an error:

         if err != nil {
             s.log.Err(err).Msg("failed to start the metrics server")
             ctx.Throw(err)
             return
         }

Likely invalid or redundant comment.

services/requester/key_store_component.go (2)

104-131: Handle Missing Key Configuration in createSigner

In the createSigner function, if neither COAKey nor COACloudKMSKey is provided, an error is returned. Ensure that this scenario is properly handled and that the error message provides clear guidance to the user.

Confirm that the configuration validation occurs earlier in the application flow to prevent reaching this point without a valid key configuration.


37-59: ⚠️ Potential issue

Ensure Immediate Return After Throwing Errors in Start

In the Start method, after calling ctx.Throw(err), the function should return immediately to prevent executing subsequent code that may depend on successful operations.

Apply this diff to add missing return statements:

         if err != nil {
             ctx.Throw(fmt.Errorf(
                 "failed to get signer info account for address: %s, with: %w",
                 k.config.COAAddress,
                 err,
             ))
+            return
         }

         signer, err := createSigner(ctx, k.config, k.log)

         if err != nil {
             ctx.Throw(err)
+            return
         }

Likely invalid or redundant comment.

cmd/run/cmd.go (1)

42-42: Include 'node' in the error message for clarity

Consider modifying the error message to "failed to initialize node" for better clarity and consistency.

Apply this diff to make the change:

-    			builder.Logger.Fatal().Err(err).Msg("failed to initialize")
+    			builder.Logger.Fatal().Err(err).Msg("failed to initialize node")
services/ingestion/engine.go (1)

116-140: Refactored run method integration looks good

The integration with the component framework and the updated error handling using ctx.Throw are appropriate. The use of ready() after initializing the subscriber ensures that the component correctly signals readiness.

bootstrap/bootstrap.go (1)

486-487: ⚠️ Potential issue

Fix typo and use variable in error message

There's a misspelling in the variable name evmBlokcHeight; it should be evmBlockHeight. Also, use the variable in the error message instead of hardcoding 0.

Apply this diff:

-	evmBlokcHeight := uint64(0)
+	evmBlockHeight := uint64(0)

	// ...

-	snapshot, err := registerStore.GetSnapshotAt(evmBlokcHeight)
+	snapshot, err := registerStore.GetSnapshotAt(evmBlockHeight)
	if err != nil {
-		return fmt.Errorf("could not get register snapshot at block height %d: %w", 0, err)
+		return fmt.Errorf("could not get register snapshot at block height %d: %w", evmBlockHeight, err)
	}

Likely invalid or redundant comment.

models/stream_test.go (1)

105-112: Ensure correct capture of loop variable in closure

When using closures inside loops, it's important to capture the loop variable correctly to avoid unexpected behavior. In this case, j is correctly captured since there is no goroutine, so the current implementation is acceptable.

tests/integration_test.go (4)

85-85: LGTM! The gateway startup has been simplified.

The change improves code readability by removing channel-based synchronization in favor of a more straightforward startGateway function call.


187-187: Consistent with previous changes.


276-276: Consistent with previous changes.


370-370: Consistent with previous changes.

tests/helpers.go (1)

179-179: Consistent with previous changes.

services/ingestion/engine_test.go (1)

73-77: LGTM! Improved publisher initialization with proper context handling.

The change ensures that publishers are properly initialized and started with the irrecoverable context, aligning with the PR's goal of improving error handling.

go.mod (1)

11-11: Verify the flow-go dependency version.

The flow-go dependency has been updated to a very specific version. Please ensure this version is stable and compatible with the current changes.

Run this script to check the dependency's stability:

✅ Verification successful

The flow-go dependency version is valid and stable.

The version points to a specific verified commit (72adf9e522c4) from January 2, 2025, which adds implementation for transaction statuses data providers. The changes are well-structured, properly tested, and merged through a reviewed pull request.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the flow-go dependency version and its stability.

# Check if the version exists in the repository
gh api repos/onflow/flow-go/git/refs/tags/v0.38.0-preview.0.4.0.20250102180624-72adf9e522c4

# Check for any known issues with this version
gh api search/issues -f q='repo:onflow/flow-go is:issue label:bug v0.38.0-preview.0.4.0.20250102180624-72adf9e522c4'

Length of output: 566


Script:

#!/bin/bash
# Check if the commit hash exists and list recent tags
gh api repos/onflow/flow-go/commits/72adf9e522c4 || echo "Commit not found"
gh api repos/onflow/flow-go/tags?per_page=5

# Check go.sum for this dependency
grep "github.com/onflow/flow-go@" go.sum || echo "No matching entry in go.sum"

Length of output: 85691

tests/go.mod (4)

226-226: LGTM! Good addition of Ginkgo testing framework.

Adding Ginkgo v2 is a good choice for behavior-driven development (BDD) style testing, which aligns well with the component-based architecture being implemented.


295-296: LGTM! Essential dependencies for component framework.

The addition of go.uber.org/dig and go.uber.org/fx is aligned with the PR objective of integrating the flow-go component model for improved resource management.


31-46: Verify the necessity of AWS SDK dependencies.

Multiple AWS SDK v2 packages have been added as indirect dependencies. Since these are marked as indirect, verify if they are actually required and through which direct dependency they were introduced.

✅ Verification successful

AWS SDK dependencies are correctly marked as indirect

These AWS SDK packages are transitive dependencies pulled in through the Flow ecosystem dependencies (flow-go, flow-emulator, etc.). There is no direct usage of AWS services in the codebase, confirming these are correctly marked as indirect dependencies and require no further verification.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find which direct dependencies are pulling in AWS SDK

# Search for AWS SDK imports in the codebase
rg --type go "github.com/aws/aws-sdk-go-v2"

Length of output: 43


Script:

#!/bin/bash
# Check root go.mod and list direct dependencies
echo "=== Root go.mod ==="
if [ -f "go.mod" ]; then
    cat go.mod
fi

echo -e "\n=== Looking for AWS/S3 related code ==="
# Search for S3, AWS, or cloud storage related terms
rg -i "s3|aws|cloud.*storage" --type go

echo -e "\n=== Direct dependencies in tests/go.mod ==="
cat tests/go.mod | awk '/^[[:space:]]*[^[:space:]\/].*[[:space:]]v[0-9]/ && !/indirect/'

Length of output: 17671


9-9: Verify compatibility with the updated Flow dependencies.

The updates to flow-emulator and flow-go are using pre-release versions. Please ensure these versions are stable and compatible with your changes.

Also applies to: 11-11

✅ Verification successful

Development versions appear to be coordinated builds

The specified versions of flow-go and flow-emulator are very recent development builds (Jan 2-3, 2025) that appear to be coordinated, with flow-emulator being built against the new flow-go version. This aligns with the ongoing component model refactoring in flow-go. The dependency resolution is successful as evidenced by the presence in both go.mod and go.sum files.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any known issues or breaking changes in the flow-go and flow-emulator versions

# Check for any tagged releases or issues mentioning these specific versions
gh issue list --repo onflow/flow-go --search "v0.38.0-preview.0.4.0.20250102180624-72adf9e522c4"
gh issue list --repo onflow/flow-emulator --search "v1.1.1-0.20250103150158-e029ea3471fe"

Length of output: 186


Script:

#!/bin/bash
# Check recent issues and go.mod files for compatibility information

# Check recent issues in both repositories
echo "=== Recent Flow Go Issues ==="
gh issue list --repo onflow/flow-go --limit 5 --state all

echo -e "\n=== Recent Flow Emulator Issues ==="
gh issue list --repo onflow/flow-emulator --limit 5 --state all

# Search for go.mod files referencing these dependencies
echo -e "\n=== Dependencies Usage Patterns ==="
rg "github.com/onflow/flow-go.*v0.38.0-preview" -A 2 -B 2
rg "github.com/onflow/flow-emulator.*v1.1.1-0" -A 2 -B 2

Length of output: 4601

Comment on lines +15 to +22
log zerolog.Logger

mux sync.RWMutex
subscribers map[Subscriber[T]]struct{}

publishChan chan T

publisherExited chan struct{}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Initialize All Fields in the Publisher Struct

The Publisher struct now includes additional fields such as Component, cm, log, publishChan, and publisherExited. Ensure that all these fields are properly initialized to avoid potential nil pointer dereferences.

Consider verifying the initialization in the constructor and ensuring that each field is appropriately set before use.

Comment on lines +101 to +115
Notify(data T) error
}

type Subscription[T any] struct {
logger zerolog.Logger
err chan error
callback func(data T) error
}

func NewSubscription[T any](logger zerolog.Logger, callback func(T) error) *Subscription[T] {
func NewSubscription[T any](callback func(T) error) *Subscription[T] {
return &Subscription[T]{
logger: logger,
callback: callback,
err: make(chan error, 1),
}
}

func (b *Subscription[T]) Notify(data T) {
err := b.callback(data)
if err != nil {
select {
case b.err <- err:
default:
b.logger.Debug().Err(err).Msg("failed to send error to subscription")
}
}
}

func (b *Subscription[T]) Error() <-chan error {
return b.err
func (b *Subscription[T]) Notify(data T) error {
return b.callback(data)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Update All Implementations to Handle the Modified Notify Signature

The Notify method now returns an error. Ensure that all implementations of the Subscriber interface and related code handle this new signature correctly. This includes checking returned errors and updating any documentation or comments related to this method.

Please review all Subscriber implementations to accommodate the new error return type from Notify.

Comment on lines +45 to +49
select {
case <-p.publisherExited:
return
default:
p.publishChan <- data
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Prevent Potential Blocking in the Publish Method

The Publish method writes to publishChan without checking if the channel is full. If publishChan is unbuffered or has a limited buffer, this could lead to blocking behavior. Consider adding a buffer to publishChan or handling cases where the channel is full to prevent potential deadlocks.

Apply this diff to add a buffer to publishChan:

-    publishChan:     make(chan T),
+    publishChan:     make(chan T, bufferSize), // Define an appropriate buffer size

Alternatively, handle the blocking scenario in the Publish method:

 func (p *Publisher[T]) Publish(data T) {
     select {
     case <-p.publisherExited:
         return
+    case p.publishChan <- data:
+        // Successfully published data
+    default:
+        // Handle channel being full
+        p.log.Warn().Msg("Publish channel is full; data may be dropped")
     }
 }

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

Comment on lines 384 to 386
Uint64("chain-cadence-height", chainLatestBlock.Height).
Uint64("gateway-cadence-height", gatewayLatestHeight).
Uint64("missed-heights", chainLatestBlock.Height-gatewayLatestHeight).
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure safe subtraction to avoid underflow in "missed-heights" calculation

When calculating missed-heights, subtracting gatewayLatestHeight from chainLatestBlock.Height may result in underflow if gatewayLatestHeight is greater. Ensure that this calculation handles such cases safely.

Apply this diff:

	l.Info().
		Uint64("chain-cadence-height", chainLatestBlock.Height).
		Uint64("gateway-cadence-height", gatewayLatestHeight).
-		Uint64("missed-heights", chainLatestBlock.Height-gatewayLatestHeight).
+		Uint64("missed-heights", calculateMissedHeights(chainLatestBlock.Height, gatewayLatestHeight)).
		Msg("indexing cadence height information")

Add the helper function:

func calculateMissedHeights(chainHeight, gatewayHeight uint64) uint64 {
	if chainHeight > gatewayHeight {
		return chainHeight - gatewayHeight
	}
	return 0
}

Comment on lines +521 to +523
Stringer("fvm_address_for_evm_storage_account", storageAddress).
Msgf("database initialized with cadence height: %d", cadenceHeight)

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use Msg instead of Msgf and include cadenceHeight as a field

zerolog does not support the Msgf method. Use Msg and include cadenceHeight as a field for structured logging.

Apply this diff:

	logger.Info().
		Stringer("fvm_address_for_evm_storage_account", storageAddress).
-		Msgf("database initialized with cadence height: %d", cadenceHeight)
+		Uint64("cadence_height", cadenceHeight).
+		Msg("database initialized")
📝 Committable suggestion

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

Suggested change
Stringer("fvm_address_for_evm_storage_account", storageAddress).
Msgf("database initialized with cadence height: %d", cadenceHeight)
Stringer("fvm_address_for_evm_storage_account", storageAddress).
Uint64("cadence_height", cadenceHeight).
Msg("database initialized")

Comment on lines +474 to +476
defer func(batch *pebble.Batch) {
innerErr = batch.Close()
}(batch)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix improper use of defer to correctly close the batch

The deferred function is executed immediately due to the function call syntax (batch). To properly defer the execution until the surrounding function returns, remove the parameter from the anonymous function and the call.

Apply this diff:

	batch := store.NewBatch()
-	defer func(batch *pebble.Batch) {
+	defer func() {
		innerErr = batch.Close()
-	}(batch)
+	}()
📝 Committable suggestion

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

Suggested change
defer func(batch *pebble.Batch) {
innerErr = batch.Close()
}(batch)
defer func() {
innerErr = batch.Close()
}()

Comment on lines +193 to +194
err := <-rpcSub.Err()
l.Debug().Err(err).Msg("client unsubscribed")
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle errors from the subscription to prevent unhandled errors

Currently, the code only listens for errors from rpcSub.Err() and ignores potential errors from subs.Err(). This may lead to unhandled errors and resource leaks. Consider adding error handling for subs.Err().

Apply this diff:

	go func() {
		defer publisher.Unsubscribe(subs)
-		err := <-rpcSub.Err()
-		l.Debug().Err(err).Msg("client unsubscribed")
+		select {
+		case err := <-rpcSub.Err():
+			l.Debug().Err(err).Msg("client unsubscribed")
+		case err := <-subs.Err():
+			l.Error().Err(err).Msg("subscription error")
+		}
	}()
📝 Committable suggestion

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

Suggested change
err := <-rpcSub.Err()
l.Debug().Err(err).Msg("client unsubscribed")
go func() {
defer publisher.Unsubscribe(subs)
select {
case err := <-rpcSub.Err():
l.Debug().Err(err).Msg("client unsubscribed")
case err := <-subs.Err():
l.Error().Err(err).Msg("subscription error")
}
}()

@janezpodhostnik janezpodhostnik force-pushed the janez/use-flow-go-components branch from 4a8ccb2 to 3e04bc3 Compare January 8, 2025 15:57
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
bootstrap/bootstrap.go (3)

521-522: Use structured logging instead of formatted message.

Replace Msgf with Msg and include cadence_height as a field for better log parsing.

Apply this diff:

 			logger.Info().
 				Stringer("fvm_address_for_evm_storage_account", storageAddress).
-				Msgf("database initialized with cadence height: %d", cadenceHeight)
+				Uint64("cadence_height", cadenceHeight).
+				Msg("database initialized")

479-479: Fix typo in variable name.

The variable evmBlokcHeight contains a typo.

Apply this diff:

-			evmBlokcHeight := uint64(0)
+			evmBlockHeight := uint64(0)

207-215: Consider reordering component initialization.

The profiler and metrics servers should be initialized first to capture debug data during startup of other components.

Apply this diff:

 func (fnb *EVMGatewayNodeBuilder) LoadComponentsAndModules() {
 	fnb.initPublishers()
 
-	fnb.Component("Profiler Server", fnb.profilerServerComponent)
-	fnb.Component("Metrics Server", fnb.metricsServerComponent)
-	fnb.Component("Key Store", fnb.initKeyStore)
-	fnb.Component("API Server", fnb.apiServerComponent)
-	fnb.Component("Event Ingestion Engine", fnb.eventIngestionEngineComponent)
+	// Initialize profiler and metrics first for debugging
+	fnb.Component("Metrics Server", fnb.metricsServerComponent)
+	fnb.Component("Profiler Server", fnb.profilerServerComponent)
+	// Initialize core components
+	fnb.Component("Key Store", fnb.initKeyStore)
+	fnb.Component("API Server", fnb.apiServerComponent)
+	fnb.Component("Event Ingestion Engine", fnb.eventIngestionEngineComponent)
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4a8ccb2 and 3e04bc3.

📒 Files selected for processing (2)
  • bootstrap/bootstrap.go (3 hunks)
  • services/requester/key_store_component.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • services/requester/key_store_component.go
🔇 Additional comments (5)
bootstrap/bootstrap.go (5)

54-78: LGTM! Clean implementation of the node structure.

The EVMGatewayNodeImp struct and NewNode function provide a clear and concise implementation for node management.


585-590: LGTM! Proper cleanup in shutdown function.

The shutdown function properly handles the cleanup of the cross-spork client.


384-386: ⚠️ Potential issue

Fix potential integer underflow in missed heights calculation.

The subtraction operation chainLatestBlock.Height-gatewayLatestHeight could underflow if gatewayLatestHeight is greater than chainLatestBlock.Height.

Apply this diff:

-		Uint64("missed-heights", chainLatestBlock.Height-gatewayLatestHeight).
+		Uint64("missed-heights", calculateMissedHeights(chainLatestBlock.Height, gatewayLatestHeight)).

// Add helper function:
func calculateMissedHeights(chainHeight, gatewayHeight uint64) uint64 {
    if chainHeight > gatewayHeight {
        return chainHeight - gatewayHeight
    }
    return 0
}

Likely invalid or redundant comment.


474-476: ⚠️ Potential issue

Fix improper use of defer with function parameters.

The deferred function is executed immediately due to the function call syntax (batch). Remove the parameter from the anonymous function.

Apply this diff:

-			defer func(batch *pebble.Batch) {
+			defer func() {
 				innerErr = batch.Close()
-			}(batch)
+			}()

Likely invalid or redundant comment.


462-467: 🛠️ Refactor suggestion

Add validation for force start height.

When force setting the starting Cadence height, there's no validation to ensure the height exists or is valid.

Add validation before setting the force start height:

 	if cfg.ForceStartCadenceHeight != 0 {
 		logger.Warn().Uint64("height", cfg.ForceStartCadenceHeight).Msg("force setting starting Cadence height!!!")
+		// Validate the height exists
+		_, err := fnb.Client.GetBlockHeaderByHeight(context.Background(), cfg.ForceStartCadenceHeight)
+		if err != nil {
+			return fmt.Errorf("invalid force start height %d: %w", cfg.ForceStartCadenceHeight, err)
+		}
 		if err := blocks.SetLatestCadenceHeight(cfg.ForceStartCadenceHeight, nil); err != nil {
 			return err
 		}
 	}
✅ Verification successful

The suggested validation is correct and follows existing patterns

The review suggestion is valid as:

  • GetBlockHeaderByHeight is the correct API to validate block heights
  • Similar validation already exists for normal cadence height in the same file
  • The suggested implementation matches existing validation patterns in the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for ForceStartCadenceHeight usage and definition
rg "ForceStartCadenceHeight" -A 3

# Look for GetBlockHeaderByHeight implementation and usage
ast-grep --pattern 'GetBlockHeaderByHeight'

# Search for any block height validation patterns
rg "GetBlockHeaderByHeight|ValidateHeight|CheckHeight" -A 2

Length of output: 3545

Comment on lines +531 to +533
//else {
// // TODO(JanezP): verify storage account owner is correct
//}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Storage account owner verification is indeed missing and needs implementation

The concern is validated and particularly important because:

  • The register store explicitly delegates owner verification responsibility to callers
  • No alternative implementation of this verification exists in the codebase
🔗 Analysis chain

Consider implementing the TODO for storage account verification.

The commented-out TODO suggests a need for storage account owner verification. This could be a security concern if left unimplemented.

Run this script to check if storage account verification is implemented elsewhere:

Would you like me to help implement the storage account verification logic or create a GitHub issue to track this task?

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for storage account verification implementations
rg -l "storage.*account.*verif|verif.*storage.*account"

Length of output: 80


Script:

#!/bin/bash
# Get context around the storage account verification in bootstrap.go
rg -B 5 -A 5 "storage.*account.*owner" bootstrap/bootstrap.go

# Also search for general storage account related code
rg -B 5 -A 5 "storage.*account" bootstrap/bootstrap.go

Length of output: 868


Script:

#!/bin/bash
# Search for any related security checks or owner verification patterns
rg -B 3 -A 3 "owner.*verif|verif.*owner" 

# Search for any related GitHub issues in comments
rg -B 2 -A 2 "TODO.*storage.*account|TODO.*owner.*verif"

Length of output: 1078

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 one 👏 👏 👏

l.Info().
Uint64("chain-cadence-height", chainLatestBlock.Height).
Uint64("gateway-cadence-height", gatewayLatestHeight).
Uint64("missed-heights", chainLatestBlock.Height-gatewayLatestHeight).
Copy link
Member

Choose a reason for hiding this comment

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

Simply avoid underflow

Suggested change
Uint64("missed-heights", chainLatestBlock.Height-gatewayLatestHeight).
Int64("missed-heights", chainLatestBlock.Height-gatewayLatestHeight).

return fmt.Errorf("could not set account status: %w", err)
}

err = registerStore.Store(delta.GetUpdates(), evmBlokcHeight, batch)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
err = registerStore.Store(delta.GetUpdates(), evmBlokcHeight, batch)
err = registerStore.Store(delta.GetUpdates(), evmBlockHeight, batch)


logger.Info().
Stringer("fvm_address_for_evm_storage_account", storageAddress).
Msgf("database initialized with cadence height: %d", cadenceHeight)
Copy link
Member

Choose a reason for hiding this comment

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

maybe also log the evm Height

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the bootstrapping code branch, so evm height will be 0

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (7)
bootstrap/bootstrap.go (4)

169-179: Enhance error handling in postShutdown

The current implementation collects errors but doesn't provide detailed context about which shutdown functions failed.

Consider enhancing error handling:

-func (fnb *EVMGatewayNodeBuilder) postShutdown() error {
+func (fnb *EVMGatewayNodeBuilder) postShutdown() error {
 	var errs *multierror.Error
-
-	for _, fn := range fnb.postShutdownFns {
+	for i, fn := range fnb.postShutdownFns {
 		err := fn()
 		if err != nil {
-			errs = multierror.Append(errs, err)
+			errs = multierror.Append(errs, fmt.Errorf("shutdown function %d failed: %w", i, err))
 		}
 	}
 	return errs.ErrorOrNil()
}

265-272: Improve rate limiter configuration

The current implementation uses math.MaxInt as a fallback which might not be the best approach for disabling rate limiting.

Consider:

  1. Using a more explicit way to disable rate limiting
  2. Adding validation for negative rate limits
  3. Adding configuration for burst limits
 	rateLimit := cfg.RateLimit
 	if rateLimit == 0 {
 		log.Warn().Msg("no rate-limiting is set")
-		rateLimit = math.MaxInt
+		// Use nil limiter for unlimited requests
+		ratelimiter = memorystore.NoopLimiter{}
+		return
 	}
+	if rateLimit < 0 {
+		return nil, fmt.Errorf("invalid rate limit: %d", rateLimit)
+	}
 	ratelimiter, err := memorystore.New(&memorystore.Config{
 		Tokens: rateLimit,
 		Interval: time.Second,
+		MaxBurst: rateLimit * 2, // Allow bursting up to 2x the rate limit
 	})

367-374: Enhance error handling for block header retrieval

The error message could be more informative about the context and potential solutions.

Consider enhancing the error message:

 	_, err = fnb.Client.GetBlockHeaderByHeight(context.Background(), latestIndexedHeight)
 	if err != nil {
 		return nil, fmt.Errorf(
-			"failed to get header for last indexed cadence height %d: %w",
+			"failed to get header for last indexed cadence height %d. Ensure the access node is synced and the height exists: %w",
 			latestIndexedHeight,
 			err,
 		)
 	}

503-506: Enhance batch commit error handling

The batch commit error handling could be more descriptive about the potential causes and recovery steps.

Consider enhancing the error handling:

 			err = batch.Commit(pebble.Sync)
 			if err != nil {
-				return fmt.Errorf("could not commit register updates: %w", err)
+				return fmt.Errorf("failed to commit register updates to database (ensure sufficient disk space and permissions): %w", err)
 			}
services/ingestion/event_subscriber.go (3)

79-82: Enhance error context for block header retrieval

The error handling is good but could provide more context about the current height being processed.

Add more context to the error:

-			eventsChan <- models.NewBlockEventsError(fmt.Errorf("failed to get latest cadence block: %w", err))
+			eventsChan <- models.NewBlockEventsError(fmt.Errorf("failed to get latest cadence block at height %d: %w", r.height, err))

92-97: Enhance logging with additional metrics

The logging is well structured but could benefit from additional metrics to aid in monitoring and debugging.

Add more metrics to the log:

 		r.logger.Info().
 			Uint64("chain-cadence-height", latestOnChainHeight).
 			Uint64("latest-indexed-height", r.height).
 			Int64("missed-heights", blocksToCatchUp).
+			Bool("needs-catchup", blocksToCatchUp > 0).
+			Str("chain-id", r.chain.String()).
 			Msg("indexing cadence height information")

77-97: Well-structured integration with component model

The new block header retrieval and status logging integrate well with the component-based architecture mentioned in the PR objectives. The error handling and resource management align with the broader architectural changes.

A few suggestions to enhance the component integration:

  1. Consider extracting the block header retrieval and status logging into a separate method for better testability
  2. Add metrics for monitoring component health

Example refactor:

+func (r *RPCEventSubscriber) getAndLogBlockStatus(ctx context.Context) (uint64, error) {
+	chainLatestBlockHeader, err := r.client.GetLatestBlockHeader(ctx, true)
+	if err != nil {
+		return 0, fmt.Errorf("failed to get latest cadence block at height %d: %w", r.height, err)
+	}
+	latestOnChainHeight := chainLatestBlockHeader.Height
+
+	blocksToCatchUp := int64(latestOnChainHeight) - int64(r.height)
+
+	r.logger.Info().
+		Uint64("chain-cadence-height", latestOnChainHeight).
+		Uint64("latest-indexed-height", r.height).
+		Int64("missed-heights", blocksToCatchUp).
+		Bool("needs-catchup", blocksToCatchUp > 0).
+		Str("chain-id", r.chain.String()).
+		Msg("indexing cadence height information")
+
+	return latestOnChainHeight, nil
+}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3e04bc3 and fc2f653.

📒 Files selected for processing (2)
  • bootstrap/bootstrap.go (3 hunks)
  • services/ingestion/event_subscriber.go (1 hunks)
🔇 Additional comments (3)
bootstrap/bootstrap.go (3)

201-205: Initialize method lacks actual initialization

The Initialize method only prints build details but doesn't perform any actual initialization.

Consider whether this method should:

  1. Initialize any required resources
  2. Validate configuration
  3. Set up any prerequisites

519-521: Implement storage account verification

The TODO comment indicates missing verification of storage account ownership.

This is a security concern that should be addressed. Would you like me to:

  1. Generate the implementation for storage account verification
  2. Create a GitHub issue to track this security enhancement

562-580: LGTM! Well-structured client initialization

The cross-spork client initialization is well-implemented with proper error handling and cleanup.

Comment on lines +85 to +90
blocksToCatchUp := int64(0)
if latestOnChainHeight > r.height {
blocksToCatchUp = int64(latestOnChainHeight - r.height)
} else {
blocksToCatchUp = int64(r.height - latestOnChainHeight)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect calculation of blocks to catch up

The calculation in the else branch is incorrect. When latestOnChainHeight is less than r.height, it means we're ahead of the chain, and there are no blocks to catch up. The current calculation would give a positive number when we should indicate we're ahead.

Apply this fix:

-		blocksToCatchUp := int64(0)
-		if latestOnChainHeight > r.height {
-			blocksToCatchUp = int64(latestOnChainHeight - r.height)
-		} else {
-			blocksToCatchUp = int64(r.height - latestOnChainHeight)
-		}
+		blocksToCatchUp := int64(latestOnChainHeight) - int64(r.height)
📝 Committable suggestion

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

Suggested change
blocksToCatchUp := int64(0)
if latestOnChainHeight > r.height {
blocksToCatchUp = int64(latestOnChainHeight - r.height)
} else {
blocksToCatchUp = int64(r.height - latestOnChainHeight)
}
blocksToCatchUp := int64(latestOnChainHeight) - int64(r.height)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Review EVM GW code to identify & fix edge-cases that could lead to stability problems
5 participants