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

[OTE-176] Reduce the cost of adding an indexer event. #1078

Merged
merged 1 commit into from
Feb 22, 2024
Merged

Conversation

lcwik
Copy link
Contributor

@lcwik lcwik commented Feb 16, 2024

Changelist

[OTE-176] Reduce the cost of adding an indexer event.

Currently we unmarshalled and marshalled all of them which grew linearly with the number of messages so as blocks got larger this became a noticeable cost during the critical section when we hold effectively a global lock.
image

After this change:
image

Test Plan

No functional change, existing tests pass.

Author/Reviewer Checklist

  • If this PR has changes that result in a different app state given the same prior state and transaction list, manually add the state-breaking label.
  • If the PR has breaking postgres changes to the indexer add the indexer-postgres-breaking label.
  • If this PR isn't state-breaking but has changes that modify behavior in PrepareProposal or ProcessProposal, manually add the label proposal-breaking.
  • If this PR is one of many that implement a specific feature, manually label them all feature:[feature-name].
  • If you wish to for mergify-bot to automatically create a PR to backport your change to a release branch, manually add the label backport/[branch-name].
  • Manually add any of the following labels: refactor, chore, bug.

Currently we unmarshalled and marshalled all of them which grew linearly with the number of messages so as blocks got larger this became a noticeable cost.
Copy link

linear bot commented Feb 16, 2024

Copy link
Contributor

coderabbitai bot commented Feb 16, 2024

Walkthrough

The updates mainly focus on improving data serialization and storage within the indexer components of a blockchain protocol. Key changes include transitioning from custom or older serialization methods to proto.Marshal for more efficient data handling. Additionally, there's a significant adjustment in how indexer events are stored and managed, with a new approach to counting and retrieving individual events. These refinements aim to enhance performance and simplify the codebase.

Changes

Files Change Summary
protocol/indexer/indexer_manager/events.go Introduced new imports, updated event storage keys, refactored event retrieval, and modified serialization to proto.Marshal. Also, improved event count management.
protocol/indexer/.../on_chain_updates.go, off_chain_updates.go, off_chain_updates_test.go Shifted from custom marshaling or common.Marshaler to proto.Marshal for data serialization. Removed unused imports and test functions related to old marshaling methods.
protocol/testing/e2e/..., protocol/testutil/keeper/... Replaced common.UnmarshalerImpl{} with proto.Unmarshal() across various test utilities for different modules, indicating a shift to more standardized unmarshaling.
protocol/x/clob/keeper/orders_test.go, x/perpetuals/keeper/perpetual_test.go, x/sending/keeper/transfer_test.go Updated test cases to align with the new serialization method (proto.Unmarshal) and adjusted key usage for indexer events, reflecting the changes in event storage strategy.

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

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • 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 tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

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

CodeRabbit Commands (invoked as PR comments)

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

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

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • 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

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

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

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 71ce2c6 and 4962bf1.
Files selected for processing (14)
  • protocol/indexer/indexer_manager/events.go (4 hunks)
  • protocol/indexer/indexer_manager/on_chain_updates.go (2 hunks)
  • protocol/indexer/off_chain_updates/off_chain_updates.go (4 hunks)
  • protocol/indexer/off_chain_updates/off_chain_updates_test.go (3 hunks)
  • protocol/testing/e2e/trading_rewards/trading_rewards_test.go (3 hunks)
  • protocol/testutil/keeper/assets.go (2 hunks)
  • protocol/testutil/keeper/keeper.go (1 hunks)
  • protocol/testutil/keeper/perpetuals.go (2 hunks)
  • protocol/testutil/keeper/prices.go (3 hunks)
  • protocol/testutil/keeper/rewards.go (3 hunks)
  • protocol/testutil/keeper/subaccounts.go (2 hunks)
  • protocol/x/clob/keeper/orders_test.go (3 hunks)
  • protocol/x/perpetuals/keeper/perpetual_test.go (4 hunks)
  • protocol/x/sending/keeper/transfer_test.go (4 hunks)
Additional comments: 27
protocol/indexer/indexer_manager/on_chain_updates.go (1)
  • 21-21: The switch to proto.Marshal for marshaling IndexerTendermintBlock aligns with the PR's goal of optimizing serialization. Ensure that corresponding unmarshaling operations are also updated to use proto.Unmarshal for consistency.
protocol/testutil/keeper/keeper.go (1)
  • 32-32: Updating the variable name to indexer_manager.TransientStoreKey improves naming clarity and consistency. Ensure that this key is correctly defined and consistently used across the system.
protocol/testutil/keeper/assets.go (1)
  • 113-113: Replacing common.UnmarshalerImpl{} with proto.Unmarshal() for unmarshaling AssetCreateEventV1 aligns with the PR's optimization goals. Ensure that AssetCreateEventV1 is fully compatible with proto.Unmarshal.
