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

[IND-467] Push ender market create logic to use a single sql function #737

Merged
merged 3 commits into from
Nov 2, 2023

Conversation

lcwik
Copy link
Contributor

@lcwik lcwik commented Nov 2, 2023

Changelist

[IND-467] Push ender market create logic to use a single sql function

Test Plan

Updated existing tests.

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 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.

Copy link
Contributor

coderabbitai bot commented Nov 2, 2023

Walkthrough

The changes introduce a new MarketModel and a SQL function for market creation in the indexer service. The updates include conditional handling of market creation based on a configuration flag, improved error handling with explicit typing, and tests for the new functionality. The changes aim to enhance the flexibility, type safety, and test coverage of the codebase.

Changes

File(s) Summary
indexer/packages/postgres/src/constants.ts
indexer/packages/postgres/src/index.ts
indexer/packages/postgres/src/models/market-model.ts
Introduced MarketModel with a new static method sqlToJsonConversions for JSON conversion types.
indexer/packages/postgres/src/loops/market-refresher.ts Added a new function updateMarket to update the idToMarket map.
indexer/services/ender/src/config.ts
indexer/services/ender/src/handlers/markets/market-create-handler.ts
Added a new configuration option USE_MARKET_CREATE_HANDLER_SQL_FUNCTION and conditional handling of market creation in market-create-handler.ts.
indexer/services/ender/__tests__/handlers/markets/market-create-handler.test.ts Added new test cases for the creation of a new market and error handling when attempting to create an existing market.
indexer/services/ender/src/handlers/order-fills/liquidation-handler.ts
indexer/services/ender/src/handlers/order-fills/order-handler.ts
indexer/services/ender/src/handlers/subaccount-update-handler.ts
indexer/services/ender/src/lib/on-message.ts
Improved error handling by specifying the type of the error parameter as Error in various handlers.
indexer/services/ender/__tests__/scripts/scripts.test.ts Improved type safety by adding a type annotation to the error parameter in the getSingleRawQueryResultRow function.
indexer/services/ender/src/helpers/postgres/postgres-functions.ts
indexer/services/ender/src/scripts/dydx_market_create_handler.sql
Added a new PostgreSQL function dydx_market_create_handler for market creation and updated the list of scripts accordingly.

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 help to get help.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.

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.json

Copy link

linear bot commented Nov 2, 2023

IND-467 Ender market create handler SQL pushdown

Update ender market create to execute updates via a SQL function.

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

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between f892a43 and b0e31dd.
Files selected for processing (14)
  • indexer/packages/postgres/src/constants.ts (2 hunks)
  • indexer/packages/postgres/src/index.ts (1 hunks)
  • indexer/packages/postgres/src/loops/market-refresher.ts (1 hunks)
  • indexer/packages/postgres/src/models/market-model.ts (1 hunks)
  • indexer/services/ender/tests/handlers/markets/market-create-handler.test.ts (2 hunks)
  • indexer/services/ender/tests/scripts/scripts.test.ts (1 hunks)
  • indexer/services/ender/src/config.ts (1 hunks)
  • indexer/services/ender/src/handlers/markets/market-create-handler.ts (3 hunks)
  • indexer/services/ender/src/handlers/order-fills/liquidation-handler.ts (1 hunks)
  • indexer/services/ender/src/handlers/order-fills/order-handler.ts (1 hunks)
  • indexer/services/ender/src/handlers/subaccount-update-handler.ts (1 hunks)
  • indexer/services/ender/src/helpers/postgres/postgres-functions.ts (2 hunks)
  • indexer/services/ender/src/lib/on-message.ts (1 hunks)
  • indexer/services/ender/src/scripts/dydx_market_create_handler.sql (1 hunks)
Files skipped from review due to trivial changes (8)
  • indexer/packages/postgres/src/constants.ts
  • indexer/packages/postgres/src/index.ts
  • indexer/services/ender/tests/scripts/scripts.test.ts
  • indexer/services/ender/src/handlers/order-fills/liquidation-handler.ts
  • indexer/services/ender/src/handlers/order-fills/order-handler.ts
  • indexer/services/ender/src/handlers/subaccount-update-handler.ts
  • indexer/services/ender/src/helpers/postgres/postgres-functions.ts
  • indexer/services/ender/src/lib/on-message.ts
Additional comments: 10
indexer/services/ender/src/config.ts (1)
  • 29-34: The new configuration option USE_MARKET_CREATE_HANDLER_SQL_FUNCTION is added and set to true by default. This means the new SQL function for market creation will be used by default. Ensure that the new SQL function is thoroughly tested and ready for production use.
