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

chore(cometBFTService): simplified CometBFTService #2026

Merged
merged 20 commits into from
Oct 1, 2024

Conversation

abi87
Copy link
Contributor

@abi87 abi87 commented Sep 28, 2024

A group of changes, listed by relevance (top to bottom):

  • Fixed ConsensusParams in InitChainResponse
  • Fixed check on validators updates returned from middleware
  • Dropped a few hollow checks on non-nil finalizeBlockState
    • Refactored setState to appease nilaway
  • Added some comments around volatile states to clarify their lifetime
  • Dropped useless waits on ctx.Done since we don't call deliveryTx
  • Reduced initHeader scope and dropped some ops on it
  • Formatted comments

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Enhanced error handling for invalid heights and nil finalize block states.
    • Simplified method signatures for better clarity and usability.
    • Introduced a streamlined state management process with the new resetState function.
  • Bug Fixes

    • Improved consistency in error reporting throughout the service.
  • Documentation

    • Added clarifying comments regarding the purpose of key variables in state management.

@abi87 abi87 self-assigned this Sep 28, 2024
Copy link
Contributor

coderabbitai bot commented Sep 28, 2024

Walkthrough

The changes introduced in this pull request involve significant modifications to the Service struct within the cometbft package, specifically in the abci.go and service.go files. Key updates include the introduction of new error handling variables, streamlined method signatures, and a simplified state management approach. The initChainer method now accepts application state bytes directly, while the setState function has been replaced with resetState, enhancing clarity and consistency in error reporting and state transitions.

Changes

Files Change Summary
mod/consensus/pkg/cometbft/service/abci.go - Introduced errInvalidHeight and errNilFinalizeBlockState for error handling.
- Updated InitChain and initChainer methods for streamlined logic and parameters.
- Adjusted PrepareProposal, ProcessProposal, and Commit methods for improved error handling.
mod/consensus/pkg/cometbft/service/service.go - Removed execMode type and constants, simplifying state management.
- Replaced setState with resetState, improving state initialization.

Possibly related PRs

Suggested reviewers

  • nidhi-singh02
  • ocnc
  • itsdevbear

Poem

🐇 In the land of code where bunnies hop,
New changes sprout, we won't stop!
Errors now tidy, states align,
With every update, our code will shine!
Hooray for the changes, let’s cheer and play,
For a smoother journey, come what may! 🌟


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between 57e8eab and 6e5b289.

📒 Files selected for processing (1)
  • mod/consensus/pkg/cometbft/service/abci.go (12 hunks)
🧰 Additional context used
📓 Learnings (1)
mod/consensus/pkg/cometbft/service/abci.go (2)
Learnt from: abi87
PR: berachain/beacon-kit#2026
File: mod/consensus/pkg/cometbft/service/abci.go:452-452
Timestamp: 2024-09-30T22:01:37.330Z
Learning: In this codebase, panicking is acceptable when CometBFT guarantees that a scenario cannot happen, such as when `finalizeBlockState` is nil.
Learnt from: abi87
PR: berachain/beacon-kit#2026
File: mod/consensus/pkg/cometbft/service/abci.go:114-118
Timestamp: 2024-09-30T21:58:05.156Z
Learning: The team prefers to address ensuring a non-empty validator set at genesis in future PRs.
🔇 Additional comments (15)
mod/consensus/pkg/cometbft/service/abci.go (15)

46-49: Definition of error variables standardizes error handling

Introducing errInvalidHeight and errNilFinalizeBlockState enhances consistency in error reporting and simplifies error handling throughout the codebase.


71-74: Initialization of s.initialHeight ensures correct starting height

Setting s.initialHeight to 1 when it's 0 guarantees that the chain does not start with an invalid block height.


86-86: Resetting finalizeBlockState for proper state initialization

Calling s.resetState() on s.finalizeBlockState ensures that the state is correctly initialized before processing begins.


104-107: Updated initChainer method call with simplified parameters

Refactoring the initChainer method to accept only appStateBytes and the context streamlines the function call, reducing complexity.


153-154: Simplified initChainer method signature enhances clarity

Changing the initChainer signature to accept appStateBytes []byte instead of the entire InitChainRequest simplifies the method and focuses it on necessary data.


204-208: Correct error formatting in PrepareProposal

The error message appropriately uses %w for error wrapping after the format string, ensuring proper error unwrapping and adherence to Go best practices.


211-213: Resetting prepareProposalState to handle timeouts

Resetting s.prepareProposalState ensures that state is fresh for each PrepareProposal call, which is crucial if timeouts occur and the method is called again.


255-259: Consistent error handling in ProcessProposal