protocol/testutil/keeper/rewards.go (1)
  • 136-136: Switching to proto.Unmarshal() for unmarshaling TradingRewardsEventV1 is in line with the PR's optimization efforts. Ensure that TradingRewardsEventV1 is fully compatible with proto.Unmarshal.
protocol/testutil/keeper/subaccounts.go (1)
  • 155-155: Replacing common.UnmarshalerImpl{} with proto.Unmarshal() for unmarshaling SubaccountUpdateEventV1 aligns with the PR's optimization goals. Ensure that SubaccountUpdateEventV1 is fully compatible with proto.Unmarshal.
protocol/indexer/indexer_manager/events.go (4)
  • 19-23: The introduction of IndexerEventsCountKey and IndexerEventsPrefix for managing indexer events storage is a good optimization. Ensure these keys are consistently used across the system.
  • 28-49: Refactoring getIndexerEventsCount and getIndexerEvents to handle count and individual events retrieval more efficiently is a positive change. Ensure thorough testing to confirm correct functionality.
  • 112-120: The modifications in addEvent to handle count increment and individual event storage using proto.Marshal align with the PR's optimization goals. Ensure compatibility and correctness of serialization.
  • 130-130: Updating clearEvents to delete the count key instead of the events key simplifies the event clearing process. Verify that this change does not impact the retrieval of events in any negative way.
protocol/testutil/keeper/perpetuals.go (2)
  • 6-6: The addition of github.com/cosmos/gogoproto/proto is appropriate for the context of optimizing serialization and deserialization processes. This aligns well with the PR's objectives.
  • 199-199: Switching to proto.Unmarshal for unmarshalling liquidityTierEvent is a positive change, enhancing efficiency and maintainability by utilizing the standard library over custom implementations.
protocol/testutil/keeper/prices.go (2)
  • 5-5: The addition of github.com/cosmos/gogoproto/proto supports the optimization of data handling processes, specifically for unmarshalling MarketEventV1.
  • 186-186: Utilizing proto.Unmarshal for unmarshalling MarketEventV1 is a beneficial change, promoting efficiency and code maintainability by leveraging standardized library functions.
protocol/indexer/off_chain_updates/off_chain_updates.go (3)
  • 255-255: The use of proto.Marshal in newOrderPlaceMessage is a positive change for standardizing serialization. Ensure that all instances where this serialized data is consumed (e.g., deserialized) are compatible with the proto format to maintain interoperability.
  • 276-276: The introduction of proto.Marshal in newOrderRemoveMessage aligns with the goal of optimizing serialization. Verify that the serialized data structure matches the expected schema in all contexts where it's used, to prevent any data integrity issues.
  • 295-295: Using proto.Marshal in newOrderUpdateMessage standardizes the serialization process. It's important to ensure that the serialized format is consistently handled across the system, especially in parts of the codebase that interact with these messages.
protocol/x/sending/keeper/transfer_test.go (3)
  • 55-55: Replacing custom unmarshalling with proto.Unmarshal in assertTransferEventInIndexerBlock is a good practice for consistency. Ensure that the TransferEventV1 struct is fully compatible with the serialized data to avoid any potential issues during tests.
  • 80-80: The use of proto.Unmarshal in assertDepositEventInIndexerBlock for standardizing unmarshalling is commendable. Double-check that the TransferEventV1 struct accurately represents the expected schema for deposit events in all test scenarios.
  • 105-105: Introducing proto.Unmarshal in assertWithdrawEventInIndexerBlock enhances consistency in data handling. Verify that the TransferEventV1 struct is correctly structured to match the serialized withdraw event data in tests.
protocol/testing/e2e/trading_rewards/trading_rewards_test.go (1)
  • 5-5: The addition of the github.com/cosmos/gogoproto/proto import aligns with the PR's objective to optimize data handling by leveraging standard serialization and deserialization methods. This change is consistent with the broader goal of improving performance and maintainability by using well-supported libraries.
protocol/x/clob/keeper/orders_test.go (6)
  • 116-127: > 📝 NOTE

This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [1-1]

The test suite provides comprehensive coverage for handling stateful and conditional orders. It's well-structured and covers a variety of scenarios, ensuring the system behaves as expected under different conditions.

  • 116-127: > 📝 NOTE

This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [1-1]

It's commendable that the tests make extensive use of mocks to isolate the system under test and focus on the behavior of the ClobKeeper component. This approach ensures that the tests remain focused and do not inadvertently depend on external systems or state.

  • 116-127: > 📝 NOTE

This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [1-1]

The tests for TestPlaceStatefulOrdersFromLastBlock and TestPlaceConditionalOrdersTriggeredInLastBlock effectively simulate the conditions under which stateful and conditional orders should be placed or ignored. These tests are crucial for ensuring the reliability and correctness of order handling logic in the system.

  • 116-127: > 📝 NOTE