indexer/services/ender/__tests__/handlers/markets/market-create-handler.test.ts (2)
  • 90-134: The test case 'creates new market' is well written and covers both the scenarios of creating a new market via knex and via SQL function. It checks if the market created matches the event data.

  • 136-180: The test case 'errors when attempting to create an existing market' is also well written and covers both the scenarios of creating an existing market via knex and via SQL function. It checks if the correct error is thrown and if the market in the database is the old market. It also checks if the error logs are correct and if no messages were sent to the producer.

indexer/packages/postgres/src/models/market-model.ts (1)
  • 54-68: The addition of the sqlToJsonConversions static method is a good practice for mapping SQL data types to JSON data types. This will help in maintaining consistency when dealing with data conversions. However, ensure that the mappings are correct and that they match the actual data types in the database. Also, the TODO comment on line 58 indicates that there might be a need to ensure consistency between jsonSchema(), sqlToJsonConversions(), and model fields. This should be addressed to avoid potential issues in the future.
indexer/services/ender/src/handlers/markets/market-create-handler.ts (5)
  • 1-15: Imports are correctly added for the new functionality.

  • 24-34: The internalHandle() method has been updated to conditionally call either handleViaSqlFunction() or handleViaKnexQueries(). Ensure that the USE_MARKET_CREATE_HANDLER_SQL_FUNCTION configuration option is correctly set in all environments where this code will run.

  • 37-40: The handleViaKnexQueries() method has been added to handle market creation via Knex queries. This is a good approach for maintaining backward compatibility.

  • 57-86: The handleViaSqlFunction() method has been added to handle market creation via a SQL function. This is a good approach for improving performance by pushing logic to the database. However, be aware that using raw SQL queries can increase the risk of SQL injection attacks. Make sure that the input to the SQL function is properly sanitized and parameterized.

-      `SELECT dydx_market_create_handler(
-        '${JSON.stringify(MarketEventV1.decode(eventDataBinary))}' 
-      ) AS result;`,
+      `SELECT dydx_market_create_handler($1) AS result;`,
+      [JSON.stringify(MarketEventV1.decode(eventDataBinary))],
  • 88-90: The createMarket() method has been updated to use MarketTable.create(). This is a good approach for improving code readability and maintainability.
indexer/services/ender/src/scripts/dydx_market_create_handler.sql (1)
  • 1-25: The SQL function dydx_market_create_handler seems to be well written and follows good practices. It checks for an existing market before creating a new one, which is a good way to prevent duplicate entries. However, it's important to ensure that the dydx_to_jsonb function used in line 22 is defined and works as expected. Also, make sure that the markets table and its columns exist and match the types used in this function.

Comment on lines 40 to +48
stats.timing(`${config.SERVICE_NAME}.loops.update_markets`, Date.now() - startTime);
}

/**
* Updates the markets map with the specified market.
*/
export function updateMarket(market: MarketFromDatabase): void {
idToMarket[market.id] = market;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The updateMarket function directly modifies the idToMarket map. This could potentially lead to data races if multiple threads are trying to update the map at the same time. Consider using a lock or other synchronization mechanism to ensure thread safety.

+ let updateLock = false;

export function updateMarket(market: MarketFromDatabase): void {
+  while(updateLock) {} // wait for lock to be released
+  updateLock = true; // acquire lock
  idToMarket[market.id] = market;
+  updateLock = false; // release lock
}

Commitable suggestion (Beta)
Suggested change
stats.timing(`${config.SERVICE_NAME}.loops.update_markets`, Date.now() - startTime);
}
/**
* Updates the markets map with the specified market.
*/
export function updateMarket(market: MarketFromDatabase): void {
idToMarket[market.id] = market;
}
let updateLock = false;
export function updateMarket(market: MarketFromDatabase): void {
while(updateLock) {} // wait for lock to be released
updateLock = true; // acquire lock
idToMarket[market.id] = market;
updateLock = false; // release lock
}

Comment on lines +9 to +11
IF FOUND THEN
RAISE EXCEPTION 'Market in MarketCreate already exists. Record: %', market_record;
END IF;
Copy link
Contributor

Choose a reason for hiding this comment

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

The error message in the exception is clear and provides useful information for debugging. However, consider adding more context to the error message, such as the event data that caused the exception. This can help with debugging if the error occurs.

- RAISE EXCEPTION 'Market in MarketCreate already exists. Record: %', market_record;
+ RAISE EXCEPTION 'Market in MarketCreate already exists. Event data: %, Record: %', event_data, market_record;

Commitable suggestion (Beta)
Suggested change
IF FOUND THEN
RAISE EXCEPTION 'Market in MarketCreate already exists. Record: %', market_record;
END IF;
IF FOUND THEN
RAISE EXCEPTION 'Market in MarketCreate already exists. Event data: %, Record: %', event_data, market_record;
END IF;

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 b0e31dd and adfc4fd.
Files selected for processing (1)
  • indexer/services/ender/src/scripts/dydx_market_create_handler.sql (1 hunks)
