diff --git a/.github/workflows/build-release-binaries.yml b/.github/workflows/build-release-binaries.yml index 267b3173..9e303e5d 100644 --- a/.github/workflows/build-release-binaries.yml +++ b/.github/workflows/build-release-binaries.yml @@ -45,7 +45,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout tagged commit - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v3.2.0 with: ref: ${{ github.event.release.target_commitish }} token: ${{ secrets.BOTTY_GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d606e81..1e470729 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v3.2.0 - uses: Swatinem/rust-cache@v2.2.0 @@ -30,7 +30,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v3.2.0 - uses: Swatinem/rust-cache@v2.0.2 @@ -44,7 +44,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v3.2.0 - uses: Swatinem/rust-cache@v2.0.2 @@ -71,7 +71,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout sources - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v3.2.0 - uses: Swatinem/rust-cache@v2.2.0 @@ -116,7 +116,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout sources - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v3.2.0 - uses: Swatinem/rust-cache@v2.2.0 @@ -152,7 +152,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v3.2.0 - uses: Swatinem/rust-cache@v2.2.0 diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 42bc50f3..f8d8d3ba 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -11,7 +11,7 @@ jobs: if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v3.2.0 - name: Extract version from branch name id: extract-version diff --git a/.github/workflows/draft-new-release.yml b/.github/workflows/draft-new-release.yml index 9c64c127..448caa33 100644 --- a/.github/workflows/draft-new-release.yml +++ b/.github/workflows/draft-new-release.yml @@ -12,7 +12,7 @@ jobs: name: "Draft a new release" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v3.2.0 with: token: ${{ secrets.BOTTY_GITHUB_TOKEN }} @@ -54,7 +54,7 @@ jobs: run: git push origin release/${{ github.event.inputs.version }} --force - name: Create pull request - uses: thomaseizinger/create-pull-request@1.2.2 + uses: thomaseizinger/create-pull-request@1.3.0 with: GITHUB_TOKEN: ${{ secrets.BOTTY_GITHUB_TOKEN }} head: release/${{ github.event.inputs.version }} diff --git a/.github/workflows/preview-release.yml b/.github/workflows/preview-release.yml index 5d5ffe63..d261fa7a 100644 --- a/.github/workflows/preview-release.yml +++ b/.github/workflows/preview-release.yml @@ -10,7 +10,7 @@ jobs: name: Create preview release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v3.2.0 - name: Delete 'preview' release uses: larryjoelane/delete-release-action@v1.0.24 diff --git a/Cargo.lock b/Cargo.lock index 3232e4e4..dc5cd399 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,12 +93,6 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "arrayvec" version = "0.7.2" @@ -225,10 +219,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] -name = "bdk" -version = "0.24.0" +name = "base64" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50e3f08fbcd7eb34f11e066a1353986d583f1f87af70f7cd50bff9fce97c817" +checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" + +[[package]] +name = "bdk" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e7eb54c6288eca1b698e6e33dd82ebe6c08a93ec1a96bb6926ddceed22c703" dependencies = [ "async-trait", "bdk-macros", @@ -643,12 +643,14 @@ dependencies = [ [[package]] name = "config" -version = "0.11.0" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1b9d958c2b1368a663f05538fc1b5975adce1e19f435acceae987aceeeb369" +checksum = "d379af7f68bfc21714c6c7dea883544201741d2ce8274bb12fa54f89507f52a7" dependencies = [ + "async-trait", "lazy_static", - "nom 5.1.2", + "nom", + "pathdiff", "serde", "toml", ] @@ -939,10 +941,21 @@ dependencies = [ ] [[package]] -name = "data-encoding" -version = "2.3.2" +name = "dashmap" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" +checksum = "4c8858831f7781322e539ea39e72449c46b059638250c14344fec8d0aa6e539c" +dependencies = [ + "cfg-if 1.0.0", + "num_cpus", + "parking_lot 0.12.0", +] + +[[package]] +name = "data-encoding" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" [[package]] name = "derive_more" @@ -1024,7 +1037,7 @@ checksum = "5caaa75cbd2b960ff1e5392d2cfb1f44717fffe12fc1f32b7b5d1267f99732a6" [[package]] name = "ecdsa_fun" version = "0.7.1" -source = "git+https://github.com/LLFourn/secp256kfun#da6ffd2ef4d58c84d508428356c92d92d5f11ac4" +source = "git+https://github.com/LLFourn/secp256kfun#9657d8c12fd26df5e57254a0063eaf41082a38ca" dependencies = [ "bincode", "rand_chacha 0.3.1", @@ -1805,19 +1818,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lexical-core" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" -dependencies = [ - "arrayvec 0.5.2", - "bitflags", - "cfg-if 1.0.0", - "ryu", - "static_assertions", -] - [[package]] name = "libc" version = "0.2.137" @@ -2419,17 +2419,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" -[[package]] -name = "nom" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "lexical-core", - "memchr", - "version_check", -] - [[package]] name = "nom" version = "7.0.0" @@ -2532,9 +2521,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" dependencies = [ "hermit-abi", "libc", @@ -2644,6 +2633,12 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pem" version = "1.1.0" @@ -3261,7 +3256,7 @@ version = "1.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33c321ee4e17d2b7abe12b5d20c1231db708dd36185c8a21e9de5fed6da4dbe9" dependencies = [ - "arrayvec 0.7.2", + "arrayvec", "borsh", "bytecheck", "byteorder", @@ -3451,7 +3446,7 @@ dependencies = [ [[package]] name = "secp256kfun" version = "0.7.1" -source = "git+https://github.com/LLFourn/secp256kfun#da6ffd2ef4d58c84d508428356c92d92d5f11ac4" +source = "git+https://github.com/LLFourn/secp256kfun#9657d8c12fd26df5e57254a0063eaf41082a38ca" dependencies = [ "digest 0.10.5", "rand_core 0.6.2", @@ -3503,9 +3498,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.148" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" +checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91" dependencies = [ "serde_derive", ] @@ -3532,9 +3527,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.148" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c" +checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e" dependencies = [ "proc-macro2", "quote", @@ -3586,6 +3581,32 @@ dependencies = [ "syn", ] +[[package]] +name = "serial_test" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92761393ee4dc3ff8f4af487bd58f4307c9329bbedea02cac0089ad9c411e153" +dependencies = [ + "dashmap", + "futures", + "lazy_static", + "log", + "parking_lot 0.12.0", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6f5d1c3087fb119617cff2966fe3808a80e5eb59a8c1601d5994d66f4346a5" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sha-1" version = "0.9.4" @@ -3647,7 +3668,7 @@ dependencies = [ [[package]] name = "sigma_fun" version = "0.4.1" -source = "git+https://github.com/LLFourn/secp256kfun#da6ffd2ef4d58c84d508428356c92d92d5f11ac4" +source = "git+https://github.com/LLFourn/secp256kfun#9657d8c12fd26df5e57254a0063eaf41082a38ca" dependencies = [ "curve25519-dalek-ng", "digest 0.10.5", @@ -3807,7 +3828,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87e292b4291f154971a43c3774364e2cbcaec599d3f5bf6fa9d122885dbc38a" dependencies = [ "itertools", - "nom 7.0.0", + "nom", "unicode_categories", ] @@ -4002,7 +4023,7 @@ dependencies = [ "async-trait", "atty", "backoff", - "base64 0.13.1", + "base64 0.20.0", "bdk", "big-bytes", "bitcoin", @@ -4039,6 +4060,7 @@ dependencies = [ "serde_cbor", "serde_json", "serde_with", + "serial_test", "sha2 0.10.6", "sigma_fun", "spectral", @@ -4383,9 +4405,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" dependencies = [ "serde", ] diff --git a/swap/Cargo.toml b/swap/Cargo.toml index 7e23ef24..b6baa8dc 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -14,13 +14,13 @@ async-compression = { version = "0.3", features = [ "bzip2", "tokio" ] } async-trait = "0.1" atty = "0.2" backoff = { version = "0.4", features = [ "tokio" ] } -base64 = "0.13" -bdk = "0.24" +base64 = "0.20" +bdk = "0.25" big-bytes = "1" bitcoin = { version = "0.29", features = [ "rand", "serde" ] } bmrng = "0.5" comfy-table = "6.1" -config = { version = "0.11", default-features = false, features = [ "toml" ] } +config = { version = "0.13", default-features = false, features = [ "toml" ] } conquer-once = "0.3" curve25519-dalek = { package = "curve25519-dalek-ng", version = "4" } data-encoding = "2.3" @@ -81,10 +81,11 @@ monero-harness = { path = "../monero-harness" } port_check = "0.1" proptest = "1" serde_cbor = "0.11" +serial_test = "0.9" spectral = "0.6" tempfile = "3" testcontainers = "0.12" [build-dependencies] -vergen = { version = "7", default-features = false, features = [ "git", "build" ] } anyhow = "1" +vergen = { version = "7", default-features = false, features = [ "git", "build" ] } diff --git a/swap/src/asb/config.rs b/swap/src/asb/config.rs index 17c94691..9c2052bd 100644 --- a/swap/src/asb/config.rs +++ b/swap/src/asb/config.rs @@ -102,12 +102,27 @@ impl Config { { let config_file = Path::new(&config_file); - let mut config = config::Config::new(); - config.merge(config::File::from(config_file))?; + let config = config::Config::builder() + .add_source(config::File::from(config_file)) + .add_source( + config::Environment::with_prefix("ASB") + .separator("__") + .list_separator(","), + ) + .build()?; + config.try_into() } } +impl TryFrom for Config { + type Error = config::ConfigError; + + fn try_from(value: config::Config) -> Result { + value.try_deserialize() + } +} + #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct Data { @@ -117,13 +132,55 @@ pub struct Data { #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct Network { + #[serde(deserialize_with = "addr_list::deserialize")] pub listen: Vec, #[serde(default)] pub rendezvous_point: Option, - #[serde(default)] + #[serde(default, deserialize_with = "addr_list::deserialize")] pub external_addresses: Vec, } +mod addr_list { + use libp2p::Multiaddr; + use serde::de::Unexpected; + use serde::{de, Deserialize, Deserializer}; + use serde_json::Value; + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let s = Value::deserialize(deserializer)?; + return match s { + Value::String(s) => { + let list: Result, _> = s + .split(',') + .filter(|s| !s.is_empty()) + .map(|s| s.parse().map_err(de::Error::custom)) + .collect(); + Ok(list?) + } + Value::Array(a) => { + let list: Result, _> = a + .iter() + .map(|v| { + if let Value::String(s) = v { + s.parse().map_err(de::Error::custom) + } else { + Err(de::Error::custom("expected a string")) + } + }) + .collect(); + Ok(list?) + } + value => Err(de::Error::invalid_type( + Unexpected::Other(&value.to_string()), + &"a string or array", + )), + }; + } +} + #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct Bitcoin { @@ -172,7 +229,7 @@ impl Default for TorConf { #[derive(thiserror::Error, Debug, Clone, Copy)] #[error("config not initialized")] -pub struct ConfigNotInitialized {} +pub struct ConfigNotInitialized; pub fn read_config(config_path: PathBuf) -> Result> { if config_path.exists() { @@ -334,9 +391,12 @@ pub fn query_user_for_initial_config(testnet: bool) -> Result { #[cfg(test)] mod tests { use super::*; + use serial_test::serial; use tempfile::tempdir; + // these tests are run serially since env vars affect the whole process #[test] + #[serial] fn config_roundtrip_testnet() { let temp_dir = tempdir().unwrap().path().to_path_buf(); let config_path = Path::join(&temp_dir, "config.toml"); @@ -358,7 +418,6 @@ mod tests { rendezvous_point: None, external_addresses: vec![], }, - monero: Monero { wallet_rpc_url: defaults.monero_wallet_rpc_url, finality_confirmations: None, @@ -380,6 +439,7 @@ mod tests { } #[test] + #[serial] fn config_roundtrip_mainnet() { let temp_dir = tempdir().unwrap().path().to_path_buf(); let config_path = Path::join(&temp_dir, "config.toml"); @@ -401,7 +461,6 @@ mod tests { rendezvous_point: None, external_addresses: vec![], }, - monero: Monero { wallet_rpc_url: defaults.monero_wallet_rpc_url, finality_confirmations: None, @@ -421,4 +480,60 @@ mod tests { assert_eq!(expected, actual); } + + #[test] + #[serial] + fn env_override() { + let temp_dir = tempfile::tempdir().unwrap().path().to_path_buf(); + let config_path = Path::join(&temp_dir, "config.toml"); + + let defaults = Mainnet::getConfigFileDefaults().unwrap(); + + let dir = PathBuf::from("/tmp/dir"); + std::env::set_var("ASB__DATA__DIR", dir.clone()); + let addr1 = "/dns4/example.com/tcp/9939"; + let addr2 = "/ip4/1.2.3.4/tcp/9940"; + let external_addresses = vec![addr1.parse().unwrap(), addr2.parse().unwrap()]; + let listen = external_addresses.clone(); + std::env::set_var( + "ASB__NETWORK__EXTERNAL_ADDRESSES", + format!("{},{}", addr1, addr2), + ); + std::env::set_var("ASB__NETWORK__LISTEN", format!("{},{}", addr1, addr2)); + + let expected = Config { + data: Data { dir }, + bitcoin: Bitcoin { + electrum_rpc_url: defaults.electrum_rpc_url, + target_block: defaults.bitcoin_confirmation_target, + finality_confirmations: None, + network: bitcoin::Network::Bitcoin, + }, + network: Network { + listen, + rendezvous_point: None, + external_addresses, + }, + monero: Monero { + wallet_rpc_url: defaults.monero_wallet_rpc_url, + finality_confirmations: None, + network: monero::Network::Mainnet, + }, + tor: Default::default(), + maker: Maker { + min_buy_btc: bitcoin::Amount::from_btc(DEFAULT_MIN_BUY_AMOUNT).unwrap(), + max_buy_btc: bitcoin::Amount::from_btc(DEFAULT_MAX_BUY_AMOUNT).unwrap(), + ask_spread: Decimal::from_f64(DEFAULT_SPREAD).unwrap(), + price_ticker_ws_url: defaults.price_ticker_ws_url, + }, + }; + + initial_setup(config_path.clone(), expected.clone()).unwrap(); + let actual = read_config(config_path).unwrap().unwrap(); + + assert_eq!(expected, actual); + std::env::remove_var("ASB__DATA__DIR"); + std::env::remove_var("ASB__NETWORK__EXTERNAL_ADDRESSES"); + std::env::remove_var("ASB__NETWORK__LISTEN"); + } }