Merge branch 'master' into bob-buffer-transfer-proofs

This commit is contained in:
binarybaron 2024-06-22 11:20:26 +02:00 committed by GitHub
commit dd445d81ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 296 additions and 94 deletions

View file

@ -54,7 +54,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout tagged commit - name: Checkout tagged commit
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
with: with:
ref: ${{ github.event.release.target_commitish }} ref: ${{ github.event.release.target_commitish }}
token: ${{ secrets.BOTTY_GITHUB_TOKEN }} token: ${{ secrets.BOTTY_GITHUB_TOKEN }}

View file

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- uses: dtolnay/rust-toolchain@master - uses: dtolnay/rust-toolchain@master
with: with:
@ -35,7 +35,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- uses: Swatinem/rust-cache@v2.7.3 - uses: Swatinem/rust-cache@v2.7.3
@ -49,7 +49,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- uses: Swatinem/rust-cache@v2.7.3 - uses: Swatinem/rust-cache@v2.7.3
@ -78,7 +78,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- uses: Swatinem/rust-cache@v2.7.3 - uses: Swatinem/rust-cache@v2.7.3
@ -131,7 +131,7 @@ jobs:
tool-cache: false tool-cache: false
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- uses: Swatinem/rust-cache@v2.7.3 - uses: Swatinem/rust-cache@v2.7.3
@ -164,11 +164,12 @@ jobs:
ensure_same_swap_id, ensure_same_swap_id,
concurrent_bobs_before_xmr_lock_proof_sent, concurrent_bobs_before_xmr_lock_proof_sent,
alice_manually_redeems_after_enc_sig_learned, alice_manually_redeems_after_enc_sig_learned,
happy_path_bob_offline_while_alice_redeems_btc,
] ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- uses: Swatinem/rust-cache@v2.7.3 - uses: Swatinem/rust-cache@v2.7.3
@ -179,7 +180,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- uses: Swatinem/rust-cache@v2.7.3 - uses: Swatinem/rust-cache@v2.7.3
@ -190,7 +191,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v4.1.6 uses: actions/checkout@v4.1.7
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable

View file

@ -11,7 +11,7 @@ jobs:
if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/') if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4.1.6 - uses: actions/checkout@v4.1.7
- name: Extract version from branch name - name: Extract version from branch name
id: extract-version id: extract-version

View file

@ -12,7 +12,7 @@ jobs:
name: "Draft a new release" name: "Draft a new release"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4.1.6 - uses: actions/checkout@v4.1.7
with: with:
token: ${{ secrets.BOTTY_GITHUB_TOKEN }} token: ${{ secrets.BOTTY_GITHUB_TOKEN }}

View file

@ -10,7 +10,7 @@ jobs:
name: Create preview release name: Create preview release
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4.1.6 - uses: actions/checkout@v4.1.7
- name: Delete 'preview' release - name: Delete 'preview' release
uses: larryjoelane/delete-release-action@v1.0.24 uses: larryjoelane/delete-release-action@v1.0.24

View file

@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- CLI: Buffer received transfer proofs for later processing if we're currently running a different swap - CLI: Buffer received transfer proofs for later processing if we're currently running a different swap
## [0.13.1] - 2024-06-10
- Add retry logic to monero-wallet-rpc wallet refresh
## [0.13.0] - 2024-05-29 ## [0.13.0] - 2024-05-29
- Minimum Supported Rust Version (MSRV) bumped to 1.74 - Minimum Supported Rust Version (MSRV) bumped to 1.74
@ -358,7 +361,8 @@ 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. - 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. 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.13.0...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.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.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.2]: https://github.com/comit-network/xmr-btc-swap/compare/0.12.1...0.12.2

163
Cargo.lock generated
View file

