|
3 | 3 | use crate::*;
|
4 | 4 | use core::str::FromStr;
|
5 | 5 |
|
6 |
| -use alloc::{borrow::ToOwned, boxed::Box, string::ToString, sync::Arc, vec::Vec}; |
| 6 | +use alloc::{ |
| 7 | + borrow::ToOwned, |
| 8 | + boxed::Box, |
| 9 | + string::{String, ToString}, |
| 10 | + sync::Arc, |
| 11 | + vec::Vec, |
| 12 | +}; |
7 | 13 | use bitcoin::consensus::{Decodable, Encodable};
|
8 | 14 | use rusqlite;
|
9 | 15 | use rusqlite::named_params;
|
@@ -55,17 +61,15 @@ fn set_schema_version(
|
55 | 61 | pub fn migrate_schema(
|
56 | 62 | db_tx: &Transaction,
|
57 | 63 | schema_name: &str,
|
58 |
| - versioned_scripts: &[&[&str]], |
| 64 | + versioned_scripts: &[String], |
59 | 65 | ) -> rusqlite::Result<()> {
|
60 | 66 | init_schemas_table(db_tx)?;
|
61 | 67 | let current_version = schema_version(db_tx, schema_name)?;
|
62 | 68 | let exec_from = current_version.map_or(0_usize, |v| v as usize + 1);
|
63 | 69 | let scripts_to_exec = versioned_scripts.iter().enumerate().skip(exec_from);
|
64 |
| - for (version, &script) in scripts_to_exec { |
| 70 | + for (version, script) in scripts_to_exec { |
65 | 71 | set_schema_version(db_tx, schema_name, version as u32)?;
|
66 |
| - for statement in script { |
67 |
| - db_tx.execute(statement, ())?; |
68 |
| - } |
| 72 | + db_tx.execute_batch(script)?; |
69 | 73 | }
|
70 | 74 | Ok(())
|
71 | 75 | }
|
@@ -205,57 +209,68 @@ impl tx_graph::ChangeSet<ConfirmationBlockTime> {
|
205 | 209 | /// Name of table that stores [`Anchor`]s.
|
206 | 210 | pub const ANCHORS_TABLE_NAME: &'static str = "bdk_anchors";
|
207 | 211 |
|
| 212 | + /// Get v0 of sqlite [tx_graph::ChangeSet] schema |
| 213 | + pub fn schema_v0() -> String { |
| 214 | + // full transactions |
| 215 | + let create_txs_table = format!( |
| 216 | + "CREATE TABLE {} ( \ |
| 217 | + txid TEXT PRIMARY KEY NOT NULL, \ |
| 218 | + raw_tx BLOB, \ |
| 219 | + last_seen INTEGER \ |
| 220 | + ) STRICT", |
| 221 | + Self::TXS_TABLE_NAME, |
| 222 | + ); |
| 223 | + // floating txouts |
| 224 | + let create_txouts_table = format!( |
| 225 | + "CREATE TABLE {} ( \ |
| 226 | + txid TEXT NOT NULL, \ |
| 227 | + vout INTEGER NOT NULL, \ |
| 228 | + value INTEGER NOT NULL, \ |
| 229 | + script BLOB NOT NULL, \ |
| 230 | + PRIMARY KEY (txid, vout) \ |
| 231 | + ) STRICT", |
| 232 | + Self::TXOUTS_TABLE_NAME, |
| 233 | + ); |
| 234 | + // anchors |
| 235 | + let create_anchors_table = format!( |
| 236 | + "CREATE TABLE {} ( \ |
| 237 | + txid TEXT NOT NULL REFERENCES {} (txid), \ |
| 238 | + block_height INTEGER NOT NULL, \ |
| 239 | + block_hash TEXT NOT NULL, \ |
| 240 | + anchor BLOB NOT NULL, \ |
| 241 | + PRIMARY KEY (txid, block_height, block_hash) \ |
| 242 | + ) STRICT", |
| 243 | + Self::ANCHORS_TABLE_NAME, |
| 244 | + Self::TXS_TABLE_NAME, |
| 245 | + ); |
| 246 | + |
| 247 | + format!("{create_txs_table}; {create_txouts_table}; {create_anchors_table}") |
| 248 | + } |
| 249 | + |
| 250 | + /// Get v1 of sqlite [tx_graph::ChangeSet] schema |
| 251 | + pub fn schema_v1() -> String { |
| 252 | + let add_confirmation_time_column = format!( |
| 253 | + "ALTER TABLE {} ADD COLUMN confirmation_time INTEGER DEFAULT -1 NOT NULL", |
| 254 | + Self::ANCHORS_TABLE_NAME, |
| 255 | + ); |
| 256 | + let extract_confirmation_time_from_anchor_column = format!( |
| 257 | + "UPDATE {} SET confirmation_time = json_extract(anchor, '$.confirmation_time')", |
| 258 | + Self::ANCHORS_TABLE_NAME, |
| 259 | + ); |
| 260 | + let drop_anchor_column = format!( |
| 261 | + "ALTER TABLE {} DROP COLUMN anchor", |
| 262 | + Self::ANCHORS_TABLE_NAME, |
| 263 | + ); |
| 264 | + format!("{add_confirmation_time_column}; {extract_confirmation_time_from_anchor_column}; {drop_anchor_column}") |
| 265 | + } |
| 266 | + |
208 | 267 | /// Initialize sqlite tables.
|
209 | 268 | pub fn init_sqlite_tables(db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> {
|
210 |
| - let schema_v0: &[&str] = &[ |
211 |
| - // full transactions |
212 |
| - &format!( |
213 |
| - "CREATE TABLE {} ( \ |
214 |
| - txid TEXT PRIMARY KEY NOT NULL, \ |
215 |
| - raw_tx BLOB, \ |
216 |
| - last_seen INTEGER \ |
217 |
| - ) STRICT", |
218 |
| - Self::TXS_TABLE_NAME, |
219 |
| - ), |
220 |
| - // floating txouts |
221 |
| - &format!( |
222 |
| - "CREATE TABLE {} ( \ |
223 |
| - txid TEXT NOT NULL, \ |
224 |
| - vout INTEGER NOT NULL, \ |
225 |
| - value INTEGER NOT NULL, \ |
226 |
| - script BLOB NOT NULL, \ |
227 |
| - PRIMARY KEY (txid, vout) \ |
228 |
| - ) STRICT", |
229 |
| - Self::TXOUTS_TABLE_NAME, |
230 |
| - ), |
231 |
| - // anchors |
232 |
| - &format!( |
233 |
| - "CREATE TABLE {} ( \ |
234 |
| - txid TEXT NOT NULL REFERENCES {} (txid), \ |
235 |
| - block_height INTEGER NOT NULL, \ |
236 |
| - block_hash TEXT NOT NULL, \ |
237 |
| - anchor BLOB NOT NULL, \ |
238 |
| - PRIMARY KEY (txid, block_height, block_hash) \ |
239 |
| - ) STRICT", |
240 |
| - Self::ANCHORS_TABLE_NAME, |
241 |
| - Self::TXS_TABLE_NAME, |
242 |
| - ), |
243 |
| - ]; |
244 |
| - let schema_v1: &[&str] = &[ |
245 |
| - &format!( |
246 |
| - "ALTER TABLE {} ADD COLUMN confirmation_time INTEGER DEFAULT -1 NOT NULL", |
247 |
| - Self::ANCHORS_TABLE_NAME, |
248 |
| - ), |
249 |
| - &format!( |
250 |
| - "UPDATE {} SET confirmation_time = json_extract(anchor, '$.confirmation_time')", |
251 |
| - Self::ANCHORS_TABLE_NAME, |
252 |
| - ), |
253 |
| - &format!( |
254 |
| - "ALTER TABLE {} DROP COLUMN anchor", |
255 |
| - Self::ANCHORS_TABLE_NAME, |
256 |
| - ), |
257 |
| - ]; |
258 |
| - migrate_schema(db_tx, Self::SCHEMA_NAME, &[schema_v0, schema_v1]) |
| 269 | + migrate_schema( |
| 270 | + db_tx, |
| 271 | + Self::SCHEMA_NAME, |
| 272 | + &[Self::schema_v0(), Self::schema_v1()], |
| 273 | + ) |
259 | 274 | }
|
260 | 275 |
|
261 | 276 | /// Construct a [`TxGraph`] from an sqlite database.
|
@@ -406,19 +421,21 @@ impl local_chain::ChangeSet {
|
406 | 421 | /// Name of sqlite table that stores blocks of [`LocalChain`](local_chain::LocalChain).
|
407 | 422 | pub const BLOCKS_TABLE_NAME: &'static str = "bdk_blocks";
|
408 | 423 |
|
| 424 | + /// Get v0 of sqlite [local_chain::ChangeSet] schema |
| 425 | + pub fn schema_v0() -> String { |
| 426 | + // blocks |
| 427 | + format!( |
| 428 | + "CREATE TABLE {} ( \ |
| 429 | + block_height INTEGER PRIMARY KEY NOT NULL, \ |
| 430 | + block_hash TEXT NOT NULL \ |
| 431 | + ) STRICT", |
| 432 | + Self::BLOCKS_TABLE_NAME, |
| 433 | + ) |
| 434 | + } |
| 435 | + |
409 | 436 | /// Initialize sqlite tables for persisting [`local_chain::LocalChain`].
|
410 | 437 | pub fn init_sqlite_tables(db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> {
|
411 |
| - let schema_v0: &[&str] = &[ |
412 |
| - // blocks |
413 |
| - &format!( |
414 |
| - "CREATE TABLE {} ( \ |
415 |
| - block_height INTEGER PRIMARY KEY NOT NULL, \ |
416 |
| - block_hash TEXT NOT NULL \ |
417 |
| - ) STRICT", |
418 |
| - Self::BLOCKS_TABLE_NAME, |
419 |
| - ), |
420 |
| - ]; |
421 |
| - migrate_schema(db_tx, Self::SCHEMA_NAME, &[schema_v0]) |
| 438 | + migrate_schema(db_tx, Self::SCHEMA_NAME, &[Self::schema_v0()]) |
422 | 439 | }
|
423 | 440 |
|
424 | 441 | /// Construct a [`LocalChain`](local_chain::LocalChain) from sqlite database.
|
@@ -480,20 +497,21 @@ impl keychain_txout::ChangeSet {
|
480 | 497 | /// Name for table that stores last revealed indices per descriptor id.
|
481 | 498 | pub const LAST_REVEALED_TABLE_NAME: &'static str = "bdk_descriptor_last_revealed";
|
482 | 499 |
|
| 500 | + /// Get v0 of sqlite [keychain_txout::ChangeSet] schema |
| 501 | + pub fn schema_v0() -> String { |
| 502 | + format!( |
| 503 | + "CREATE TABLE {} ( \ |
| 504 | + descriptor_id TEXT PRIMARY KEY NOT NULL, \ |
| 505 | + last_revealed INTEGER NOT NULL \ |
| 506 | + ) STRICT", |
| 507 | + Self::LAST_REVEALED_TABLE_NAME, |
| 508 | + ) |
| 509 | + } |
| 510 | + |
483 | 511 | /// Initialize sqlite tables for persisting
|
484 | 512 | /// [`KeychainTxOutIndex`](keychain_txout::KeychainTxOutIndex).
|
485 | 513 | pub fn init_sqlite_tables(db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> {
|
486 |
| - let schema_v0: &[&str] = &[ |
487 |
| - // last revealed |
488 |
| - &format!( |
489 |
| - "CREATE TABLE {} ( \ |
490 |
| - descriptor_id TEXT PRIMARY KEY NOT NULL, \ |
491 |
| - last_revealed INTEGER NOT NULL \ |
492 |
| - ) STRICT", |
493 |
| - Self::LAST_REVEALED_TABLE_NAME, |
494 |
| - ), |
495 |
| - ]; |
496 |
| - migrate_schema(db_tx, Self::SCHEMA_NAME, &[schema_v0]) |
| 514 | + migrate_schema(db_tx, Self::SCHEMA_NAME, &[Self::schema_v0()]) |
497 | 515 | }
|
498 | 516 |
|
499 | 517 | /// Construct [`KeychainTxOutIndex`](keychain_txout::KeychainTxOutIndex) from sqlite database
|
|
0 commit comments