From 51e73606b14691190bf7b5a9610605c34b973659 Mon Sep 17 00:00:00 2001 From: Jakob Notland Date: Wed, 25 Mar 2026 11:26:17 +0100 Subject: [PATCH] Review and clean up --- src/db/cauldron/ohlcv.rs | 26 ++------------------------ src/db/cauldron/pool.rs | 10 ++++++++++ src/db/cauldron/utxo_funding.rs | 6 ++++++ src/main.rs | 17 ++++++----------- src/rpc/candlesticks.rs | 10 +++++----- 5 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/db/cauldron/ohlcv.rs b/src/db/cauldron/ohlcv.rs index f5bb937..b345816 100644 --- a/src/db/cauldron/ohlcv.rs +++ b/src/db/cauldron/ohlcv.rs @@ -25,27 +25,6 @@ pub async fn create_table(pool: &SqlitePool) { .await .expect("failed to create ohlcv_1h table"); - // Needed for fast joins in rebuild_range; use IF NOT EXISTS so this is safe on existing DBs. - sqlx::query("CREATE INDEX IF NOT EXISTS idx_phe_txid ON pool_history_entry(txid)") - .execute(pool) - .await - .expect("failed to create idx_phe_txid index"); - - // Composite index for fast token+time range scans in the candlestick raw CTE. - sqlx::query( - "CREATE INDEX IF NOT EXISTS idx_phe_token_id_ts ON pool_history_entry(token_id, effective_timestamp)", - ) - .execute(pool) - .await - .expect("failed to create idx_phe_token_id_ts index"); - - // Index for tx_latest token-filtered query: JOIN utxo_funding WHERE token_id = ? → ORDER BY tx.effective_timestamp. - sqlx::query( - "CREATE INDEX IF NOT EXISTS idx_utxo_funding_token_txid ON utxo_funding(token_id, txid)", - ) - .execute(pool) - .await - .expect("failed to create idx_utxo_funding_token_txid index"); } /// Returns the highest `bucket_ts` in `ohlcv_1h`, or `None` if the table is empty. @@ -61,10 +40,9 @@ pub async fn get_max_bucket_ts(pool: &SqlitePool) -> Result> { /// so the background task doesn't scan from Unix epoch 0. pub async fn get_min_trade_bucket_ts(pool: &SqlitePool) -> Result> { let row: Option<(Option,)> = sqlx::query_as( - "SELECT (MIN(tx.effective_timestamp) / 3600) * 3600 + "SELECT (MIN(phe.effective_timestamp) / 3600) * 3600 FROM pool_history_entry AS phe - JOIN tx ON tx.txid = phe.txid - WHERE tx.blockhash IS NOT NULL", + WHERE phe.mtp_timestamp IS NOT NULL", ) .fetch_optional(pool) .await?; diff --git a/src/db/cauldron/pool.rs b/src/db/cauldron/pool.rs index 5cfd741..9c7d807 100644 --- a/src/db/cauldron/pool.rs +++ b/src/db/cauldron/pool.rs @@ -83,6 +83,16 @@ pub async fn create_table(pool: &SqlitePool) { .execute(pool) .await .unwrap(); + sqlx::query("CREATE INDEX IF NOT EXISTS idx_phe_txid ON pool_history_entry(txid)") + .execute(pool) + .await + .unwrap(); + sqlx::query( + "CREATE INDEX IF NOT EXISTS idx_phe_token_id_ts ON pool_history_entry(token_id, effective_timestamp)", + ) + .execute(pool) + .await + .unwrap(); } async fn get_pool_by_utxo( diff --git a/src/db/cauldron/utxo_funding.rs b/src/db/cauldron/utxo_funding.rs index cbc8452..3e3a43c 100644 --- a/src/db/cauldron/utxo_funding.rs +++ b/src/db/cauldron/utxo_funding.rs @@ -27,6 +27,12 @@ pub async fn create_table(pool: &SqlitePool) { .execute(pool) .await .unwrap(); + sqlx::query( + "CREATE INDEX IF NOT EXISTS idx_utxo_funding_token_txid ON utxo_funding(token_id, txid)", + ) + .execute(pool) + .await + .unwrap(); } pub async fn insert_utxo_funding( diff --git a/src/main.rs b/src/main.rs index 8c591d8..6cbc68f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -412,11 +412,10 @@ async fn launch() -> _ { db::cauldron::ohlcv::create_table(&dbpool.cauldron_w).await; // Bootstrap OhlcvState from whatever is already in the table (survives restarts). - let initial_ohlcv_end = db::cauldron::ohlcv::get_max_bucket_ts(&dbpool.cauldron_r) + let max_bucket_ts = db::cauldron::ohlcv::get_max_bucket_ts(&dbpool.cauldron_r) .await - .unwrap_or(None) - .map(|ts| ts + 3600) - .unwrap_or(0); + .unwrap_or(None); + let initial_ohlcv_end = max_bucket_ts.map(|ts| ts + 3600).unwrap_or(0); let ohlcv_state = Arc::new(OhlcvState { materialized_end: AtomicI64::new(initial_ohlcv_end), }); @@ -439,9 +438,9 @@ async fn launch() -> _ { let now = crate::timeutil::time_now(); let cutoff = (now - BACKFILL_SAFETY_SECS) / 3600 * 3600; - let since_opt = match db::cauldron::ohlcv::get_max_bucket_ts(&dbpool.cauldron_r).await { - Ok(Some(ts)) => Some(ts + 3600), - Ok(None) => { + let since_opt = match max_bucket_ts { + Some(ts) => Some(ts + 3600), + None => { match db::cauldron::ohlcv::get_min_trade_bucket_ts(&dbpool.cauldron_r).await { Ok(v) => v, Err(e) => { @@ -450,10 +449,6 @@ async fn launch() -> _ { } } } - Err(e) => { - warn!("ohlcv backfill: could not read max bucket ts: {e}"); - None - } }; if since_opt.is_none() { info!("ohlcv backfill: no confirmed trades found, skipping"); diff --git a/src/rpc/candlesticks.rs b/src/rpc/candlesticks.rs index 599dbdf..11a25ea 100644 --- a/src/rpc/candlesticks.rs +++ b/src/rpc/candlesticks.rs @@ -578,27 +578,27 @@ mod tests { .await .unwrap(); - // Insert tx rows + // Insert tx rows in realistic order: mempool first, then confirmed. let block_zero = BlockHash::all_zeros(); + insert_mempool_tx(&mut *conn, &txid1, TIME_1).await.unwrap(); insert_block_tx(&mut *conn, &txid1, &block_zero, TIME_1 as i64) .await .unwrap(); - insert_mempool_tx(&mut *conn, &txid1, TIME_1).await.unwrap(); + insert_mempool_tx(&mut *conn, &txid2, TIME_2).await.unwrap(); insert_block_tx(&mut *conn, &txid2, &block_zero, TIME_2 as i64) .await .unwrap(); - insert_mempool_tx(&mut *conn, &txid2, TIME_2).await.unwrap(); + insert_mempool_tx(&mut *conn, &txid3, TIME_3).await.unwrap(); insert_block_tx(&mut *conn, &txid3, &block_zero, TIME_3 as i64) .await .unwrap(); - insert_mempool_tx(&mut *conn, &txid3, TIME_3).await.unwrap(); + insert_mempool_tx(&mut *conn, &txid4, TIME_4).await.unwrap(); insert_block_tx(&mut *conn, &txid4, &block_zero, TIME_4 as i64) .await .unwrap(); - insert_mempool_tx(&mut *conn, &txid4, TIME_4).await.unwrap(); // Insert pool_history_entry let pool1 = OutPointHash::from_inner([0x0a; 32]);