@ -743,7 +743,7 @@ dependencies = [
"nom", "nom",
"pathdiff", "pathdiff",
"serde", "serde",
"toml 0.8.13", "toml 0.8.14",
] ]
[[package]] [[package]]
@ -1017,17 +1017,6 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "dashmap"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8858831f7781322e539ea39e72449c46b059638250c14344fec8d0aa6e539c"
dependencies = [
"cfg-if 1.0.0",
"num_cpus",
"parking_lot 0.12.0",
]
[[package]] [[package]]
name = "data-encoding" name = "data-encoding"
version = "2.6.0" version = "2.6.0"
@ -1788,19 +1777,20 @@ dependencies = [
[[package]] [[package]]
name = "hyper-rustls" name = "hyper-rustls"
version = "0.26.0" version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"http 1.0.0", "http 1.0.0",
"hyper 1.3.1", "hyper 1.3.1",
"hyper-util", "hyper-util",
"rustls 0.22.2", "rustls 0.23.10",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
"tokio-rustls 0.25.0", "tokio-rustls 0.26.0",
"tower-service", "tower-service",
"webpki-roots 0.26.1",
] ]
[[package]] [[package]]
@ -2597,13 +2587,13 @@ dependencies = [
[[package]] [[package]]
name = "mockito" name = "mockito"
version = "1.3.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c84fe1f1d8c56dc157f79942056fad4b9efceebba374a01b222428b553facb" checksum = "d2f6e023aa5bdf392aa06c78e4a4e6d498baab5138d0c993503350ebbc37bf1e"
dependencies = [ dependencies = [
"assert-json-diff", "assert-json-diff",
"colored", "colored",
"futures", "futures-core",
"hyper 0.14.28", "hyper 0.14.28",
"log", "log",
"rand 0.8.3", "rand 0.8.3",
@ -2837,9 +2827,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.13.0" version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]] [[package]]
name = "opaque-debug" name = "opaque-debug"
@ -3271,6 +3261,53 @@ dependencies = [
"pin-project-lite 0.1.12", "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]] [[package]]
name = "quote" name = "quote"
version = "1.0.35" version = "1.0.35"
@ -3442,9 +3479,9 @@ dependencies = [
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.12.4" version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bytes", "bytes",
@ -3464,7 +3501,8 @@ dependencies = [
"once_cell", "once_cell",
"percent-encoding", "percent-encoding",
"pin-project-lite 0.2.13", "pin-project-lite 0.2.13",
"rustls 0.22.2", "quinn",
"rustls 0.23.10",
"rustls-pemfile 2.1.2", "rustls-pemfile 2.1.2",
"rustls-pki-types", "rustls-pki-types",
"serde", "serde",
@ -3472,7 +3510,7 @@ dependencies = [
"serde_urlencoded", "serde_urlencoded",
"sync_wrapper", "sync_wrapper",
"tokio", "tokio",
"tokio-rustls 0.25.0", "tokio-rustls 0.26.0",
"tokio-socks", "tokio-socks",
"tokio-util", "tokio-util",
"tower-service", "tower-service",
@ -3644,11 +3682,11 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.22.2" version = "0.23.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402"
dependencies = [ dependencies = [
"log", "once_cell",
"ring 0.17.3", "ring 0.17.3",
"rustls-pki-types", "rustls-pki-types",
"rustls-webpki", "rustls-webpki",
@ -3701,15 +3739,15 @@ dependencies = [
[[package]] [[package]]
name = "rustls-pki-types" name = "rustls-pki-types"
version = "1.3.1" version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ede67b28608b4c60685c7d54122d4400d90f62b40caee7700e700380a390fa8" checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.102.2" version = "0.102.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e"
dependencies = [ dependencies = [
"ring 0.17.3", "ring 0.17.3",
"rustls-pki-types", "rustls-pki-types",
@ -3751,6 +3789,15 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "scc"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76ad2bbb0ae5100a07b7a6f2ed7ab5fd0045551a4c507989b7a620046ea3efdc"
dependencies = [
"sdd",
]
[[package]] [[package]]
name = "schannel" name = "schannel"
version = "0.1.19" version = "0.1.19"
@ -3787,6 +3834,12 @@ dependencies = [
"untrusted 0.7.1", "untrusted 0.7.1",
] ]
[[package]]
name = "sdd"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b84345e4c9bd703274a082fb80caaa99b7612be48dfaa1dd9266577ec412309d"
[[package]] [[package]]
name = "seahash" name = "seahash"
version = "4.1.0" version = "4.1.0"
@ -4030,23 +4083,23 @@ dependencies = [
[[package]] [[package]]
name = "serial_test" name = "serial_test"
version = "3.0.0" version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ad9342b3aaca7cb43c45c097dd008d4907070394bd0751a0aa8817e5a018d" checksum = "4b4b487fe2acf240a021cf57c6b2b4903b1e78ca0ecd862a71b71d2a51fed77d"
dependencies = [ dependencies = [
"dashmap",
"futures", "futures",
"lazy_static",
"log", "log",
"once_cell",
"parking_lot 0.12.0", "parking_lot 0.12.0",
"scc",
"serial_test_derive", "serial_test_derive",
] ]
[[package]] [[package]]
name = "serial_test_derive" name = "serial_test_derive"
version = "3.0.0" version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b93fb4adc70021ac1b47f7d45e8cc4169baaa7ea58483bc5b721d19a26202212" checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -4456,7 +4509,7 @@ checksum = "8049cf85f0e715d6af38dde439cb0ccb91f67fb9f5f63c80f8b43e48356e1a3f"
[[package]] [[package]]
name = "swap" name = "swap"
version = "0.13.0" version = "0.13.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-compression", "async-compression",
@ -4520,7 +4573,7 @@ dependencies = [
"tokio-tar", "tokio-tar",
"tokio-tungstenite", "tokio-tungstenite",
"tokio-util", "tokio-util",
"toml 0.8.13", "toml 0.8.14",
"torut", "torut",
"tracing", "tracing",
"tracing-appender", "tracing-appender",
@ -4557,9 +4610,9 @@ dependencies = [
[[package]] [[package]]
name = "sync_wrapper" name = "sync_wrapper"
version = "0.1.2" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
[[package]] [[package]]
name = "synstructure" name = "synstructure"
@ -4719,9 +4772,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.37.0" version = "1.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@ -4738,9 +4791,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "2.2.0" version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -4771,11 +4824,11 @@ dependencies = [
[[package]] [[package]]
name = "tokio-rustls" name = "tokio-rustls"
version = "0.25.0" version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
dependencies = [ dependencies = [
"rustls 0.22.2", "rustls 0.23.10",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
] ]
@ -4860,9 +4913,9 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.8.13" version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
dependencies = [ dependencies = [
"serde", "serde",
"serde_spanned", "serde_spanned",
@ -4881,9 +4934,9 @@ dependencies = [
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.22.13" version = "0.22.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
dependencies = [ dependencies = [
"indexmap 2.1.0", "indexmap 2.1.0",
"serde", "serde",
@ -5250,9 +5303,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]] [[package]]
name = "url" name = "url"
version = "2.5.0" version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
dependencies = [ dependencies = [
"form_urlencoded", "form_urlencoded",
"idna 0.5.0", "idna 0.5.0",

View file

@ -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. 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. 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. 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. 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. Currently, we use a spot-price model, i.e. the ASB dictates the price to the CLI.

View file

@ -162,6 +162,12 @@ pub struct BlockHeight {
pub height: u32, 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)] #[derive(Clone, Copy, Debug, Deserialize)]
#[serde(from = "CheckTxKeyResponse")] #[serde(from = "CheckTxKeyResponse")]
pub struct CheckTxKey { pub struct CheckTxKey {

View file

@ -1,6 +1,6 @@
[package] [package]
name = "swap" name = "swap"
version = "0.13.0" version = "0.13.1"
authors = [ "The COMIT guys <hello@comit.network>" ] authors = [ "The COMIT guys <hello@comit.network>" ]
edition = "2021" edition = "2021"
description = "XMR/BTC trustless atomic swaps." description = "XMR/BTC trustless atomic swaps."
@ -81,13 +81,13 @@ bitcoin-harness = { git = "https://github.com/delta1/bitcoin-harness-rs.git", re
get-port = "3" get-port = "3"
hyper = "1.3" hyper = "1.3"
jsonrpsee = { version = "0.16.2", features = [ "ws-client" ] } jsonrpsee = { version = "0.16.2", features = [ "ws-client" ] }
mockito = "1.3.0" mockito = "1.4"
monero-harness = { path = "../monero-harness" } monero-harness = { path = "../monero-harness" }
port_check = "0.2" port_check = "0.2"
proptest = "1" proptest = "1"
sequential-test = "0.2.4" sequential-test = "0.2.4"
serde_cbor = "0.11" serde_cbor = "0.11"
serial_test = "3.0" serial_test = "3.1"
tempfile = "3" tempfile = "3"
testcontainers = "0.15" testcontainers = "0.15"

View file

@ -882,19 +882,24 @@ where
loop { loop {
let min_outstanding = bid_quote.min_quantity - max_giveable; let min_outstanding = bid_quote.min_quantity - max_giveable;
let min_fee = estimate_fee(min_outstanding).await?; let min_bitcoin_lock_tx_fee = estimate_fee(min_outstanding).await?;
let min_deposit = min_outstanding + min_fee; 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!( tracing::info!(
"Deposit at least {} to cover the min quantity with fee!", "Deposit at least {} to cover the min quantity with fee!",
min_deposit min_deposit_until_swap_will_start
); );
tracing::info!( tracing::info!(
%deposit_address, %deposit_address,
%min_deposit, %min_deposit_until_swap_will_start,
%max_deposit_until_maximum_amount_is_reached,
%max_giveable, %max_giveable,
%minimum_amount, %minimum_amount,
%maximum_amount, %maximum_amount,
%min_bitcoin_lock_tx_fee,
price = %bid_quote.price,
"Waiting for Bitcoin deposit", "Waiting for Bitcoin deposit",
); );
@ -913,7 +918,7 @@ where
tracing::info!(%new_balance, %max_giveable, "Received Bitcoin"); tracing::info!(%new_balance, %max_giveable, "Received Bitcoin");
if max_giveable < bid_quote.min_quantity { 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; continue;
} }

View file

@ -39,7 +39,7 @@ pub async fn cancel(
| AliceState::BtcRedeemed | AliceState::BtcRedeemed
| AliceState::XmrRefunded | AliceState::XmrRefunded
| AliceState::BtcPunished | 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 { let txid = match state3.submit_tx_cancel(bitcoin_wallet.as_ref()).await {

View file

@ -45,6 +45,7 @@ impl Wallet {
pub async fn connect(client: wallet::Client, name: String, env_config: Config) -> Result<Self> { pub async fn connect(client: wallet::Client, name: String, env_config: Config) -> Result<Self> {
let main_address = let main_address =
monero::Address::from_str(client.get_address(0).await?.address.as_str())?; monero::Address::from_str(client.get_address(0).await?.address.as_str())?;
Ok(Self { Ok(Self {
inner: Mutex::new(client), inner: Mutex::new(client),
network: env_config.monero_network, network: env_config.monero_network,
@ -125,13 +126,14 @@ impl Wallet {
let temp_wallet_address = let temp_wallet_address =
Address::standard(self.network, public_spend_key, public_view_key); 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 // Close the default wallet before generating the other wallet to ensure that
// it saves its state correctly // 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( .generate_from_keys(
file_name, file_name,
temp_wallet_address.to_string(), temp_wallet_address.to_string(),
@ -144,8 +146,14 @@ impl Wallet {
.await?; .await?;
// Try to send all the funds from the generated wallet to the default wallet // Try to send all the funds from the generated wallet to the default wallet
match wallet.refresh().await { match self.refresh(3).await {
Ok(_) => match wallet.sweep_all(self.main_address.to_string()).await { Ok(_) => match self
.inner
.lock()
.await
.sweep_all(self.main_address.to_string())
.await
{
Ok(sweep_all) => { Ok(sweep_all) => {
for tx in sweep_all.tx_hash_list { for tx in sweep_all.tx_hash_list {
tracing::info!( 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(()) Ok(())
} }
@ -261,8 +274,44 @@ impl Wallet {
self.main_address self.main_address
} }
pub async fn refresh(&self) -> Result<Refreshed> { pub async fn refresh(&self, max_attempts: usize) -> Result<Refreshed> {
Ok(self.inner.lock().await.refresh().await?) 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");
} }
} }

View file

@ -352,6 +352,7 @@ impl WalletRpc {
.arg("--disable-rpc-login") .arg("--disable-rpc-login")
.arg("--wallet-dir") .arg("--wallet-dir")
.arg(self.working_dir.join("monero-data")) .arg(self.working_dir.join("monero-data"))
.arg("--no-initial-sync")
.spawn()?; .spawn()?;
let stdout = child 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 // 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")] #[cfg(target_os = "windows")]
while let Ok(line) = while let Ok(line) =
tokio::time::timeout(std::time::Duration::from_secs(3), reader.next_line()).await tokio::time::timeout(std::time::Duration::from_secs(3), reader.next_line()).await
@ -479,7 +480,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_is_daemon_available_success() { async fn test_is_daemon_available_success() {
let mut server = mockito::Server::new(); let mut server = mockito::Server::new_async().await;
let _ = server let _ = server
.mock("GET", "/get_info") .mock("GET", "/get_info")
@ -510,7 +511,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_is_daemon_available_wrong_network_failure() { async fn test_is_daemon_available_wrong_network_failure() {
let mut server = mockito::Server::new(); let mut server = mockito::Server::new_async().await;
let _ = server let _ = server
.mock("GET", "/get_info") .mock("GET", "/get_info")
@ -541,7 +542,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_is_daemon_available_not_synced_failure() { async fn test_is_daemon_available_not_synced_failure() {
let mut server = mockito::Server::new(); let mut server = mockito::Server::new_async().await;
let _ = server let _ = server
.mock("GET", "/get_info") .mock("GET", "/get_info")

View file

@ -489,6 +489,27 @@ pub struct State4 {
} }
impl State4 { impl State4 {
pub async fn check_for_tx_redeem(&self, bitcoin_wallet: &bitcoin::Wallet) -> Result<State5> {
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 { pub fn tx_redeem_encsig(&self) -> bitcoin::EncryptedSignature {
let tx_redeem = let tx_redeem =
bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address, self.tx_redeem_fee); bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address, self.tx_redeem_fee);

View file

@ -202,6 +202,13 @@ async fn next_state(
} }
} }
BobState::XmrLocked(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; let tx_lock_status = bitcoin_wallet.subscribe_to(state.tx_lock.clone()).await;
if let ExpiredTimelocks::None { .. } = state.expired_timelock(bitcoin_wallet).await? { if let ExpiredTimelocks::None { .. } = state.expired_timelock(bitcoin_wallet).await? {
@ -226,6 +233,13 @@ async fn next_state(
} }
} }
BobState::EncSigSent(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; let tx_lock_status = bitcoin_wallet.subscribe_to(state.tx_lock.clone()).await;
if let ExpiredTimelocks::None { .. } = state.expired_timelock(bitcoin_wallet).await? { if let ExpiredTimelocks::None { .. } = state.expired_timelock(bitcoin_wallet).await? {
@ -263,13 +277,13 @@ async fn next_state(
// might not be able to ever transfer the Monero. // might not be able to ever transfer the Monero.
tracing::warn!("Failed to generate monero wallet from keys: {:#}", e); tracing::warn!("Failed to generate monero wallet from keys: {:#}", e);
tracing::info!(%wallet_file_name, 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?; monero_wallet.open(wallet_file_name).await?;
} }
// Ensure that the generated wallet is synced so we have a proper balance // 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 // Sweep (transfer all funds) to the given address
let tx_hashes = monero_wallet.sweep_all(monero_receive_address).await?; let tx_hashes = monero_wallet.sweep_all(monero_receive_address).await?;

View file

@ -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;
}

View file

@ -892,7 +892,7 @@ impl Wallet for monero::Wallet {
type Amount = monero::Amount; type Amount = monero::Amount;
async fn refresh(&self) -> Result<()> { async fn refresh(&self) -> Result<()> {
self.refresh().await?; self.refresh(1).await?;
Ok(()) Ok(())
} }
@ -997,6 +997,10 @@ pub mod alice_run_until {
pub fn is_encsig_learned(state: &AliceState) -> bool { pub fn is_encsig_learned(state: &AliceState) -> bool {
matches!(state, AliceState::EncSigLearned { .. }) matches!(state, AliceState::EncSigLearned { .. })
} }
pub fn is_btc_redeemed(state: &AliceState) -> bool {
matches!(state, AliceState::BtcRedeemed { .. })
}
} }
pub mod bob_run_until { pub mod bob_run_until {