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 #2911: Update OracleSet transaction model, unit, integ tests #2913

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

Conversation

ckeshava
Copy link
Collaborator

High Level Overview of Change

Please refer to this issue: #2911

Context of Change

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (non-breaking change that only restructures code)
  • Tests (You added tests for code that already exists, or your new feature included in this PR)
  • Documentation Updates
  • Release

Did you update HISTORY.md?

  • Yes
  • No, this change does not impact library users

Test Plan

@ckeshava ckeshava requested a review from khancode February 26, 2025 18:49
Copy link

coderabbitai bot commented Feb 26, 2025

Walkthrough

This pull request updates the handling of the AssetPrice field in the OracleSet transaction. The changes document the new behavior in HISTORY.md, modify the validation logic using the isHex utility in oracleSet.ts, and add test cases to verify the enhanced hexadecimal string support. The modifications ensure that both integration and unit tests assess valid and invalid input scenarios without altering the public API.

Changes

File(s) Change Summary
packages/xrpl/.../HISTORY.md Added a new "Fixed" section under "Unreleased" to document the change that allows hex string values for the AssetPrice field.
packages/xrpl/.../oracleSet.ts Imported isHex and updated validateOracleSet to accept either a number or a hexadecimal string (with 1–16 characters) for AssetPrice; updated ESLint comments to block style.
packages/xrpl/test/.../oracleSet.test.ts Expanded test cases: the integration test now includes an additional PriceDataSeries entry with a large hexadecimal string, and the unit tests cover invalid hex formats, valid hex values, and incorrect type scenarios.

Possibly related PRs

Suggested reviewers

  • mvadari
  • justinr1234
  • khancode

Poem

I'm a nimble rabbit, hopping through the code,
With hex strings and validations neatly bestowed.
Oracle fixes now shine in every line,
Bugs and errors, no longer a sign.
I celebrate these changes with a joyful, bouncy ode!
🐰✨


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a92df19 and f1eb73a.

📒 Files selected for processing (2)
  • packages/xrpl/src/models/transactions/oracleSet.ts (4 hunks)
  • packages/xrpl/test/models/oracleSet.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/xrpl/src/models/transactions/oracleSet.ts
  • packages/xrpl/test/models/oracleSet.test.ts
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: unit (18.x)
  • GitHub Check: snippets (20.x)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @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.

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.

Copy link

@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: 0

🧹 Nitpick comments (2)
packages/xrpl/src/models/transactions/oracleSet.ts (1)

13-13: Fix import ordering and formatting.

The import statement for HEX_REGEX should be placed with the other imports before line 13, and spacing should be fixed.

- import {HEX_REGEX} from 'ripple-binary-codec/dist/types/uint-64'
+ import { HEX_REGEX } from 'ripple-binary-codec/dist/types/uint-64'
🧰 Tools
🪛 ESLint

[error] 13-13: ripple-binary-codec/dist/types/uint-64 import should occur before import of ../../errors

(import/order)


[error] 13-13: Replace HEX_REGEX with ·HEX_REGEX·

(prettier/prettier)

packages/xrpl/HISTORY.md (1)

7-9: Changelog Entry Clarity and Traceability:
The new "Fixed" entry under "Unreleased" clearly indicates that the OracleSet transaction now accepts hexadecimal string values for the AssetPrice field. This aligns well with the bug fix outlined in the PR objectives.