The error formatting correctly uses %w, allowing wrapped errors to be unwrapped later if needed, which is consistent with Go's error handling conventions.


262-269: State management in ProcessProposal ensures reliability

By resetting s.processProposalState and conditionally resetting s.finalizeBlockState, the code accurately handles state transitions, preventing unwanted state overwrites.


310-314: Initializing finalizeBlockState during block replay

Detecting when s.finalizeBlockState is nil and resetting it accommodates scenarios where ProcessProposal is skipped, such as during block replay, ensuring state consistency.


361-365: Proper error wrapping in validateFinalizeBlockHeight

The error message in validateFinalizeBlockHeight correctly uses %w for wrapping, aiding in error propagation and diagnostics.


401-401: Properly setting AppHash after finalizing the block

Assigning res.AppHash using s.workingHash() ensures that the application hash reflects the current state after block finalization.


420-422: Intentional panic on unexpected nil finalizeBlockState in Commit

Panicking when s.finalizeBlockState is nil aligns with the guarantees provided by CometBFT and is acceptable in this context.


450-455: Intentional panic in workingHash for unexpected nil state

Panic is used appropriately here to indicate critical unexpected state, as workingHash should only be called when s.finalizeBlockState is not nil.


478-487: Handling context in getContextForProposal with appropriate safeguards

The method ensures that, for the initial height, the context is retrieved from s.finalizeBlockState, and panics if s.finalizeBlockState is unexpectedly nil, which is acceptable due to CometBFT's guarantees.


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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@@ -42,6 +42,8 @@ import (
"github.com/sourcegraph/conc/iter"
)

