]> Untitled Git - bdk/commitdiff
refactor(chain)!: impl sqlite for ConfirmationBlockTime anchored changesets
authornymius <155548262+nymius@users.noreply.github.com>
Wed, 27 Nov 2024 01:05:08 +0000 (22:05 -0300)
committernymius <155548262+nymius@users.noreply.github.com>
Wed, 4 Dec 2024 17:14:09 +0000 (14:14 -0300)
We want to not depend on serde_json. If we keep it around for
serializing anchors we won't be able to remove it in the future because
it will always be needed to do migrations.
Currently there is only one widely used anchor, ConfirmationBlockTime.

The desicion was to constrain support to just be for a single anchor
type ConfirmationBlockTime. The anchor table will represent all fields
of ConfirmationBlockTime, each one in its own column.

The reasons:

- No one is using rusqlite with any other anchor type, and if they are,
  they can do something custom anyway.
- The anchor representation may change in the future, supporting for
  multiple Anchor types here will cause more problems for migration
  later on.

crates/chain/src/rusqlite_impl.rs

index cf3d6bc9a1566657a6b8519f589090884f5cc035..6b7228273b45fb75975709f0294ebcd817adeb95 100644 (file)
@@ -211,10 +211,7 @@ fn to_sql_error<E: std::error::Error + Send + Sync + 'static>(err: E) -> rusqlit
     rusqlite::Error::ToSqlConversionFailure(Box::new(err))
 }
 
-impl<A> tx_graph::ChangeSet<A>
-where
-    A: Anchor + Clone + Ord + serde::Serialize + serde::de::DeserializeOwned,
-{
+impl tx_graph::ChangeSet<ConfirmationBlockTime> {
     /// Schema name for [`tx_graph::ChangeSet`].
     pub const SCHEMA_NAME: &'static str = "bdk_txgraph";
     /// Name of table that stores full transactions and `last_seen` timestamps.
@@ -260,7 +257,21 @@ where
                 Self::TXS_TABLE_NAME,
             ),
         ];
-        migrate_schema(db_tx, Self::SCHEMA_NAME, &[schema_v0])
+        let schema_v1: &[&str] = &[
+            &format!(
+                "ALTER TABLE {} ADD COLUMN confirmation_time INTEGER DEFAULT -1 NOT NULL",
+                Self::ANCHORS_TABLE_NAME,
+            ),
+            &format!(
+                "UPDATE {} SET confirmation_time = json_extract(anchor, '$.confirmation_time')",
+                Self::ANCHORS_TABLE_NAME,
+            ),
+            &format!(
+                "ALTER TABLE {} DROP COLUMN anchor",
+                Self::ANCHORS_TABLE_NAME,
+            ),
+        ];
+        migrate_schema(db_tx, Self::SCHEMA_NAME, &[schema_v0, schema_v1])
     }
 
     /// Construct a [`TxGraph`] from an sqlite database.
@@ -314,18 +325,26 @@ where
         }
 
         let mut statement = db_tx.prepare(&format!(
-            "SELECT json(anchor), txid FROM {}",
+            "SELECT block_hash, block_height, confirmation_time, txid FROM {}",
             Self::ANCHORS_TABLE_NAME,
         ))?;
         let row_iter = statement.query_map([], |row| {
             Ok((
-                row.get::<_, AnchorImpl<A>>("json(anchor)")?,
+                row.get::<_, Impl<bitcoin::BlockHash>>("block_hash")?,
+                row.get::<_, u32>("block_height")?,
+                row.get::<_, u64>("confirmation_time")?,
                 row.get::<_, Impl<bitcoin::Txid>>("txid")?,
             ))
         })?;
         for row in row_iter {
-            let (AnchorImpl(anchor), Impl(txid)) = row?;
-            changeset.anchors.insert((anchor, txid));
+            let (hash, height, confirmation_time, Impl(txid)) = row?;
+            changeset.anchors.insert((
+                ConfirmationBlockTime {
+                    block_id: BlockId::from((&height, &hash.0)),
+                    confirmation_time,
+                },
+                txid,
+            ));
         }
 
         Ok(changeset)
@@ -373,7 +392,7 @@ where
         }
 
         let mut statement = db_tx.prepare_cached(&format!(
-            "REPLACE INTO {}(txid, block_height, block_hash, anchor) VALUES(:txid, :block_height, :block_hash, jsonb(:anchor))",
+            "REPLACE INTO {}(txid, block_height, block_hash, confirmation_time) VALUES(:txid, :block_height, :block_hash, :confirmation_time)",
             Self::ANCHORS_TABLE_NAME,
         ))?;
         let mut statement_txid = db_tx.prepare_cached(&format!(
@@ -389,7 +408,7 @@ where
                 ":txid": Impl(*txid),
                 ":block_height": anchor_block.height,
                 ":block_hash": Impl(anchor_block.hash),
-                ":anchor": AnchorImpl(anchor.clone()),
+                ":confirmation_time": anchor.confirmation_time,
             })?;
         }