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(core, proto): use i128 for price instead of u128 #1991

Merged
merged 5 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions crates/astria-core/src/connect/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ pub mod v2 {
use crate::generated::connect::types::v2 as raw;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Price(u128);
pub struct Price(i128);

impl Price {
#[must_use]
pub const fn new(value: u128) -> Self {
pub const fn new(value: i128) -> Self {
Self(value)
}

#[must_use]
pub fn get(self) -> u128 {
pub fn get(self) -> i128 {
self.0
}
}
Expand All @@ -33,7 +33,7 @@ pub mod v2 {
self.get().checked_add(rhs.get()).map(Self)
}

pub fn checked_div(self, rhs: u128) -> Option<Self> {
pub fn checked_div(self, rhs: i128) -> Option<Self> {
self.get().checked_div(rhs).map(Self)
}
}
Expand Down Expand Up @@ -73,7 +73,7 @@ pub mod v2 {
let be_bytes = <[u8; 16]>::try_from(&*input).map_err(|_| Self::Error {
input,
})?;
Ok(Price::new(u128::from_be_bytes(be_bytes)))
Ok(Price::new(i128::from_be_bytes(be_bytes)))
}
}

Expand Down Expand Up @@ -448,5 +448,11 @@ pub mod v2 {
"ETH /USD".parse::<CurrencyPair>().unwrap_err();
"ETH/ USD".parse::<CurrencyPair>().unwrap_err();
}

#[test]
fn can_parse_negative_price() {
let price = "-1".parse::<Price>().unwrap();
assert_eq!(price.get(), -1);
Copy link
Member

Choose a reason for hiding this comment

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

IMO compare on Price::new(-1) instead.

}
}
}
12 changes: 6 additions & 6 deletions crates/astria-core/src/connect/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ mod test {
}
}