var errInvalidHeight = errors.New("invalid 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.

nit, which allows to find all places where req.Height is checked more easily

@@ -57,7 +59,6 @@ func (s *Service[LoggerT]) InitChain(

// On a new chain, we consider the init chain block height as 0, even though
// req.InitialHeight is 1 by default.
initHeader := cmtproto.Header{ChainID: req.ChainId, Time: req.Time}
Copy link
Contributor Author

@abi87 abi87 Sep 28, 2024

Choose a reason for hiding this comment

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

initHeader is really used only in defer call, to prepare context for next block. Moved it to defer to simplify logic and reduce its scope. This is different from cosmos SDK BaseApp where the header is used to setup the state

@@ -70,14 +71,13 @@ func (s *Service[LoggerT]) InitChain(
// proposing
// or processing the first block or not.
s.initialHeight = req.InitialHeight
if s.initialHeight == 0 { // If initial height is 0, set it to 1
Copy link
Contributor Author

Choose a reason for hiding this comment

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

non informative comment, dropped

@@ -90,19 +90,19 @@ func (s *Service[LoggerT]) InitChain(
// InitChain represents the state of the application BEFORE the first
// block, i.e. the genesis block. This means that when processing the
// app's InitChain handler, the block height is zero by default.
// However, after Commit is called
Copy link
Contributor Author

Choose a reason for hiding this comment

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

nit: Commit is not really called for setting initial state

Copy link

codecov bot commented Sep 28, 2024

Codecov Report

Attention: Patch coverage is 0% with 65 lines in your changes missing coverage. Please review.

Project coverage is 22.42%. Comparing base (320256c) to head (6e5b289).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
mod/consensus/pkg/cometbft/service/abci.go 0.00% 63 Missing ⚠️
mod/consensus/pkg/cometbft/service/service.go 0.00% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2026      +/-   ##
==========================================
+ Coverage   22.38%   22.42%   +0.04%     
==========================================
  Files         358      358              
  Lines       16042    16012      -30     
  Branches       12       12              
==========================================
  Hits         3591     3591              
+ Misses      12302    12272      -30     
  Partials      149      149              
Flag Coverage Δ
22.42% <0.00%> (+0.04%) ⬆️
Files with missing lines Coverage Δ
mod/consensus/pkg/cometbft/service/service.go 0.00% <0.00%> (ø)
mod/consensus/pkg/cometbft/service/abci.go 0.00% <0.00%> (ø)

Comment on lines -323 to -325
if s.finalizeBlockState == nil {
return nil, errors.New("finalizeBlockState is nil")
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

redundant check since s.setState(execModeFinalize) is called right before. We don't do these checks after setState is called for proposals.

return ctx
}
ctx, _ = s.finalizeBlockState.Context().CacheContext()
if height != s.initialHeight || s.finalizeBlockState == nil {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

nit: reduced indentation. This is really a personal preference, I am happy to revert it if we like the current version better

Comment on lines 76 to 78
// initialHeight is used to determine if we are
// proposing or processing the first block or not.
initialHeight int64
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like an explanation of attributes where we declare them. Happy to revert if we don't agree on this (or it breaks codebase conventions)

@abi87 abi87 force-pushed the cometBFT-some-more-cleanup-2 branch from a14da18 to cfe9f30 Compare September 28, 2024 15:35
@abi87 abi87 changed the title chore(cometBFTService): simplified initHeader chore(cometBFTService): fixed initChainer + nits Sep 28, 2024
return &cmtabci.InitChainResponse{
ConsensusParams: res.ConsensusParams,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ConsensusParams is not set by the response generated in initChainer, so this effectively assigning default value of ConsensusParams.
Replaced with ConsensusParams from request, which I believe is what we need to do

@abi87 abi87 changed the base branch from main to appease-generate-check September 28, 2024 16:56
Comment on lines -101 to -103
if s.finalizeBlockState == nil {
return nil, errors.New("finalizeBlockState is nil")
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

redundant check since s.setState(execModeFinalize) is called right before. We don't do these checks after setState is called for proposals.

@abi87 abi87 force-pushed the cometBFT-some-more-cleanup-2 branch from cc31d0d to daa2785 Compare September 28, 2024 17:07
@@ -42,7 +42,8 @@ import (
"github.com/sourcegraph/conc/iter"
)

//nolint:gocognit // todo fix.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

side-effect of InitChain changes

@abi87 abi87 force-pushed the cometBFT-some-more-cleanup-2 branch from daa2785 to f54e688 Compare September 28, 2024 17:12
Base automatically changed from appease-generate-check to main September 28, 2024 17:13
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: 2

🧹 Outside diff range comments (1)
mod/consensus/pkg/cometbft/service/abci.go (1)

Line range hint 472-486: Avoid panicking in workingHash; handle nil finalizeBlockState gracefully

Using panic when s.finalizeBlockState is nil can cause the application to crash unexpectedly. It's better to handle this scenario by returning an error or logging an appropriate message.

Consider modifying the function to return an error instead of panicking:

-func (s *Service[LoggerT]) workingHash() []byte {
+func (s *Service[LoggerT]) workingHash() ([]byte, error) {
     // Write the FinalizeBlock state into branched storage and commit the
     // MultiStore.
     if s.finalizeBlockState == nil {
-        panic(fmt.Errorf("workingHash: %w", errNilFinalizeBlockState))
+        return nil, fmt.Errorf("workingHash: %w", errNilFinalizeBlockState)
     }
     s.finalizeBlockState.ms.Write()

     // Get the hash of all writes to return the app hash.
     commitHash := s.sm.CommitMultiStore().WorkingHash()
     s.logger.Debug(
         "hash of all writes",
         "workingHash",
         fmt.Sprintf("%X", commitHash),
     )

-    return commitHash
+    return commitHash, nil
 }

Update the calling code to handle the returned error appropriately.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between b6c134d and d0834cc.

📒 Files selected for processing (2)
  • mod/consensus/pkg/cometbft/service/abci.go (10 hunks)
  • mod/consensus/pkg/cometbft/service/service.go (2 hunks)
🔇 Additional comments (4)
mod/consensus/pkg/cometbft/service/abci.go (4)

45-48: Introduction of standard error variables looks good

Defining errInvalidHeight and errNilFinalizeBlockState standardizes error handling throughout the service, enhancing maintainability and consistency.


263-268: Review the resetting of s.finalizeBlockState in ProcessProposal

Resetting s.finalizeBlockState within ProcessProposal when req.Height > s.initialHeight may have unintended side effects if s.finalizeBlockState is expected to persist between proposals or rounds. Please ensure that this reset aligns with the application's state management and does not interfere with other operations.


495-498: Verify context selection logic in getContextForProposal

In getContextForProposal, the context from s.finalizeBlockState is used when height == s.initialHeight and s.finalizeBlockState is not nil. Please confirm that using the context from finalizeBlockState in this scenario is intentional and that it won't cause issues with state consistency.


162-165: ⚠️ Potential issue

Handle missing 'beacon' key in genesisState

Accessing genesisState["beacon"] without verifying its existence could lead to a runtime error if the key is missing. Please ensure that the 'beacon' key exists before using it.

Consider modifying the code to handle the missing key:

     if err := json.Unmarshal(appStateBytes, &genesisState); err != nil {
         return nil, err
     }

+    beaconState, exists := genesisState["beacon"]
+    if !exists {
+        return nil, errors.New("'beacon' key missing in genesisState")
+    }

     valUpdates, err := s.Middleware.InitGenesis(
         ctx,
-        []byte(genesisState["beacon"]),
+        []byte(beaconState),
     )
     if err != nil {
         return nil, err
     }

Likely invalid or redundant comment.

Comment on lines +209 to +210
// A state is explicitly returned to avoid false positives from
// nilaway tool.
Copy link
Contributor

@coderabbitai coderabbitai bot Sep 28, 2024

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Clarify the comment regarding static analysis tool.

The comment references the "nilaway tool," which might be unclear or incorrectly named. For better clarity, consider specifying the correct tool name or generalizing the statement.

Suggested revision:

-// A state is explicitly returned to avoid false positives from
-// nilaway tool.
+// Explicitly returning the state helps avoid false positives from
+// static analysis tools that check for nil references.
📝 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
// A state is explicitly returned to avoid false positives from
// nilaway tool.
// Explicitly returning the state helps avoid false positives from
// static analysis tools that check for nil references.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like being specific (a different tool may give different results) but @itsdevbear and @ocnc may have a different opinion

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

mod/consensus/pkg/cometbft/service/abci.go Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between d0834cc and f4b97a5.

📒 Files selected for processing (1)
  • mod/consensus/pkg/cometbft/service/abci.go (10 hunks)
🔇 Additional comments (1)
mod/consensus/pkg/cometbft/service/abci.go (1)

106-109: Update usage of initChainer to match the new signature

The initChainer method now accepts appStateBytes []byte instead of the entire InitChainRequest. This change simplifies the function parameters. Ensure that all invocations of initChainer are updated accordingly, and that appStateBytes correctly represents the application state.

Comment on lines 380 to 382
if req.Height < 1 {
return fmt.Errorf("invalid height: %d", req.Height)
return fmt.Errorf("FinalizeBlock: %w %v", errInvalidHeight, req.Height)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks good, nit: error message generally starts with smaller case letter. Similar comments at few other places.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for spotting this, @nidhi-singh02 . Fixed

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between f4b97a5 and f7e82fd.

📒 Files selected for processing (1)
  • mod/consensus/pkg/cometbft/service/abci.go (10 hunks)
🔇 Additional comments (3)
mod/consensus/pkg/cometbft/service/abci.go (3)

46-47: Error messages should start with lowercase letters

According to Go conventions, error messages should start with lowercase letters unless they begin with a proper noun or acronyms.


128-142: Ensure both validator lists are sorted before comparison

Currently, only req.Validators is sorted before the comparison with resValidators. To ensure accurate matching of validators, both lists should be sorted.


471-471: Avoid panicking; handle nil finalizeBlockState gracefully

Panicking when s.finalizeBlockState is nil can lead to undesirable crashes. It's better to handle this scenario by returning an error to maintain application stability.

mod/consensus/pkg/cometbft/service/abci.go Outdated Show resolved Hide resolved
mod/consensus/pkg/cometbft/service/abci.go Outdated Show resolved Hide resolved
mod/consensus/pkg/cometbft/service/abci.go Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between f7e82fd and f943e95.

📒 Files selected for processing (1)
  • mod/consensus/pkg/cometbft/service/abci.go (10 hunks)
🔇 Additional comments (3)
mod/consensus/pkg/cometbft/service/abci.go (3)

45-48: Added error variables for standardized error handling

The introduction of errInvalidHeight and errNilFinalizeBlockState improves error consistency across the codebase, enhancing maintainability.


158-159: Simplified initChainer method signature

Updating the initChainer function to accept only appStateBytes []byte enhances clarity and reduces unnecessary parameter passing.


106-109: Ensure all calls to initChainer have updated signatures

The initChainer method signature has been updated to accept appStateBytes []byte instead of the entire request. Please verify that all invocations of initChainer in the codebase have been updated accordingly.

Run the following script to find all usages of initChainer:

✅ Verification successful

Verification Passed: All calls to initChainer use the updated signature initChainer(ctx sdk.Context, appStateBytes []byte).

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all calls to `initChainer` and display their signatures.

# Expected: All calls should match the new signature `initChainer(ctx sdk.Context, appStateBytes []byte)`

rg --type go --no-heading --line-number 'initChainer\('

Length of output: 229


Script:

#!/bin/bash
# Description: Retrieve the line where `initChainer` is called to inspect its arguments.

# Fetch the specific line from abci.go
sed -n '106p' mod/consensus/pkg/cometbft/service/abci.go

Length of output: 94


Script:

#!/bin/bash
# Description: Retrieve lines 106-109 from abci.go to inspect arguments passed to `initChainer`.

sed -n '106,109p' mod/consensus/pkg/cometbft/service/abci.go

Length of output: 156

)
}

// check validators
if len(req.Validators) > 0 {
Copy link
Contributor Author

@abi87 abi87 Sep 30, 2024

Choose a reason for hiding this comment

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

q: this allows an empty validator set. I saw that cosmos sdk baseApp does the same. But should we? In which case we are fine having no validators defined at genesis? @ocnc @itsdevbear

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between b679d11 and cfec782.

📒 Files selected for processing (1)
  • mod/consensus/pkg/cometbft/service/abci.go (10 hunks)
🔇 Additional comments (10)
mod/consensus/pkg/cometbft/service/abci.go (10)

45-47: Consistent Error Handling: Define Error Variables

Defining error variables errInvalidHeight and errNilFinalizeBlockState enhances consistency in error handling and makes the code more maintainable.


88-88: Ensure finalizeBlockState is Properly Reset

Setting s.finalizeBlockState by calling s.resetState() ensures that the state is clean before initialization.


94-95: Correct Block Height After Genesis

Adjusting the height in the initHeader after genesis handling ensures that the block height reflects the true state of the blockchain.


106-109: Simplify initChainer Parameters

Updating the initChainer method to accept appStateBytes instead of the entire InitChainRequest simplifies the function signature and focuses on the necessary data.


146-146: Set Appropriate Consensus Parameters in InitChainResponse

Assigning ConsensusParams from the request ensures that the consensus parameters are correctly initialized in the response.


158-158: Handle Potential Unmarshal Errors Gracefully

Ensure that any errors during JSON unmarshalling of appStateBytes are properly handled and logged, providing clarity in case of initialization issues.


216-216: Reset prepareProposalState Before Use

Resetting s.prepareProposalState ensures a clean state for each proposal preparation, preventing unintended state carryover.


272-272: Reset finalizeBlockState Appropriately

Resetting s.finalizeBlockState when processing proposals after the initial height ensures that the state is accurate and prevents stale data usage.


315-315: Initialize finalizeBlockState if Nil

Initializing s.finalizeBlockState if it's nil prevents potential nil pointer dereferences during finalization.


114-120: Verify Validator Set Consistency

The code checks that the length of the validators in the request matches the genesis validators, and compares their properties. Ensure that this logic correctly enforces validator consistency at genesis.

Run the following script to confirm validator consistency:

Comment on lines 209 to 213
return nil, fmt.Errorf(
"prepareProposal, height %v: %w",
req.Height,
errInvalidHeight,
)
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

Correct Error Formatting in PrepareProposal

When using fmt.Errorf with %w for error wrapping, %w should not be combined with other verbs. Modify the error message to ensure proper error unwrapping.

Suggested Change:

-return nil, fmt.Errorf(
-    "prepareProposal, height %v: %w",
-    req.Height,
-    errInvalidHeight,
-)
+return nil, fmt.Errorf(
+    "prepareProposal at height %v: %w",
+    req.Height,
+    errInvalidHeight,
+)
📝 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
return nil, fmt.Errorf(
"prepareProposal, height %v: %w",
req.Height,
errInvalidHeight,
)
return nil, fmt.Errorf(
"prepareProposal at height %v: %w",
req.Height,
errInvalidHeight,
)

Comment on lines 258 to 262
return nil, fmt.Errorf(
"processProposal, height %v: %w",
req.Height,
errInvalidHeight,
)
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

Correct Error Formatting in ProcessProposal

As in PrepareProposal, ensure that error messages in ProcessProposal use %w correctly for wrapping errors.

Suggested Change:

-return nil, fmt.Errorf(
-    "processProposal, height %v: %w",
-    req.Height,
-    errInvalidHeight,
-)
+return nil, fmt.Errorf(
+    "processProposal at height %v: %w",
+    req.Height,
+    errInvalidHeight,
+)
📝 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
return nil, fmt.Errorf(
"processProposal, height %v: %w",
req.Height,
errInvalidHeight,
)
return nil, fmt.Errorf(
"processProposal at height %v: %w",
req.Height,
errInvalidHeight,
)

@@ -449,7 +444,7 @@
context.Context, *cmtabci.CommitRequest,
) (*cmtabci.CommitResponse, error) {
if s.finalizeBlockState == nil {
return nil, errors.New("finalizeBlockState is nil")
return nil, fmt.Errorf("commit: %w", errNilFinalizeBlockState)
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

Improve Error Message in Commit

Provide a more descriptive error message when s.finalizeBlockState is nil during commit to aid in debugging.

Suggested Change:

-return nil, fmt.Errorf("commit: %w", errNilFinalizeBlockState)
+return nil, fmt.Errorf("commit failed: %w", errNilFinalizeBlockState)
📝 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
return nil, fmt.Errorf("commit: %w", errNilFinalizeBlockState)
return nil, fmt.Errorf("commit failed: %w", errNilFinalizeBlockState)

Comment on lines 388 to 392
return fmt.Errorf(
"finalizeBlock, height %v: %w",
req.Height,
errInvalidHeight,
)
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

Correct Error Formatting in validateFinalizeBlockHeight

Ensure proper error wrapping by adjusting the use of %w in fmt.Errorf.

Suggested Change:

-return fmt.Errorf(
-    "finalizeBlock, height %v: %w",
-    req.Height,
-    errInvalidHeight,
-)
+return fmt.Errorf(
+    "finalizeBlock at height %v: %w",
+    req.Height,
+    errInvalidHeight,
+)
📝 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
return fmt.Errorf(
"finalizeBlock, height %v: %w",
req.Height,
errInvalidHeight,
)
return fmt.Errorf(
"finalizeBlock at height %v: %w",
req.Height,
errInvalidHeight,
)

mod/consensus/pkg/cometbft/service/abci.go Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between cfec782 and 7621133.

📒 Files selected for processing (2)
  • mod/consensus/pkg/cometbft/service/abci.go (10 hunks)
  • mod/consensus/pkg/cometbft/service/service.go (2 hunks)
🔇 Additional comments (13)
mod/consensus/pkg/cometbft/service/abci.go (11)

46-50: Good practice: Consistent error handling with defined error variables

Defining error variables like errInvalidHeight and errNilFinalizeBlockState enhances consistency and maintainability in error handling across the codebase.


89-89: Initialize finalizeBlockState in InitChain

Resetting s.finalizeBlockState at the beginning of InitChain ensures that the state is properly initialized before processing the genesis block, preventing any residual state from affecting the initialization process.


97-101: Set initial block header after genesis handling

Initializing initHeader with the correct ChainID, Time, and Height ensures that the application context reflects the true block height after genesis. This is crucial for the correct operation of subsequent blocks.


107-110: Simplify initChainer parameters for clarity

By updating initChainer to accept only appStateBytes, the function signature is simplified, making it clearer and more focused on its purpose. This improves readability and reduces unnecessary parameter passing.


147-147: Use ConsensusParams from the request

Returning ConsensusParams: req.ConsensusParams ensures that the consensus parameters are correctly initialized in the response, matching the parameters provided in the InitChainRequest.


159-159: Unmarshal appStateBytes into genesisState

Properly unmarshalling appStateBytes into genesisState ensures that the genesis state is correctly initialized from the application state bytes provided in the request.


170-170: Convert validator updates to cmtabci.ValidatorUpdate

Using iter.MapErr to convert validator updates ensures compatibility with the expected types in the response, facilitating correct communication with the consensus engine.


214-214: Reset prepareProposalState in PrepareProposal

Resetting s.prepareProposalState ensures a clean state for each proposal preparation, preventing potential state leakage between proposals. This is important for maintaining the integrity of each individual proposal.


265-267: Document the rationale for state resetting

The added comments clearly explain the need to reset finalizeBlockState to prevent issues in subsequent rounds of ProcessProposal. This documentation improves code maintainability by providing context for future developers.


268-270: Reset proposal and finalize block states appropriately

Ensuring that both processProposalState and finalizeBlockState are reset maintains the integrity of the state machine between proposals, preventing unintended side effects from previous states.


313-313: Initialize finalizeBlockState if nil in internalFinalizeBlock

Checking if s.finalizeBlockState is nil and resetting it if necessary ensures that the block finalization process has a valid state to work with, preventing potential runtime errors.

mod/consensus/pkg/cometbft/service/service.go (2)

212-218: LGTM

The resetState function correctly initializes a new state and enhances clarity in state management.


68-68: ⚠️ Potential issue

Verify initialization of initialHeight.

Ensure that initialHeight is properly initialized before it is used in the codebase to prevent potential runtime errors.

Run the following script to check where initialHeight is assigned a value:

✅ Verification successful

Initialization of initialHeight Verified Successfully.

initialHeight is correctly initialized using req.InitialHeight and defaults to 1 when req.InitialHeight is 0. All usages occur after these assignments, ensuring no potential runtime errors related to its initialization.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find assignments to `initialHeight` in the codebase.

# Test: Search for assignments to `initialHeight`. Expect: Should find at least one assignment.

rg --type go --pcre2 'initialHeight\s*='

Length of output: 257


Script:

#!/bin/bash
# Description: Find all usages of `initialHeight` to ensure it's properly initialized before use.

# Search for usages of `initialHeight` that are not assignments.
rg --type go --pcre2 'initialHeight(?!\s*=)'

Length of output: 627

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between 7621133 and 4f9dd82.

📒 Files selected for processing (1)
  • mod/consensus/pkg/cometbft/service/abci.go (10 hunks)
🔇 Additional comments (17)
mod/consensus/pkg/cometbft/service/abci.go (17)

46-49: Define standardized error variables

The introduction of errInvalidHeight and errNilFinalizeBlockState ensures consistent error handling throughout the service.


76-76: Ensure initialHeight defaults to 1 when unset

Setting s.initialHeight to 1 when it's zero ensures that the block height starts correctly.


89-89: Initialize finalizeBlockState appropriately

Resetting finalizeBlockState here prepares the state for initialization.


98-101: Initialize initHeader with correct values

The initHeader is correctly initialized with ChainID, Time, and InitialHeight.


107-110: Update initChainer invocation with new parameters

Passing appStateBytes simplifies the function call and aligns with the updated initChainer signature.


147-148: Set ConsensusParams from the request

By assigning ConsensusParams from the request, the initial consensus parameters are correctly established.


156-157: Simplify initChainer function signature

Updating initChainer to accept appStateBytes reduces dependencies and improves modularity.


159-159: Handle JSON unmarshalling errors

Properly handling errors during unmarshalling ensures robustness in processing the genesis state.


170-170: Convert validator updates effectively

Using iter.MapErr for transforming validator updates enhances code readability and efficiency.


207-211: Correct error wrapping in PrepareProposal

The error message correctly uses %w to wrap errInvalidHeight, ensuring proper error propagation.


214-214: Reset prepareProposalState appropriately

Resetting the state prevents residual data from affecting proposal preparation.


256-260: Correct error wrapping in ProcessProposal

Consistent error formatting with %w ensures errors are wrapped properly for ProcessProposal.


265-270: Reset states to avoid stale data

Resetting processProposalState and finalizeBlockState appropriately prevents state contamination between blocks.


313-313: Initialize finalizeBlockState if nil

Ensuring finalizeBlockState is reset when nil maintains state integrity during block finalization.


386-390: Proper error wrapping in validateFinalizeBlockHeight

Using %w correctly wraps errInvalidHeight, aiding in error unwrapping and handling.


445-445: Return error when finalizeBlockState is nil in Commit

Returning an error instead of proceeding prevents potential nil pointer dereferences.


480-480: ⚠️ Potential issue

Avoid panicking; handle nil finalizeBlockState gracefully

Panicking can crash the application unexpectedly. Consider logging the error and returning nil to handle this case more gracefully.

Suggested Change:

 if s.finalizeBlockState == nil {
-    panic(fmt.Errorf("workingHash: %w", errNilFinalizeBlockState))
+    s.logger.Error("workingHash failed: finalizeBlockState is nil")
+    return nil
 }

Likely invalid or redundant comment.

mod/consensus/pkg/cometbft/service/abci.go Outdated Show resolved Hide resolved
mod/consensus/pkg/cometbft/service/abci.go Show resolved Hide resolved
mod/consensus/pkg/cometbft/service/abci.go Show resolved Hide resolved
mod/consensus/pkg/cometbft/service/abci.go Outdated Show resolved Hide resolved
@abi87 abi87 force-pushed the cometBFT-some-more-cleanup-2 branch from bfe5ffc to 197ddbf Compare September 30, 2024 21:55
@abi87 abi87 force-pushed the cometBFT-some-more-cleanup-2 branch from 197ddbf to 57e8eab Compare September 30, 2024 21:56
Comment on lines -325 to -331
// First check for an abort signal after beginBlock, as it's the first place
// we spend any significant amount of time.
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
// continue
Copy link
Contributor Author

Choose a reason for hiding this comment

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

useful in cosmos sdk baseApp but not here since we don't call delivarTx. Same applies below

@@ -447,7 +417,7 @@ func (s *Service[LoggerT]) Commit(
context.Context, *cmtabci.CommitRequest,
) (*cmtabci.CommitResponse, error) {
if s.finalizeBlockState == nil {
return nil, errors.New("finalizeBlockState is nil")
panic(fmt.Errorf("commit: %w", errNilFinalizeBlockState))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

CometBFT calls ordering guarantees that this cannot happen. CosmosSDK baseApp, which is our model here, does not do this check, but we need to appease nilaway.
Turning this into a panic, as we do with workingHash, since I believe it's a similar situation

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

🧹 Outside diff range comments (2)
mod/consensus/pkg/cometbft/service/service.go (1)

Line range hint 228-247: Consider creating an issue for the TODO comment.

The convertValidatorUpdate function seems to work correctly, but the TODO comment suggests that there's room for improvement in terms of type conversion and abstraction.

Would you like me to create a GitHub issue to track the potential improvement mentioned in the TODO comment? This would help ensure that the suggestion to simplify the type conversion process (possibly using a codec or a passed-in function) is not forgotten and can be addressed in future refactoring efforts.

mod/consensus/pkg/cometbft/service/abci.go (1)

Line range hint 156-167: Check for the existence of the "beacon" key in genesisState

In the initChainer function, you are accessing genesisState["beacon"] without verifying that the "beacon" key exists. This could lead to a panic or a runtime error if the "beacon" key is missing from the genesis state.

Consider adding a check to ensure that the "beacon" key is present before using it. Here's a possible modification:

 if err := json.Unmarshal(appStateBytes, &genesisState); err != nil {
 	return nil, err
 }

+beaconState, ok := genesisState["beacon"]
+if !ok {
+	return nil, errors.New("missing 'beacon' key in genesisState")
+}

 valUpdates, err := s.Middleware.InitGenesis(
 	ctx,
-	[]byte(genesisState["beacon"]),
+	beaconState,
 )

This change enhances the robustness of your code by preventing potential nil pointer dereferences or panics when the "beacon" key is absent.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between 4f9dd82 and 57e8eab.

📒 Files selected for processing (2)
  • mod/consensus/pkg/cometbft/service/abci.go (12 hunks)
  • mod/consensus/pkg/cometbft/service/service.go (2 hunks)
🧰 Additional context used
📓 Learnings (1)
mod/consensus/pkg/cometbft/service/abci.go (1)
Learnt from: abi87
PR: berachain/beacon-kit#2026
File: mod/consensus/pkg/cometbft/service/abci.go:114-118
Timestamp: 2024-09-30T21:58:05.156Z
Learning: The team prefers to address ensuring a non-empty validator set at genesis in future PRs.

Comment on lines +60 to +80
// prepareProposalState is used for PrepareProposal, which is set based on the
// previous block's state. This state is never committed. In case of multiple
// consensus rounds, the state is always reset to the previous block's state.
prepareProposalState *state

// processProposalState is used for ProcessProposal, which is set based on the
// previous block's state. This state is never committed. In case of multiple
// consensus rounds, the state is always reset to the previous block's state.
processProposalState *state
finalizeBlockState *state
interBlockCache storetypes.MultiStorePersistentCache
paramStore *params.ConsensusParamsStore
initialHeight int64
minRetainBlocks uint64

// finalizeBlockState is used for FinalizeBlock, which is set based on the
// previous block's state. This state is committed. finalizeBlockState is set
// on InitChain and FinalizeBlock and set to nil on Commit.
finalizeBlockState *state

interBlockCache storetypes.MultiStorePersistentCache
paramStore *params.ConsensusParamsStore

// initialHeight is the initial height at which we start the node
initialHeight int64
minRetainBlocks uint64
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

LGTM! Consider minor comment improvements.

The addition of separate state fields for different stages of block processing (prepare proposal, process proposal, and finalize block) is a good design choice. It clearly separates concerns and should make the code easier to reason about and maintain.

The comments explaining the purpose and lifecycle of each state are helpful. However, consider adding a brief explanation for the initialHeight and minRetainBlocks fields to maintain consistency in documentation.

Consider adding comments for the new fields:

// initialHeight is the initial block height at which the node starts
initialHeight   int64

// minRetainBlocks is the minimum number of recent blocks to retain
minRetainBlocks uint64

Comment on lines +217 to 226
// resetState provides a fresh state which can be used to reset
// prepareProposal/processProposal/finalizeBlock State.
// A state is explicitly returned to avoid false positives from
// nilaway tool.
func (s *Service[LoggerT]) resetState() *state {
ms := s.sm.CommitMultiStore().CacheMultiStore()
baseState := &state{
return &state{
ms: ms,
ctx: sdk.NewContext(ms, false, servercmtlog.WrapSDKLogger(s.logger)),
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

LGTM! Consider clarifying the comment about static analysis.

The resetState method is a good addition that simplifies state management for different stages of block processing. It provides a consistent way to create a fresh state with a cached multi-store and a new context.

The comment explaining the purpose of explicitly returning the state is helpful. However, it could be more specific about which static analysis tool it's referring to.

Consider updating the comment to be more specific:

// resetState provides a fresh state which can be used to reset
// prepareProposal/processProposal/finalizeBlock State.
// A state is explicitly returned to avoid false positives from
// static analysis tools that check for nil references (e.g., nilaway).

@abi87 abi87 changed the title chore(cometBFTService): fixed initChainer + nits chore(cometBFTService): simplified CometBFTService Sep 30, 2024
Copy link
Contributor

@nidhi-singh02 nidhi-singh02 left a comment

Choose a reason for hiding this comment

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

lgtm!

@itsdevbear itsdevbear merged commit ed6800f into main Oct 1, 2024
16 checks passed
@itsdevbear itsdevbear deleted the cometBFT-some-more-cleanup-2 branch October 1, 2024 16:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants