Skip to content

Commit

Permalink
fix(pindexer): correct encoding of Amount into Postgres (#4772)
Browse files Browse the repository at this point in the history
I tried and tried to actually use Numeric directly in a smart way,
instead the hack is to just cast text into it in the SQL query. Oh well.

## Checklist before requesting a review

- [x] If this code contains consensus-breaking changes, I have added the
"consensus-breaking" label. Otherwise, I declare my belief that there
are not consensus-breaking changes, for the following reason:

  > pindexer bug fix
  • Loading branch information
cronokirby authored Jul 26, 2024
1 parent dd9efd6 commit 899f3e6
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 58 deletions.
15 changes: 0 additions & 15 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion crates/bin/pindexer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ penumbra-asset = {workspace = true, default-features = false}
penumbra-proto = {workspace = true, default-features = false}
tokio = {workspace = true, features = ["full"]}
serde_json = {workspace = true}
sqlx = { workspace = true, features = ["bigdecimal", "chrono", "postgres"] }
sqlx = { workspace = true, features = ["chrono", "postgres"] }
tracing = {workspace = true}
22 changes: 11 additions & 11 deletions crates/bin/pindexer/src/dex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ impl Event {
sqlx::query(
r#"
INSERT INTO dex_value_circuit_breaker_change
VALUES ($1, $2);
VALUES ($1, CAST($2 AS Amount));
"#,
)
.bind(Sql::from(*asset_id))
.bind(Sql::from(amount))
.bind(amount.to_string())
.execute(dbtx.as_mut())
.await?;
Ok(())
Expand All @@ -78,11 +78,11 @@ impl Event {
sqlx::query(
r#"
INSERT INTO dex_value_circuit_breaker_change
VALUES ($1, -$2);
VALUES ($1, -(CAST($2 AS Amount)));
"#,
)
.bind(Sql::from(*asset_id))
.bind(Sql::from(amount))
.bind(amount.to_string())
.execute(dbtx.as_mut())
.await?;
Ok(())
Expand All @@ -94,10 +94,10 @@ impl Event {
let mut step_start = None;
let mut step_end = None;
for step in trace {
let (id,): (i64,) = sqlx::query_as(
r#"INSERT INTO trace_step VALUES (DEFAULT, ($1, $2)) RETURNING id;"#,
let (id,): (i32,) = sqlx::query_as(
r#"INSERT INTO trace_step VALUES (DEFAULT, (CAST($1 AS Amount), $2)) RETURNING id;"#,
)
.bind(Sql::from(step.amount))
.bind(step.amount.to_string())
.bind(Sql::from(step.asset_id))
.fetch_one(dbtx.as_mut())
.await?;
Expand All @@ -106,7 +106,7 @@ impl Event {
}
step_end = Some(id);
}
let (id,): (i64,) = sqlx::query_as(
let (id,): (i32,) = sqlx::query_as(
r#"INSERT INTO trace VALUES (DEFAULT, $1, $2) RETURNING id;"#,
)
.bind(step_start)
Expand All @@ -118,11 +118,11 @@ impl Event {
}
trace_end = Some(id);
}
sqlx::query(r#"INSERT INTO arb VALUES ($1, ($2, $3), ($4, $5), $6, $7);"#)
sqlx::query(r#"INSERT INTO arb VALUES ($1, (CAST($2 AS Amount), $3), (CAST($4 AS AMOUNT), $5), $6, $7);"#)
.bind(i64::try_from(*height)?)
.bind(Sql::from(execution.input.amount))
.bind(execution.input.amount.to_string())
.bind(Sql::from(execution.input.asset_id))
.bind(Sql::from(execution.output.amount))
.bind(execution.output.amount.to_string())
.bind(Sql::from(execution.output.asset_id))
.bind(trace_start)
.bind(trace_end)
Expand Down
32 changes: 1 addition & 31 deletions crates/bin/pindexer/src/sql.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use std::error::Error;

use anyhow::anyhow;
use num_bigint::{BigInt, Sign};
use penumbra_asset::asset::Id as AssetId;
use penumbra_num::Amount;
use sqlx::{types::BigDecimal, Decode, Encode, Postgres, Type};
use sqlx::{Decode, Encode, Postgres, Type};

/// An extension trait to make it easier to implement serialization for existing Penumbra types.
///
Expand Down Expand Up @@ -74,33 +71,6 @@ where
}
}

impl SqlExt for Amount {
type SqlT = BigDecimal;

fn to_sql_type(&self) -> Self::SqlT {
BigDecimal::from(BigInt::from_bytes_le(
Sign::Plus,
self.to_le_bytes().as_slice(),
))
}

fn from_sql_type(value: Self::SqlT) -> anyhow::Result<Self> {
if !value.is_integer() {
return Err(anyhow!("database value is not an integer").into());
}
let big_int = value.as_bigint_and_exponent().0;
// Get the bytes only from a positive BigInt
let bytes = match big_int.to_bytes_le() {
(Sign::Plus | Sign::NoSign, bytes) => bytes,
(Sign::Minus, bytes) => bytes,
};
let bytes: [u8; 16] = bytes
.try_into()
.map_err(|_| anyhow!("failed to convert slice to 16 bytes"))?;
Ok(Amount::from_le_bytes(bytes))
}
}

impl SqlExt for AssetId {
type SqlT = [u8; 32];

Expand Down

0 comments on commit 899f3e6

Please sign in to comment.