diff --git a/.github/workflows/build-release-binaries.yml b/.github/workflows/build-release-binaries.yml index ecfde0c8..bcd2c806 100644 --- a/.github/workflows/build-release-binaries.yml +++ b/.github/workflows/build-release-binaries.yml @@ -61,7 +61,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.70" + toolchain: "1.74" targets: armv7-unknown-linux-gnueabihf - name: Build ${{ matrix.target }} ${{ matrix.bin }} release binary diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b92d60de..7619754b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.70" + toolchain: "1.74" components: clippy,rustfmt - uses: Swatinem/rust-cache@v2.7.3 @@ -31,6 +31,22 @@ jobs: - name: Run clippy with all features enabled run: cargo clippy --workspace --all-targets --all-features -- -D warnings + check_stable: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4.1.1 + + - uses: dtolnay/rust-toolchain@stable + + - name: Override rust stable + run: | + rustup override set stable + + - name: Run cargo check on rust stable + run: cargo check --all-targets + + bdk_test: runs-on: ubuntu-latest steps: @@ -84,7 +100,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.70" + toolchain: "1.74" targets: armv7-unknown-linux-gnueabihf - name: Build binary diff --git a/.github/workflows/draft-new-release.yml b/.github/workflows/draft-new-release.yml index 48fb2d3a..09df0bd7 100644 --- a/.github/workflows/draft-new-release.yml +++ b/.github/workflows/draft-new-release.yml @@ -42,8 +42,8 @@ jobs: - name: Commit changelog and manifest files id: make-commit env: - DPRINT_VERSION: 0.39.1 - RUST_TOOLCHAIN: 1.70 + DPRINT_VERSION: "0.39.1" + RUST_TOOLCHAIN: "1.74" run: | rustup component add rustfmt --toolchain "$RUST_TOOLCHAIN-x86_64-unknown-linux-gnu" curl -fsSL https://dprint.dev/install.sh | sh -s $DPRINT_VERSION diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a299af8..e3e510a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- Minimum Supported Rust Version (MSRV) bumped to 1.70 +- Minimum Supported Rust Version (MSRV) bumped to 1.74 - Lowered default Bitcoin confirmation target for Bob to 1 to make sure Bitcoin transactions get confirmed in time - Added support for starting the CLI (using the `start-daemon` subcommand) as a Daemon that accepts JSON-RPC requests - Update monero-wallet-rpc version to v0.18.3.1 diff --git a/Cargo.lock b/Cargo.lock index 34ced0d5..435a86bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -347,6 +347,25 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" +dependencies = [ + "bincode_derive", + "serde", +] + +[[package]] +name = "bincode_derive" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e30759b3b99a1b802a7a3aa21c85c3ded5c28e1c83170d82d70f08bbf7f3e4c" +dependencies = [ + "virtue", +] + [[package]] name = "bit-set" version = "0.5.2" @@ -371,7 +390,7 @@ dependencies = [ "base64 0.13.1", "bech32", "bitcoin_hashes", - "secp256k1", + "secp256k1 0.24.1", "serde", ] @@ -1112,10 +1131,11 @@ checksum = "5caaa75cbd2b960ff1e5392d2cfb1f44717fffe12fc1f32b7b5d1267f99732a6" [[package]] name = "ecdsa_fun" -version = "0.7.1" -source = "git+https://github.com/LLFourn/secp256kfun#9657d8c12fd26df5e57254a0063eaf41082a38ca" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd850b7ece4e4ddaa1478d5de36b6d4d599f2d521f73456ca706b4e2b32a4ec" dependencies = [ - "bincode", + "bincode 1.3.3", "rand_chacha 0.3.1", "secp256kfun", "sigma_fun", @@ -1306,12 +1326,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - [[package]] name = "futures" version = "0.3.30" @@ -2589,7 +2603,6 @@ dependencies = [ "futures", "monero-rpc", "rand 0.7.3", - "spectral", "testcontainers", "tokio", "tracing", @@ -2723,42 +2736,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" -dependencies = [ - "num-integer", - "num-traits", - "rand 0.4.6", - "rustc-serialize", -] - -[[package]] -name = "num-complex" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" -dependencies = [ - "num-traits", - "rustc-serialize", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -2775,29 +2752,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", - "rustc-serialize", -] - [[package]] name = "num-traits" version = "0.2.15" @@ -3281,19 +3235,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", -] - [[package]] name = "rand" version = "0.7.3" @@ -3339,21 +3280,6 @@ dependencies = [ "rand_core 0.6.2", ] -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - [[package]] name = "rand_core" version = "0.5.1" @@ -3399,15 +3325,6 @@ dependencies = [ "rand_core 0.6.2", ] -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "redox_syscall" version = "0.2.10" @@ -3632,12 +3549,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" - [[package]] name = "rustc_version" version = "0.3.3" @@ -3825,7 +3736,27 @@ checksum = "ff55dc09d460954e9ef2fa8a7ced735a964be9981fd50e870b2b3b0705e14964" dependencies = [ "bitcoin_hashes", "rand 0.8.3", - "secp256k1-sys", + "secp256k1-sys 0.6.1", + "serde", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys 0.8.1", + "serde", +] + +[[package]] +name = "secp256k1" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +dependencies = [ + "secp256k1-sys 0.9.2", "serde", ] @@ -3839,17 +3770,49 @@ dependencies = [ ] [[package]] -name = "secp256kfun" -version = "0.7.1" -source = "git+https://github.com/LLFourn/secp256kfun#9657d8c12fd26df5e57254a0063eaf41082a38ca" +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" dependencies = [ + "cc", +] + +[[package]] +name = "secp256k1-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +dependencies = [ + "cc", +] + +[[package]] +name = "secp256kfun" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecc2adce3ef929c5dc7dacdd612d65ab98002ee18119215ce25d8054ed53c1a" +dependencies = [ + "bincode 2.0.0-rc.3", "digest 0.10.7", "rand_core 0.6.2", - "secp256k1", + "secp256k1 0.27.0", + "secp256k1 0.28.2", + "secp256kfun_arithmetic_macros", "serde", "subtle-ng", ] +[[package]] +name = "secp256kfun_arithmetic_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91b7c385a72530ebfe6010ff476ad9e235743fb33408a360052bb706f1481e1e" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "security-framework" version = "2.3.1" @@ -4091,8 +4054,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "sigma_fun" -version = "0.4.1" -source = "git+https://github.com/LLFourn/secp256kfun#9657d8c12fd26df5e57254a0063eaf41082a38ca" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8e9462de42c6f14c7e20154d18d8e9e8683750798885e76f06973317b1cb1d" dependencies = [ "curve25519-dalek-ng", "digest 0.10.7", @@ -4217,15 +4181,6 @@ dependencies = [ "sha-1", ] -[[package]] -name = "spectral" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3c15181f4b14e52eeaac3efaeec4d2764716ce9c86da0c934c3e318649c5ba" -dependencies = [ - "num", -] - [[package]] name = "spin" version = "0.5.2" @@ -4488,7 +4443,6 @@ dependencies = [ "serial_test", "sha2 0.10.8", "sigma_fun", - "spectral", "sqlx", "structopt", "strum", @@ -5309,6 +5263,12 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +[[package]] +name = "virtue" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314" + [[package]] name = "void" version = "1.0.2" diff --git a/Cargo.toml b/Cargo.toml index 0f654d91..ab29e919 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "monero-harness", "monero-rpc", "swap", "monero-wallet" ] [patch.crates-io] diff --git a/README.md b/README.md index 71a37896..35adc5f0 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Please have a look at the [contribution guidelines](./CONTRIBUTING.md). ## Rust Version Support Please note that only the latest stable Rust toolchain is supported. -All stable toolchains since 1.70 _should_ work. +All stable toolchains since 1.74 _should_ work. ## Contact diff --git a/monero-harness/Cargo.toml b/monero-harness/Cargo.toml index 6780dbd8..a4c9ce72 100644 --- a/monero-harness/Cargo.toml +++ b/monero-harness/Cargo.toml @@ -10,7 +10,6 @@ anyhow = "1" futures = "0.3" monero-rpc = { path = "../monero-rpc" } rand = "0.7" -spectral = "0.6" testcontainers = "0.14" tokio = { version = "1", default-features = false, features = [ "rt-multi-thread", "time", "macros" ] } tracing = "0.1" diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index d5f8a513..61c12a27 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -225,7 +225,7 @@ impl<'c> Monerod { name: String, network: String, ) -> Result<(Self, Container<'c, image::Monerod>)> { - let image = image::Monerod::default(); + let image = image::Monerod; let image: RunnableImage = RunnableImage::from(image) .with_container_name(name.clone()) .with_network(network.clone()); diff --git a/monero-harness/tests/monerod.rs b/monero-harness/tests/monerod.rs index d218167b..f454fb74 100644 --- a/monero-harness/tests/monerod.rs +++ b/monero-harness/tests/monerod.rs @@ -1,6 +1,5 @@ use monero_harness::Monero; use monero_rpc::monerod::MonerodRpc as _; -use spectral::prelude::*; use std::time::Duration; use testcontainers::clients::Cli; use tokio::time; @@ -21,12 +20,12 @@ async fn init_miner_and_mine_to_miner_address() { let miner_wallet = monero.wallet("miner").unwrap(); let got_miner_balance = miner_wallet.balance().await.unwrap(); - assert_that!(got_miner_balance).is_greater_than(0); + assert!(got_miner_balance > 0); time::sleep(Duration::from_millis(1010)).await; // after a bit more than 1 sec another block should have been mined let block_height = monerod.client().get_block_count().await.unwrap().count; - assert_that(&block_height).is_greater_than(70); + assert!(block_height > 70); } diff --git a/monero-harness/tests/wallet.rs b/monero-harness/tests/wallet.rs index b25683ad..67d11645 100644 --- a/monero-harness/tests/wallet.rs +++ b/monero-harness/tests/wallet.rs @@ -1,6 +1,5 @@ use monero_harness::{Monero, MoneroWalletRpc}; use monero_rpc::wallet::MoneroWalletRpc as _; -use spectral::prelude::*; use std::time::Duration; use testcontainers::clients::Cli; use tokio::time::sleep; @@ -29,7 +28,7 @@ async fn fund_transfer_and_check_tx_key() { // check alice balance let got_alice_balance = alice_wallet.balance().await.unwrap(); - assert_that(&got_alice_balance).is_equal_to(fund_alice); + assert_eq!(got_alice_balance, fund_alice); // transfer from alice to bob let bob_address = bob_wallet.address().await.unwrap().address; @@ -41,7 +40,7 @@ async fn fund_transfer_and_check_tx_key() { wait_for_wallet_to_catch_up(bob_wallet, send_to_bob).await; let got_bob_balance = bob_wallet.balance().await.unwrap(); - assert_that(&got_bob_balance).is_equal_to(send_to_bob); + assert_eq!(got_bob_balance, send_to_bob); // check if tx was actually seen let tx_id = transfer.tx_hash; @@ -52,7 +51,7 @@ async fn fund_transfer_and_check_tx_key() { .await .expect("failed to check tx by key"); - assert_that!(res.received).is_equal_to(send_to_bob); + assert_eq!(res.received, send_to_bob); } async fn wait_for_wallet_to_catch_up(wallet: &MoneroWalletRpc, expected_balance: u64) { diff --git a/monero-wallet/src/lib.rs b/monero-wallet/src/lib.rs index 080c2599..7f2928c3 100644 --- a/monero-wallet/src/lib.rs +++ b/monero-wallet/src/lib.rs @@ -65,7 +65,7 @@ mod tests { #[tokio::test] async fn get_outs_for_key_offsets() { let cli = Cli::default(); - let container = cli.run(Monerod::default()); + let container = cli.run(Monerod); let rpc_client = Client::localhost(container.get_host_port_ipv4(18081)).unwrap(); rpc_client.generateblocks(150, "498AVruCDWgP9Az9LjMm89VWjrBrSZ2W2K3HFBiyzzrRjUJWUcCVxvY1iitfuKoek2FdX6MKGAD9Qb1G1P8QgR5jPmmt3Vj".to_owned()).await.unwrap(); let wallet = Wallet { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index d03c251b..cc47d97a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.70" # also update this in the readme, changelog, and github actions +channel = "1.74" # also update this in the readme, changelog, and github actions components = ["clippy"] targets = ["armv7-unknown-linux-gnueabihf"] diff --git a/swap/Cargo.toml b/swap/Cargo.toml index b73d61bb..3f9349d6 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -27,7 +27,7 @@ data-encoding = "2.6" dialoguer = "0.11" digest = "0.10.7" directories-next = "2" -ecdsa_fun = { git = "https://github.com/LLFourn/secp256kfun", default-features = false, features = [ "libsecp_compat", "serde", "adaptor" ] } +ecdsa_fun = { version = "0.10", default-features = false, features = [ "libsecp_compat", "serde", "adaptor" ] } ed25519-dalek = "1" futures = { version = "0.3", default-features = false } hex = "0.4" @@ -50,7 +50,7 @@ serde_cbor = "0.11" serde_json = "1" serde_with = { version = "1", features = [ "macros" ] } sha2 = "0.10" -sigma_fun = { git = "https://github.com/LLFourn/secp256kfun", default-features = false, features = [ "ed25519", "serde", "secp256k1", "alloc" ] } +sigma_fun = { version = "0.7", default-features = false, features = [ "ed25519", "serde", "secp256k1", "alloc" ] } sqlx = { version = "0.6.3", features = [ "sqlite", "runtime-tokio-rustls", "offline" ] } structopt = "0.3" strum = { version = "0.26", features = [ "derive" ] } @@ -88,7 +88,6 @@ proptest = "1" sequential-test = "0.2.4" serde_cbor = "0.11" serial_test = "3.0" -spectral = "0.6" tempfile = "3" testcontainers = "0.14" diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 4083f130..0d6de9a7 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -279,10 +279,10 @@ where SwarmEvent::IncomingConnectionError { send_back_addr: address, error, .. } => { tracing::warn!(%address, "Failed to set up connection with peer: {:#}", error); } - SwarmEvent::ConnectionClosed { peer_id: peer, num_established, endpoint, cause: Some(error) } if num_established == 0 => { + SwarmEvent::ConnectionClosed { peer_id: peer, num_established: 0, endpoint, cause: Some(error) } => { tracing::debug!(%peer, address = %endpoint.get_remote_address(), "Lost connection to peer: {:#}", error); } - SwarmEvent::ConnectionClosed { peer_id: peer, num_established, endpoint, cause: None } if num_established == 0 => { + SwarmEvent::ConnectionClosed { peer_id: peer, num_established: 0, endpoint, cause: None } => { tracing::info!(%peer, address = %endpoint.get_remote_address(), "Successfully closed connection"); } SwarmEvent::NewListenAddr{address, ..} => { @@ -296,7 +296,7 @@ where Some(Ok((peer, transfer_proof, responder))) => { if !self.swarm.behaviour_mut().transfer_proof.is_connected(&peer) { tracing::warn!(%peer, "No active connection to peer, buffering transfer proof"); - self.buffered_transfer_proofs.entry(peer).or_insert_with(Vec::new).push((transfer_proof, responder)); + self.buffered_transfer_proofs.entry(peer).or_default().push((transfer_proof, responder)); continue; } diff --git a/swap/src/asb/network.rs b/swap/src/asb/network.rs index 181ec9bc..7b85f8fb 100644 --- a/swap/src/asb/network.rs +++ b/swap/src/asb/network.rs @@ -302,7 +302,7 @@ pub mod rendezvous { fn inject_disconnected(&mut self, peer_id: &PeerId) { for i in 0..self.rendezvous_nodes.len() { - let mut node = &mut self.rendezvous_nodes[i]; + let node = &mut self.rendezvous_nodes[i]; if peer_id == &node.peer_id { node.connection_status = ConnectionStatus::Disconnected; } @@ -325,7 +325,7 @@ pub mod rendezvous { _error: &DialError, ) { for i in 0..self.rendezvous_nodes.len() { - let mut node = &mut self.rendezvous_nodes[i]; + let node = &mut self.rendezvous_nodes[i]; if let Some(id) = peer_id { if id == node.peer_id { node.connection_status = ConnectionStatus::Disconnected; diff --git a/swap/src/bitcoin.rs b/swap/src/bitcoin.rs index 556d8453..2d86d303 100644 --- a/swap/src/bitcoin.rs +++ b/swap/src/bitcoin.rs @@ -16,6 +16,7 @@ pub use crate::bitcoin::timelocks::{BlockHeight, ExpiredTimelocks}; pub use ::bitcoin::util::amount::Amount; pub use ::bitcoin::util::psbt::PartiallySignedTransaction; pub use ::bitcoin::{Address, AddressType, Network, Transaction, Txid}; +use bitcoin::secp256k1::ecdsa; pub use ecdsa_fun::adaptor::EncryptedSignature; pub use ecdsa_fun::fun::Scalar; pub use ecdsa_fun::Signature; @@ -25,9 +26,8 @@ pub use wallet::Wallet; pub use wallet::WalletBuilder; use crate::bitcoin::wallet::ScriptStatus; -use ::bitcoin::hashes::hex::ToHex; use ::bitcoin::hashes::Hash; -use ::bitcoin::{secp256k1, Sighash}; +use ::bitcoin::Sighash; use anyhow::{bail, Context, Result}; use bdk::miniscript::descriptor::Wsh; use bdk::miniscript::{Descriptor, Segwitv0}; @@ -206,20 +206,21 @@ pub fn verify_encsig( #[error("encrypted signature is invalid")] pub struct InvalidEncryptedSignature; -pub fn build_shared_output_descriptor(A: Point, B: Point) -> Descriptor { +pub fn build_shared_output_descriptor( + A: Point, + B: Point, +) -> Result> { const MINISCRIPT_TEMPLATE: &str = "c:and_v(v:pk(A),pk_k(B))"; - // NOTE: This shouldn't be a source of error, but maybe it is - let A = ToHex::to_hex(&secp256k1::PublicKey::from(A)); - let B = ToHex::to_hex(&secp256k1::PublicKey::from(B)); - - let miniscript = MINISCRIPT_TEMPLATE.replace('A', &A).replace('B', &B); + let miniscript = MINISCRIPT_TEMPLATE + .replace('A', &A.to_string()) + .replace('B', &B.to_string()); let miniscript = bdk::miniscript::Miniscript::::from_str(&miniscript) .expect("a valid miniscript"); - Descriptor::Wsh(Wsh::new(miniscript).expect("a valid descriptor")) + Ok(Descriptor::Wsh(Wsh::new(miniscript)?)) } pub fn recover(S: PublicKey, sig: Signature, encsig: EncryptedSignature) -> Result { @@ -305,6 +306,13 @@ pub mod bitcoin_address { } } +// Transform the ecdsa der signature bytes into a secp256kfun ecdsa signature type. +pub fn extract_ecdsa_sig(sig: &[u8]) -> Result { + let data = &sig[..sig.len() - 1]; + let sig = ecdsa::Signature::from_der(data)?.serialize_compact(); + Signature::from_bytes(sig).ok_or(anyhow::anyhow!("invalid signature")) +} + /// Bitcoin error codes: https://github.com/bitcoin/bitcoin/blob/97d3500601c1d28642347d014a6de1e38f53ae4e/src/rpc/protocol.h#L23 pub enum RpcErrorCode { /// Transaction or block was rejected by network rules. Error code -26. @@ -378,6 +386,8 @@ mod tests { use super::*; use crate::env::{GetConfig, Regtest}; use crate::protocol::{alice, bob}; + use bitcoin::secp256k1; + use ecdsa_fun::fun::marker::{NonZero, Public}; use rand::rngs::OsRng; use std::matches; use uuid::Uuid; @@ -524,4 +534,16 @@ mod tests { transaction ) } + + #[test] + fn compare_point_hex() { + // secp256kfun Point and secp256k1 PublicKey should have the same bytes and hex representation + let secp = secp256k1::Secp256k1::default(); + let keypair = secp256k1::KeyPair::new(&secp, &mut OsRng); + + let pubkey = keypair.public_key(); + let point: Point<_, Public, NonZero> = Point::from_bytes(pubkey.serialize()).unwrap(); + + assert_eq!(pubkey.to_string(), point.to_string()); + } } diff --git a/swap/src/bitcoin/cancel.rs b/swap/src/bitcoin/cancel.rs index aec3fe38..34612148 100644 --- a/swap/src/bitcoin/cancel.rs +++ b/swap/src/bitcoin/cancel.rs @@ -5,7 +5,8 @@ use crate::bitcoin::{ }; use ::bitcoin::util::sighash::SighashCache; use ::bitcoin::{ - EcdsaSighashType, OutPoint, PackedLockTime, Script, Sequence, Sighash, TxIn, TxOut, Txid, + secp256k1, EcdsaSighashType, OutPoint, PackedLockTime, Script, Sequence, Sighash, TxIn, TxOut, + Txid, }; use anyhow::Result; use bdk::miniscript::Descriptor; @@ -117,8 +118,8 @@ impl TxCancel { A: PublicKey, B: PublicKey, spending_fee: Amount, - ) -> Self { - let cancel_output_descriptor = build_shared_output_descriptor(A.0, B.0); + ) -> Result { + let cancel_output_descriptor = build_shared_output_descriptor(A.0, B.0)?; let tx_in = TxIn { previous_output: tx_lock.as_outpoint(), @@ -148,12 +149,12 @@ impl TxCancel { ) .expect("sighash"); - Self { + Ok(Self { inner: transaction, digest, output_descriptor: cancel_output_descriptor, lock_output_descriptor: tx_lock.output_descriptor.clone(), - } + }) } pub fn txid(&self) -> Txid { @@ -214,25 +215,27 @@ impl TxCancel { let A = ::bitcoin::PublicKey { compressed: true, - inner: A.0.into(), + inner: secp256k1::PublicKey::from_slice(&A.0.to_bytes())?, }; let B = ::bitcoin::PublicKey { compressed: true, - inner: B.0.into(), + inner: secp256k1::PublicKey::from_slice(&B.0.to_bytes())?, }; // The order in which these are inserted doesn't matter + let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?; + let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?; satisfier.insert( A, ::bitcoin::EcdsaSig { - sig: sig_a.into(), + sig: sig_a, hash_ty: EcdsaSighashType::All, }, ); satisfier.insert( B, ::bitcoin::EcdsaSig { - sig: sig_b.into(), + sig: sig_b, hash_ty: EcdsaSighashType::All, }, ); diff --git a/swap/src/bitcoin/lock.rs b/swap/src/bitcoin/lock.rs index f8aa9a39..0a9bd8f8 100644 --- a/swap/src/bitcoin/lock.rs +++ b/swap/src/bitcoin/lock.rs @@ -32,7 +32,7 @@ impl TxLock { C: EstimateFeeRate, D: BatchDatabase, { - let lock_output_descriptor = build_shared_output_descriptor(A.0, B.0); + let lock_output_descriptor = build_shared_output_descriptor(A.0, B.0)?; let address = lock_output_descriptor .address(wallet.get_network()) .expect("can derive address from descriptor"); @@ -84,7 +84,7 @@ impl TxLock { } }; - let descriptor = build_shared_output_descriptor(A.0, B.0); + let descriptor = build_shared_output_descriptor(A.0, B.0)?; let legit_shared_output_script = descriptor.script_pubkey(); if shared_output_candidate.script_pubkey != legit_shared_output_script { @@ -263,7 +263,7 @@ mod tests { fn estimated_tx_lock_script_size_never_changes(a in crate::proptest::ecdsa_fun::point(), b in crate::proptest::ecdsa_fun::point()) { proptest::prop_assume!(a != b); - let computed_size = build_shared_output_descriptor(a, b).script_pubkey().len(); + let computed_size = build_shared_output_descriptor(a, b).unwrap().script_pubkey().len(); assert_eq!(computed_size, SCRIPT_SIZE); } diff --git a/swap/src/bitcoin/punish.rs b/swap/src/bitcoin/punish.rs index 247c904f..9d687544 100644 --- a/swap/src/bitcoin/punish.rs +++ b/swap/src/bitcoin/punish.rs @@ -1,7 +1,7 @@ use crate::bitcoin::wallet::Watchable; use crate::bitcoin::{self, Address, Amount, PunishTimelock, Transaction, TxCancel, Txid}; use ::bitcoin::util::sighash::SighashCache; -use ::bitcoin::{EcdsaSighashType, Sighash}; +use ::bitcoin::{secp256k1, EcdsaSighashType, Sighash}; use anyhow::{Context, Result}; use bdk::bitcoin::Script; use bdk::miniscript::Descriptor; @@ -64,18 +64,20 @@ impl TxPunish { let A = a.public().try_into()?; let B = B.try_into()?; + let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?; + let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?; // The order in which these are inserted doesn't matter satisfier.insert( A, ::bitcoin::EcdsaSig { - sig: sig_a.into(), + sig: sig_a, hash_ty: EcdsaSighashType::All, }, ); satisfier.insert( B, ::bitcoin::EcdsaSig { - sig: sig_b.into(), + sig: sig_b, hash_ty: EcdsaSighashType::All, }, ); diff --git a/swap/src/bitcoin/redeem.rs b/swap/src/bitcoin/redeem.rs index e91c25ee..a6a55e4b 100644 --- a/swap/src/bitcoin/redeem.rs +++ b/swap/src/bitcoin/redeem.rs @@ -6,7 +6,7 @@ use crate::bitcoin::{ use ::bitcoin::{Sighash, Txid}; use anyhow::{bail, Context, Result}; use bdk::miniscript::Descriptor; -use bitcoin::secp256k1::ecdsa; +use bitcoin::secp256k1; use bitcoin::util::sighash::SighashCache; use bitcoin::{EcdsaSighashType, Script}; use ecdsa_fun::adaptor::{Adaptor, HashTranscript}; @@ -16,6 +16,8 @@ use ecdsa_fun::Signature; use sha2::Sha256; use std::collections::HashMap; +use super::extract_ecdsa_sig; + #[derive(Clone, Debug)] pub struct TxRedeem { inner: Transaction, @@ -64,7 +66,7 @@ impl TxRedeem { ) -> Result { verify_encsig( B, - PublicKey::from(s_a.clone()), + PublicKey::from(s_a), &self.digest(), &encrypted_signature, ) @@ -79,25 +81,27 @@ impl TxRedeem { let A = ::bitcoin::PublicKey { compressed: true, - inner: a.public.into(), + inner: secp256k1::PublicKey::from_slice(&a.public.to_bytes())?, }; let B = ::bitcoin::PublicKey { compressed: true, - inner: B.0.into(), + inner: secp256k1::PublicKey::from_slice(&B.0.to_bytes())?, }; + let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?; + let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?; // The order in which these are inserted doesn't matter satisfier.insert( A, ::bitcoin::EcdsaSig { - sig: sig_a.into(), + sig: sig_a, hash_ty: EcdsaSighashType::All, }, ); satisfier.insert( B, ::bitcoin::EcdsaSig { - sig: sig_b.into(), + sig: sig_b, hash_ty: EcdsaSighashType::All, }, ); @@ -120,16 +124,16 @@ impl TxRedeem { let input = match candidate_transaction.input.as_slice() { [input] => input, [] => bail!(NoInputs), - [inputs @ ..] => bail!(TooManyInputs(inputs.len())), + inputs => bail!(TooManyInputs(inputs.len())), }; - let sigs = match input.witness.iter().collect::>().as_slice() { + let sigs = match input.witness.to_vec().as_slice() { [sig_1, sig_2, _script] => [sig_1, sig_2] - .iter() - .map(|sig| ecdsa::Signature::from_der(&sig[..sig.len() - 1]).map(Signature::from)) - .collect::, _>>(), + .into_iter() + .map(|sig| extract_ecdsa_sig(sig)) + .collect::, _>>(), [] => bail!(EmptyWitnessStack), - [witnesses @ ..] => bail!(NotThreeWitnesses(witnesses.len())), + witnesses => bail!(NotThreeWitnesses(witnesses.len())), }?; let sig = sigs diff --git a/swap/src/bitcoin/refund.rs b/swap/src/bitcoin/refund.rs index a73dd0e3..ec9fc802 100644 --- a/swap/src/bitcoin/refund.rs +++ b/swap/src/bitcoin/refund.rs @@ -4,7 +4,7 @@ use crate::bitcoin::{ TooManyInputs, Transaction, TxCancel, }; use crate::{bitcoin, monero}; -use ::bitcoin::secp256k1::ecdsa; +use ::bitcoin::secp256k1; use ::bitcoin::util::sighash::SighashCache; use ::bitcoin::{EcdsaSighashType, Script, Sighash, Txid}; use anyhow::{bail, Context, Result}; @@ -12,6 +12,8 @@ use bdk::miniscript::Descriptor; use ecdsa_fun::Signature; use std::collections::HashMap; +use super::extract_ecdsa_sig; + #[derive(Debug)] pub struct TxRefund { inner: Transaction, @@ -62,25 +64,27 @@ impl TxRefund { let A = ::bitcoin::PublicKey { compressed: true, - inner: A.0.into(), + inner: secp256k1::PublicKey::from_slice(&A.0.to_bytes())?, }; let B = ::bitcoin::PublicKey { compressed: true, - inner: B.0.into(), + inner: secp256k1::PublicKey::from_slice(&B.0.to_bytes())?, }; + let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?; + let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?; // The order in which these are inserted doesn't matter satisfier.insert( A, ::bitcoin::EcdsaSig { - sig: sig_a.into(), + sig: sig_a, hash_ty: EcdsaSighashType::All, }, ); satisfier.insert( B, ::bitcoin::EcdsaSig { - sig: sig_b.into(), + sig: sig_b, hash_ty: EcdsaSighashType::All, }, ); @@ -127,16 +131,16 @@ impl TxRefund { let input = match candidate_transaction.input.as_slice() { [input] => input, [] => bail!(NoInputs), - [inputs @ ..] => bail!(TooManyInputs(inputs.len())), + inputs => bail!(TooManyInputs(inputs.len())), }; - let sigs = match input.witness.iter().collect::>().as_slice() { + let sigs = match input.witness.to_vec().as_slice() { [sig_1, sig_2, _script] => [sig_1, sig_2] - .iter() - .map(|sig| ecdsa::Signature::from_der(&sig[..sig.len() - 1]).map(Signature::from)) - .collect::, _>>(), + .into_iter() + .map(|sig| extract_ecdsa_sig(sig)) + .collect::, _>>(), [] => bail!(EmptyWitnessStack), - [witnesses @ ..] => bail!(NotThreeWitnesses(witnesses.len())), + witnesses => bail!(NotThreeWitnesses(witnesses.len())), }?; let sig = sigs diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index 5d8685f3..9748d740 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -65,9 +65,7 @@ impl Wallet { database, ) { Ok(w) => w, - Err(e) if matches!(e, bdk::Error::ChecksumMismatch) => { - Self::migrate(data_dir, xprivkey, network)? - } + Err(bdk::Error::ChecksumMismatch) => Self::migrate(data_dir, xprivkey, network)?, err => err?, }; diff --git a/swap/src/cli/event_loop.rs b/swap/src/cli/event_loop.rs index 23aa0f38..befe1dc5 100644 --- a/swap/src/cli/event_loop.rs +++ b/swap/src/cli/event_loop.rs @@ -168,7 +168,7 @@ impl EventLoop { tracing::info!("Successfully closed connection to Alice"); return; } - SwarmEvent::OutgoingConnectionError { peer_id, error } if matches!(peer_id, Some(alice_peer_id) if alice_peer_id == self.alice_peer_id) => { + SwarmEvent::OutgoingConnectionError { peer_id: Some(alice_peer_id), error } if alice_peer_id == self.alice_peer_id => { tracing::warn!(%error, "Failed to dial Alice"); if let Some(duration) = self.swarm.behaviour_mut().redial.until_next_redial() { diff --git a/swap/src/network/cbor_request_response.rs b/swap/src/network/cbor_request_response.rs index 18e193ee..634dd729 100644 --- a/swap/src/network/cbor_request_response.rs +++ b/swap/src/network/cbor_request_response.rs @@ -19,7 +19,7 @@ pub struct CborCodec { impl Default for CborCodec { fn default() -> Self { Self { - phantom: PhantomData::default(), + phantom: PhantomData, } } } diff --git a/swap/src/network/json_pull_codec.rs b/swap/src/network/json_pull_codec.rs index bf473e84..01fcf494 100644 --- a/swap/src/network/json_pull_codec.rs +++ b/swap/src/network/json_pull_codec.rs @@ -25,7 +25,7 @@ pub struct JsonPullCodec { impl Default for JsonPullCodec { fn default() -> Self { Self { - phantom: PhantomData::default(), + phantom: PhantomData, } } } diff --git a/swap/src/network/test.rs b/swap/src/network/test.rs index a5c316b1..5a324385 100644 --- a/swap/src/network/test.rs +++ b/swap/src/network/test.rs @@ -40,7 +40,7 @@ where .expect("failed to create dh_keys"); let noise = NoiseConfig::xx(dh_keys).into_authenticated(); - let transport = MemoryTransport::default() + let transport = MemoryTransport .or_transport(TokioTcpConfig::new()) .upgrade(Version::V1) .authenticate(noise) diff --git a/swap/src/protocol/alice/state.rs b/swap/src/protocol/alice/state.rs index b34e0326..b4e155a6 100644 --- a/swap/src/protocol/alice/state.rs +++ b/swap/src/protocol/alice/state.rs @@ -310,7 +310,8 @@ impl State2 { self.a.public(), self.B, self.tx_cancel_fee, - ); + ) + .expect("valid cancel tx"); let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); @@ -335,7 +336,7 @@ impl State2 { self.a.public(), self.B, self.tx_cancel_fee, - ); + )?; bitcoin::verify_sig(&self.B, &tx_cancel.digest(), &msg.tx_cancel_sig) .context("Failed to verify cancel transaction")?; let tx_punish = bitcoin::TxPunish::new( @@ -458,6 +459,7 @@ impl State3 { self.B, self.tx_cancel_fee, ) + .expect("valid cancel tx") } pub fn tx_refund(&self) -> TxRefund { diff --git a/swap/src/protocol/bob/state.rs b/swap/src/protocol/bob/state.rs index edf902b6..aa0045ea 100644 --- a/swap/src/protocol/bob/state.rs +++ b/swap/src/protocol/bob/state.rs @@ -243,7 +243,7 @@ impl State1 { self.A, self.b.public(), self.tx_cancel_fee, - ); + )?; let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); @@ -316,7 +316,8 @@ impl State2 { self.A, self.b.public(), self.tx_cancel_fee, - ); + ) + .expect("valid cancel tx"); let tx_cancel_sig = self.b.sign(tx_cancel.digest()); let tx_punish = bitcoin::TxPunish::new( &tx_cancel, @@ -450,7 +451,7 @@ impl State3 { self.A, self.b.public(), self.tx_cancel_fee, - ); + )?; let tx_lock_status = bitcoin_wallet.status_of_script(&self.tx_lock).await?; let tx_cancel_status = bitcoin_wallet.status_of_script(&tx_cancel).await?; @@ -531,7 +532,7 @@ impl State4 { self.A, self.b.public(), self.tx_cancel_fee, - ); + )?; let tx_lock_status = bitcoin_wallet.status_of_script(&self.tx_lock).await?; let tx_cancel_status = bitcoin_wallet.status_of_script(&tx_cancel).await?; @@ -612,7 +613,7 @@ impl State6 { self.A, self.b.public(), self.tx_cancel_fee, - ); + )?; let tx_lock_status = bitcoin_wallet.status_of_script(&self.tx_lock).await?; let tx_cancel_status = bitcoin_wallet.status_of_script(&tx_cancel).await?; @@ -635,7 +636,7 @@ impl State6 { self.A, self.b.public(), self.tx_cancel_fee, - ); + )?; let tx = bitcoin_wallet.get_raw_transaction(tx_cancel.txid()).await?; @@ -652,7 +653,7 @@ impl State6 { self.A, self.b.public(), self.tx_cancel_fee, - ) + )? .complete_as_bob(self.A, self.b.clone(), self.tx_cancel_sig_a.clone()) .context("Failed to complete Bitcoin cancel transaction")?; @@ -675,7 +676,7 @@ impl State6 { self.A, self.b.public(), self.tx_cancel_fee, - ); + )?; let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee);