From 2a9bba4631b58e8e1d3e3a8c28e908cd154c2a84 Mon Sep 17 00:00:00 2001 From: yse Date: Fri, 29 Mar 2024 04:22:10 +0100 Subject: [PATCH] feat: add backup and restore functionality doc: add documentation for backup/restore fmt fix: simplify backup command --- cli/Cargo.lock | 20 ++--- cli/src/commands.rs | 15 ++++ lib/Cargo.lock | 103 ++++++++++++++------------ lib/Cargo.toml | 2 +- lib/ls-sdk-core/Cargo.toml | 4 +- lib/ls-sdk-core/README.md | 14 ++++ lib/ls-sdk-core/src/persist/backup.rs | 38 ++++++++++ lib/ls-sdk-core/src/persist/mod.rs | 5 +- lib/ls-sdk-core/src/wallet.rs | 16 ++++ 9 files changed, 154 insertions(+), 63 deletions(-) create mode 100644 lib/ls-sdk-core/src/persist/backup.rs diff --git a/cli/Cargo.lock b/cli/Cargo.lock index cc6da8eb5..90748b402 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -581,9 +581,9 @@ checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" [[package]] name = "fallible-iterator" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fallible-streaming-iterator" @@ -803,9 +803,9 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.8.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "692eaaf7f7607518dd3cef090f1474b61edc5301d8012f09579920df68b725ee" dependencies = [ "hashbrown", ] @@ -1023,9 +1023,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libsqlite3-sys" -version = "0.26.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" +checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" dependencies = [ "pkg-config", "vcpkg", @@ -1590,9 +1590,9 @@ dependencies = [ [[package]] name = "rusqlite" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" +checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" dependencies = [ "bitflags 2.5.0", "fallible-iterator", @@ -1604,9 +1604,9 @@ dependencies = [ [[package]] name = "rusqlite_migration" -version = "1.0.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef7dd29a4426624704d5966416682fb7ab3682f724986e9e3893eaca44accabc" +checksum = "55709bc01054c69e2f1cefdc886642b5e6376a8db3c86f761be0c423eebf178b" dependencies = [ "log", "rusqlite", diff --git a/cli/src/commands.rs b/cli/src/commands.rs index 51c45780f..03035d86a 100644 --- a/cli/src/commands.rs +++ b/cli/src/commands.rs @@ -41,6 +41,13 @@ pub(crate) enum Command { GetInfo, /// Empties the encrypted wallet transaction cache EmptyCache, + /// Backs up the current pending swaps + Backup, + /// Retrieve a list of backups + Restore { + #[arg(short, long)] + backup_path: Option, + }, } #[derive(Helper, Completer, Hinter, Validator)] @@ -151,6 +158,14 @@ pub(crate) fn handle_command( wallet.empty_wallet_cache()?; command_result!("Cache emptied successfully") } + Command::Backup => { + wallet.backup()?; + command_result!("Backup created successfully!") + } + Command::Restore { backup_path } => { + wallet.restore(backup_path)?; + command_result!("Backup restored successfully!") + } }) } diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 7794718c7..db61cc25b 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -413,9 +413,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.92" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" [[package]] name = "cfg-if" @@ -628,9 +628,9 @@ dependencies = [ [[package]] name = "fallible-iterator" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fallible-streaming-iterator" @@ -871,9 +871,9 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.8.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "692eaaf7f7607518dd3cef090f1474b61edc5301d8012f09579920df68b725ee" dependencies = [ "hashbrown", ] @@ -1082,9 +1082,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libsqlite3-sys" -version = "0.26.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" +checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" dependencies = [ "pkg-config", "vcpkg", @@ -1500,9 +1500,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] @@ -1699,9 +1699,9 @@ dependencies = [ [[package]] name = "rusqlite" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" +checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" dependencies = [ "bitflags 2.5.0", "fallible-iterator", @@ -1713,9 +1713,9 @@ dependencies = [ [[package]] name = "rusqlite_migration" -version = "1.0.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef7dd29a4426624704d5966416682fb7ab3682f724986e9e3893eaca44accabc" +checksum = "55709bc01054c69e2f1cefdc886642b5e6376a8db3c86f761be0c423eebf178b" dependencies = [ "log", "rusqlite", @@ -1742,9 +1742,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.10" +version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" dependencies = [ "log", "ring", @@ -1917,9 +1917,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ "serde_derive", ] @@ -1945,9 +1945,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ "proc-macro2", "quote", @@ -1956,9 +1956,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", @@ -2051,9 +2051,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "2.0.58" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -2701,7 +2701,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -2721,17 +2721,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -2742,9 +2743,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -2754,9 +2755,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -2766,9 +2767,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -2778,9 +2785,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -2790,9 +2797,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -2802,9 +2809,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -2814,9 +2821,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winreg" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index b84e00b52..8b125b9e1 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -15,4 +15,4 @@ uniffi = "0.27.1" uniffi_macros = "0.27.1" [patch.crates-io] -secp256k1-zkp = {git = "https://github.com/BlockstreamResearch/rust-secp256k1-zkp.git", rev = "60e631c24588a0c9e271badd61959294848c665d"} \ No newline at end of file +secp256k1-zkp = {git = "https://github.com/BlockstreamResearch/rust-secp256k1-zkp.git", rev = "60e631c24588a0c9e271badd61959294848c665d"} diff --git a/lib/ls-sdk-core/Cargo.toml b/lib/ls-sdk-core/Cargo.toml index 61cb460f2..7fda294bc 100644 --- a/lib/ls-sdk-core/Cargo.toml +++ b/lib/ls-sdk-core/Cargo.toml @@ -14,11 +14,11 @@ log = "0.4.20" lwk_common = "0.3.0" lwk_signer = "0.3.0" lwk_wollet = "0.3.0" -rusqlite = "0.29" +rusqlite = { version = "0.31", features = ["backup"] } rusqlite_migration = "1.0" serde = { version = "1.0.197", features = ["derive"] } thiserror = { workspace = true } [dev-dependencies] tempdir = "0.3.7" -uuid = { version = "1.8.0", features = ["v4"] } \ No newline at end of file +uuid = { version = "1.8.0", features = ["v4"] } diff --git a/lib/ls-sdk-core/README.md b/lib/ls-sdk-core/README.md index 5a1d6e76d..00dd0eb0d 100644 --- a/lib/ls-sdk-core/README.md +++ b/lib/ls-sdk-core/README.md @@ -8,6 +8,20 @@ Your system must have the sqlite3 development files installed: # On Debian sudo apt install libsqlite3-dev ``` +## Features + +### Backup/Restore +The wallet provides the ability to `backup` and `restore` ongoing swaps via the corresponding methods: +```rust +let mnemonic = "..."; +let data_dir = None; +let network = Network::LiquidTestnet; +let breez_wallet = Wallet::init(mnemonic, data_dir, network)?; + +breez_wallet.backup()?; // Backs up the pending swaps under `{data_dir}/backup.sql`. Overwrites previous versions. +let backup_path = None; // Can also be Some(String), a path pointing to the database. Default is `{data_dir}/backup.sql` +breez_wallet.restore(backup_path)?; // Restores the specified backup +``` ## Tests In order to run tests, you can execute `cargo test -- --nocapture --test-threads 1`. This is due to the fact that currently tests require some degree of interaction (e.g. adding the funding invoice) in order to work, and thus should be run with a single thread (sequentially). diff --git a/lib/ls-sdk-core/src/persist/backup.rs b/lib/ls-sdk-core/src/persist/backup.rs new file mode 100644 index 000000000..bc3c9eee0 --- /dev/null +++ b/lib/ls-sdk-core/src/persist/backup.rs @@ -0,0 +1,38 @@ +use anyhow::Result; +use rusqlite::{backup::Backup, Connection}; +use std::path::Path; + +use super::Persister; +use crate::Network; + +impl Persister { + pub(crate) fn backup(&self) -> Result<()> { + let con = self.get_connection()?; + + let backup_file = match self.network { + Network::Liquid => "backup.sql", + Network::LiquidTestnet => "backup-testnet.sql", + }; + + con.backup( + rusqlite::DatabaseName::Main, + self.main_db_dir.join(backup_file), + None, + )?; + + Ok(()) + } + + pub(crate) fn restore_from_backup

(&self, backup_path: P) -> Result<()> + where + P: AsRef, + { + let src_con = self.get_connection()?; + let mut dst_con = Connection::open(backup_path)?; + + let backup = Backup::new(&src_con, &mut dst_con)?; + backup.run_to_completion(5, std::time::Duration::from_millis(250), None)?; + + Ok(()) + } +} diff --git a/lib/ls-sdk-core/src/persist/mod.rs b/lib/ls-sdk-core/src/persist/mod.rs index 72345db69..31b2dacb1 100644 --- a/lib/ls-sdk-core/src/persist/mod.rs +++ b/lib/ls-sdk-core/src/persist/mod.rs @@ -1,3 +1,4 @@ +mod backup; mod migrations; use std::{collections::HashMap, fs::create_dir_all, path::PathBuf, str::FromStr}; @@ -10,8 +11,8 @@ use rusqlite_migration::{Migrations, M}; use crate::{Network, Network::*, OngoingSwap, PaymentData}; pub(crate) struct Persister { - main_db_dir: PathBuf, - network: Network, + pub main_db_dir: PathBuf, + pub network: Network, } impl Persister { diff --git a/lib/ls-sdk-core/src/wallet.rs b/lib/ls-sdk-core/src/wallet.rs index 40890277e..7da32ff18 100644 --- a/lib/ls-sdk-core/src/wallet.rs +++ b/lib/ls-sdk-core/src/wallet.rs @@ -1,6 +1,7 @@ use std::{ fs, path::PathBuf, + str::FromStr, sync::{Arc, Mutex}, thread, time::Duration, @@ -592,4 +593,19 @@ impl Wallet { Ok(()) } + + pub fn restore(&self, backup_path: Option) -> Result<()> { + let backup_path = match backup_path { + Some(p) => PathBuf::from_str(&p)?, + None => self.persister.main_db_dir.join(match self.network { + Network::Liquid => "backup.sql", + Network::LiquidTestnet => "backup-testnet.sql", + }), + }; + self.persister.restore_from_backup(backup_path) + } + + pub fn backup(&self) -> Result<()> { + self.persister.backup() + } }