fn oracle_vote_extension<I: IntoIterator<Item = u128>>(prices: I) -> OracleVoteExtension {
fn oracle_vote_extension<I: IntoIterator<Item = i128>>(prices: I) -> OracleVoteExtension {
OracleVoteExtension {
prices: prices
.into_iter()
Expand Down Expand Up @@ -221,7 +221,7 @@ mod test {

#[test]
fn should_calculate_median() {
fn prices<I: IntoIterator<Item = u128>>(prices: I) -> Vec<Price> {
fn prices<I: IntoIterator<Item = i128>>(prices: I) -> Vec<Price> {
prices.into_iter().map(Price::new).collect()
}

Expand All @@ -245,14 +245,14 @@ mod test {

// Should handle large values in a set with odd number of entries.
assert_eq!(
u128::MAX,
median(prices([u128::MAX, u128::MAX, 1])).unwrap().get()
i128::MAX,
median(prices([i128::MAX, i128::MAX, 1])).unwrap().get()
);

// Should handle large values in a set with even number of entries.
assert_eq!(
u128::MAX - 1,
median(prices([u128::MAX, u128::MAX, u128::MAX - 1, u128::MAX - 1]))
i128::MAX - 1,
median(prices([i128::MAX, i128::MAX, i128::MAX - 1, i128::MAX - 1]))
.unwrap()
.get()
);
Expand Down
28 changes: 27 additions & 1 deletion crates/astria-core/src/generated/astria.primitive.v1.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

114 changes: 114 additions & 0 deletions crates/astria-core/src/generated/astria.primitive.v1.serde.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 53 additions & 0 deletions crates/astria-core/src/primitive/v1/i128.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//! Transformations of compiled protobuf types to other types.

use crate::generated::astria::primitive::v1::Int128;
impl From<i128> for Int128 {
fn from(primitive: i128) -> Self {
let [h0, h1, h2, h3, h4, h5, h6, h7, l0, l1, l2, l3, l4, l5, l6, l7] =
primitive.to_be_bytes();
let lo = u64::from_be_bytes([l0, l1, l2, l3, l4, l5, l6, l7]);
let hi = u64::from_be_bytes([h0, h1, h2, h3, h4, h5, h6, h7]);
Self {
lo,
hi,
}
}
}

impl From<Int128> for i128 {
fn from(pb: Int128) -> i128 {
let [l0, l1, l2, l3, l4, l5, l6, l7] = pb.lo.to_be_bytes();
let [h0, h1, h2, h3, h4, h5, h6, h7] = pb.hi.to_be_bytes();
i128::from_be_bytes([
h0, h1, h2, h3, h4, h5, h6, h7, l0, l1, l2, l3, l4, l5, l6, l7,
])
}
}

impl<'a> From<&'a i128> for Int128 {
fn from(primitive: &'a i128) -> Self {
(*primitive).into()
}
}

#[cfg(test)]
mod tests {
use super::Int128;

#[track_caller]
fn i128_roundtrip_check(expected: i128) {
let pb: Int128 = expected.into();
let actual: i128 = pb.into();
assert_eq!(expected, actual);
}
#[test]
fn i128_roundtrips_work() {
Copy link
Member

Choose a reason for hiding this comment

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

This should contain the case of i128::MIN, -1, and other distinct negative i128 values.

i128_roundtrip_check(0i128);
i128_roundtrip_check(1i128);
i128_roundtrip_check(i128::from(u64::MAX));
i128_roundtrip_check(i128::from(u64::MAX) + 1i128);
i128_roundtrip_check(1i128 << 127);
i128_roundtrip_check((1i128 << 127) + (1i128 << 63));
i128_roundtrip_check(i128::MAX);
}
}
1 change: 1 addition & 0 deletions crates/astria-core/src/primitive/v1/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod asset;
pub mod i128;
pub mod u128;

pub use astria_core_address::{
Expand Down
2 changes: 1 addition & 1 deletion crates/astria-core/src/protocol/genesis/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1147,7 +1147,7 @@ mod tests {
id: CurrencyPairId::new(1),
nonce: CurrencyPairNonce::new(0),
currency_pair_price: Some(QuotePrice {
price: Price::new(3_138_872_234_u128),
price: Price::new(3_138_872_234_i128),
block_height: 0,
block_timestamp: pbjson_types::Timestamp {
seconds: 1_720_122_395,
Expand Down
2 changes: 1 addition & 1 deletion crates/astria-sequencer-utils/src/blob_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ impl Display for PrintableDeposit {

#[derive(Serialize, Debug)]
struct PrintableOracleData {
prices: Vec<(String, u128, u64)>,
prices: Vec<(String, i128, u64)>,
}

impl TryFrom<&RawOracleData> for PrintableOracleData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl From<Timestamp> for DomainTimestamp {

#[derive(Debug, BorshSerialize, BorshDeserialize)]
struct QuotePrice {
price: u128,
price: i128,
block_timestamp: Timestamp,
block_height: u64,
}
Expand Down
18 changes: 17 additions & 1 deletion proto/primitives/astria/primitive/v1/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ syntax = "proto3";

package astria.primitive.v1;

// A 128 bit unsigned integer encoded in protobuf.,
// A 128 bit unsigned integer encoded in protobuf.
//
// Protobuf does not support integers larger than 64 bits,
// so this message encodes a u128 by splitting it into its
Expand All @@ -18,6 +18,22 @@ message Uint128 {
uint64 hi = 2;
}

// A 128 bit signed integer encoded in protobuf.
//
// Protobuf does not support integers larger than 64 bits,
// so this message encodes a i128 by splitting it into its
// upper 64 and lower 64 bits, each encoded as a uint64.
//
// A native i128 x can then be constructed by casting both
// integers to i128, left shifting hi by 64 positions and
// adding lo:
//
// x = (hi as i128) << 64 + (lo as i128)
message Int128 {
uint64 lo = 1;
uint64 hi = 2;
}

// A proof for a tree of the given size containing the audit path from a leaf to the root.
message Proof {
// A sequence of 32 byte hashes used to reconstruct a Merkle Tree Hash.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,6 @@ message OracleData {

message Price {
connect.types.v2.CurrencyPair currency_pair = 1;
astria.primitive.v1.Uint128 price = 2;
astria.primitive.v1.Int128 price = 2;
uint64 decimals = 3;
}
Loading