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

fix: pass FinalizeBlock request and response to ABCIListener #18486

Merged

Conversation

MSalopek
Copy link
Contributor

@MSalopek MSalopek commented Nov 16, 2023

Description

Closes: #18485

ABCIListener hooks were not being called in FinalizeBlock.

This PR passes FinalizeBlock request/response to registered ABCIListeners.


Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • included the correct type prefix in the PR title
  • added ! to the type prefix if API or client breaking change
  • targeted the correct branch (see PR Targeting)
  • provided a link to the relevant issue or specification
  • followed the guidelines for building modules
  • included the necessary unit and integration tests
  • added a changelog entry to CHANGELOG.md
  • included comments for documenting Go code
  • updated the relevant documentation or specification
  • reviewed "Files changed" and left comments if necessary
  • run make lint and make test
  • confirmed all CI checks have passed

Reviewers Checklist

All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.

I have...

  • confirmed the correct type prefix in the PR title
  • confirmed ! in the type prefix if API or client breaking change
  • confirmed all author checklist items have been addressed
  • reviewed state machine logic
  • reviewed API design and naming
  • reviewed documentation is accurate
  • reviewed tests and test coverage
  • manually tested (if applicable)

Summary by CodeRabbit

  • New Features

    • Integrated streaming service hooks to receive FinalizeBlock messages, enhancing real-time data processing capabilities.
  • Bug Fixes

    • Resolved a data race issue within the BaseApp context.
    • Fixed an inconsistency with viper prefix settings across client and server configurations.
    • Addressed execution issues with the make test-sim-custom-genesis-fast command for simulation tests.
  • Improvements

    • Streamlined error handling for streaming service hooks by logging errors during FinalizeBlock execution.
  • Documentation

    • Updated CHANGELOG.md with detailed notes on bug fixes and improvements for transparency and user reference.

@MSalopek MSalopek requested a review from a team as a code owner November 16, 2023 13:04
Copy link
Contributor

coderabbitai bot commented Nov 16, 2023

Walkthrough

Walkthrough

The changes involve updates to the cosmos-sdk, specifically within the BaseApp's FinalizeBlock function. The updates add a loop to call streaming service hooks, ensuring that FinalizeBlock messages are passed to ABCIListeners. This addresses a previously reported issue. Additionally, the changelog entries detail bug fixes and improvements, including a resolved data race, consistent viper prefix settings, and a fix for a simulation test command.

Changes

File Change Summary
baseapp/abci.go Added a loop to call streaming service hooks with FinalizeBlock messages, logging errors if they occur.
CHANGELOG.md Documented fixes and improvements including the FinalizeBlock hook fix, data race resolution, viper prefix consistency, and simulation test command fix.

Tips

Chat with CodeRabbit Bot (@coderabbitai)

  • If you reply to a review comment from CodeRabbit, the bot will automatically respond.
  • To engage with CodeRabbit bot directly around the specific lines of code in the PR, mention @coderabbitai in your review comment
  • Note: Review comments are made on code diffs or files, not on the PR overview.
  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

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.

Note: For conversation with the bot, please use the review comments on code diffs or files.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • 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/coderabbit-overrides.v2.json

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.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 3853e7f and 9143e38.
Files selected for processing (1)
  • baseapp/abci.go (1 hunks)