Additional comments: 5
indexer/services/ender/src/scripts/dydx_market_create_handler.sql (5)
  • 1-7: The function documentation is clear and provides a good overview of the function's purpose, parameters, and return value. It also provides links to the relevant data structures, which is helpful for understanding the context.

  • 13-14: The code correctly retrieves the marketId from the event_data and checks if a market with the same ID already exists in the markets table.

  • 16-18: The error handling here is appropriate. If a market with the same ID already exists, an exception is raised with a clear error message.

  • 20-23: The market_record is populated with the necessary fields from the event_data. The code correctly handles the conversion of JSON fields to the appropriate data types.

  • 27-30: The function correctly returns the created market as a JSON object in the market-model format.

market_record."exponent" = (event_data->'marketCreate'->'exponent')::integer;
market_record."minPriceChangePpm" = (event_data->'marketCreate'->'base'->'minPriceChangePpm')::integer;

INSERT INTO markets VALUES (market_record.*);
Copy link
Contributor

Choose a reason for hiding this comment

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

The INSERT INTO statement doesn't specify the columns for which the values are being inserted. This can lead to errors if the structure of the markets table changes in the future. It's a good practice to always specify the column names in an INSERT INTO statement.

- INSERT INTO markets VALUES (market_record.*);
+ INSERT INTO markets (id, pair, exponent, minPriceChangePpm) VALUES (market_record.id, market_record.pair, market_record.exponent, market_record.minPriceChangePpm);

Commitable suggestion (Beta)
Suggested change
INSERT INTO markets VALUES (market_record.*);
INSERT INTO markets (id, pair, exponent, minPriceChangePpm) VALUES (market_record.id, market_record.pair, market_record.exponent, market_record.minPriceChangePpm);

Copy link
Contributor

@vincentwschau vincentwschau left a comment

Choose a reason for hiding this comment

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

Seems like tests are failing because this test is missing a call to await createPostgresFunctions(); in beforeEach.

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 adfc4fd and 557c902.
Files selected for processing (2)
  • indexer/services/ender/tests/lib/sync-handlers.test.ts (3 hunks)
  • indexer/services/ender/src/handlers/markets/market-create-handler.ts (3 hunks)
Additional comments: 6
indexer/services/ender/__tests__/lib/sync-handlers.test.ts (3)
  • 30-33: The import of createPostgresFunctions is fine. Ensure that the function is defined and exported correctly in the '../../src/helpers/postgres/postgres-functions' module.

  • 67-69: The beforeAll block is correctly used to set up the Postgres functions before running the tests.

  • 94-96: The afterAll block is correctly used to tear down the database after running the tests.

indexer/services/ender/src/handlers/markets/market-create-handler.ts (3)
  • 24-34: The internalHandle() method now checks the configuration to decide whether to use the SQL function or Knex queries for market creation. This is a good approach for gradually transitioning between two different implementations and allows for easy rollback if issues arise with the new implementation.

  • 57-80: The handleViaSqlFunction() method executes a raw SQL query and handles any errors that occur. It's important to note that raw SQL queries can be vulnerable to SQL injection attacks. However, in this case, the query does not directly incorporate user-provided data, so the risk is mitigated. Still, it's a good practice to use parameterized queries or prepared statements whenever possible to further reduce the risk.

-      `SELECT dydx_market_create_handler(
-        '${JSON.stringify(MarketEventV1.decode(eventDataBinary))}'
-      ) AS result;`,
+      `SELECT dydx_market_create_handler($1) AS result;`,
+      [JSON.stringify(MarketEventV1.decode(eventDataBinary))],
  • 88-90: The createMarket() method now uses MarketTable.create() instead of directly inserting the market data. This is a good practice as it abstracts the database operations and makes the code more maintainable.

@lcwik lcwik merged commit b6cdc15 into main Nov 2, 2023
11 checks passed
@lcwik lcwik deleted the lukeind467 branch November 2, 2023 19:59
vincentwschau pushed a commit that referenced this pull request Nov 9, 2023
…#737)

* [IND-467] Push ender market create logic to use a single sql function
vincentwschau pushed a commit that referenced this pull request Nov 9, 2023
…#737)

* [IND-467] Push ender market create logic to use a single sql function
vincentwschau pushed a commit that referenced this pull request Nov 10, 2023
…#737)

* [IND-467] Push ender market create logic to use a single sql function
vincentwschau pushed a commit that referenced this pull request Nov 10, 2023
…#737)

* [IND-467] Push ender market create logic to use a single sql function
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.

4 participants