diff --git a/.github/workflows/build-release-binaries.yml b/.github/workflows/build-release-binaries.yml index 8a35a88f..662e3a5e 100644 --- a/.github/workflows/build-release-binaries.yml +++ b/.github/workflows/build-release-binaries.yml @@ -22,6 +22,7 @@ jobs: - bin: swap target: x86_64-apple-darwin os: macos-12 + archive_ext: tar - bin: swap target: aarch64-apple-darwin os: macos-latest @@ -53,7 +54,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout tagged commit - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 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 cb869ccf..6b3fdbf3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - uses: dtolnay/rust-toolchain@master with: @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - uses: Swatinem/rust-cache@v2.7.3 @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - uses: Swatinem/rust-cache@v2.7.3 @@ -78,7 +78,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout sources - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - uses: Swatinem/rust-cache@v2.7.3 @@ -131,7 +131,7 @@ jobs: tool-cache: false - name: Checkout sources - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - uses: Swatinem/rust-cache@v2.7.3 @@ -164,11 +164,12 @@ jobs: ensure_same_swap_id, concurrent_bobs_before_xmr_lock_proof_sent, alice_manually_redeems_after_enc_sig_learned, + happy_path_bob_offline_while_alice_redeems_btc, ] runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - uses: Swatinem/rust-cache@v2.7.3 @@ -179,7 +180,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - uses: Swatinem/rust-cache@v2.7.3 @@ -190,7 +191,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 2e52519a..443c4418 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@v4.1.6 + - uses: actions/checkout@v4.1.7 - 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 09df0bd7..74ff34ba 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@v4.1.6 + - uses: actions/checkout@v4.1.7 with: token: ${{ secrets.BOTTY_GITHUB_TOKEN }} diff --git a/.github/workflows/preview-release.yml b/.github/workflows/preview-release.yml index 63ecfe6f..ccd7e641 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@v4.1.6 + - uses: actions/checkout@v4.1.7 - name: Delete 'preview' release uses: larryjoelane/delete-release-action@v1.0.24 diff --git a/CHANGELOG.md b/CHANGELOG.md index e3e510a9..e2c930c9 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] +## [0.13.1] - 2024-06-10 + +- Add retry logic to monero-wallet-rpc wallet refresh + +## [0.13.0] - 2024-05-29 + - 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 @@ -354,7 +360,9 @@ It is possible to migrate critical data from the old db to the sqlite but there - Fixed an issue where Alice would not verify if Bob's Bitcoin lock transaction is semantically correct, i.e. pays the agreed upon amount to an output owned by both of them. Fixing this required a **breaking change** on the network layer and hence old versions are not compatible with this version. -[Unreleased]: https://github.com/comit-network/xmr-btc-swap/compare/0.12.3...HEAD +[unreleased]: https://github.com/comit-network/xmr-btc-swap/compare/0.13.1...HEAD +[0.13.1]: https://github.com/comit-network/xmr-btc-swap/compare/0.13.0...0.13.1 +[0.13.0]: https://github.com/comit-network/xmr-btc-swap/compare/0.12.3...0.13.0 [0.12.3]: https://github.com/comit-network/xmr-btc-swap/compare/0.12.2...0.12.3 [0.12.2]: https://github.com/comit-network/xmr-btc-swap/compare/0.12.1...0.12.2 [0.12.1]: https://github.com/comit-network/xmr-btc-swap/compare/0.12.0...0.12.1 diff --git a/Cargo.lock b/Cargo.lock index 7ff2325a..a5e73dcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -267,12 +267,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -396,19 +390,21 @@ dependencies = [ [[package]] name = "bitcoin-harness" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b6a18713ec8acbc96d1e843f6998f00e8c5d81173e38760023b84926b8db3b8" +version = "0.2.1" +source = "git+https://github.com/delta1/bitcoin-harness-rs.git?rev=80cc8d05db2610d8531011be505b7bee2b5cdf9f#80cc8d05db2610d8531011be505b7bee2b5cdf9f" dependencies = [ "base64 0.12.3", "bitcoin", "bitcoincore-rpc-json", "futures", "hex", + "hmac 0.12.1", "jsonrpc_client", + "rand 0.8.3", "reqwest", "serde", "serde_json", + "sha2 0.10.8", "testcontainers", "thiserror", "tokio", @@ -496,11 +492,10 @@ dependencies = [ [[package]] name = "bollard-stubs" -version = "1.41.0" +version = "1.42.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2f2e73fffe9455141e170fb9c1feb0ac521ec7e7dcd47a7cab72a658490fb8" +checksum = "ed59b5c00048f48d7af971b71f800fdf23e858844a6f9e4d32ca72e9399e7864" dependencies = [ - "chrono", "serde", "serde_with", ] @@ -656,21 +651,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chacha20" -version = "0.7.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f08493fa7707effc63254c66c6ea908675912493cd67952eda23c09fae2610b1" +checksum = "fee7ad89dc1128635074c268ee661f90c3f7e83d9fd12910608c36b47d6c3412" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures 0.2.1", + "cpufeatures 0.1.4", "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.8.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6547abe025f4027edacd9edaa357aded014eecec42a5070d9b885c3c334aba2" +checksum = "1580317203210c517b6d44794abfbe600698276db18127e37ad3e69bf5e848e5" dependencies = [ "aead", "chacha20", @@ -688,8 +683,6 @@ dependencies = [ "libc", "num-integer", "num-traits", - "serde", - "time 0.1.43", "winapi", ] @@ -750,7 +743,7 @@ dependencies = [ "nom", "pathdiff", "serde", - "toml 0.8.13", + "toml 0.8.14", ] [[package]] @@ -945,9 +938,9 @@ dependencies = [ [[package]] name = "crypto-mac" -version = "0.11.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" dependencies = [ "generic-array", "subtle", @@ -1197,15 +1190,6 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" -[[package]] -name = "encoding_rs" -version = "0.8.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "enum-as-inner" version = "0.3.3" @@ -1553,6 +1537,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "h2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 1.0.0", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "1.7.1" @@ -1649,7 +1652,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "crypto-mac 0.11.1", + "crypto-mac 0.11.0", "digest 0.9.0", ] @@ -1715,6 +1718,19 @@ dependencies = [ "http 1.0.0", ] +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http 1.0.0", + "http-body 1.0.0", + "pin-project-lite 0.2.13", +] + [[package]] name = "httparse" version = "1.8.0" @@ -1737,14 +1753,13 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.18", "http 0.2.11", "http-body 0.4.0", "httparse", "httpdate", "itoa", "pin-project-lite 0.2.13", - "socket2 0.5.5", "tokio", "tower-service", "tracing", @@ -1758,22 +1773,55 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ "bytes", + "futures-channel", + "futures-util", + "h2 0.4.3", "http 1.0.0", "http-body 1.0.0", + "httparse", + "itoa", + "pin-project-lite 0.2.13", + "smallvec", "tokio", + "want", ] [[package]] name = "hyper-rustls" -version = "0.24.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ - "http 0.2.11", - "hyper 0.14.28", - "rustls 0.21.10", + "futures-util", + "http 1.0.0", + "hyper 1.3.1", + "hyper-util", + "rustls 0.23.10", + "rustls-pki-types", "tokio", - "tokio-rustls 0.24.0", + "tokio-rustls 0.26.0", + "tower-service", + "webpki-roots 0.26.1", +] + +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "hyper 1.3.1", + "pin-project-lite 0.2.13", + "socket2 0.5.5", + "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -1927,8 +1975,7 @@ dependencies = [ [[package]] name = "jsonrpc_client" version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c1ec33c537dc1d5a8b597313db6d213fee54320f81ea0d19b0c3869b282e1a" +source = "git+https://github.com/delta1/rust-jsonrpc-client.git?rev=3b6081697cd616c952acb9c2f02d546357d35506#3b6081697cd616c952acb9c2f02d546357d35506" dependencies = [ "async-trait", "jsonrpc_client_macro", @@ -1941,8 +1988,7 @@ dependencies = [ [[package]] name = "jsonrpc_client_macro" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97c11e429f0eaa41fe659013680b459d2368d8f0a3e69dccfb7a35800b0dc27b" +source = "git+https://github.com/delta1/rust-jsonrpc-client.git?rev=3b6081697cd616c952acb9c2f02d546357d35506#3b6081697cd616c952acb9c2f02d546357d35506" dependencies = [ "quote", "syn 1.0.109", @@ -2792,9 +2838,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -3226,6 +3272,53 @@ dependencies = [ "pin-project-lite 0.1.12", ] +[[package]] +name = "quinn" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +dependencies = [ + "bytes", + "pin-project-lite 0.2.13", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.10", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +dependencies = [ + "bytes", + "rand 0.8.3", + "ring 0.17.3", + "rustc-hash", + "rustls 0.23.10", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +dependencies = [ + "libc", + "once_cell", + "socket2 0.5.5", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.35" @@ -3397,20 +3490,21 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.27" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "bytes", - "encoding_rs", "futures-core", "futures-util", - "h2", - "http 0.2.11", - "http-body 0.4.0", - "hyper 0.14.28", + "h2 0.4.3", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.3.1", "hyper-rustls", + "hyper-util", "ipnet", "js-sys", "log", @@ -3418,15 +3512,16 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite 0.2.13", - "rustls 0.21.10", - "rustls-pemfile", + "quinn", + "rustls 0.23.10", + "rustls-pemfile 2.1.2", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", - "tokio-rustls 0.24.0", + "tokio-rustls 0.26.0", "tokio-socks", "tokio-util", "tower-service", @@ -3435,8 +3530,8 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.25.3", - "winreg 0.50.0", + "webpki-roots 0.26.1", + "winreg 0.52.0", ] [[package]] @@ -3598,14 +3693,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.10" +version = "0.23.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" dependencies = [ - "log", + "once_cell", "ring 0.17.3", + "rustls-pki-types", "rustls-webpki", - "sct 0.7.0", + "subtle", + "zeroize", ] [[package]] @@ -3627,7 +3724,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 1.0.0", "schannel", "security-framework", ] @@ -3642,12 +3739,29 @@ dependencies = [ ] [[package]] -name = "rustls-webpki" -version = "0.101.7" +name = "rustls-pemfile" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustls-webpki" +version = "0.102.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ "ring 0.17.3", + "rustls-pki-types", "untrusted 0.9.0", ] @@ -4111,9 +4225,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snow" @@ -4251,7 +4365,7 @@ dependencies = [ "paste", "percent-encoding", "rustls 0.20.2", - "rustls-pemfile", + "rustls-pemfile 1.0.0", "serde", "sha2 0.10.8", "smallvec", @@ -4379,9 +4493,9 @@ dependencies = [ [[package]] name = "subtle" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "subtle-ng" @@ -4391,7 +4505,7 @@ checksum = "8049cf85f0e715d6af38dde439cb0ccb91f67fb9f5f63c80f8b43e48356e1a3f" [[package]] name = "swap" -version = "0.12.3" +version = "0.13.1" dependencies = [ "anyhow", "async-compression", @@ -4455,7 +4569,7 @@ dependencies = [ "tokio-tar", "tokio-tungstenite", "tokio-util", - "toml 0.8.13", + "toml 0.8.14", "torut", "tracing", "tracing-appender", @@ -4492,9 +4606,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "synstructure" @@ -4508,27 +4622,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tempfile" version = "3.10.1" @@ -4553,9 +4646,9 @@ dependencies = [ [[package]] name = "testcontainers" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e2b1567ca8a2b819ea7b28c92be35d9f76fb9edb214321dcc86eb96023d1f87" +checksum = "f83d2931d7f521af5bae989f716c3fa43a6af9af7ec7a5e21b59ae40878cec00" dependencies = [ "bollard-stubs", "futures", @@ -4675,9 +4768,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -4694,9 +4787,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", @@ -4727,11 +4820,12 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.21.10", + "rustls 0.23.10", + "rustls-pki-types", "tokio", ] @@ -4815,9 +4909,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.13" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ "serde", "serde_spanned", @@ -4836,9 +4930,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.13" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ "indexmap 2.1.0", "serde", @@ -4871,6 +4965,11 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ + "futures-core", + "futures-util", + "pin-project 1.0.5", + "pin-project-lite 0.2.13", + "tokio", "tower-layer", "tower-service", "tracing", @@ -5200,9 +5299,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna 0.5.0", @@ -5435,9 +5534,12 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.3" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" +checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +dependencies = [ + "rustls-pki-types", +] [[package]] name = "which" @@ -5672,9 +5774,9 @@ dependencies = [ [[package]] name = "winreg" -version = "0.50.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" dependencies = [ "cfg-if 1.0.0", "windows-sys 0.48.0", @@ -5718,23 +5820,22 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.2.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.0.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", - "synstructure", + "syn 2.0.46", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ab29e919..c3d131a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,4 +3,6 @@ resolver = "2" members = [ "monero-harness", "monero-rpc", "swap", "monero-wallet" ] [patch.crates-io] +# patch until new release https://github.com/thomaseizinger/rust-jsonrpc-client/pull/51 +jsonrpc_client = { git = "https://github.com/delta1/rust-jsonrpc-client.git", rev = "3b6081697cd616c952acb9c2f02d546357d35506" } monero = { git = "https://github.com/comit-network/monero-rs", rev = "818f38b" } diff --git a/docs/asb/README.md b/docs/asb/README.md index b1acc877..88448b71 100644 --- a/docs/asb/README.md +++ b/docs/asb/README.md @@ -110,7 +110,7 @@ The minimum and maximum amount as well as a spread, that is added on top of the In order to be able to trade, the ASB must define a price to be able to agree on the amounts to be swapped with a CLI. The `XMR<>BTC` price is currently determined by the price from the central exchange Kraken. Upon startup the ASB connects to the Kraken price websocket and listens on the stream for price updates. -You can plug in a different price ticker websocket using the the `price_ticker_ws_url` configuration option. +You can plug in a different price ticker websocket using the `price_ticker_ws_url` configuration option. You will have to make sure that the format returned is the same as the format used by Kraken. Currently, we use a spot-price model, i.e. the ASB dictates the price to the CLI. diff --git a/monero-harness/Cargo.toml b/monero-harness/Cargo.toml index a4c9ce72..1151f47a 100644 --- a/monero-harness/Cargo.toml +++ b/monero-harness/Cargo.toml @@ -10,7 +10,7 @@ anyhow = "1" futures = "0.3" monero-rpc = { path = "../monero-rpc" } rand = "0.7" -testcontainers = "0.14" +testcontainers = "0.15" tokio = { version = "1", default-features = false, features = [ "rt-multi-thread", "time", "macros" ] } tracing = "0.1" tracing-subscriber = { version = "0.2", default-features = false, features = [ "fmt", "ansi", "env-filter", "tracing-log" ] } diff --git a/monero-rpc/Cargo.toml b/monero-rpc/Cargo.toml index 6da1e88a..18843745 100644 --- a/monero-rpc/Cargo.toml +++ b/monero-rpc/Cargo.toml @@ -12,7 +12,7 @@ jsonrpc_client = { version = "0.7", features = [ "reqwest" ] } monero = "0.12" monero-epee-bin-serde = "1" rand = "0.7" -reqwest = { version = "0.11", default-features = false, features = [ "json" ] } +reqwest = { version = "0.12", default-features = false, features = [ "json" ] } rust_decimal = { version = "1", features = [ "serde-float" ] } serde = { version = "1.0", features = [ "derive" ] } serde_json = "1.0" diff --git a/monero-rpc/src/wallet.rs b/monero-rpc/src/wallet.rs index bc78e7a6..3e21ad1b 100644 --- a/monero-rpc/src/wallet.rs +++ b/monero-rpc/src/wallet.rs @@ -162,6 +162,12 @@ pub struct BlockHeight { pub height: u32, } +impl fmt::Display for BlockHeight { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.height) + } +} + #[derive(Clone, Copy, Debug, Deserialize)] #[serde(from = "CheckTxKeyResponse")] pub struct CheckTxKey { diff --git a/monero-wallet/Cargo.toml b/monero-wallet/Cargo.toml index 81982c83..99bd3f4d 100644 --- a/monero-wallet/Cargo.toml +++ b/monero-wallet/Cargo.toml @@ -14,6 +14,6 @@ rand = "0.7" curve25519-dalek = "3" monero-harness = { path = "../monero-harness" } rand = "0.7" -testcontainers = "0.14" +testcontainers = "0.15" tokio = { version = "1", features = [ "rt-multi-thread", "time", "macros", "sync", "process", "fs" ] } tracing-subscriber = { version = "0.2", default-features = false, features = [ "fmt", "ansi", "env-filter", "chrono", "tracing-log" ] } diff --git a/swap/Cargo.toml b/swap/Cargo.toml index 4ebbadc5..5d949408 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap" -version = "0.12.3" +version = "0.13.1" authors = [ "The COMIT guys " ] edition = "2021" description = "XMR/BTC trustless atomic swaps." @@ -42,7 +42,7 @@ proptest = "1" qrcode = "0.14" rand = "0.8" rand_chacha = "0.3" -reqwest = { version = "0.11", features = [ "rustls-tls", "stream", "socks" ], default-features = false } +reqwest = { version = "0.12", features = [ "http2", "rustls-tls", "stream", "socks" ], default-features = false } rust_decimal = { version = "1", features = [ "serde-float" ] } rust_decimal_macros = "1" serde = { version = "1", features = [ "derive" ] } @@ -77,7 +77,7 @@ tokio-tar = "0.3" zip = "0.5" [dev-dependencies] -bitcoin-harness = "0.2.2" +bitcoin-harness = { git = "https://github.com/delta1/bitcoin-harness-rs.git", rev = "80cc8d05db2610d8531011be505b7bee2b5cdf9f" } get-port = "3" hyper = "1.3" jsonrpsee = { version = "0.16.2", features = [ "ws-client" ] } @@ -89,7 +89,7 @@ sequential-test = "0.2.4" serde_cbor = "0.11" serial_test = "3.0" tempfile = "3" -testcontainers = "0.14" +testcontainers = "0.15" [build-dependencies] anyhow = "1" diff --git a/swap/src/api/request.rs b/swap/src/api/request.rs index 02bf27e1..338432c3 100644 --- a/swap/src/api/request.rs +++ b/swap/src/api/request.rs @@ -882,19 +882,24 @@ where loop { let min_outstanding = bid_quote.min_quantity - max_giveable; - let min_fee = estimate_fee(min_outstanding).await?; - let min_deposit = min_outstanding + min_fee; + let min_bitcoin_lock_tx_fee = estimate_fee(min_outstanding).await?; + let min_deposit_until_swap_will_start = min_outstanding + min_bitcoin_lock_tx_fee; + let max_deposit_until_maximum_amount_is_reached = + maximum_amount - max_giveable + min_bitcoin_lock_tx_fee; tracing::info!( "Deposit at least {} to cover the min quantity with fee!", - min_deposit + min_deposit_until_swap_will_start ); tracing::info!( %deposit_address, - %min_deposit, + %min_deposit_until_swap_will_start, + %max_deposit_until_maximum_amount_is_reached, %max_giveable, %minimum_amount, %maximum_amount, + %min_bitcoin_lock_tx_fee, + price = %bid_quote.price, "Waiting for Bitcoin deposit", ); @@ -913,7 +918,7 @@ where tracing::info!(%new_balance, %max_giveable, "Received Bitcoin"); if max_giveable < bid_quote.min_quantity { - tracing::info!("Deposited amount is less than `min_quantity`"); + tracing::info!("Deposited amount is not enough to cover `min_quantity` when accounting for network fees"); continue; } diff --git a/swap/src/asb/recovery/cancel.rs b/swap/src/asb/recovery/cancel.rs index ec70a8df..8da1508f 100644 --- a/swap/src/asb/recovery/cancel.rs +++ b/swap/src/asb/recovery/cancel.rs @@ -39,7 +39,7 @@ pub async fn cancel( | AliceState::BtcRedeemed | AliceState::XmrRefunded | AliceState::BtcPunished - | AliceState::SafelyAborted => bail!("Swap is is in state {} which is not cancelable", state), + | AliceState::SafelyAborted => bail!("Swap is in state {} which is not cancelable", state), }; let txid = match state3.submit_tx_cancel(bitcoin_wallet.as_ref()).await { diff --git a/swap/src/monero/wallet.rs b/swap/src/monero/wallet.rs index 56fd8e60..99fa206a 100644 --- a/swap/src/monero/wallet.rs +++ b/swap/src/monero/wallet.rs @@ -45,6 +45,7 @@ impl Wallet { pub async fn connect(client: wallet::Client, name: String, env_config: Config) -> Result { let main_address = monero::Address::from_str(client.get_address(0).await?.address.as_str())?; + Ok(Self { inner: Mutex::new(client), network: env_config.monero_network, @@ -125,13 +126,14 @@ impl Wallet { let temp_wallet_address = Address::standard(self.network, public_spend_key, public_view_key); - let wallet = self.inner.lock().await; - // Close the default wallet before generating the other wallet to ensure that // it saves its state correctly - let _ = wallet.close_wallet().await?; + let _ = self.inner.lock().await.close_wallet().await?; - let _ = wallet + let _ = self + .inner + .lock() + .await .generate_from_keys( file_name, temp_wallet_address.to_string(), @@ -144,8 +146,14 @@ impl Wallet { .await?; // Try to send all the funds from the generated wallet to the default wallet - match wallet.refresh().await { - Ok(_) => match wallet.sweep_all(self.main_address.to_string()).await { + match self.refresh(3).await { + Ok(_) => match self + .inner + .lock() + .await + .sweep_all(self.main_address.to_string()) + .await + { Ok(sweep_all) => { for tx in sweep_all.tx_hash_list { tracing::info!( @@ -166,7 +174,12 @@ impl Wallet { } } - let _ = wallet.open_wallet(self.name.clone()).await?; + let _ = self + .inner + .lock() + .await + .open_wallet(self.name.clone()) + .await?; Ok(()) } @@ -261,8 +274,44 @@ impl Wallet { self.main_address } - pub async fn refresh(&self) -> Result { - Ok(self.inner.lock().await.refresh().await?) + pub async fn refresh(&self, max_attempts: usize) -> Result { + const RETRY_INTERVAL: Duration = Duration::from_secs(1); + + for i in 1..=max_attempts { + tracing::info!(name = %self.name, attempt=i, "Syncing Monero wallet"); + + let result = self.inner.lock().await.refresh().await; + + match result { + Ok(refreshed) => { + tracing::info!(name = %self.name, "Monero wallet synced"); + return Ok(refreshed); + } + Err(error) => { + let attempts_left = max_attempts - i; + + // We would not want to fail here if the height is not available + // as it is not critical for the operation of the wallet. + // We can just log a warning and continue. + let height = match self.inner.lock().await.get_height().await { + Ok(height) => height.to_string(), + Err(_) => { + tracing::warn!(name = %self.name, "Failed to fetch Monero wallet height during sync"); + "unknown".to_string() + } + }; + + tracing::warn!(attempt=i, %height, %attempts_left, name = %self.name, %error, "Failed to sync Monero wallet"); + + if attempts_left == 0 { + return Err(error.into()); + } + } + } + + tokio::time::sleep(RETRY_INTERVAL).await; + } + unreachable!("Loop should have returned by now"); } } diff --git a/swap/src/monero/wallet_rpc.rs b/swap/src/monero/wallet_rpc.rs index b64592e1..609c3eab 100644 --- a/swap/src/monero/wallet_rpc.rs +++ b/swap/src/monero/wallet_rpc.rs @@ -352,6 +352,7 @@ impl WalletRpc { .arg("--disable-rpc-login") .arg("--wallet-dir") .arg(self.working_dir.join("monero-data")) + .arg("--no-initial-sync") .spawn()?; let stdout = child @@ -369,7 +370,7 @@ impl WalletRpc { } // If we do not hear from the monero_wallet_rpc process for 3 seconds we assume - // it is is ready + // it is ready #[cfg(target_os = "windows")] while let Ok(line) = tokio::time::timeout(std::time::Duration::from_secs(3), reader.next_line()).await diff --git a/swap/src/protocol/bob/state.rs b/swap/src/protocol/bob/state.rs index aa0045ea..58c1d723 100644 --- a/swap/src/protocol/bob/state.rs +++ b/swap/src/protocol/bob/state.rs @@ -489,6 +489,27 @@ pub struct State4 { } impl State4 { + pub async fn check_for_tx_redeem(&self, bitcoin_wallet: &bitcoin::Wallet) -> Result { + let tx_redeem = + bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address, self.tx_redeem_fee); + let tx_redeem_encsig = self.b.encsign(self.S_a_bitcoin, tx_redeem.digest()); + + let tx_redeem_candidate = bitcoin_wallet.get_raw_transaction(tx_redeem.txid()).await?; + + let tx_redeem_sig = + tx_redeem.extract_signature_by_key(tx_redeem_candidate, self.b.public())?; + let s_a = bitcoin::recover(self.S_a_bitcoin, tx_redeem_sig, tx_redeem_encsig)?; + let s_a = monero::private_key_from_secp256k1_scalar(s_a.into()); + + Ok(State5 { + s_a, + s_b: self.s_b, + v: self.v, + tx_lock: self.tx_lock.clone(), + monero_wallet_restore_blockheight: self.monero_wallet_restore_blockheight, + }) + } + pub fn tx_redeem_encsig(&self) -> bitcoin::EncryptedSignature { let tx_redeem = bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address, self.tx_redeem_fee); diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 37a6b65a..3900a17b 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -183,6 +183,13 @@ async fn next_state( } } BobState::XmrLocked(state) => { + // In case we send the encrypted signature to Alice, but she doesn't give us a confirmation + // We need to check if she still published the Bitcoin redeem transaction + // Otherwise we risk staying stuck in "XmrLocked" + if let Ok(state5) = state.check_for_tx_redeem(bitcoin_wallet).await { + return Ok(BobState::BtcRedeemed(state5)); + } + let tx_lock_status = bitcoin_wallet.subscribe_to(state.tx_lock.clone()).await; if let ExpiredTimelocks::None { .. } = state.expired_timelock(bitcoin_wallet).await? { @@ -207,6 +214,13 @@ async fn next_state( } } BobState::EncSigSent(state) => { + // We need to make sure that Alice did not publish the redeem transaction while we were offline + // Even if the cancel timelock expired, if Alice published the redeem transaction while we were away we cannot miss it + // If we do we cannot refund and will never be able to leave the "CancelTimelockExpired" state + if let Ok(state5) = state.check_for_tx_redeem(bitcoin_wallet).await { + return Ok(BobState::BtcRedeemed(state5)); + } + let tx_lock_status = bitcoin_wallet.subscribe_to(state.tx_lock.clone()).await; if let ExpiredTimelocks::None { .. } = state.expired_timelock(bitcoin_wallet).await? { @@ -244,13 +258,13 @@ async fn next_state( // might not be able to ever transfer the Monero. tracing::warn!("Failed to generate monero wallet from keys: {:#}", e); tracing::info!(%wallet_file_name, - "Falling back to trying to open the the wallet if it already exists", + "Falling back to trying to open the wallet if it already exists", ); monero_wallet.open(wallet_file_name).await?; } // Ensure that the generated wallet is synced so we have a proper balance - monero_wallet.refresh().await?; + monero_wallet.refresh(20).await?; // Sweep (transfer all funds) to the given address let tx_hashes = monero_wallet.sweep_all(monero_receive_address).await?; diff --git a/swap/tests/happy_path_bob_offline_while_alice_redeems_btc.rs b/swap/tests/happy_path_bob_offline_while_alice_redeems_btc.rs new file mode 100644 index 00000000..c958c4f0 --- /dev/null +++ b/swap/tests/happy_path_bob_offline_while_alice_redeems_btc.rs @@ -0,0 +1,44 @@ +pub mod harness; + +use crate::harness::bob_run_until::is_encsig_sent; +use swap::asb::FixedRate; +use swap::protocol::bob::BobState; +use swap::protocol::{alice, bob}; +use tokio::join; + +#[tokio::test] +async fn given_bob_restarts_while_alice_redeems_btc() { + harness::setup_test(harness::SlowCancelConfig, |mut ctx| async move { + let (bob_swap, bob_handle) = ctx.bob_swap().await; + let swap_id = bob_swap.id; + + let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_encsig_sent)); + + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); + + let (bob_state, alice_state) = join!(bob_swap, alice_swap); + ctx.assert_alice_redeemed(alice_state??).await; + assert!(matches!(bob_state??, BobState::EncSigSent { .. })); + + let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_handle, swap_id).await; + + if let BobState::EncSigSent(state4) = bob_swap.state.clone() { + bob_swap + .bitcoin_wallet + .subscribe_to(state4.tx_lock) + .await + .wait_until_confirmed_with(state4.cancel_timelock) + .await?; + } else { + panic!("Bob in unexpected state {}", bob_swap.state); + } + + // Restart Bob + let bob_state = bob::run(bob_swap).await?; + ctx.assert_bob_redeemed(bob_state).await; + + Ok(()) + }) + .await; +} diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index c099376d..24083a71 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -891,7 +891,7 @@ impl Wallet for monero::Wallet { type Amount = monero::Amount; async fn refresh(&self) -> Result<()> { - self.refresh().await?; + self.refresh(1).await?; Ok(()) } @@ -996,6 +996,10 @@ pub mod alice_run_until { pub fn is_encsig_learned(state: &AliceState) -> bool { matches!(state, AliceState::EncSigLearned { .. }) } + + pub fn is_btc_redeemed(state: &AliceState) -> bool { + matches!(state, AliceState::BtcRedeemed { .. }) + } } pub mod bob_run_until {