Suggestion: Consider appending a reference to the associated issue (e.g., (#2911)) to improve traceability and to help users quickly correlate the changelog entry with the underlying fix.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a45c58 and afba82f.

📒 Files selected for processing (5)
  • packages/ripple-binary-codec/src/types/uint-64.ts (1 hunks)
  • packages/xrpl/HISTORY.md (1 hunks)
  • packages/xrpl/src/models/transactions/oracleSet.ts (2 hunks)
  • packages/xrpl/test/integration/transactions/oracleSet.test.ts (2 hunks)
  • packages/xrpl/test/models/oracleSet.test.ts (1 hunks)
🧰 Additional context used
🪛 ESLint
packages/xrpl/src/models/transactions/oracleSet.ts

[error] 13-13: ripple-binary-codec/dist/types/uint-64 import should occur before import of ../../errors

(import/order)


[error] 13-13: Replace HEX_REGEX with ·HEX_REGEX·

(prettier/prettier)


[error] 151-151: Replace isNumber(priceData.PriceData.AssetPrice)·||·(typeof·priceData.PriceData.AssetPrice·===·'string'·&&·HEX_REGEX.test(priceData.PriceData.AssetPrice)) with ⏎··········isNumber(priceData.PriceData.AssetPrice)·||⏎··········(typeof·priceData.PriceData.AssetPrice·===·'string'·&&⏎············HEX_REGEX.test(priceData.PriceData.AssetPrice))⏎········

(prettier/prettier)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: snippets (22.x)
  • GitHub Check: snippets (20.x)
  • GitHub Check: snippets (18.x)
🔇 Additional comments (7)
packages/ripple-binary-codec/src/types/uint-64.ts (1)

132-132: Export HEX_REGEX to make it available for external validation.

This change exposes the internal HEX_REGEX constant (which validates hexadecimal strings of 1-16 characters) for use in other modules. This is a good approach for sharing validation patterns consistently across the codebase.

packages/xrpl/src/models/transactions/oracleSet.ts (1)

151-151: Enhance AssetPrice validation to support hexadecimal strings.

Good enhancement to allow both numeric values and properly formatted hexadecimal strings for the AssetPrice field. This provides more flexibility, especially for large values that can't be precisely represented by JavaScript numbers.

The conditional could be formatted more clearly for readability:

- !(isNumber(priceData.PriceData.AssetPrice) || (typeof priceData.PriceData.AssetPrice === 'string' && HEX_REGEX.test(priceData.PriceData.AssetPrice)))
+ !(
+   isNumber(priceData.PriceData.AssetPrice) || 
+   (typeof priceData.PriceData.AssetPrice === 'string' && 
+     HEX_REGEX.test(priceData.PriceData.AssetPrice)
+   )
+ )
🧰 Tools
🪛 ESLint

[error] 151-151: Replace isNumber(priceData.PriceData.AssetPrice)·||·(typeof·priceData.PriceData.AssetPrice·===·'string'·&&·HEX_REGEX.test(priceData.PriceData.AssetPrice)) with ⏎··········isNumber(priceData.PriceData.AssetPrice)·||⏎··········(typeof·priceData.PriceData.AssetPrice·===·'string'·&&⏎············HEX_REGEX.test(priceData.PriceData.AssetPrice))⏎········

(prettier/prettier)

packages/xrpl/test/integration/transactions/oracleSet.test.ts (3)

42-52: Add test case for hexadecimal string AssetPrice values.

Excellent addition of a test case using a large hexadecimal string value for AssetPrice. The comments clearly explain why a string representation is necessary for large values that exceed JavaScript's number precision limits.


76-76: Update assertion to account for added test case.

Correctly updated the assertion to check for 2 items in the PriceDataSeries array.


83-87: Add validation for hexadecimal string serialization.

Good addition of an assertion to specifically verify that large hexadecimal string values for AssetPrice are properly serialized and preserved.

packages/xrpl/test/models/oracleSet.test.ts (2)

169-174: LGTM: Updated test case correctly validates non-hexadecimal strings

The test case has been properly updated to use 'ghij' which cannot be parsed as a hexadecimal string, ensuring validation correctly rejects invalid hex values for the AssetPrice field. This aligns with the PR objective to allow hexadecimal strings while maintaining proper validation.


176-181: Good addition: Adding type validation for array values

This new test case is a valuable addition that ensures the validation logic properly rejects array values for the AssetPrice field, strengthening the type safety of the OracleSet transaction model. This complements the existing validations and provides more comprehensive test coverage.

Comment on lines 169 to 177
it(`throws w/ invalid AssetPrice of PriceDataSeries`, function () {
tx.PriceDataSeries[0].PriceData.AssetPrice = '1234'
tx.PriceDataSeries[0].PriceData.AssetPrice = 'ghij' // value cannot be parsed as hexadecimal number
const errorMessage = 'OracleSet: invalid field AssetPrice'
assert.throws(() => validateOracleSet(tx), ValidationError, errorMessage)
assert.throws(() => validate(tx), ValidationError, errorMessage)
})

it(`throws w/ invalid AssetPrice type in PriceDataSeries`, function () {
tx.PriceDataSeries[0].PriceData.AssetPrice = ['sample', 'invalid', 'type']
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you also add a positive test case with AssetPrice using a valid string value?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@@ -10,6 +10,8 @@ import {
validateRequiredField,
} from './common'

import {HEX_REGEX} from 'ripple-binary-codec/dist/types/uint-64'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't there a HEX_REGEX somewhere in xrpl.js? I don't like the idea of importing from ripple-binary-codec like this

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, it's actually wrapped in a utility function called isHex() in packages/xrpl/src/models/utils/index.ts

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

These are the two other definitions of HEX_REGEX outside of ripple-binary-codec package. Both of them do not fit the bill. Perhaps a suitable regex is defined with a slightly different name?

export const HEX_REGEX = /^[A-F0-9]*$/iu

const HEX_REGEX = /^[0-9A-Fa-f]+$/u

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@khancode That is the second regex in my above message, it does not satisfy our requirements.

Copy link
Collaborator

Choose a reason for hiding this comment

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

How do they not fit it? What are the requirements?

Copy link
Collaborator

@mvadari mvadari Mar 3, 2025

Choose a reason for hiding this comment

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

If the isHex helper function doesn't work here, then it should be modified. We shouldn't have 5 different ways of checking if a string is hex.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@khancode The HEX_REGEX in this file accepts any non-zero length string comprising of the specified characters. However, the std::uint64_t cannot accommodate arbitrarily large strings. This is due to the range restrictions of the data type.

@mvadari There are multiple HEX_REGEX values in the code base because rippled has different uses of the hexa-decimal representation. Reconciling all the existing HEX_REGEX values is not possible. For instance, Currency representation uses this regex

I am happy to rename this variable as HEX_REGEX_UINT64, if that helps with readability.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not use isHex and do a separate length check, then?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree with @mvadari . You could also update isHex to take in a length parameter.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@@ -146,7 +148,7 @@ export function validateOracleSet(tx: Record<string, unknown>): void {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
'AssetPrice' in priceData.PriceData &&
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- we are validating the type
!isNumber(priceData.PriceData.AssetPrice)
!(isNumber(priceData.PriceData.AssetPrice) || (typeof priceData.PriceData.AssetPrice === 'string' && HEX_REGEX.test(priceData.PriceData.AssetPrice)))
Copy link
Collaborator

Choose a reason for hiding this comment

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

This regex test should potentially be included in isNumber

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There are many unsigned int values which aren't std::uint64_t amongst sfABCD values. Such values do not accept a str representation. There are 37 usages of this method in packages/xrpl/. Apart from a case-by-case decision, I don't know of a sweeping way to disambiguate this usage.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Is that just true of the library or does rippled also not accept hex for smaller int values?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Based on a perfunctory glance at the code base, rippled does not have any constructors which convert a hexa-decimal string into a std::uint<>_t type. All of them accept a std::uint<>_t type or a byte-string.

c++ code does not need a hexadecimal string -> UINT conversion because the std::uint<>_t types sufficiently represent the values. My understanding is that (non-c++) client libraries rely on strings to preserve the precision of values.

Source: https://github.com/XRPLF/rippled/blob/af018c7b0bd2d019a009e4405cfb7c3923c3a078/include/xrpl/protocol/STInteger.h#L38

@ckeshava ckeshava requested review from khancode and mvadari February 27, 2025 03:56
Copy link
Collaborator

@achowdhry-ripple achowdhry-ripple left a comment

Choose a reason for hiding this comment

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

lgtm

@ckeshava ckeshava requested a review from khancode March 4, 2025 18:15
) {
throw new ValidationError('OracleSet: invalid field AssetPrice')
}
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's this for?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This helps me address typescript linter errors. Without these directives, the compiler does not understand that priceData array members have the AssetPrice field.

@@ -173,4 +185,5 @@ export function validateOracleSet(tx: Record<string, unknown>): void {
}
return true
})
/* eslint-enable max-statements, max-lines-per-function */
Copy link
Collaborator

Choose a reason for hiding this comment

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

ditto

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm re-enabling the directive after this method. I'd like this directive to be enforced after this function definition.

@ckeshava ckeshava requested a review from khancode March 5, 2025 22:18
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.

4 participants