From d1f6739e59ec854d003ed78a683573473bc998df Mon Sep 17 00:00:00 2001 From: rishflab Date: Wed, 13 Oct 2021 10:38:56 +1100 Subject: [PATCH] Remove support for the sled database --- CHANGELOG.md | 6 + Cargo.lock | 1 - swap/Cargo.toml | 1 - swap/src/asb/command.rs | 37 ---- swap/src/bin/asb.rs | 6 +- swap/src/bin/swap.rs | 15 +- swap/src/cli/command.rs | 27 --- swap/src/database.rs | 82 ++------ swap/src/database/sled.rs | 400 -------------------------------------- 9 files changed, 23 insertions(+), 552 deletions(-) delete mode 100644 swap/src/database/sled.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 736dc05e..8a959ede 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Removed + +- Support for the old sled database. + The ASB and CLI only support the new sqlite database. + If you haven't already, you can migrate your old data using the 0.9.0 release. + ### Changed - The ASB to no longer work as a rendezvous server. diff --git a/Cargo.lock b/Cargo.lock index 66175210..2e64f0dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3952,7 +3952,6 @@ dependencies = [ "serde_with", "sha2", "sigma_fun", - "sled", "spectral", "sqlx", "structopt", diff --git a/swap/Cargo.toml b/swap/Cargo.toml index b87fda1c..b7a9c2dc 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -48,7 +48,6 @@ serde_json = "1" serde_with = { version = "1", features = [ "macros" ] } sha2 = "0.9" sigma_fun = { git = "https://github.com/LLFourn/secp256kfun", default-features = false, features = [ "ed25519", "serde" ] } -sled = "0.34" sqlx = { version = "0.5", features = [ "sqlite", "runtime-tokio-rustls", "offline" ] } structopt = "0.3" strum = { version = "0.21", features = [ "derive" ] } diff --git a/swap/src/asb/command.rs b/swap/src/asb/command.rs index fba13667..7780fc56 100644 --- a/swap/src/asb/command.rs +++ b/swap/src/asb/command.rs @@ -21,7 +21,6 @@ where let json = args.json; let disable_timestamp = args.disable_timestamp; let testnet = args.testnet; - let sled = args.sled; let config = args.config; let command: RawCommand = args.cmd; @@ -30,7 +29,6 @@ where testnet, json, disable_timestamp, - sled, config_path: config_path(config, testnet)?, env_config: env_config(testnet), cmd: Command::Start { resume_only }, @@ -39,7 +37,6 @@ where testnet, json, disable_timestamp, - sled, config_path: config_path(config, testnet)?, env_config: env_config(testnet), cmd: Command::History, @@ -48,7 +45,6 @@ where testnet, json, disable_timestamp, - sled, config_path: config_path(config, testnet)?, env_config: env_config(testnet), cmd: Command::WithdrawBtc { @@ -60,7 +56,6 @@ where testnet, json, disable_timestamp, - sled, config_path: config_path(config, testnet)?, env_config: env_config(testnet), cmd: Command::Balance, @@ -68,7 +63,6 @@ where RawCommand::Config => Arguments { testnet, json, - sled, disable_timestamp, config_path: config_path(config, testnet)?, env_config: env_config(testnet), @@ -77,7 +71,6 @@ where RawCommand::ExportBitcoinWallet => Arguments { testnet, json, - sled, disable_timestamp, config_path: config_path(config, testnet)?, env_config: env_config(testnet), @@ -90,7 +83,6 @@ where testnet, json, disable_timestamp, - sled, config_path: config_path(config, testnet)?, env_config: env_config(testnet), cmd: Command::Redeem { @@ -105,7 +97,6 @@ where testnet, json, disable_timestamp, - sled, config_path: config_path(config, testnet)?, env_config: env_config(testnet), cmd: Command::Cancel { swap_id }, @@ -116,7 +107,6 @@ where testnet, json, disable_timestamp, - sled, config_path: config_path(config, testnet)?, env_config: env_config(testnet), cmd: Command::Refund { swap_id }, @@ -127,7 +117,6 @@ where testnet, json, disable_timestamp, - sled, config_path: config_path(config, testnet)?, env_config: env_config(testnet), cmd: Command::Punish { swap_id }, @@ -136,7 +125,6 @@ where testnet, json, disable_timestamp, - sled, config_path: config_path(config, testnet)?, env_config: env_config(testnet), cmd: Command::SafelyAbort { swap_id }, @@ -196,7 +184,6 @@ pub struct BitcoinAddressNetworkMismatch { pub struct Arguments { pub testnet: bool, pub json: bool, - pub sled: bool, pub disable_timestamp: bool, pub config_path: PathBuf, pub env_config: env::Config, @@ -259,13 +246,6 @@ pub struct RawArguments { )] pub disable_timestamp: bool, - #[structopt( - short, - long = "sled", - help = "Forces the asb to use the deprecated sled db if it is available" - )] - pub sled: bool, - #[structopt( long = "config", help = "Provide a custom path to the configuration file. The configuration file must be a toml file.", @@ -386,7 +366,6 @@ mod tests { let expected_args = Arguments { testnet: false, json: false, - sled: false, disable_timestamp: false, config_path: default_mainnet_conf_path, env_config: mainnet_env_config, @@ -405,7 +384,6 @@ mod tests { let expected_args = Arguments { testnet: false, json: false, - sled: false, disable_timestamp: false, config_path: default_mainnet_conf_path, env_config: mainnet_env_config, @@ -424,7 +402,6 @@ mod tests { let expected_args = Arguments { testnet: false, json: false, - sled: false, disable_timestamp: false, config_path: default_mainnet_conf_path, env_config: mainnet_env_config, @@ -447,7 +424,6 @@ mod tests { let expected_args = Arguments { testnet: false, json: false, - sled: false, disable_timestamp: false, config_path: default_mainnet_conf_path, env_config: mainnet_env_config, @@ -475,7 +451,6 @@ mod tests { let expected_args = Arguments { testnet: false, json: false, - sled: false, disable_timestamp: false, config_path: default_mainnet_conf_path, env_config: mainnet_env_config, @@ -502,7 +477,6 @@ mod tests { let expected_args = Arguments { testnet: false, json: false, - sled: false, disable_timestamp: false, config_path: default_mainnet_conf_path, env_config: mainnet_env_config, @@ -529,7 +503,6 @@ mod tests { let expected_args = Arguments { testnet: false, json: false, - sled: false, disable_timestamp: false, config_path: default_mainnet_conf_path, env_config: mainnet_env_config, @@ -556,7 +529,6 @@ mod tests { let expected_args = Arguments { testnet: false, json: false, - sled: false, disable_timestamp: false, config_path: default_mainnet_conf_path, env_config: mainnet_env_config, @@ -577,7 +549,6 @@ mod tests { let expected_args = Arguments { testnet: true, json: false, - sled: false, disable_timestamp: false, config_path: default_testnet_conf_path, env_config: testnet_env_config, @@ -596,7 +567,6 @@ mod tests { let expected_args = Arguments { testnet: true, json: false, - sled: false, disable_timestamp: false, config_path: default_testnet_conf_path, env_config: testnet_env_config, @@ -615,7 +585,6 @@ mod tests { let expected_args = Arguments { testnet: true, json: false, - sled: false, disable_timestamp: false, config_path: default_testnet_conf_path, env_config: testnet_env_config, @@ -640,7 +609,6 @@ mod tests { let expected_args = Arguments { testnet: true, json: false, - sled: false, disable_timestamp: false, config_path: default_testnet_conf_path, env_config: testnet_env_config, @@ -668,7 +636,6 @@ mod tests { let expected_args = Arguments { testnet: true, json: false, - sled: false, disable_timestamp: false, config_path: default_testnet_conf_path, env_config: testnet_env_config, @@ -696,7 +663,6 @@ mod tests { let expected_args = Arguments { testnet: true, json: false, - sled: false, disable_timestamp: false, config_path: default_testnet_conf_path, env_config: testnet_env_config, @@ -724,7 +690,6 @@ mod tests { let expected_args = Arguments { testnet: true, json: false, - sled: false, disable_timestamp: false, config_path: default_testnet_conf_path, env_config: testnet_env_config, @@ -752,7 +717,6 @@ mod tests { let expected_args = Arguments { testnet: true, json: false, - sled: false, disable_timestamp: false, config_path: default_testnet_conf_path, env_config: testnet_env_config, @@ -773,7 +737,6 @@ mod tests { let expected_args = Arguments { testnet: false, json: false, - sled: false, disable_timestamp: true, config_path: default_mainnet_conf_path, env_config: mainnet_env_config, diff --git a/swap/src/bin/asb.rs b/swap/src/bin/asb.rs index be8e2fcf..23300f20 100644 --- a/swap/src/bin/asb.rs +++ b/swap/src/bin/asb.rs @@ -47,7 +47,6 @@ async fn main() -> Result<()> { testnet, json, disable_timestamp, - sled, config_path, env_config, cmd, @@ -92,10 +91,7 @@ async fn main() -> Result<()> { )); } - let db_path = config.data.dir.join("database"); - let sled_path = config.data.dir.join(db_path); - - let db = open_db(sled_path, config.data.dir.join("sqlite"), sled).await?; + let db = open_db(config.data.dir.join("sqlite")).await?; let seed = Seed::from_file_or_generate(&config.data.dir).expect("Could not retrieve/initialize seed"); diff --git a/swap/src/bin/swap.rs b/swap/src/bin/swap.rs index ffbb49d0..c41212bb 100644 --- a/swap/src/bin/swap.rs +++ b/swap/src/bin/swap.rs @@ -45,7 +45,6 @@ async fn main() -> Result<()> { data_dir, debug, json, - sled, cmd, } = match parse_args_and_apply_defaults(env::args_os())? { ParseResult::Arguments(args) => args, @@ -68,7 +67,7 @@ async fn main() -> Result<()> { let swap_id = Uuid::new_v4(); cli::tracing::init(debug, json, data_dir.join("logs"), Some(swap_id))?; - let db = open_db(data_dir.join("database"), data_dir.join("sqlite"), sled).await?; + let db = open_db(data_dir.join("sqlite")).await?; let seed = Seed::from_file_or_generate(data_dir.as_path()) .context("Failed to read in seed file")?; @@ -139,7 +138,7 @@ async fn main() -> Result<()> { } } Command::History => { - let db = open_db(data_dir.join("database"), data_dir.join("sqlite"), sled).await?; + let db = open_db(data_dir.join("sqlite")).await?; let mut table = Table::new(); table.set_header(vec!["SWAP ID", "STATE"]); @@ -157,10 +156,6 @@ async fn main() -> Result<()> { "Log files locations: {}", format!("{}/wallet", data_dir.display()) ); - println!( - "Sled folder location: {}", - format!("{}/database", data_dir.display()) - ); println!( "Sqlite file location: {}", format!("{}/sqlite", data_dir.display()) @@ -240,7 +235,7 @@ async fn main() -> Result<()> { tor_socks5_port, } => { cli::tracing::init(debug, json, data_dir.join("logs"), Some(swap_id))?; - let db = open_db(data_dir.join("database"), data_dir.join("sqlite"), sled).await?; + let db = open_db(data_dir.join("sqlite")).await?; let seed = Seed::from_file_or_generate(data_dir.as_path()) .context("Failed to read in seed file")?; @@ -302,7 +297,7 @@ async fn main() -> Result<()> { bitcoin_target_block, } => { cli::tracing::init(debug, json, data_dir.join("logs"), Some(swap_id))?; - let db = open_db(data_dir.join("database"), data_dir.join("sqlite"), sled).await?; + let db = open_db(data_dir.join("sqlite")).await?; let seed = Seed::from_file_or_generate(data_dir.as_path()) .context("Failed to read in seed file")?; @@ -324,7 +319,7 @@ async fn main() -> Result<()> { bitcoin_target_block, } => { cli::tracing::init(debug, json, data_dir.join("logs"), Some(swap_id))?; - let db = open_db(data_dir.join("database"), data_dir.join("sqlite"), sled).await?; + let db = open_db(data_dir.join("sqlite")).await?; let seed = Seed::from_file_or_generate(data_dir.as_path()) .context("Failed to read in seed file")?; diff --git a/swap/src/cli/command.rs b/swap/src/cli/command.rs index 10d3582e..491f3dea 100644 --- a/swap/src/cli/command.rs +++ b/swap/src/cli/command.rs @@ -33,7 +33,6 @@ pub struct Arguments { pub env_config: env::Config, pub debug: bool, pub json: bool, - pub sled: bool, pub data_dir: PathBuf, pub cmd: Command, } @@ -67,7 +66,6 @@ where let debug = args.debug; let json = args.json; - let sled = args.sled; let is_testnet = args.testnet; let data = args.data; @@ -92,7 +90,6 @@ where env_config: env_config_from(is_testnet), debug, json, - sled, data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::BuyXmr { seller, @@ -109,7 +106,6 @@ where env_config: env_config_from(is_testnet), debug, json, - sled, data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::History, }, @@ -117,7 +113,6 @@ where env_config: env_config_from(is_testnet), debug, json, - sled, data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::Config, }, @@ -135,7 +130,6 @@ where env_config: env_config_from(is_testnet), debug, json, - sled, data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::Balance { bitcoin_electrum_rpc_url, @@ -155,7 +149,6 @@ where env_config: env_config_from(is_testnet), debug, json, - sled, data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::WithdrawBtc { bitcoin_electrum_rpc_url, @@ -179,7 +172,6 @@ where env_config: env_config_from(is_testnet), debug, json, - sled, data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::Resume { swap_id, @@ -201,7 +193,6 @@ where env_config: env_config_from(is_testnet), debug, json, - sled, data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::Cancel { swap_id, @@ -221,7 +212,6 @@ where env_config: env_config_from(is_testnet), debug, json, - sled, data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::Refund { swap_id, @@ -237,7 +227,6 @@ where env_config: env_config_from(is_testnet), debug, json, - sled, data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::ListSellers { rendezvous_point, @@ -253,7 +242,6 @@ where env_config: env_config_from(is_testnet), debug, json, - sled, data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::ExportBitcoinWallet { bitcoin_electrum_rpc_url, @@ -349,13 +337,6 @@ struct RawArguments { )] json: bool, - #[structopt( - short, - long = "sled", - help = "Forces the swap-cli to use the deprecated sled db if it is available" - )] - sled: bool, - #[structopt(subcommand)] cmd: RawCommand, } @@ -1164,7 +1145,6 @@ mod tests { env_config: env::Testnet::get_config(), debug: false, json: false, - sled: false, data_dir: data_dir_path_cli().join(TESTNET), cmd: Command::BuyXmr { seller: Multiaddr::from_str(MULTI_ADDRESS).unwrap(), @@ -1185,7 +1165,6 @@ mod tests { env_config: env::Mainnet::get_config(), debug: false, json: false, - sled: false, data_dir: data_dir_path_cli().join(MAINNET), cmd: Command::BuyXmr { seller: Multiaddr::from_str(MULTI_ADDRESS).unwrap(), @@ -1205,7 +1184,6 @@ mod tests { env_config: env::Testnet::get_config(), debug: false, json: false, - sled: false, data_dir: data_dir_path_cli().join(TESTNET), cmd: Command::Resume { swap_id: Uuid::from_str(SWAP_ID).unwrap(), @@ -1223,7 +1201,6 @@ mod tests { env_config: env::Mainnet::get_config(), debug: false, json: false, - sled: false, data_dir: data_dir_path_cli().join(MAINNET), cmd: Command::Resume { swap_id: Uuid::from_str(SWAP_ID).unwrap(), @@ -1240,7 +1217,6 @@ mod tests { env_config: env::Testnet::get_config(), debug: false, json: false, - sled: false, data_dir: data_dir_path_cli().join(TESTNET), cmd: Command::Cancel { swap_id: Uuid::from_str(SWAP_ID).unwrap(), @@ -1256,7 +1232,6 @@ mod tests { env_config: env::Mainnet::get_config(), debug: false, json: false, - sled: false, data_dir: data_dir_path_cli().join(MAINNET), cmd: Command::Cancel { swap_id: Uuid::from_str(SWAP_ID).unwrap(), @@ -1271,7 +1246,6 @@ mod tests { env_config: env::Testnet::get_config(), debug: false, json: false, - sled: false, data_dir: data_dir_path_cli().join(TESTNET), cmd: Command::Refund { swap_id: Uuid::from_str(SWAP_ID).unwrap(), @@ -1287,7 +1261,6 @@ mod tests { env_config: env::Mainnet::get_config(), debug: false, json: false, - sled: false, data_dir: data_dir_path_cli().join(MAINNET), cmd: Command::Refund { swap_id: Uuid::from_str(SWAP_ID).unwrap(), diff --git a/swap/src/database.rs b/swap/src/database.rs index d6c300c2..7af16196 100644 --- a/swap/src/database.rs +++ b/swap/src/database.rs @@ -1,4 +1,3 @@ -pub use self::sled::SledDatabase; pub use alice::Alice; pub use bob::Bob; pub use sqlite::SqliteDatabase; @@ -13,7 +12,6 @@ use std::sync::Arc; mod alice; mod bob; -mod sled; mod sqlite; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] @@ -85,74 +83,16 @@ impl Swap { } } -pub async fn open_db( - sled_path: impl AsRef, - sqlite_path: impl AsRef, - force_sled: bool, -) -> Result> { - // if sled exists and sqlite doesnt exist try and migrate - // if sled and sqlite exists and the sled flag is set, use sled - // if sled and sqlite exists, use sqlite - match ( - sled_path.as_ref().exists(), - sqlite_path.as_ref().exists(), - force_sled, - ) { - (true, false, false) => { - tracing::info!("Attempting to migrate old data to the new sqlite database..."); - let sled_db = SledDatabase::open(sled_path.as_ref()).await?; - - ensure_directory_exists(sqlite_path.as_ref())?; - tokio::fs::File::create(&sqlite_path).await?; - let sqlite = SqliteDatabase::open(sqlite_path).await?; - - let swap_states = sled_db.all().await?; - for (swap_id, state) in swap_states.iter() { - sqlite.insert_latest_state(*swap_id, state.clone()).await?; - } - - let monero_addresses = sled_db.get_all_monero_addresses(); - for (swap_id, monero_address) in monero_addresses.flatten() { - sqlite - .insert_monero_address(swap_id, monero_address) - .await?; - } - - let peer_addresses = sled_db.get_all_addresses(); - for (peer_id, addresses) in peer_addresses.flatten() { - for address in addresses { - sqlite.insert_address(peer_id, address).await?; - } - } - - let peers = sled_db.get_all_peers(); - for (swap_id, peer_id) in peers.flatten() { - sqlite.insert_peer_id(swap_id, peer_id).await?; - } - - tracing::info!("Sucessfully migrated data to sqlite! Using sqlite."); - - Ok(Arc::new(sqlite)) - } - (_, false, false) => { - tracing::debug!("Creating and using new sqlite database."); - ensure_directory_exists(sqlite_path.as_ref())?; - tokio::fs::File::create(&sqlite_path).await?; - let sqlite = SqliteDatabase::open(sqlite_path).await?; - Ok(Arc::new(sqlite)) - } - (_, true, false) => { - tracing::debug!("Using existing sqlite database."); - let sqlite = SqliteDatabase::open(sqlite_path).await?; - Ok(Arc::new(sqlite)) - } - (false, _, true) => { - bail!("Sled database does not exist at specified location") - } - (true, _, true) => { - tracing::debug!("Sled flag set. Using sled database."); - let sled = SledDatabase::open(sled_path.as_ref()).await?; - Ok(Arc::new(sled)) - } +pub async fn open_db(sqlite_path: impl AsRef) -> Result> { + if sqlite_path.as_ref().exists() { + tracing::debug!("Using existing sqlite database."); + let sqlite = SqliteDatabase::open(sqlite_path).await?; + Ok(Arc::new(sqlite)) + } else { + tracing::debug!("Creating and using new sqlite database."); + ensure_directory_exists(sqlite_path.as_ref())?; + tokio::fs::File::create(&sqlite_path).await?; + let sqlite = SqliteDatabase::open(sqlite_path).await?; + Ok(Arc::new(sqlite)) } } diff --git a/swap/src/database/sled.rs b/swap/src/database/sled.rs deleted file mode 100644 index b1e2d9ab..00000000 --- a/swap/src/database/sled.rs +++ /dev/null @@ -1,400 +0,0 @@ -use crate::database::Swap; -use crate::protocol::{Database, State}; -use anyhow::{anyhow, Context, Result}; -use async_trait::async_trait; -use libp2p::{Multiaddr, PeerId}; -use serde::de::DeserializeOwned; -use serde::Serialize; -use std::path::Path; -use std::str::FromStr; -use uuid::Uuid; - -pub use crate::database::alice::Alice; -pub use crate::database::bob::Bob; - -pub struct SledDatabase { - swaps: sled::Tree, - peers: sled::Tree, - addresses: sled::Tree, - monero_addresses: sled::Tree, -} - -#[async_trait] -impl Database for SledDatabase { - async fn insert_peer_id(&self, swap_id: Uuid, peer_id: PeerId) -> Result<()> { - let peer_id_str = peer_id.to_string(); - - let key = serialize(&swap_id)?; - let value = serialize(&peer_id_str).context("Could not serialize peer-id")?; - - self.peers.insert(key, value)?; - - self.peers - .flush_async() - .await - .map(|_| ()) - .context("Could not flush db") - } - - async fn get_peer_id(&self, swap_id: Uuid) -> Result { - let key = serialize(&swap_id)?; - - let encoded = self - .peers - .get(&key)? - .ok_or_else(|| anyhow!("No peer-id found for swap id {} in database", swap_id))?; - - let peer_id: String = deserialize(&encoded).context("Could not deserialize peer-id")?; - Ok(PeerId::from_str(peer_id.as_str())?) - } - - async fn insert_monero_address(&self, swap_id: Uuid, address: monero::Address) -> Result<()> { - let key = swap_id.as_bytes(); - let value = serialize(&address)?; - - self.monero_addresses.insert(key, value)?; - - self.monero_addresses - .flush_async() - .await - .map(|_| ()) - .context("Could not flush db") - } - - async fn get_monero_address(&self, swap_id: Uuid) -> Result { - let encoded = self - .monero_addresses - .get(swap_id.as_bytes())? - .ok_or_else(|| { - anyhow!( - "No Monero address found for swap id {} in database", - swap_id - ) - })?; - - let monero_address = deserialize(&encoded)?; - - Ok(monero_address) - } - - async fn insert_address(&self, peer_id: PeerId, address: Multiaddr) -> Result<()> { - let key = peer_id.to_bytes(); - - let existing_addresses = self.addresses.get(&key)?; - - let new_addresses = { - let existing_addresses = existing_addresses.clone(); - - Some(match existing_addresses { - Some(encoded) => { - let mut addresses = deserialize::>(&encoded)?; - addresses.push(address); - - serialize(&addresses)? - } - None => serialize(&[address])?, - }) - }; - - self.addresses - .compare_and_swap(key, existing_addresses, new_addresses)??; - - self.addresses - .flush_async() - .await - .map(|_| ()) - .context("Could not flush db") - } - - async fn get_addresses(&self, peer_id: PeerId) -> Result> { - let key = peer_id.to_bytes(); - - let addresses = match self.addresses.get(&key)? { - Some(encoded) => deserialize(&encoded).context("Failed to deserialize addresses")?, - None => vec![], - }; - - Ok(addresses) - } - - async fn insert_latest_state(&self, swap_id: Uuid, state: State) -> Result<()> { - let key = serialize(&swap_id)?; - let swap = Swap::from(state); - let new_value = serialize(&swap).context("Could not serialize new state value")?; - - let old_value = self.swaps.get(&key)?; - - self.swaps - .compare_and_swap(key, old_value, Some(new_value)) - .context("Could not write in the DB")? - .context("Stored swap somehow changed, aborting saving")?; - - self.swaps - .flush_async() - .await - .map(|_| ()) - .context("Could not flush db") - } - - async fn get_state(&self, swap_id: Uuid) -> Result { - let key = serialize(&swap_id)?; - - let encoded = self - .swaps - .get(&key)? - .ok_or_else(|| anyhow!("Swap with id {} not found in database", swap_id))?; - - let swap = deserialize::(&encoded).context("Could not deserialize state")?; - - let state = State::from(swap); - - Ok(state) - } - - async fn all(&self) -> Result> { - self.all_iter().collect() - } -} - -impl SledDatabase { - pub async fn open(path: &Path) -> Result { - tracing::debug!("Opening database at {}", path.display()); - - let db = - sled::open(path).with_context(|| format!("Could not open the DB at {:?}", path))?; - - let swaps = db.open_tree("swaps")?; - let peers = db.open_tree("peers")?; - let addresses = db.open_tree("addresses")?; - let monero_addresses = db.open_tree("monero_addresses")?; - - Ok(SledDatabase { - swaps, - peers, - addresses, - monero_addresses, - }) - } - - pub fn get_all_peers(&self) -> impl Iterator> { - self.peers.iter().map(|item| { - let (key, value) = item.context("Failed to retrieve peer id from DB")?; - - let swap_id = deserialize::(&key)?; - let peer_id_bytes = - deserialize::>(&value).context("Failed to deserialize swap")?; - - let peer_id = PeerId::from_bytes(&peer_id_bytes)?; - - Ok((swap_id, peer_id)) - }) - } - - pub fn get_all_addresses(&self) -> impl Iterator)>> { - self.addresses.iter().map(|item| { - let (key, value) = item.context("Failed to retrieve peer address from DB")?; - - let peer_id_bytes = deserialize::>(&key)?; - let addr = - deserialize::>(&value).context("Failed to deserialize swap")?; - - let peer_id = PeerId::from_bytes(&peer_id_bytes)?; - - Ok((peer_id, addr)) - }) - } - - pub fn get_all_monero_addresses( - &self, - ) -> impl Iterator> { - self.monero_addresses.iter().map(|item| { - let (key, value) = item.context("Failed to retrieve monero address from DB")?; - - let swap_id = deserialize::(&key)?; - let addr = - deserialize::(&value).context("Failed to deserialize swap")?; - - Ok((swap_id, addr)) - }) - } - - fn all_iter(&self) -> impl Iterator> { - self.swaps.iter().map(|item| { - let (key, value) = item.context("Failed to retrieve swap from DB")?; - - let swap_id = deserialize::(&key)?; - let swap = deserialize::(&value).context("Failed to deserialize swap")?; - - let state = State::from(swap); - - Ok((swap_id, state)) - }) - } -} - -pub fn serialize(t: &T) -> Result> -where - T: Serialize, -{ - Ok(serde_cbor::to_vec(t)?) -} - -pub fn deserialize(v: &[u8]) -> Result -where - T: DeserializeOwned, -{ - Ok(serde_cbor::from_slice(&v)?) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::protocol::alice::AliceState; - - #[tokio::test] - async fn can_write_and_read_to_multiple_keys() { - let db_dir = tempfile::tempdir().unwrap(); - let db = SledDatabase::open(db_dir.path()).await.unwrap(); - - let state_1 = State::from(AliceState::BtcRedeemed); - let swap_id_1 = Uuid::new_v4(); - db.insert_latest_state(swap_id_1, state_1.clone()) - .await - .expect("Failed to save second state"); - - let state_2 = State::from(AliceState::BtcPunished); - let swap_id_2 = Uuid::new_v4(); - db.insert_latest_state(swap_id_2, state_2.clone()) - .await - .expect("Failed to save first state"); - - let recovered_1 = db - .get_state(swap_id_1) - .await - .expect("Failed to recover first state"); - - let recovered_2 = db - .get_state(swap_id_2) - .await - .expect("Failed to recover second state"); - - assert_eq!(recovered_1, state_1); - assert_eq!(recovered_2, state_2); - } - - #[tokio::test] - async fn can_write_twice_to_one_key() { - let db_dir = tempfile::tempdir().unwrap(); - let db = SledDatabase::open(db_dir.path()).await.unwrap(); - - let state = State::from(AliceState::SafelyAborted); - - let swap_id = Uuid::new_v4(); - db.insert_latest_state(swap_id, state.clone()) - .await - .expect("Failed to save state the first time"); - let recovered = db - .get_state(swap_id) - .await - .expect("Failed to recover state the first time"); - - // We insert and recover twice to ensure database implementation allows the - // caller to write to an existing key - db.insert_latest_state(swap_id, recovered) - .await - .expect("Failed to save state the second time"); - let recovered = db - .get_state(swap_id) - .await - .expect("Failed to recover state the second time"); - - assert_eq!(recovered, state); - } - - #[tokio::test] - async fn can_save_swap_state_and_peer_id_with_same_swap_id() -> Result<()> { - let db_dir = tempfile::tempdir().unwrap(); - let db = SledDatabase::open(db_dir.path()).await.unwrap(); - - let alice_id = Uuid::new_v4(); - let alice_state = State::from(AliceState::BtcPunished); - let peer_id = PeerId::random(); - - db.insert_latest_state(alice_id, alice_state.clone()) - .await?; - db.insert_peer_id(alice_id, peer_id).await?; - - let loaded_swap = db.get_state(alice_id).await?; - let loaded_peer_id = db.get_peer_id(alice_id).await?; - - assert_eq!(alice_state, loaded_swap); - assert_eq!(peer_id, loaded_peer_id); - - Ok(()) - } - - #[tokio::test] - async fn test_reopen_db() -> Result<()> { - let db_dir = tempfile::tempdir().unwrap(); - let alice_id = Uuid::new_v4(); - let alice_state = State::from(AliceState::BtcPunished); - - let peer_id = PeerId::random(); - - { - let db = SledDatabase::open(db_dir.path()).await.unwrap(); - db.insert_latest_state(alice_id, alice_state.clone()) - .await?; - db.insert_peer_id(alice_id, peer_id).await?; - } - - let db = SledDatabase::open(db_dir.path()).await.unwrap(); - - let loaded_swap = db.get_state(alice_id).await?; - let loaded_peer_id = db.get_peer_id(alice_id).await?; - - assert_eq!(alice_state, loaded_swap); - assert_eq!(peer_id, loaded_peer_id); - - Ok(()) - } - - #[tokio::test] - async fn save_and_load_addresses() -> Result<()> { - let db_dir = tempfile::tempdir()?; - let peer_id = PeerId::random(); - let home1 = "/ip4/127.0.0.1/tcp/1".parse::()?; - let home2 = "/ip4/127.0.0.1/tcp/2".parse::()?; - - { - let db = SledDatabase::open(db_dir.path()).await?; - db.insert_address(peer_id, home1.clone()).await?; - db.insert_address(peer_id, home2.clone()).await?; - } - - let addresses = SledDatabase::open(db_dir.path()) - .await? - .get_addresses(peer_id) - .await?; - - assert_eq!(addresses, vec![home1, home2]); - - Ok(()) - } - - #[tokio::test] - async fn save_and_load_monero_address() -> Result<()> { - let db_dir = tempfile::tempdir()?; - let swap_id = Uuid::new_v4(); - - SledDatabase::open(db_dir.path()).await?.insert_monero_address(swap_id, "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a".parse()?).await?; - let loaded_monero_address = SledDatabase::open(db_dir.path()) - .await? - .get_monero_address(swap_id) - .await?; - - assert_eq!(loaded_monero_address.to_string(), "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a"); - - Ok(()) - } -}