Improve add transaction (#1164)

* fix(wallet): move transaction ID calculation before database operations

* fix(sql): remove on ys from on conflict transaction insert

Since the id is created from the ys we know that if there is a conflict
the ys are the same and do not need to be updated.

* feat: bench for transactio id

* chore: fmt
This commit is contained in:
tsk
2025-10-09 16:20:06 +01:00
committed by GitHub
parent 3075ac4e59
commit 95aa64477a
6 changed files with 44 additions and 5 deletions

View File

@@ -66,6 +66,7 @@ clap = { version = "4.5.31", features = ["derive"] }
ciborium = { version = "0.2.2", default-features = false, features = ["std"] }
cbor-diag = "0.1.12"
config = { version = "0.15.11", features = ["toml"] }
criterion = "0.6.0"
futures = { version = "0.3.28", default-features = false, features = ["async-await"] }
lightning-invoice = { version = "0.33.0", features = ["serde", "std"] }
lightning = { version = "0.1.2", default-features = false, features = ["std"]}

View File

@@ -53,3 +53,8 @@ wasm-bindgen-futures = "0.4"
rand.workspace = true
bip39.workspace = true
wasm-bindgen-test = "0.3"
criterion.workspace = true
[[bench]]
name = "transaction_id_benchmark"
harness = false

View File

@@ -0,0 +1,29 @@
use cashu::nuts::nut01::SecretKey;
use cashu::PublicKey;
use cdk_common::wallet::TransactionId;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
fn generate_public_keys(count: usize) -> Vec<PublicKey> {
(0..count)
.map(|_| SecretKey::generate().public_key())
.collect()
}
fn bench_transaction_id(c: &mut Criterion) {
let mut group = c.benchmark_group("TransactionId::new");
let sizes = vec![1, 10, 50, 100, 500];
for size in sizes {
let public_keys = generate_public_keys(size);
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, _| {
b.iter(|| TransactionId::new(public_keys.clone()));
});
}
group.finish();
}
criterion_group!(benches, bench_transaction_id);
criterion_main!(benches);

View File

@@ -827,6 +827,8 @@ impl WalletDatabase for WalletRedbDatabase {
#[instrument(skip(self))]
async fn add_transaction(&self, transaction: Transaction) -> Result<(), Self::Err> {
let id = transaction.id();
let write_txn = self.db.begin_write().map_err(Error::from)?;
{
@@ -835,7 +837,7 @@ impl WalletDatabase for WalletRedbDatabase {
.map_err(Error::from)?;
table
.insert(
transaction.id().as_slice(),
id.as_slice(),
serde_json::to_string(&transaction)
.map_err(Error::from)?
.as_str(),

View File

@@ -954,7 +954,6 @@ ON CONFLICT(id) DO UPDATE SET
#[instrument(skip(self))]
async fn add_transaction(&self, transaction: Transaction) -> Result<(), Self::Err> {
let conn = self.pool.get().map_err(|e| Error::Database(Box::new(e)))?;
let mint_url = transaction.mint_url.to_string();
let direction = transaction.direction.to_string();
let unit = transaction.unit.to_string();
@@ -966,6 +965,10 @@ ON CONFLICT(id) DO UPDATE SET
.flat_map(|y| y.to_bytes().to_vec())
.collect::<Vec<_>>();
let id = transaction.id();
let conn = self.pool.get().map_err(|e| Error::Database(Box::new(e)))?;
query(
r#"
INSERT INTO transactions
@@ -978,7 +981,6 @@ ON CONFLICT(id) DO UPDATE SET
unit = excluded.unit,
amount = excluded.amount,
fee = excluded.fee,
ys = excluded.ys,
timestamp = excluded.timestamp,
memo = excluded.memo,
metadata = excluded.metadata,
@@ -988,7 +990,7 @@ ON CONFLICT(id) DO UPDATE SET
;
"#,
)?
.bind("id", transaction.id().as_slice().to_vec())
.bind("id", id.as_slice().to_vec())
.bind("mint_url", mint_url)
.bind("direction", direction)
.bind("unit", unit)

View File

@@ -143,7 +143,7 @@ rand.workspace = true
cdk-sqlite.workspace = true
bip39.workspace = true
tracing-subscriber.workspace = true
criterion = "0.6.0"
criterion.workspace = true
reqwest = { workspace = true }
anyhow.workspace = true
ureq = { version = "3.1.0", features = ["json"] }