baseapp/abci.go Outdated
Comment on lines 895 to 900
// call the streaming service hooks with the FinalizeBlock messages
for _, streamingListener := range app.streamingManager.ABCIListeners {
if err := streamingListener.ListenFinalizeBlock(app.finalizeBlockState.ctx, *req, *res); err != nil {
panic(fmt.Errorf("ListenFinalizeBlock listening hook failed, height: %d, err: %w", req.Height, err))
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The code correctly iterates over all ABCIListeners and calls the ListenFinalizeBlock method. However, the use of panic to handle errors from listeners is a bit aggressive. While it is true that a failure in the listeners could indicate a critical system failure that requires immediate attention, panicking will abruptly terminate the application, which might not always be the desired behavior. Consider logging the error and deciding on a recovery strategy that does not necessarily involve panicking, unless this behavior is an explicit requirement.

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.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 9143e38 and fa2c1ce.
Files selected for processing (1)
  • CHANGELOG.md (1 hunks)
Additional comments: 1
CHANGELOG.md (1)
  • 69-69: The changelog entry is clear and concise, providing direct links to the pull requests for further details. It correctly summarizes the changes made in the pull requests, which include bug fixes and improvements across different modules of the Cosmos SDK. The use of parentheses to indicate the specific part of the SDK that is affected (e.g., baseapp, client/server, simulation) is helpful for readers to quickly understand the scope of the changes.

baseapp/abci.go Outdated
// call the streaming service hooks with the FinalizeBlock messages
for _, streamingListener := range app.streamingManager.ABCIListeners {
if err := streamingListener.ListenFinalizeBlock(app.finalizeBlockState.ctx, *req, *res); err != nil {
panic(fmt.Errorf("ListenFinalizeBlock listening hook failed, height: %d, err: %w", req.Height, err))
Copy link
Member

Choose a reason for hiding this comment

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

We should return an error. It will still panic then.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What about just logging the error like in ListenCommit?

for _, abciListener := range abciListeners {
	if err := abciListener.ListenCommit(ctx, *resp, changeSet); err != nil {
		app.logger.Error("Commit listening hook failed", "height", blockHeight, "err", err)
	}
}

Copy link
Member

Choose a reason for hiding this comment

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

lets return an error instead of panicking

Copy link
Member

Choose a reason for hiding this comment

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

Possibly, even better for consistency:

app.logger.Error("Commit listening hook failed", "height", blockHeight, "err", err)

Or switch the other to return an error as well.

FYI: #14207 changed the previous panicking to logging.

Given that CometBFT will still panic at errors, maybe that was the reason.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So, just log the error without panicking? Instrucions are a bit unclear

Copy link
Member

Choose a reason for hiding this comment

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

I think we should stay consistent, so if we return an error, we need to update it for the commit listening hook. If we don't, then this one should as well just log.
Personally, maybe it is a bit hard to stop a node if a streaming method returns an error.

Copy link
Member

Choose a reason for hiding this comment

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

ah sorry, was thinking wrong, we dont want to error here. There is some consistency within streamer but the streamer should not panic or halt the node in baseapp

Copy link
Member

Choose a reason for hiding this comment

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

only log, sorry for confusion

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fix applied here. Listeners will only log and never panic or return errors.

@julienrbrt julienrbrt added the backport/v0.50.x PR scheduled for inclusion in the v0.50's next stable release label Nov 16, 2023
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.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between fa2c1ce and e465962.
Files selected for processing (1)
  • baseapp/abci.go (1 hunks)

@MSalopek MSalopek force-pushed the masa/18485-abci-listener-finalize-block branch from e465962 to 9f820c4 Compare November 16, 2023 15:33
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.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 7a28425 and 9f820c4.
Files selected for processing (2)
  • CHANGELOG.md (1 hunks)
  • baseapp/abci.go (1 hunks)
Additional comments: 1
CHANGELOG.md (1)
  • 69-69: The changelog entries are clear and provide direct links to the pull requests for easy reference. Each entry is categorized by the part of the system it affects (e.g., baseapp, client/server, simulation), which is good for readability and understanding the scope of the changes.

baseapp/abci.go Outdated
Comment on lines 891 to 900
if res != nil {
res.AppHash = app.workingHash()
}

// call the streaming service hooks with the FinalizeBlock messages
for _, streamingListener := range app.streamingManager.ABCIListeners {
if err := streamingListener.ListenFinalizeBlock(app.finalizeBlockState.ctx, *req, *res); err != nil {
app.logger.Error("ListenFinalizeBlock listening hook failed, height: %d, err: %w", req.Height, err)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The code correctly iterates over the ABCIListeners and calls the ListenFinalizeBlock method for each listener. However, there are a few considerations to be made:

  1. Error Handling: The error from ListenFinalizeBlock is logged but not handled beyond that. Depending on the criticality of the listener's actions, you might want to consider how errors should be handled. Should the error affect the finalization process, or should it only be logged?

  2. Logging Context: The error logging does not provide the context of which listener failed. Including the listener's identifier in the log message could be helpful for debugging.

  3. Context Cancellation: There is no check for context cancellation before calling the listeners. If the context is canceled, it might be prudent to skip the listener invocation or handle it differently.

Here's a proposed change that addresses the logging context issue:

- app.logger.Error("ListenFinalizeBlock listening hook failed, height: %d, err: %w", req.Height, err)
+ app.logger.Error("ListenFinalizeBlock listening hook failed", "listener", streamingListener.Name(), "height", req.Height, "err", err)

And for context cancellation, you could add a check before the loop:

select {
case <-app.finalizeBlockState.ctx.Done():
    app.logger.Info("Context cancelled before invoking ABCIListeners")
    return res, app.finalizeBlockState.ctx.Err()
default:
    // continue to invoke listeners
}

Please verify if these changes align with the intended behavior and error handling strategy of the application.

Copy link
Contributor

@alexanderbez alexanderbez left a comment

Choose a reason for hiding this comment

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

👏

baseapp/abci.go Outdated Show resolved Hide resolved
Co-authored-by: Aleksandr Bezobchuk <[email protected]>
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.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 9f820c4 and 9ba0740.
Files selected for processing (1)
  • baseapp/abci.go (1 hunks)

baseapp/abci.go Outdated Show resolved Hide resolved
Copy link
Member

@tac0turtle tac0turtle left a comment

Choose a reason for hiding this comment

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

thank you

@tac0turtle
Copy link
Member

after fixing the lint issue, it will be merged automatically

auto-merge was automatically disabled November 16, 2023 17:33

Head branch was pushed to by a user without write access

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.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 9ba0740 and caa228b.
Files selected for processing (1)
  • baseapp/abci.go (1 hunks)

Comment on lines 891 to 903
if res != nil {
res.AppHash = app.workingHash()
}

// call the streaming service hooks with the FinalizeBlock messages
for _, streamingListener := range app.streamingManager.ABCIListeners {
if err := streamingListener.ListenFinalizeBlock(app.finalizeBlockState.ctx, *req, *res); err != nil {
app.logger.Error("ListenFinalizeBlock listening hook failed", "height", req.Height, "err", err)
}
}

return res, err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The added code block correctly implements the logic to call ListenFinalizeBlock on each ABCIListener registered with the streamingManager. However, there are a few considerations to ensure robustness:

  1. Error Handling: The error from ListenFinalizeBlock is logged but not handled beyond that. If the error indicates a critical failure that should prevent the block from finalizing, this should be considered. If the listeners are not critical to block finalization, the current approach is acceptable.

  2. Context Cancellation: The context passed to ListenFinalizeBlock is the finalizeBlockState.ctx. Ensure that this context is appropriate for the listeners and consider if a separate context with a timeout should be used for each listener to prevent one listener from blocking others in case it hangs or takes too long.

  3. Logging: The error logging is good, but it might be beneficial to also log successful calls to ListenFinalizeBlock for debugging and monitoring purposes.

  4. Performance: If there are many listeners and ListenFinalizeBlock is not a lightweight operation, this could introduce a performance bottleneck. Consider if these calls should be made concurrently.

  5. Resilience: If one listener fails, the loop continues to the next. This is typically desired behavior, but ensure that this aligns with the application's fault tolerance requirements.

  6. State Mutation: If ListenFinalizeBlock mutates shared state, ensure that it's safe from race conditions.

Here's a suggestion to log successful listener invocations and to consider the use of goroutines for concurrent execution if appropriate:

	// call the streaming service hooks with the FinalizeBlock messages
	for _, streamingListener := range app.streamingManager.ABCIListeners {
		if err := streamingListener.ListenFinalizeBlock(app.finalizeBlockState.ctx, *req, *res); err != nil {
			app.logger.Error("ListenFinalizeBlock listening hook failed", "height", req.Height, "err", err)
		} else {
+			app.logger.Info("ListenFinalizeBlock listening hook succeeded", "height", req.Height)
+		}
	}

And if concurrency is deemed necessary:

var wg sync.WaitGroup
for _, streamingListener := range app.streamingManager.ABCIListeners {
	wg.Add(1)
	go func(listener ABCIListener) {
		defer wg.Done()
		if err := listener.ListenFinalizeBlock(app.finalizeBlockState.ctx, *req, *res); err != nil {
			app.logger.Error("ListenFinalizeBlock listening hook failed", "height", req.Height, "err", err)
		} else {
			app.logger.Info("ListenFinalizeBlock listening hook succeeded", "height", req.Height)
		}
	}(streamingListener)
}
wg.Wait()

Note that if you choose to execute the listeners concurrently, you must ensure that any shared state accessed by ListenFinalizeBlock is thread-safe.

@facundomedica facundomedica added this pull request to the merge queue Nov 16, 2023
Merged via the queue into cosmos:main with commit a27cfa0 Nov 16, 2023
57 of 59 checks passed
mergify bot pushed a commit that referenced this pull request Nov 16, 2023
Co-authored-by: Aleksandr Bezobchuk <[email protected]>
(cherry picked from commit a27cfa0)

# Conflicts:
#	CHANGELOG.md
tac0turtle added a commit that referenced this pull request Nov 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport/v0.50.x PR scheduled for inclusion in the v0.50's next stable release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: ABCIListeners not receiving FinalizeBlock request and response
6 participants