This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [1-1]

The use of require.PanicsWithValue in tests like TestPlaceStatefulOrdersFromLastBlock and TestPlaceConditionalOrdersTriggeredInLastBlock is a good practice for ensuring that the system behaves as expected in error scenarios. It's important to ensure that the system fails gracefully and provides meaningful error messages when encountering unexpected conditions.

  • 116-127: > 📝 NOTE

This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [1-1]

The tests make good use of the memClob mock to simulate the behavior of the in-memory order book. This approach allows for precise control over the system's behavior during testing and ensures that the tests can focus on the logic of the ClobKeeper without being affected by the complexities of order book management.

  • 116-127: > 📝 NOTE

This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [1-1]

The setup for each test case is thorough and carefully constructs the necessary state and conditions for the test to run. This meticulous setup is essential for ensuring that the tests accurately reflect the scenarios they are intended to simulate and that the assertions made at the end of each test are meaningful and valid.

protocol/x/perpetuals/keeper/perpetual_test.go (1)
  • 1968-1968: The function getFundingBlockEventsFromIndexerBlock directly accesses the ProduceBlock method of the IndexerEventManager and iterates through all events, looking specifically for funding events. This approach is efficient for extracting funding events but assumes that all events are correctly formatted and relevant to the context.

The logic for extracting funding events is clear and straightforward. However, ensure that the broader system guarantees the integrity and relevance of these events to avoid processing irrelevant or malformed data.

var block indexer_manager.IndexerTendermintBlock
_ = unmarshaler.Unmarshal(msgSender.GetOnchainMessages()[0].Value, &block)
_ = proto.Unmarshal(msgSender.GetOnchainMessages()[0].Value, &block)
Copy link
Contributor

Choose a reason for hiding this comment

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

The replacement of a custom unmarshalling implementation with proto.Unmarshal() is a significant improvement in terms of both performance and code maintainability. By using a standard library method, the code becomes more readable, easier to maintain, and potentially more efficient. However, it's crucial to ensure that all data structures being unmarshalled are compatible with the proto package and that this change does not introduce any regressions in how data is interpreted or processed.

One minor suggestion is to add error handling for the proto.Unmarshal() call. Ignoring the error returned by this function can lead to hard-to-debug issues if the unmarshalling fails for any reason (e.g., due to incompatible data structures or corrupted data). Proper error handling would improve the robustness of the test code.

- _ = proto.Unmarshal(msgSender.GetOnchainMessages()[0].Value, &block)
+ err := proto.Unmarshal(msgSender.GetOnchainMessages()[0].Value, &block)
+ require.NoError(t, err, "Failed to unmarshal indexer tendermint block")

Committable suggestion

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

Suggested change
_ = proto.Unmarshal(msgSender.GetOnchainMessages()[0].Value, &block)
err := proto.Unmarshal(msgSender.GetOnchainMessages()[0].Value, &block)
require.NoError(t, err, "Failed to unmarshal indexer tendermint block")

var fundingEvent indexerevents.FundingEventV1
err := unmarshaler.Unmarshal(event.DataBytes, &fundingEvent)
err := proto.Unmarshal(event.DataBytes, &fundingEvent)
Copy link
Contributor

Choose a reason for hiding this comment

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

The use of proto.Unmarshal directly without checking the event.Subtype against a specific subtype related to funding events might lead to incorrect unmarshalling if the event data does not match the expected structure. It's crucial to ensure that the event data structure matches the expected indexerevents.FundingEventV1 structure to avoid runtime errors.

Consider adding a subtype check or ensuring through other means that the event data structure is indeed what is expected before attempting to unmarshal it.


Using panic within the getFundingBlockEventsFromIndexerBlock function upon encountering an error in proto.Unmarshal is a harsh error handling strategy that could terminate the entire application. It's generally advisable to handle errors gracefully, especially in a blockchain context where stability is crucial.

Recommend replacing panic with a more graceful error handling mechanism, such as returning the error to the caller, to prevent the application from crashing.

- panic(err)
+ return nil, err

Committable suggestion

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

Suggested change
err := proto.Unmarshal(event.DataBytes, &fundingEvent)
err := proto.Unmarshal(event.DataBytes, &fundingEvent)
return nil, err

The error handling in getFundingBlockEventsFromIndexerBlock using panic for unmarshalling errors is aggressive and could lead to service disruption. In blockchain applications, where uptime and reliability are paramount, consider handling errors more gracefully.

Suggest logging the error and continuing with the next event or returning an error collection for the caller to handle, rather than using panic.

@lcwik lcwik merged commit 524d60f into main Feb 22, 2024
17 checks passed
@lcwik lcwik deleted the lukeote176 branch February 22, 2024 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging this pull request may close these issues.

2 participants