From 0600a7048eaff63b9b72578f697716a47c569c7c Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Mon, 1 Feb 2021 16:10:43 +1100 Subject: [PATCH 1/8] Cancel command --- Cargo.lock | 428 +++++++++++++++----------------- swap/src/cli.rs | 19 ++ swap/src/main.rs | 33 ++- swap/src/protocol/bob.rs | 2 + swap/src/protocol/bob/cancel.rs | 60 +++++ 5 files changed, 307 insertions(+), 235 deletions(-) create mode 100644 swap/src/protocol/bob/cancel.rs diff --git a/Cargo.lock b/Cargo.lock index ed5439a9..8a3e61d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,9 +80,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.35" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" [[package]] name = "arrayref" @@ -146,27 +146,6 @@ dependencies = [ "syn", ] -[[package]] -name = "async-stream" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3670df70cbc01729f901f94c887814b3c68db038aad1329a418bae178bc5295c" -dependencies = [ - "async-stream-impl", - "futures-core", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3548b8efc9f8e8a5a0a2808c5bd8451a9031b9e5b879a79590304ae928b0a70" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "async-trait" version = "0.1.42" @@ -184,7 +163,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb4401f0a3622dad2e0763fa79e0eb328bc70fb7dccfdd645341f00d671247d6" dependencies = [ - "bytes 1.0.1", + "bytes", "futures-sink", "futures-util", "memchr", @@ -229,10 +208,10 @@ version = "0.2.2-alpha.0" source = "git+https://github.com/ihrwein/backoff?rev=9d03992a83dfdc596be26276d4e5c5254a4b11a2#9d03992a83dfdc596be26276d4e5c5254a4b11a2" dependencies = [ "futures-core", - "getrandom 0.2.2", + "getrandom 0.2.1", "instant", - "pin-project 1.0.2", - "rand 0.8.3", + "pin-project 1.0.4", + "rand 0.8.2", "tokio", ] @@ -445,15 +424,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - -[[package]] -name = "bytes" -version = "0.5.6" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" [[package]] name = "bytes" @@ -555,9 +528,9 @@ dependencies = [ [[package]] name = "conquer-once" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cb45322099323eefa1b48850ce6c148f5b510894c531e038539f6370c887214" +checksum = "7c6d3a9775a69f6d1fe2cc888999b67ed30257d3da4d2af91984e722f2ec918a" dependencies = [ "conquer-util", ] @@ -586,9 +559,9 @@ dependencies = [ [[package]] name = "const_fn" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826" +checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" [[package]] name = "constant_time_eq" @@ -639,7 +612,7 @@ version = "0.1.0" source = "git+https://github.com/comit-network/cross-curve-dleq?rev=eddcdea1d1f16fa33ef581d1744014ece535c920#eddcdea1d1f16fa33ef581d1744014ece535c920" dependencies = [ "bit-vec", - "curve25519-dalek 2.1.0", + "curve25519-dalek 2.1.2", "ecdsa_fun", "generic-array 0.14.4", "hex-literal", @@ -731,9 +704,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "2.1.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5" +checksum = "434e1720189a637d44fe464f4df1e6eb900b4835255b14354497c78af37d9bb8" dependencies = [ "byteorder", "digest 0.8.1", @@ -745,9 +718,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.0.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8492de420e9e60bc9a1d66e2dbb91825390b738a388606600663fc529b4b307" +checksum = "f627126b946c25a4638eec0ea634fc52506dea98db118aae985118ce7c3d723f" dependencies = [ "byteorder", "digest 0.9.0", @@ -764,9 +737,9 @@ checksum = "993a608597367c6377b258c25d7120740f00ed23a2252b729b1932dd7866f908" [[package]] name = "derivative" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" +checksum = "eaed5874effa6cde088c644ddcdcb4ffd1511391c5be4fdd7a5ccd02c7e4a183" dependencies = [ "proc-macro2", "quote", @@ -833,18 +806,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" dependencies = [ "libc", - "redox_users", + "redox_users 0.3.5", "winapi", ] [[package]] name = "dirs-sys-next" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99de365f605554ae33f115102a02057d4fc18b01f3284d6870be0938743cfe7d" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.0", "winapi", ] @@ -879,7 +852,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek 3.0.0", + "curve25519-dalek 3.0.2", "ed25519", "rand 0.7.3", "serde", @@ -1051,9 +1024,9 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "futures" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3b0c040a1fe6529d30b3c5944b280c7f0dcb2930d2c3062bca967b602583d0" +checksum = "90fa4cc29d25b0687b8570b0da86eac698dcb525110ad8b938fe6712baa711ec" dependencies = [ "futures-channel", "futures-core", @@ -1066,9 +1039,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7109687aa4e177ef6fe84553af6280ef2778bdb7783ba44c9dc3399110fe64" +checksum = "31ebc390c6913de330e418add60e1a7e5af4cb5ec600d19111b339cafcdcc027" dependencies = [ "futures-core", "futures-sink", @@ -1076,15 +1049,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "847ce131b72ffb13b6109a221da9ad97a64cbe48feb1028356b836b47b8f1748" +checksum = "089bd0baf024d3216916546338fffe4fc8dfffdd901e33c278abb091e0d52111" [[package]] name = "futures-executor" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4caa2b2b68b880003057c1dd49f1ed937e38f22fcf6c212188a121f08cf40a65" +checksum = "d0cb59f15119671c94cd9cc543dc9a50b8d5edc468b4ff5f0bb8567f66c6b48a" dependencies = [ "futures-core", "futures-task", @@ -1094,9 +1067,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611834ce18aaa1bd13c4b374f5d653e1027cf99b6b502584ff8c9a64413b30bb" +checksum = "3868967e4e5ab86614e2176c99949eeef6cbcacaee737765f6ae693988273997" [[package]] name = "futures-lite" @@ -1115,9 +1088,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77408a692f1f97bcc61dc001d752e00643408fbc922e4d634c655df50d595556" +checksum = "95778720c3ee3c179cd0d8fd5a0f9b40aa7d745c080f86a8f8bed33c4fd89758" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -1127,15 +1100,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f878195a49cee50e006b02b93cf7e0a95a38ac7b776b4c4d9cc1207cd20fcb3d" +checksum = "d4e0f6be0ec0357772fd58fb751958dd600bd0b3edfd429e77793e4282831360" [[package]] name = "futures-task" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c554eb5bf48b2426c4771ab68c6b14468b6e76cc90996f528c3338d761a4d0d" +checksum = "868090f28a925db6cb7462938c51d807546e298fb314088239f0e52fb4338b96" dependencies = [ "once_cell", ] @@ -1148,9 +1121,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d304cff4a7b99cfb7986f7d43fbe93d175e72e704a8860787cc95e9ffd85cbd2" +checksum = "cad5e82786df758d407932aded1235e24d8e2eb438b6adafd37930c2462fb5d1" dependencies = [ "futures-channel", "futures-core", @@ -1159,7 +1132,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project 1.0.2", + "pin-project-lite", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -1175,19 +1148,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "generator" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc" -dependencies = [ - "cc", - "libc", - "log", - "rustc_version", - "winapi", -] - [[package]] name = "generic-array" version = "0.12.3" @@ -1215,32 +1175,33 @@ checksum = "ac6c41a39c60ae1fc5bf0e220347ce90fa1e4bb0fcdac65b09bb5f4576bebc84" [[package]] name = "getrandom" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi 0.10.1+wasi-snapshot-preview1", ] [[package]] name = "ghash" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6e27f0689a6e15944bdce7e45425efb87eaa8ab0c6e87f11d0987a9133e2531" +checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" dependencies = [ + "opaque-debug 0.3.0", "polyval", ] @@ -1250,7 +1211,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5" dependencies = [ - "bytes 1.0.1", + "bytes", "fnv", "futures-core", "futures-sink", @@ -1290,9 +1251,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" dependencies = [ "unicode-segmentation", ] @@ -1370,11 +1331,11 @@ dependencies = [ [[package]] name = "http" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84129d298a6d57d246960ff8eb831ca4af3f96d29e2e28848dae275408658e26" +checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" dependencies = [ - "bytes 0.5.6", + "bytes", "fnv", "itoa", ] @@ -1385,7 +1346,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994" dependencies = [ - "bytes 1.0.1", + "bytes", "http", ] @@ -1407,7 +1368,7 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12219dc884514cb4a6a03737f4413c0e01c23a1b059b0156004b23f1e19dccbe" dependencies = [ - "bytes 1.0.1", + "bytes", "futures-channel", "futures-core", "futures-util", @@ -1417,7 +1378,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project 1.0.2", + "pin-project 1.0.4", "socket2", "tokio", "tower-service", @@ -1431,7 +1392,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes 1.0.1", + "bytes", "hyper", "native-tls", "tokio", @@ -1472,9 +1433,9 @@ dependencies = [ [[package]] name = "if-watch" -version = "0.1.8" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b8538953a3f0d0d3868f0a706eb4273535e10d72acb5c82c1c23ae48835c85" +checksum = "16d7c5e361e6b05c882b4847dd98992534cebc6fcde7f4bc98225bcf10fd6d0d" dependencies = [ "async-io", "futures", @@ -1531,9 +1492,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "js-sys" @@ -1607,9 +1568,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" [[package]] name = "libp2p" @@ -1618,7 +1579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5133112ce42be9482f6a87be92a605dd6bbc9e93c297aee77d172ff06908f3a" dependencies = [ "atomic", - "bytes 1.0.1", + "bytes", "futures", "lazy_static", "libp2p-core", @@ -1632,7 +1593,7 @@ dependencies = [ "libp2p-yamux", "parity-multiaddr", "parking_lot", - "pin-project 1.0.2", + "pin-project 1.0.4", "smallvec", "wasm-timer", ] @@ -1666,7 +1627,7 @@ dependencies = [ "multistream-select", "parity-multiaddr", "parking_lot", - "pin-project 1.0.2", + "pin-project 1.0.4", "prost", "prost-build", "rand 0.7.3", @@ -1708,7 +1669,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2705dc94b01ab9e3779b42a09bbf3712e637ed213e875c30face247291a85af0" dependencies = [ "asynchronous-codec", - "bytes 1.0.1", + "bytes", "futures", "libp2p-core", "log", @@ -1725,8 +1686,8 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4aca322b52a0c5136142a7c3971446fb1e9964923a526c9cc6ef3b7c94e57778" dependencies = [ - "bytes 1.0.1", - "curve25519-dalek 3.0.0", + "bytes", + "curve25519-dalek 3.0.2", "futures", "lazy_static", "libp2p-core", @@ -1748,7 +1709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d37637a4b33b5390322ccc068a33897d0aa541daf4fec99f6a7efbf37295346e" dependencies = [ "async-trait", - "bytes 1.0.1", + "bytes", "futures", "libp2p-core", "libp2p-swarm", @@ -1763,9 +1724,9 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.27.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4f89ebb4d8953bda12623e9871959fe728dea3bf6eae0421dc9c42dc821e488" +checksum = "22ea8c69839a0e593c8c6a24282cb234d48ac37be4153183f4914e00f5303e75" dependencies = [ "either", "futures", @@ -1836,32 +1797,19 @@ dependencies = [ [[package]] name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if 0.1.10", - "serde", -] - -[[package]] -name = "loom" -version = "0.3.6" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed" +checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" dependencies = [ "cfg-if 0.1.10", - "generator", - "scoped-tls", "serde", - "serde_json", ] [[package]] name = "lru" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3abe07af102235a56ac9a6dd904aab1e05483e2e8afdfffec3598be55b1b7606" +checksum = "3aae342b73d57ad0b8b364bd12584819f2c1fe9114285dfcf8b0722607671635" dependencies = [ "hashbrown", ] @@ -1915,18 +1863,18 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "minicbor" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3265a9f5210bb726f81ef9c456ae0aff5321cd95748c0e71889b0e19d8f0332b" +checksum = "0164190d1771b1458c3742075b057ed55d25cd9dfb930aade99315a1eb1fe12d" dependencies = [ "minicbor-derive", ] [[package]] name = "minicbor-derive" -version = "0.6.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "130b9455e28a3f308f6579671816a6f2621e2e0cbf55dc2f886345bef699481e" +checksum = "2e071b3159835ee91df62dbdbfdd7ec366b7ea77c838f43aff4acda6b61bcfb9" dependencies = [ "proc-macro2", "quote", @@ -1974,7 +1922,7 @@ checksum = "d53d4207d0bd4d1eb3323e33a64f9ea99e5e3d257d5cd7a659fad5be48c8b9af" dependencies = [ "base58-monero", "byteorder", - "curve25519-dalek 2.1.0", + "curve25519-dalek 2.1.2", "fixed-hash 0.3.2", "hex 0.4.2", "keccak-hash 0.3.0", @@ -2043,19 +1991,19 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10ddc0eb0117736f19d556355464fc87efc8ad98b29e3fd84f02531eb6e90840" dependencies = [ - "bytes 1.0.1", + "bytes", "futures", "log", - "pin-project 1.0.2", + "pin-project 1.0.4", "smallvec", "unsigned-varint 0.6.0", ] [[package]] name = "native-tls" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fcc7939b5edc4e4f86b1b4a04bb1498afaaf871b1a6691838ed06fcb48d3a3f" +checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" dependencies = [ "lazy_static", "libc", @@ -2213,9 +2161,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.31" +version = "0.10.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d008f51b1acffa0d3450a68606e6a51c123012edaacb0f4e1426bd978869187" +checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" dependencies = [ "bitflags", "cfg-if 1.0.0", @@ -2233,9 +2181,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.59" +version = "0.9.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de52d8eabd217311538a39bba130d7dea1f1e118010fee7a033d966845e7d5fe" +checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" dependencies = [ "autocfg 1.0.1", "cc", @@ -2264,9 +2212,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "1.3.5" +version = "1.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c740e5fbcb6847058b40ac7e5574766c6388f585e184d769910fe0d3a2ca861" +checksum = "79602888a81ace83e3d1d4b2873286c1f5f906c84db667594e8db8da3506c383" dependencies = [ "arrayvec", "bitvec", @@ -2293,14 +2241,14 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c6d9b8427445284a09c55be860a15855ab580a417ccad9da88f5a06787ced0" +checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall", + "redox_syscall 0.1.57", "smallvec", "winapi", ] @@ -2343,11 +2291,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccc2237c2c489783abd8c4c80e5450fc0e98644555b1364da68cc29aa151ca7" +checksum = "95b70b68509f17aa2857863b6fa00bf21fc93674c7a8893de2f469f6aa7ca2f2" dependencies = [ - "pin-project-internal 1.0.2", + "pin-project-internal 1.0.4", ] [[package]] @@ -2363,9 +2311,9 @@ dependencies = [ [[package]] name = "pin-project-internal" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f" +checksum = "caa25a6393f22ce819b0f50e0be89287292fda8d425be38ee0ca14c4931d9e71" dependencies = [ "proc-macro2", "quote", @@ -2374,9 +2322,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c" +checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" [[package]] name = "pin-utils" @@ -2415,11 +2363,12 @@ dependencies = [ [[package]] name = "polyval" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4fd92d8e0c06d08525d2e2643cc2b5c80c69ae8eb12c18272d501cd7079ccc0" +checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" dependencies = [ "cpuid-bool 0.2.0", + "opaque-debug 0.3.0", "universal-hash", ] @@ -2501,9 +2450,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro-nested" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" @@ -2520,7 +2469,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e6984d2f1a23009bd270b8bb56d0926810a3d483f59c987d77969e9d8e840b2" dependencies = [ - "bytes 1.0.1", + "bytes", "prost-derive", ] @@ -2530,7 +2479,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32d3ebd75ac2679c2af3a92246639f9fcc8a442ee420719cc4fe195b98dd5fa3" dependencies = [ - "bytes 1.0.1", + "bytes", "heck", "itertools", "log", @@ -2561,15 +2510,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b518d7cdd93dab1d1122cf07fa9a60771836c668dde9d9e2a139f957f0d9f1bb" dependencies = [ - "bytes 1.0.1", + "bytes", "prost", ] [[package]] name = "quote" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ "proc-macro2", ] @@ -2631,7 +2580,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", @@ -2640,9 +2589,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "18519b42a40024d661e1714153e9ad0c3de27cd495760ceb09710920f1098b1e" dependencies = [ "libc", "rand_chacha 0.3.0", @@ -2701,7 +2650,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", ] [[package]] @@ -2710,7 +2659,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" dependencies = [ - "getrandom 0.2.2", + "getrandom 0.2.1", ] [[package]] @@ -2808,22 +2757,41 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_syscall" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom 0.1.15", - "redox_syscall", + "getrandom 0.1.16", + "redox_syscall 0.1.57", "rust-argon2", ] +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom 0.2.1", + "redox_syscall 0.2.4", +] + [[package]] name = "regex" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" +checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" dependencies = [ "regex-syntax", ] @@ -2840,9 +2808,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.21" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" +checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" [[package]] name = "remove_dir_all" @@ -2860,7 +2828,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd281b1030aa675fb90aa994d07187645bb3c8fc756ca766e7c3070b439de9de" dependencies = [ "base64 0.13.0", - "bytes 1.0.1", + "bytes", "encoding_rs", "futures-core", "futures-util", @@ -2917,9 +2885,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e81662973c7a8d9663e64a0de4cd642b89a21d64966e3d99606efdc5fb0cc6" +checksum = "a5c739ba050709eae138f053356d27ff818d71fe54ce5a8d9f4c7a660bfb6684" dependencies = [ "num-traits", "serde", @@ -2973,12 +2941,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - [[package]] name = "scopeguard" version = "1.1.0" @@ -3067,9 +3029,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.118" +version = "1.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +checksum = "9bdd36f49e35b61d49efd8aa7fc068fd295961fd2286d0b2ee9a4c7a14e99cc3" dependencies = [ "serde_derive", ] @@ -3105,9 +3067,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "552954ce79a059ddd5fd68c271592374bd15cab2274970380c000118aeffe1cd" dependencies = [ "proc-macro2", "quote", @@ -3116,9 +3078,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" +checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" dependencies = [ "itoa", "ryu", @@ -3170,19 +3132,18 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4921be914e16899a80adefb821f8ddb7974e3f1250223575a44ed994882127" +checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3" dependencies = [ "lazy_static", - "loom", ] [[package]] name = "signature" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f060a7d147e33490ec10da418795238fd7545bba241504d6b31a409f2e6210" +checksum = "0f0242b8e50dd9accdd56170e94ca1ebd223b098eb9c83539a6e367d0f36ae68" [[package]] name = "slab" @@ -3208,9 +3169,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "snow" @@ -3232,9 +3193,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97e0e9fd577458a4f61fb91fcb559ea2afecc54c934119421f9f5d3d5b1a1057" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" dependencies = [ "cfg-if 1.0.0", "libc", @@ -3258,9 +3219,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "standback" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf906c8b8fc3f6ecd1046e01da1d8ddec83e48c8b08b84dcc02b585a6bedf5a8" +checksum = "c66a8cff4fa24853fdf6b51f75c6d7f8206d7c75cab4e467bcd7f25c2b1febe0" dependencies = [ "version_check", ] @@ -3414,7 +3375,7 @@ dependencies = [ "config", "conquer-once", "cross-curve-dleq", - "curve25519-dalek 2.1.0", + "curve25519-dalek 2.1.2", "derivative", "dialoguer", "directories-next", @@ -3462,9 +3423,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.54" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" +checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" dependencies = [ "proc-macro2", "quote", @@ -3485,14 +3446,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", - "rand 0.7.3", - "redox_syscall", + "rand 0.8.2", + "redox_syscall 0.2.4", "remove_dir_all", "winapi", ] @@ -3545,18 +3506,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e" +checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56" +checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" dependencies = [ "proc-macro2", "quote", @@ -3565,18 +3526,18 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" dependencies = [ "lazy_static", ] [[package]] name = "time" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcdaeea317915d59b2b4cd3b5efcd156c309108664277793f5351700c02ce98b" +checksum = "273d3ed44dca264b0d6b3665e8d48fb515042d42466fad93d2a45b90ec4058f7" dependencies = [ "const_fn", "libc", @@ -3636,12 +3597,12 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.1.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8efab2086f17abcddb8f756117665c958feee6b2e39974c2f1600592ab3a4195" +checksum = "0ca04cec6ff2474c638057b65798f60ac183e5e79d3448bb7163d36a39cff6ec" dependencies = [ "autocfg 1.0.1", - "bytes 1.0.1", + "bytes", "libc", "memchr", "mio", @@ -3684,12 +3645,11 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb971a26599ffd28066d387f109746df178eff14d5ea1e235015c5601967a4b" +checksum = "12ae4751faa60b9f96dd8344d74592e5a17c0c9a220413dbc6942d14139bbfcc" dependencies = [ - "async-stream", - "bytes 1.0.1", + "bytes", "futures-core", "futures-sink", "log", @@ -3879,7 +3839,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35581ff83d4101e58b582e607120c7f5ffb17e632a980b1f38334d76b36908b2" dependencies = [ "asynchronous-codec", - "bytes 1.0.1", + "bytes", "futures-io", "futures-util", ] @@ -3905,11 +3865,11 @@ dependencies = [ [[package]] name = "uuid" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "rand 0.7.3", + "getrandom 0.2.1", "serde", ] @@ -3967,9 +3927,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.10.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" [[package]] name = "wasm-bindgen" @@ -4129,7 +4089,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc614d95359fd7afc321b66d2107ede58b246b844cf5d8a0adcca413e439f088" dependencies = [ - "curve25519-dalek 3.0.0", + "curve25519-dalek 3.0.2", "rand_core 0.5.1", "zeroize 1.2.0", ] diff --git a/swap/src/cli.rs b/swap/src/cli.rs index 4a04359b..43aa1bd7 100644 --- a/swap/src/cli.rs +++ b/swap/src/cli.rs @@ -50,6 +50,7 @@ pub enum Command { }, History, Resume(Resume), + Cancel(Cancel), } #[derive(structopt::StructOpt, Debug)] @@ -79,6 +80,24 @@ pub enum Resume { }, } +#[derive(structopt::StructOpt, Debug)] +pub enum Cancel { + BuyXmr { + #[structopt(long = "swap-id")] + swap_id: Uuid, + + // TODO: Remove Alice peer-id/address, it should be saved in the database when running swap + // and loaded from the database when running resume/cancel/refund + #[structopt(long = "counterpart-peer-id")] + alice_peer_id: PeerId, + #[structopt(long = "counterpart-addr")] + alice_addr: Multiaddr, + + #[structopt(flatten)] + config: Config, + }, +} + #[derive(structopt::StructOpt, Debug)] pub struct Config { #[structopt( diff --git a/swap/src/main.rs b/swap/src/main.rs index 450fd4dc..08de692b 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -13,11 +13,12 @@ #![allow(non_snake_case)] use crate::{ - cli::{Command, Options, Resume}, + cli::{Cancel, Command, Options, Resume}, config::{ initial_setup, query_user_for_initial_testnet_config, read_config, ConfigNotInitialized, }, execution_params::GetExecutionParams, + protocol::bob::cancel::CancelError, }; use anyhow::{Context, Result}; use database::Database; @@ -209,6 +210,36 @@ async fn main() -> Result<()> { tokio::spawn(async move { event_loop.run().await }); bob::run(swap).await?; } + Command::Cancel(Cancel::BuyXmr { + swap_id, + alice_peer_id, + alice_addr, + config, + }) => { + // TODO: Optimization: Only init the Bitcoin wallet, Monero wallet unnecessary + let (bitcoin_wallet, monero_wallet) = + init_wallets(config.path, bitcoin_network, monero_network).await?; + + let bob_factory = Builder::new( + seed, + db_path, + swap_id, + Arc::new(bitcoin_wallet), + Arc::new(monero_wallet), + alice_addr, + alice_peer_id, + execution_params, + ); + let (swap, event_loop) = bob_factory.build().await?; + + tokio::spawn(async move { event_loop.run().await }); + + match bob::cancel(swap.swap_id, swap.state, swap.bitcoin_wallet, swap.db).await? { + Ok((txid, _)) => { info!("Cancel transaction successfully published with id {}", txid)}, + Err(CancelError::CancelTimelockNotExpiredYet) => {info!("The Cancel Transaction cannot be published yet, because the timelock has not expired. Please try again later.")}, + Err(CancelError::CancelTxAlreadyPublished) => {info!("The Cancel Transaction has already been published.")} + } + } }; Ok(()) diff --git a/swap/src/protocol/bob.rs b/swap/src/protocol/bob.rs index 94afa7fa..e12ab8b2 100644 --- a/swap/src/protocol/bob.rs +++ b/swap/src/protocol/bob.rs @@ -20,6 +20,7 @@ use tracing::{debug, info}; use uuid::Uuid; pub use self::{ + cancel::cancel, encrypted_signature::EncryptedSignature, event_loop::{EventLoop, EventLoopHandle}, state::*, @@ -29,6 +30,7 @@ pub use self::{ pub use execution_setup::{Message0, Message2, Message4}; use libp2p::request_response::ResponseChannel; +pub mod cancel; mod encrypted_signature; pub mod event_loop; mod execution_setup; diff --git a/swap/src/protocol/bob/cancel.rs b/swap/src/protocol/bob/cancel.rs new file mode 100644 index 00000000..5cff9710 --- /dev/null +++ b/swap/src/protocol/bob/cancel.rs @@ -0,0 +1,60 @@ +use crate::{ + bitcoin::{timelocks::ExpiredTimelocks, Txid, Wallet}, + database::{Database, Swap}, + protocol::bob::BobState, +}; +use anyhow::{bail, Result}; +use std::sync::Arc; +use uuid::Uuid; + +#[derive(Debug, thiserror::Error, Clone, Copy)] +pub enum CancelError { + #[error("The cancel timelock has not expired yet.")] + CancelTimelockNotExpiredYet, + #[error("The cancel transaction has already been published.")] + CancelTxAlreadyPublished, +} + +pub async fn cancel( + swap_id: Uuid, + state: BobState, + bitcoin_wallet: Arc, + db: Database, +) -> Result> { + let state4 = match state { + BobState::BtcLocked(state3) => state3.state4(), + BobState::XmrLockProofReceived { state, .. } => state.state4(), + BobState::XmrLocked(state4) => state4, + BobState::EncSigSent(state4) => state4, + BobState::CancelTimelockExpired(state4) => state4, + _ => bail!( + "Cannot cancel swap {} because it is in state {} which is not refundable.", + swap_id, + state + ), + }; + + if let ExpiredTimelocks::None = state4.expired_timelock(bitcoin_wallet.as_ref()).await? { + return Ok(Err(CancelError::CancelTimelockNotExpiredYet)); + } + + if state4 + .check_for_tx_cancel(bitcoin_wallet.as_ref()) + .await + .is_ok() + { + let state = BobState::BtcCancelled(state4); + let db_state = state.into(); + db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?; + + return Ok(Err(CancelError::CancelTxAlreadyPublished)); + } + + let txid = state4.submit_tx_cancel(bitcoin_wallet.as_ref()).await?; + + let state = BobState::BtcCancelled(state4); + let db_state = state.clone().into(); + db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?; + + Ok(Ok((txid, state))) +} From ad2aefc2a59ac61d566532b6aef885e3adb2cf0e Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Mon, 1 Feb 2021 16:25:33 +1100 Subject: [PATCH 2/8] Refund Command --- swap/src/cli.rs | 19 ++++++++++++++ swap/src/main.rs | 46 ++++++++++++++++++++++++++++++--- swap/src/protocol/bob.rs | 2 ++ swap/src/protocol/bob/refund.rs | 39 ++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 swap/src/protocol/bob/refund.rs diff --git a/swap/src/cli.rs b/swap/src/cli.rs index 43aa1bd7..6fa8d56b 100644 --- a/swap/src/cli.rs +++ b/swap/src/cli.rs @@ -51,6 +51,7 @@ pub enum Command { History, Resume(Resume), Cancel(Cancel), + Refund(Refund), } #[derive(structopt::StructOpt, Debug)] @@ -98,6 +99,24 @@ pub enum Cancel { }, } +#[derive(structopt::StructOpt, Debug)] +pub enum Refund { + BuyXmr { + #[structopt(long = "swap-id")] + swap_id: Uuid, + + // TODO: Remove Alice peer-id/address, it should be saved in the database when running swap + // and loaded from the database when running resume/cancel/refund + #[structopt(long = "counterpart-peer-id")] + alice_peer_id: PeerId, + #[structopt(long = "counterpart-addr")] + alice_addr: Multiaddr, + + #[structopt(flatten)] + config: Config, + }, +} + #[derive(structopt::StructOpt, Debug)] pub struct Config { #[structopt( diff --git a/swap/src/main.rs b/swap/src/main.rs index 08de692b..0b7573d6 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -13,7 +13,7 @@ #![allow(non_snake_case)] use crate::{ - cli::{Cancel, Command, Options, Resume}, + cli::{Cancel, Command, Options, Refund, Resume}, config::{ initial_setup, query_user_for_initial_testnet_config, read_config, ConfigNotInitialized, }, @@ -235,11 +235,49 @@ async fn main() -> Result<()> { tokio::spawn(async move { event_loop.run().await }); match bob::cancel(swap.swap_id, swap.state, swap.bitcoin_wallet, swap.db).await? { - Ok((txid, _)) => { info!("Cancel transaction successfully published with id {}", txid)}, - Err(CancelError::CancelTimelockNotExpiredYet) => {info!("The Cancel Transaction cannot be published yet, because the timelock has not expired. Please try again later.")}, - Err(CancelError::CancelTxAlreadyPublished) => {info!("The Cancel Transaction has already been published.")} + Ok((txid, _)) => { + info!("Cancel transaction successfully published with id {}", txid) + } + Err(CancelError::CancelTimelockNotExpiredYet) => { + info!("The Cancel Transaction cannot be published yet, because the timelock has not expired. Please try again later.") + } + Err(CancelError::CancelTxAlreadyPublished) => { + info!("The Cancel Transaction has already been published.") + } } } + Command::Refund(Refund::BuyXmr { + swap_id, + alice_peer_id, + alice_addr, + config, + }) => { + let (bitcoin_wallet, monero_wallet) = + init_wallets(config.path, bitcoin_network, monero_network).await?; + + // TODO: Optimize to only use the Bitcoin wallet, Monero wallet is unnecessary + let bob_factory = Builder::new( + seed, + db_path, + swap_id, + Arc::new(bitcoin_wallet), + Arc::new(monero_wallet), + alice_addr, + alice_peer_id, + execution_params, + ); + let (swap, event_loop) = bob_factory.build().await?; + + tokio::spawn(async move { event_loop.run().await }); + bob::refund( + swap.swap_id, + swap.state, + swap.execution_params, + swap.bitcoin_wallet, + swap.db, + ) + .await??; + } }; Ok(()) diff --git a/swap/src/protocol/bob.rs b/swap/src/protocol/bob.rs index e12ab8b2..4807d16e 100644 --- a/swap/src/protocol/bob.rs +++ b/swap/src/protocol/bob.rs @@ -23,6 +23,7 @@ pub use self::{ cancel::cancel, encrypted_signature::EncryptedSignature, event_loop::{EventLoop, EventLoopHandle}, + refund::refund, state::*, swap::{run, run_until}, swap_request::*, @@ -34,6 +35,7 @@ pub mod cancel; mod encrypted_signature; pub mod event_loop; mod execution_setup; +pub mod refund; pub mod state; pub mod swap; mod swap_request; diff --git a/swap/src/protocol/bob/refund.rs b/swap/src/protocol/bob/refund.rs new file mode 100644 index 00000000..88331516 --- /dev/null +++ b/swap/src/protocol/bob/refund.rs @@ -0,0 +1,39 @@ +use crate::{ + bitcoin::Wallet, + database::{Database, Swap}, + execution_params::ExecutionParams, + protocol::bob::BobState, +}; +use anyhow::Result; +use std::sync::Arc; +use uuid::Uuid; + +#[derive(thiserror::Error, Debug, Clone, Copy)] +#[error("Cannot refund because swap {0} was not cancelled yet. Make sure to cancel the swap before trying to refund.")] +pub struct SwapNotCancelledYet(Uuid); + +pub async fn refund( + swap_id: Uuid, + state: BobState, + execution_params: ExecutionParams, + bitcoin_wallet: Arc, + db: Database, +) -> Result> { + let state4 = match state { + BobState::BtcCancelled(state4) => state4, + _ => { + return Ok(Err(SwapNotCancelledYet(swap_id))); + } + }; + + state4 + .refund_btc(bitcoin_wallet.as_ref(), execution_params) + .await?; + + let state = BobState::BtcRefunded(state4); + let db_state = state.clone().into(); + + db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?; + + Ok(Ok(state)) +} From c9adbde5d570b82dc18ee2b8a5f55db7f08ebfa1 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Mon, 1 Feb 2021 18:13:08 +1100 Subject: [PATCH 3/8] Add test for Bob's manual cancel and refund --- .github/workflows/ci.yml | 1 + ...refunds_using_cancel_and_refund_command.rs | 66 +++++++++++++++++++ .../happy_path_restart_bob_after_comm.rs | 2 +- ...h_restart_bob_after_lock_proof_received.rs | 2 +- .../happy_path_restart_bob_before_comm.rs | 2 +- swap/tests/punish.rs | 2 +- swap/tests/testutils/mod.rs | 6 +- 7 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 swap/tests/bob_refunds_using_cancel_and_refund_command.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af1d0e69..ebe60e3e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,6 +134,7 @@ jobs: punish, refund_restart_alice_cancelled, refund_restart_alice, + bob_refunds_using_cancel_and_refund_command, ] runs-on: ubuntu-latest steps: diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command.rs new file mode 100644 index 00000000..04b33df1 --- /dev/null +++ b/swap/tests/bob_refunds_using_cancel_and_refund_command.rs @@ -0,0 +1,66 @@ +pub mod testutils; + +use swap::protocol::{alice, bob, bob::BobState}; +use testutils::{bob_run_until::is_btc_locked, FastCancelConfig}; + +#[tokio::test] +async fn given_bob_manually_refunds_after_btc_locked_bob_refunds() { + testutils::setup_test(FastCancelConfig, |mut ctx| async move { + let (alice_swap, _) = ctx.new_swap_as_alice().await; + let (bob_swap, bob_join_handle) = ctx.new_swap_as_bob().await; + + let alice_handle = alice::run(alice_swap); + tokio::spawn(alice_handle); + + let bob_state = bob::run_until(bob_swap, is_btc_locked).await.unwrap(); + + assert!(matches!(bob_state, BobState::BtcLocked { .. })); + + let (bob_swap, bob_join_handle) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + + // Ensure Bob's timelock is expired + if let BobState::BtcLocked(state3) = bob_swap.state.clone() { + state3 + .wait_for_cancel_timelock_to_expire(bob_swap.bitcoin_wallet.as_ref()) + .await + .unwrap(); + } else { + panic!("Bob in unexpected state {}", bob_swap.state); + } + + // Bob manually cancels + let (_, state) = bob::cancel( + bob_swap.swap_id, + bob_swap.state, + bob_swap.bitcoin_wallet, + bob_swap.db, + ) + .await + .unwrap() + .unwrap(); + assert!(matches!(state, BobState::BtcCancelled { .. })); + + let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + assert!(matches!(bob_swap.state, BobState::BtcCancelled { .. })); + + // Bob manually refunds + let bob_state = bob::refund( + bob_swap.swap_id, + bob_swap.state, + bob_swap.execution_params, + bob_swap.bitcoin_wallet, + bob_swap.db, + ) + .await + .unwrap() + .unwrap(); + + ctx.assert_bob_refunded(bob_state).await; + + // TODO: Alice hangs indefinitely waiting for Blob's acknowledge on + // sending the transfer proof + // let alice_state = alice_swap_handle.await.unwrap().unwrap(); + // ctx.assert_alice_refunded(alice_state).await; + }) + .await; +} diff --git a/swap/tests/happy_path_restart_bob_after_comm.rs b/swap/tests/happy_path_restart_bob_after_comm.rs index 87a3b861..6cd08c64 100644 --- a/swap/tests/happy_path_restart_bob_after_comm.rs +++ b/swap/tests/happy_path_restart_bob_after_comm.rs @@ -16,7 +16,7 @@ async fn given_bob_restarts_after_encsig_is_sent_resume_swap() { assert!(matches!(bob_state, BobState::EncSigSent { .. })); - let bob_swap = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; assert!(matches!(bob_swap.state, BobState::EncSigSent { .. })); let bob_state = bob::run(bob_swap).await.unwrap(); diff --git a/swap/tests/happy_path_restart_bob_after_lock_proof_received.rs b/swap/tests/happy_path_restart_bob_after_lock_proof_received.rs index 7101c0ab..d335acc9 100644 --- a/swap/tests/happy_path_restart_bob_after_lock_proof_received.rs +++ b/swap/tests/happy_path_restart_bob_after_lock_proof_received.rs @@ -18,7 +18,7 @@ async fn given_bob_restarts_after_lock_proof_received_resume_swap() { assert!(matches!(bob_state, BobState::XmrLockProofReceived { .. })); - let bob_swap = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; assert!(matches!( bob_swap.state, BobState::XmrLockProofReceived { .. } diff --git a/swap/tests/happy_path_restart_bob_before_comm.rs b/swap/tests/happy_path_restart_bob_before_comm.rs index fd5f8979..7c72adf9 100644 --- a/swap/tests/happy_path_restart_bob_before_comm.rs +++ b/swap/tests/happy_path_restart_bob_before_comm.rs @@ -16,7 +16,7 @@ async fn given_bob_restarts_after_xmr_is_locked_resume_swap() { assert!(matches!(bob_state, BobState::XmrLocked { .. })); - let bob_swap = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; assert!(matches!(bob_swap.state, BobState::XmrLocked { .. })); let bob_state = bob::run(bob_swap).await.unwrap(); diff --git a/swap/tests/punish.rs b/swap/tests/punish.rs index 61de0577..ea29a95a 100644 --- a/swap/tests/punish.rs +++ b/swap/tests/punish.rs @@ -23,7 +23,7 @@ async fn alice_punishes_if_bob_never_acts_after_fund() { // Restart Bob after Alice punished to ensure Bob transitions to // punished and does not run indefinitely - let bob_swap = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; assert!(matches!(bob_swap.state, BobState::BtcLocked { .. })); let bob_state = bob::run(bob_swap).await.unwrap(); diff --git a/swap/tests/testutils/mod.rs b/swap/tests/testutils/mod.rs index 847af388..91a7949f 100644 --- a/swap/tests/testutils/mod.rs +++ b/swap/tests/testutils/mod.rs @@ -145,14 +145,14 @@ impl TestContext { pub async fn stop_and_resume_bob_from_db( &mut self, join_handle: BobEventLoopJoinHandle, - ) -> bob::Swap { + ) -> (bob::Swap, BobEventLoopJoinHandle) { join_handle.0.abort(); let (swap, event_loop) = self.bob_params.builder().build().await.unwrap(); - tokio::spawn(async move { event_loop.run().await }); + let join_handle = tokio::spawn(async move { event_loop.run().await }); - swap + (swap, BobEventLoopJoinHandle(join_handle)) } pub async fn assert_alice_redeemed(&self, state: AliceState) { From 2d5d70d8563534ff4cc3a25c8eba2bd397d854a8 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Mon, 1 Feb 2021 18:14:53 +1100 Subject: [PATCH 4/8] Timeout for Alice waiting for ack for sending transfer proof If dialing Bob fails Alice waits for the acknowledgement of the transfer proof indefinitely. The timout prevents her execution from hanging. Added a ToDo to re-visit the ack receivers. They don't add value at the moment and should be removed. --- swap/src/protocol/alice/event_loop.rs | 30 +++++++++++++++---- swap/src/protocol/alice/steps.rs | 11 +++++-- swap/src/protocol/alice/swap.rs | 1 + ...refunds_using_cancel_and_refund_command.rs | 8 ++--- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index 26efd22b..b2b3873c 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -1,4 +1,5 @@ use crate::{ + execution_params::ExecutionParams, network::{transport::SwapTransport, TokioExecutor}, protocol::{ alice::{Behaviour, OutEvent, State0, State3, SwapResponse, TransferProof}, @@ -9,7 +10,10 @@ use anyhow::{anyhow, Context, Result}; use libp2p::{ core::Multiaddr, futures::FutureExt, request_response::ResponseChannel, PeerId, Swarm, }; -use tokio::sync::mpsc::{Receiver, Sender}; +use tokio::{ + sync::mpsc::{Receiver, Sender}, + time::timeout, +}; use tracing::{error, trace}; #[allow(missing_debug_implementations)] @@ -91,13 +95,27 @@ impl EventLoopHandle { Ok(()) } - pub async fn send_transfer_proof(&mut self, bob: PeerId, msg: TransferProof) -> Result<()> { + pub async fn send_transfer_proof( + &mut self, + bob: PeerId, + msg: TransferProof, + execution_params: ExecutionParams, + ) -> Result<()> { let _ = self.send_transfer_proof.send((bob, msg)).await?; - self.recv_transfer_proof_ack - .recv() - .await - .ok_or_else(|| anyhow!("Failed to receive transfer proof ack from Bob"))?; + // TODO: Re-evaluate if these acknowledges are necessary at all. + // If we don't use a timeout here and Alice fails to dial Bob she will wait + // indefinitely for this acknowledge. + if timeout( + execution_params.bob_time_to_act, + self.recv_transfer_proof_ack.recv(), + ) + .await + .is_err() + { + error!("Failed to receive transfer proof ack from Bob") + } + Ok(()) } } diff --git a/swap/src/protocol/alice/steps.rs b/swap/src/protocol/alice/steps.rs index d07b72d7..8cff4b5e 100644 --- a/swap/src/protocol/alice/steps.rs +++ b/swap/src/protocol/alice/steps.rs @@ -96,6 +96,7 @@ pub async fn lock_xmr( state3: alice::State3, event_loop_handle: &mut EventLoopHandle, monero_wallet: Arc, + execution_params: ExecutionParams, ) -> Result<()> where W: Transfer, @@ -117,9 +118,13 @@ where // Otherwise Alice might publish the lock tx twice! event_loop_handle - .send_transfer_proof(bob_peer_id, TransferProof { - tx_lock_proof: transfer_proof, - }) + .send_transfer_proof( + bob_peer_id, + TransferProof { + tx_lock_proof: transfer_proof, + }, + execution_params, + ) .await?; Ok(()) diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index beb17e91..1d7d5a79 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -165,6 +165,7 @@ async fn run_until_internal( *state3.clone(), &mut event_loop_handle, monero_wallet.clone(), + execution_params, ) .await?; diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command.rs index 04b33df1..854fbe33 100644 --- a/swap/tests/bob_refunds_using_cancel_and_refund_command.rs +++ b/swap/tests/bob_refunds_using_cancel_and_refund_command.rs @@ -10,7 +10,7 @@ async fn given_bob_manually_refunds_after_btc_locked_bob_refunds() { let (bob_swap, bob_join_handle) = ctx.new_swap_as_bob().await; let alice_handle = alice::run(alice_swap); - tokio::spawn(alice_handle); + let alice_swap_handle = tokio::spawn(alice_handle); let bob_state = bob::run_until(bob_swap, is_btc_locked).await.unwrap(); @@ -57,10 +57,8 @@ async fn given_bob_manually_refunds_after_btc_locked_bob_refunds() { ctx.assert_bob_refunded(bob_state).await; - // TODO: Alice hangs indefinitely waiting for Blob's acknowledge on - // sending the transfer proof - // let alice_state = alice_swap_handle.await.unwrap().unwrap(); - // ctx.assert_alice_refunded(alice_state).await; + let alice_state = alice_swap_handle.await.unwrap().unwrap(); + ctx.assert_alice_refunded(alice_state).await; }) .await; } From 02f8eb7f185ea6ea48a7b1f948904dc932347319 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Mon, 1 Feb 2021 19:17:53 +1100 Subject: [PATCH 5/8] Add test for cancel/refund before timelock expired --- .github/workflows/ci.yml | 1 + ..._and_refund_command_timelock_not_exired.rs | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ebe60e3e..b3dbb7ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -135,6 +135,7 @@ jobs: refund_restart_alice_cancelled, refund_restart_alice, bob_refunds_using_cancel_and_refund_command, + bob_refunds_using_cancel_and_refund_command_timelock_not_exired, ] runs-on: ubuntu-latest steps: diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs new file mode 100644 index 00000000..3540a18c --- /dev/null +++ b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs @@ -0,0 +1,56 @@ +pub mod testutils; + +use bob::cancel::CancelError; +use swap::protocol::{alice, bob, bob::BobState}; +use testutils::{bob_run_until::is_btc_locked, SlowCancelConfig}; + +#[tokio::test] +async fn given_bob_manually_cancels_when_timelock_not_expired_errors() { + testutils::setup_test(SlowCancelConfig, |mut ctx| async move { + let (alice_swap, _) = ctx.new_swap_as_alice().await; + let (bob_swap, bob_join_handle) = ctx.new_swap_as_bob().await; + + let alice_handle = alice::run(alice_swap); + tokio::spawn(alice_handle); + + let bob_state = bob::run_until(bob_swap, is_btc_locked).await.unwrap(); + assert!(matches!(bob_state, BobState::BtcLocked {..})); + + let (bob_swap, bob_join_handle) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + assert!(matches!(bob_swap.state, BobState::BtcLocked {..})); + + // Bob manually cancels + let result = bob::cancel( + bob_swap.swap_id, + bob_swap.state, + bob_swap.bitcoin_wallet, + bob_swap.db, + ) + .await + .unwrap() + .err() + .unwrap(); + + assert!(matches!(result, CancelError::CancelTimelockNotExpiredYet)); + + let (bob_swap, bob_join_handle) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + assert!(matches!(bob_swap.state, BobState::BtcLocked {..})); + + // Bob manually refunds + bob::refund( + bob_swap.swap_id, + bob_swap.state, + bob_swap.execution_params, + bob_swap.bitcoin_wallet, + bob_swap.db, + ) + .await + .unwrap() + .err() + .unwrap(); + + let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + assert!(matches!(bob_swap.state, BobState::BtcLocked {..})); + }) + .await; +} From c930ad84a4c3e504beb1da256190cff3e3d67570 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Mon, 1 Feb 2021 22:32:54 +1100 Subject: [PATCH 6/8] Add --force flag for cancel and refund --- .github/workflows/ci.yml | 1 + swap/src/cli.rs | 6 +++ swap/src/main.rs | 13 ++++- swap/src/protocol/bob/cancel.rs | 31 ++++++----- swap/src/protocol/bob/refund.rs | 27 ++++++++-- ...refunds_using_cancel_and_refund_command.rs | 2 + ..._and_refund_command_timelock_not_exired.rs | 10 ++-- ...efund_command_timelock_not_exired_force.rs | 54 +++++++++++++++++++ 8 files changed, 120 insertions(+), 24 deletions(-) create mode 100644 swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3dbb7ab..a46ef1f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,6 +136,7 @@ jobs: refund_restart_alice, bob_refunds_using_cancel_and_refund_command, bob_refunds_using_cancel_and_refund_command_timelock_not_exired, + bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force, ] runs-on: ubuntu-latest steps: diff --git a/swap/src/cli.rs b/swap/src/cli.rs index 6fa8d56b..16f80f2b 100644 --- a/swap/src/cli.rs +++ b/swap/src/cli.rs @@ -96,6 +96,9 @@ pub enum Cancel { #[structopt(flatten)] config: Config, + + #[structopt(short, long)] + force: bool, }, } @@ -114,6 +117,9 @@ pub enum Refund { #[structopt(flatten)] config: Config, + + #[structopt(short, long)] + force: bool, }, } diff --git a/swap/src/main.rs b/swap/src/main.rs index 0b7573d6..71798092 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -215,6 +215,7 @@ async fn main() -> Result<()> { alice_peer_id, alice_addr, config, + force, }) => { // TODO: Optimization: Only init the Bitcoin wallet, Monero wallet unnecessary let (bitcoin_wallet, monero_wallet) = @@ -234,7 +235,15 @@ async fn main() -> Result<()> { tokio::spawn(async move { event_loop.run().await }); - match bob::cancel(swap.swap_id, swap.state, swap.bitcoin_wallet, swap.db).await? { + match bob::cancel( + swap.swap_id, + swap.state, + swap.bitcoin_wallet, + swap.db, + force, + ) + .await? + { Ok((txid, _)) => { info!("Cancel transaction successfully published with id {}", txid) } @@ -251,6 +260,7 @@ async fn main() -> Result<()> { alice_peer_id, alice_addr, config, + force, }) => { let (bitcoin_wallet, monero_wallet) = init_wallets(config.path, bitcoin_network, monero_network).await?; @@ -275,6 +285,7 @@ async fn main() -> Result<()> { swap.execution_params, swap.bitcoin_wallet, swap.db, + force, ) .await??; } diff --git a/swap/src/protocol/bob/cancel.rs b/swap/src/protocol/bob/cancel.rs index 5cff9710..0c1cb0fe 100644 --- a/swap/src/protocol/bob/cancel.rs +++ b/swap/src/protocol/bob/cancel.rs @@ -20,6 +20,7 @@ pub async fn cancel( state: BobState, bitcoin_wallet: Arc, db: Database, + force: bool, ) -> Result> { let state4 = match state { BobState::BtcLocked(state3) => state3.state4(), @@ -34,20 +35,22 @@ pub async fn cancel( ), }; - if let ExpiredTimelocks::None = state4.expired_timelock(bitcoin_wallet.as_ref()).await? { - return Ok(Err(CancelError::CancelTimelockNotExpiredYet)); - } - - if state4 - .check_for_tx_cancel(bitcoin_wallet.as_ref()) - .await - .is_ok() - { - let state = BobState::BtcCancelled(state4); - let db_state = state.into(); - db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?; - - return Ok(Err(CancelError::CancelTxAlreadyPublished)); + if !force { + if let ExpiredTimelocks::None = state4.expired_timelock(bitcoin_wallet.as_ref()).await? { + return Ok(Err(CancelError::CancelTimelockNotExpiredYet)); + } + + if state4 + .check_for_tx_cancel(bitcoin_wallet.as_ref()) + .await + .is_ok() + { + let state = BobState::BtcCancelled(state4); + let db_state = state.into(); + db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?; + + return Ok(Err(CancelError::CancelTxAlreadyPublished)); + } } let txid = state4.submit_tx_cancel(bitcoin_wallet.as_ref()).await?; diff --git a/swap/src/protocol/bob/refund.rs b/swap/src/protocol/bob/refund.rs index 88331516..b341dad2 100644 --- a/swap/src/protocol/bob/refund.rs +++ b/swap/src/protocol/bob/refund.rs @@ -4,7 +4,7 @@ use crate::{ execution_params::ExecutionParams, protocol::bob::BobState, }; -use anyhow::Result; +use anyhow::{bail, Result}; use std::sync::Arc; use uuid::Uuid; @@ -18,11 +18,28 @@ pub async fn refund( execution_params: ExecutionParams, bitcoin_wallet: Arc, db: Database, + force: bool, ) -> Result> { - let state4 = match state { - BobState::BtcCancelled(state4) => state4, - _ => { - return Ok(Err(SwapNotCancelledYet(swap_id))); + let state4 = if force { + match state { + BobState::BtcLocked(state3) => state3.state4(), + BobState::XmrLockProofReceived { state, .. } => state.state4(), + BobState::XmrLocked(state4) => state4, + BobState::EncSigSent(state4) => state4, + BobState::CancelTimelockExpired(state4) => state4, + BobState::BtcCancelled(state4) => state4, + _ => bail!( + "Cannot refund swap {} because it is in state {} which is not refundable.", + swap_id, + state + ), + } + } else { + match state { + BobState::BtcCancelled(state4) => state4, + _ => { + return Ok(Err(SwapNotCancelledYet(swap_id))); + } } }; diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command.rs index 854fbe33..9b64d826 100644 --- a/swap/tests/bob_refunds_using_cancel_and_refund_command.rs +++ b/swap/tests/bob_refunds_using_cancel_and_refund_command.rs @@ -34,6 +34,7 @@ async fn given_bob_manually_refunds_after_btc_locked_bob_refunds() { bob_swap.state, bob_swap.bitcoin_wallet, bob_swap.db, + false, ) .await .unwrap() @@ -50,6 +51,7 @@ async fn given_bob_manually_refunds_after_btc_locked_bob_refunds() { bob_swap.execution_params, bob_swap.bitcoin_wallet, bob_swap.db, + false, ) .await .unwrap() diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs index 3540a18c..a1c3da82 100644 --- a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs +++ b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs @@ -14,10 +14,10 @@ async fn given_bob_manually_cancels_when_timelock_not_expired_errors() { tokio::spawn(alice_handle); let bob_state = bob::run_until(bob_swap, is_btc_locked).await.unwrap(); - assert!(matches!(bob_state, BobState::BtcLocked {..})); + assert!(matches!(bob_state, BobState::BtcLocked { .. })); let (bob_swap, bob_join_handle) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; - assert!(matches!(bob_swap.state, BobState::BtcLocked {..})); + assert!(matches!(bob_swap.state, BobState::BtcLocked { .. })); // Bob manually cancels let result = bob::cancel( @@ -25,6 +25,7 @@ async fn given_bob_manually_cancels_when_timelock_not_expired_errors() { bob_swap.state, bob_swap.bitcoin_wallet, bob_swap.db, + false, ) .await .unwrap() @@ -34,7 +35,7 @@ async fn given_bob_manually_cancels_when_timelock_not_expired_errors() { assert!(matches!(result, CancelError::CancelTimelockNotExpiredYet)); let (bob_swap, bob_join_handle) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; - assert!(matches!(bob_swap.state, BobState::BtcLocked {..})); + assert!(matches!(bob_swap.state, BobState::BtcLocked { .. })); // Bob manually refunds bob::refund( @@ -43,6 +44,7 @@ async fn given_bob_manually_cancels_when_timelock_not_expired_errors() { bob_swap.execution_params, bob_swap.bitcoin_wallet, bob_swap.db, + false, ) .await .unwrap() @@ -50,7 +52,7 @@ async fn given_bob_manually_cancels_when_timelock_not_expired_errors() { .unwrap(); let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; - assert!(matches!(bob_swap.state, BobState::BtcLocked {..})); + assert!(matches!(bob_swap.state, BobState::BtcLocked { .. })); }) .await; } diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs new file mode 100644 index 00000000..098f8752 --- /dev/null +++ b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs @@ -0,0 +1,54 @@ +pub mod testutils; + +use swap::protocol::{alice, bob, bob::BobState}; +use testutils::{bob_run_until::is_btc_locked, SlowCancelConfig}; + +#[tokio::test] +async fn given_bob_manually_forces_cancel_when_timelock_not_expired_errors() { + testutils::setup_test(SlowCancelConfig, |mut ctx| async move { + let (alice_swap, _) = ctx.new_swap_as_alice().await; + let (bob_swap, bob_join_handle) = ctx.new_swap_as_bob().await; + + let alice_handle = alice::run(alice_swap); + tokio::spawn(alice_handle); + + let bob_state = bob::run_until(bob_swap, is_btc_locked).await.unwrap(); + assert!(matches!(bob_state, BobState::BtcLocked { .. })); + + let (bob_swap, bob_join_handle) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + assert!(matches!(bob_swap.state, BobState::BtcLocked { .. })); + + // Bob forces a cancel that will fail + let is_error = bob::cancel( + bob_swap.swap_id, + bob_swap.state, + bob_swap.bitcoin_wallet, + bob_swap.db, + true, + ) + .await + .is_err(); + + assert!(is_error); + + let (bob_swap, bob_join_handle) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + assert!(matches!(bob_swap.state, BobState::BtcLocked { .. })); + + // Bob forces a refund that will fail + let is_error = bob::refund( + bob_swap.swap_id, + bob_swap.state, + bob_swap.execution_params, + bob_swap.bitcoin_wallet, + bob_swap.db, + true, + ) + .await + .is_err(); + + assert!(is_error); + let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + assert!(matches!(bob_swap.state, BobState::BtcLocked { .. })); + }) + .await; +} From 86290649e7d683baafaad013e97ca0e5e4db776b Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Thu, 4 Feb 2021 10:43:02 +1100 Subject: [PATCH 7/8] work in review comments --- swap/src/main.rs | 11 ++++++----- ...g_cancel_and_refund_command_timelock_not_exired.rs | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/swap/src/main.rs b/swap/src/main.rs index 71798092..a088ed5e 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -29,7 +29,7 @@ use protocol::{alice, bob, bob::Builder, SwapAmounts}; use std::{path::PathBuf, sync::Arc}; use structopt::StructOpt; use trace::init_tracing; -use tracing::info; +use tracing::{error, info, warn}; use uuid::Uuid; pub mod bitcoin; @@ -247,11 +247,12 @@ async fn main() -> Result<()> { Ok((txid, _)) => { info!("Cancel transaction successfully published with id {}", txid) } - Err(CancelError::CancelTimelockNotExpiredYet) => { - info!("The Cancel Transaction cannot be published yet, because the timelock has not expired. Please try again later.") - } + Err(CancelError::CancelTimelockNotExpiredYet) => error!( + "The Cancel Transaction cannot be published yet, \ + because the timelock has not expired. Please try again later." + ), Err(CancelError::CancelTxAlreadyPublished) => { - info!("The Cancel Transaction has already been published.") + warn!("The Cancel Transaction has already been published.") } } } diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs index a1c3da82..07b69590 100644 --- a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs +++ b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs @@ -19,7 +19,7 @@ async fn given_bob_manually_cancels_when_timelock_not_expired_errors() { let (bob_swap, bob_join_handle) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; assert!(matches!(bob_swap.state, BobState::BtcLocked { .. })); - // Bob manually cancels + // Bob tries but fails to manually cancel let result = bob::cancel( bob_swap.swap_id, bob_swap.state, @@ -37,7 +37,7 @@ async fn given_bob_manually_cancels_when_timelock_not_expired_errors() { let (bob_swap, bob_join_handle) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; assert!(matches!(bob_swap.state, BobState::BtcLocked { .. })); - // Bob manually refunds + // Bob tries but fails to manually refund bob::refund( bob_swap.swap_id, bob_swap.state, From 53fcd9224c77b7f3292d5ca27f7c0183fca939f2 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Tue, 9 Feb 2021 12:13:43 +1100 Subject: [PATCH 8/8] Give finding the refund tx priority over waiting for the punish transaction to be finalized. This was introduced due to a CI run, where Bob included tx_refund, but Alice had waited until T2 had expired, and then went for punishing Bob instead of refunding. Weirdly, Alice's punich transaction did not fail in that scenario. --- swap/src/protocol/alice/swap.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 1d7d5a79..97a542de 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -417,9 +417,16 @@ async fn run_until_internal( pin_mut!(punish_tx_finalised); pin_mut!(refund_tx_seen); - match select(punish_tx_finalised, refund_tx_seen).await { - Either::Left(_) => { - let state = AliceState::BtcPunished; + match select(refund_tx_seen, punish_tx_finalised).await { + Either::Left((published_refund_tx, _)) => { + let spend_key = extract_monero_private_key( + published_refund_tx, + tx_refund, + state3.s_a, + state3.a.clone(), + state3.S_b_bitcoin, + )?; + let state = AliceState::BtcRefunded { spend_key, state3 }; let db_state = (&state).into(); db.insert_latest_state(swap_id, database::Swap::Alice(db_state)) .await?; @@ -435,15 +442,8 @@ async fn run_until_internal( ) .await } - Either::Right((published_refund_tx, _)) => { - let spend_key = extract_monero_private_key( - published_refund_tx, - tx_refund, - state3.s_a, - state3.a.clone(), - state3.S_b_bitcoin, - )?; - let state = AliceState::BtcRefunded { spend_key, state3 }; + Either::Right(_) => { + let state = AliceState::BtcPunished; let db_state = (&state).into(); db.insert_latest_state(swap_id, database::Swap::Alice(db_state)) .await?;