diff --git a/.docker/Dockerfile.dev-release b/.docker/Dockerfile.dev-release index 33aa9c5d27..3167c38a59 100644 --- a/.docker/Dockerfile.dev-release +++ b/.docker/Dockerfile.dev-release @@ -1,5 +1,5 @@ FROM docker.io/debian:stable-slim WORKDIR /mm2 -COPY target/ci/mm2 /usr/local/bin/mm2 +COPY target/release/mm2 /usr/local/bin/mm2 EXPOSE 7783 CMD ["mm2"] diff --git a/.dockerignore b/.dockerignore index 1cc2f87bf7..5e4e3785e1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,7 +5,7 @@ cmake-build-debug /Dockerfile !/target/release/mm2 -!/target/ci/mm2 +!/target/debug/mm2 /mm2src/*/target /build diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index e43b91bfe6..59ba122cc7 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -15,7 +15,7 @@ env: jobs: linux-x86-64: - timeout-minutes: 30 + timeout-minutes: 60 runs-on: ubuntu-latest container: komodoofficial/ci-container:latest steps: @@ -45,7 +45,7 @@ jobs: run: | rm -f ./MM_VERSION echo $COMMIT_HASH > ./MM_VERSION - cargo build --bin mm2 --profile ci + cargo build --bin mm2 --release - name: Compress build output env: @@ -53,7 +53,7 @@ jobs: if: ${{ env.AVAILABLE != '' }} run: | NAME="mm2_$COMMIT_HASH-linux-x86-64.zip" - zip $NAME target/ci/mm2 -j + zip $NAME target/release/mm2 -j mkdir $BRANCH_NAME mv $NAME ./$BRANCH_NAME/ @@ -83,7 +83,7 @@ jobs: docker push komodoofficial/atomicdexapi:dev-latest mac-x86-64: - timeout-minutes: 30 + timeout-minutes: 60 runs-on: macos-latest steps: - uses: actions/checkout@v3 @@ -104,7 +104,7 @@ jobs: run: | rm -f ./MM_VERSION echo $COMMIT_HASH > ./MM_VERSION - cargo build --bin mm2 --profile ci --target x86_64-apple-darwin + cargo build --bin mm2 --release --target x86_64-apple-darwin - name: Compress build output env: @@ -112,7 +112,7 @@ jobs: if: ${{ env.AVAILABLE != '' }} run: | NAME="mm2_$COMMIT_HASH-mac-x86-64.zip" - zip $NAME target/x86_64-apple-darwin/ci/mm2 -j + zip $NAME target/x86_64-apple-darwin/release/mm2 -j mkdir $BRANCH_NAME mv $NAME ./$BRANCH_NAME/ @@ -130,7 +130,7 @@ jobs: remote: "/uploads/${{ env.BRANCH_NAME }}" win-x86-64: - timeout-minutes: 30 + timeout-minutes: 60 runs-on: windows-latest steps: - uses: actions/checkout@v3 @@ -153,7 +153,7 @@ jobs: remove-item "./MM_VERSION" } echo $Env:COMMIT_HASH > ./MM_VERSION - cargo build --bin mm2 --profile ci + cargo build --bin mm2 --release - name: Compress build output env: @@ -161,7 +161,7 @@ jobs: if: ${{ env.AVAILABLE != '' }} run: | $NAME="mm2_$Env:COMMIT_HASH-win-x86-64.zip" - 7z a $NAME .\target\ci\mm2.exe .\target\ci\*.dll + 7z a $NAME .\target\release\mm2.exe .\target\release\*.dll mkdir $Env:BRANCH_NAME mv $NAME ./$Env:BRANCH_NAME/ @@ -179,7 +179,7 @@ jobs: remote: "/uploads/${{ env.BRANCH_NAME }}" mac-dylib-x86-64: - timeout-minutes: 30 + timeout-minutes: 60 runs-on: macos-latest steps: - uses: actions/checkout@v3 @@ -200,7 +200,7 @@ jobs: run: | rm -f ./MM_VERSION echo $COMMIT_HASH > ./MM_VERSION - cargo rustc --target x86_64-apple-darwin --lib --profile ci --package mm2_bin_lib --crate-type=staticlib + cargo rustc --target x86_64-apple-darwin --lib --release --package mm2_bin_lib --crate-type=staticlib - name: Compress build output env: @@ -208,8 +208,8 @@ jobs: if: ${{ env.AVAILABLE != '' }} run: | NAME="mm2_$COMMIT_HASH-mac-dylib-x86-64.zip" - mv target/x86_64-apple-darwin/ci/libmm2lib.a target/x86_64-apple-darwin/ci/libmm2.a - zip $NAME target/x86_64-apple-darwin/ci/libmm2.a -j + mv target/x86_64-apple-darwin/release/libmm2lib.a target/x86_64-apple-darwin/release/libmm2.a + zip $NAME target/x86_64-apple-darwin/release/libmm2.a -j mkdir $BRANCH_NAME mv $NAME ./$BRANCH_NAME/ @@ -227,7 +227,7 @@ jobs: remote: "/uploads/${{ env.BRANCH_NAME }}" wasm: - timeout-minutes: 30 + timeout-minutes: 60 runs-on: ubuntu-latest container: komodoofficial/ci-container:latest steps: @@ -261,7 +261,7 @@ jobs: run: | rm -f ./MM_VERSION echo $COMMIT_HASH > ./MM_VERSION - wasm-pack build mm2src/mm2_bin_lib --target web --out-dir ../../target/target-wasm-release + wasm-pack build --release mm2src/mm2_bin_lib --target web --out-dir ../../target/target-wasm-release - name: Compress build output env: @@ -287,7 +287,7 @@ jobs: remote: "/uploads/${{ env.BRANCH_NAME }}" ios-aarch64: - timeout-minutes: 30 + timeout-minutes: 60 runs-on: macos-latest steps: - uses: actions/checkout@v3 @@ -309,7 +309,7 @@ jobs: run: | rm -f ./MM_VERSION echo $COMMIT_HASH > ./MM_VERSION - cargo rustc --target aarch64-apple-ios --lib --profile ci --package mm2_bin_lib --crate-type=staticlib + cargo rustc --target aarch64-apple-ios --lib --release --package mm2_bin_lib --crate-type=staticlib - name: Compress build output env: @@ -317,8 +317,8 @@ jobs: if: ${{ env.AVAILABLE != '' }} run: | NAME="mm2_$COMMIT_HASH-ios-aarch64.zip" - mv target/aarch64-apple-ios/ci/libmm2lib.a target/aarch64-apple-ios/ci/libmm2.a - zip $NAME target/aarch64-apple-ios/ci/libmm2.a -j + mv target/aarch64-apple-ios/release/libmm2lib.a target/aarch64-apple-ios/release/libmm2.a + zip $NAME target/aarch64-apple-ios/release/libmm2.a -j mkdir $BRANCH_NAME mv $NAME ./$BRANCH_NAME/ @@ -336,7 +336,7 @@ jobs: remote: "/uploads/${{ env.BRANCH_NAME }}" android-aarch64: - timeout-minutes: 30 + timeout-minutes: 60 runs-on: ubuntu-latest container: komodoofficial/ci-container:latest steps: @@ -372,7 +372,7 @@ jobs: echo $COMMIT_HASH > ./MM_VERSION export PATH=$PATH:/android-ndk/bin - CC_aarch64_linux_android=aarch64-linux-android21-clang CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android21-clang cargo rustc --target=aarch64-linux-android --lib --profile ci --crate-type=staticlib --package mm2_bin_lib + CC_aarch64_linux_android=aarch64-linux-android21-clang CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android21-clang cargo rustc --target=aarch64-linux-android --lib --release --crate-type=staticlib --package mm2_bin_lib - name: Compress build output env: @@ -380,8 +380,8 @@ jobs: if: ${{ env.AVAILABLE != '' }} run: | NAME="mm2_$COMMIT_HASH-android-aarch64.zip" - mv target/aarch64-linux-android/ci/libmm2lib.a target/aarch64-linux-android/ci/libmm2.a - zip $NAME target/aarch64-linux-android/ci/libmm2.a -j + mv target/aarch64-linux-android/release/libmm2lib.a target/aarch64-linux-android/release/libmm2.a + zip $NAME target/aarch64-linux-android/release/libmm2.a -j mkdir $BRANCH_NAME mv $NAME ./$BRANCH_NAME/ @@ -399,7 +399,7 @@ jobs: remote: "/uploads/${{ env.BRANCH_NAME }}" android-armv7: - timeout-minutes: 30 + timeout-minutes: 60 runs-on: ubuntu-latest container: komodoofficial/ci-container:latest steps: @@ -435,7 +435,7 @@ jobs: echo $COMMIT_HASH > ./MM_VERSION export PATH=$PATH:/android-ndk/bin - CC_armv7_linux_androideabi=armv7a-linux-androideabi21-clang CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=armv7a-linux-androideabi21-clang cargo rustc --target=armv7-linux-androideabi --lib --profile ci --crate-type=staticlib --package mm2_bin_lib + CC_armv7_linux_androideabi=armv7a-linux-androideabi21-clang CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=armv7a-linux-androideabi21-clang cargo rustc --target=armv7-linux-androideabi --lib --release --crate-type=staticlib --package mm2_bin_lib - name: Compress build output env: @@ -443,8 +443,8 @@ jobs: if: ${{ env.AVAILABLE != '' }} run: | NAME="mm2_$COMMIT_HASH-android-armv7.zip" - mv target/armv7-linux-androideabi/ci/libmm2lib.a target/armv7-linux-androideabi/ci/libmm2.a - zip $NAME target/armv7-linux-androideabi/ci/libmm2.a -j + mv target/armv7-linux-androideabi/release/libmm2lib.a target/armv7-linux-androideabi/release/libmm2.a + zip $NAME target/armv7-linux-androideabi/release/libmm2.a -j mkdir $BRANCH_NAME mv $NAME ./$BRANCH_NAME/ diff --git a/.github/workflows/fmt-and-lint.yml b/.github/workflows/fmt-and-lint.yml index 09ab32ba8b..2eb992bc8b 100644 --- a/.github/workflows/fmt-and-lint.yml +++ b/.github/workflows/fmt-and-lint.yml @@ -19,11 +19,17 @@ jobs: rustup toolchain install nightly-2022-10-29 --no-self-update --profile=minimal --component rustfmt clippy rustup default nightly-2022-10-29 + - name: Install OS dependencies + run: | + sudo apt-get update + sudo apt-get -y install libudev-dev + if: matrix.os == 'ubuntu-latest' + - name: fmt check run: cargo fmt -- --check - name: x86-64 code lint - run: cargo clippy --all-targets --profile ci -- --D warnings + run: cargo clippy --all-targets --all-features -- --D warnings wasm-lint: timeout-minutes: 45 @@ -37,4 +43,4 @@ jobs: rustup target add wasm32-unknown-unknown - name: wasm code lint - run: cargo clippy --target wasm32-unknown-unknown --profile ci -- --D warnings + run: cargo clippy --target wasm32-unknown-unknown -- --D warnings diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5ff6f0e491..23f3b3d107 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: - name: Test run: | # wget -O - https://raw.githubusercontent.com/KomodoPlatform/komodo/master/zcutil/fetch-params-alt.sh | bash - cargo test --bins --lib --profile ci + cargo test --bins --lib mac-x86-64-unit: timeout-minutes: 90 @@ -50,7 +50,7 @@ jobs: - name: Test run: | # wget -O - https://raw.githubusercontent.com/KomodoPlatform/komodo/master/zcutil/fetch-params-alt.sh | bash - cargo test --bins --lib --target x86_64-apple-darwin --profile ci + cargo test --bins --lib --target x86_64-apple-darwin win-x86-64-unit: timeout-minutes: 90 @@ -86,7 +86,7 @@ jobs: # Restart-Service docker # Get-Service docker - cargo test --bins --lib --profile ci + cargo test --bins --lib linux-x86-64-mm2-integration: timeout-minutes: 90 @@ -105,7 +105,7 @@ jobs: rustup default nightly-2022-10-29 - name: Test - run: cargo test --test 'mm2_tests_main' --profile ci + run: cargo test --test 'mm2_tests_main' # https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration#usage-limits # https://github.com/KomodoPlatform/atomicDEX-API/actions/runs/4419618128/jobs/7748266141#step:4:1790 @@ -127,7 +127,7 @@ jobs: # rustup target add x86_64-apple-darwin # - name: Test - # run: cargo test --test 'mm2_tests_main' --target x86_64-apple-darwin --profile ci + # run: cargo test --test 'mm2_tests_main' --target x86_64-apple-darwin win-x86-64-mm2-integration: timeout-minutes: 90 @@ -146,7 +146,7 @@ jobs: rustup default nightly-2022-10-29 - name: Test - run: cargo test --test 'mm2_tests_main' --profile ci + run: cargo test --test 'mm2_tests_main' docker-tests: timeout-minutes: 90 @@ -167,7 +167,7 @@ jobs: - name: Test run: | wget -O - https://raw.githubusercontent.com/KomodoPlatform/komodo/master/zcutil/fetch-params-alt.sh | bash - cargo test --test 'docker_tests_main' --features run-docker-tests --profile ci + cargo test --test 'docker_tests_main' --features run-docker-tests wasm: timeout-minutes: 90 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e23dc19aa..6a563426fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +## v1.0.3-beta - 2023-04-28 + +**Features:** + +**Enhancements/Fixes:** +- cosmos/iris ethermint account compatibility implemented [#1765](https://github.com/KomodoPlatform/atomicDEX-API/pull/1765) +- p2p stack is improved [#1755](https://github.com/KomodoPlatform/atomicDEX-API/pull/1755) +- - Validate topics if they are mixed or not. +- - Do early return if the message data is not valid (since no point to iterate over and over on the invalid message) +- - Break the loop right after processing any of `SWAP_PREFIX`, `WATCHER_PREFIX`, `TX_HELPER_PREFIX` topic. +- An issue was fixed where we don't have to wait for all EVM nodes to sync the latest account nonce [#1757](https://github.com/KomodoPlatform/atomicDEX-API/pull/1757) +- optimized dev and release compilation profiles and removed ci [#1759](https://github.com/KomodoPlatform/atomicDEX-API/pull/1759) +- fix receiver trade fee for cosmos swaps [#1767](https://github.com/KomodoPlatform/atomicDEX-API/pull/1767) +- All features were enabled to be checked under x86-64 code lint CI step with `--all-features` option [#1760](https://github.com/KomodoPlatform/atomicDEX-API/pull/1760) +- use OS generated secrets for cryptographically secure randomness in `maker_swap` and `tendermint_coin::get_sender_trade_fee_for_denom` [#1753](https://github.com/KomodoPlatform/atomicDEX-API/pull/1753) + + ## v1.0.2-beta - 2023-04-11 **Features:** diff --git a/Cargo.lock b/Cargo.lock index c062b19c4d..9fcb0a62d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4128,7 +4128,7 @@ dependencies = [ [[package]] name = "mm2_bin_lib" -version = "1.0.2-beta" +version = "1.0.3-beta" dependencies = [ "chrono", "common", diff --git a/Cargo.toml b/Cargo.toml index 388116abd7..07bae2c797 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,10 @@ debug-assertions = false # For some reason, opt-level 3 started causing infinite Windows builds after Cosmos integration # TODO troubleshoot it opt-level = 2 +# strip = true +codegen-units = 1 +# lto = true +panic = "abort" [profile.test] # required to avoid a long running process of librustcash additional chain validation that is enabled with debug assertions @@ -63,8 +67,10 @@ debug-assertions = false # Turns debugging symbols off for the out-of-workspace dependencies. debug = false -[profile.ci] -inherits = "dev" -# full debug info is not required +[profile.dev] +opt-level = 0 debug = 1 -debug-assertions = false \ No newline at end of file +debug-assertions = false +panic = 'unwind' +incremental = true +codegen-units = 256 \ No newline at end of file diff --git a/deny.toml b/deny.toml deleted file mode 100644 index a58cbd21e0..0000000000 --- a/deny.toml +++ /dev/null @@ -1,322 +0,0 @@ -# This template contains all of the possible sections and their default values - -# Note that all fields that take a lint level have these possible values: -# * deny - An error will be produced and the check will fail -# * warn - A warning will be produced, but the check will not fail -# * allow - No warning or error will be produced, though in some cases a note -# will be - -# The values provided in this template are the default values that will be used -# when any section or field is not specified in your own configuration - -# If 1 or more target triples (and optionally, target_features) are specified, -# only the specified targets will be checked when running `cargo deny check`. -# This means, if a particular package is only ever used as a target specific -# dependency, such as, for example, the `nix` crate only being used via the -# `target_family = "unix"` configuration, that only having windows targets in -# this list would mean the nix crate, as well as any of its exclusive -# dependencies not shared by any other crates, would be ignored, as the target -# list here is effectively saying which targets you are building for. -targets = [ - # The triple can be any string, but only the target triples built in to - # rustc (as of 1.40) can be checked against actual config expressions - #{ triple = "x86_64-unknown-linux-musl" }, - # You can also specify which target_features you promise are enabled for a - # particular target. target_features are currently not validated against - # the actual valid features supported by the target architecture. - #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, -] - -# This section is considered when running `cargo deny check advisories` -# More documentation for the advisories section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html -[advisories] -# The path where the advisory database is cloned/fetched into -db-path = "~/.cargo/advisory-db" -# The url(s) of the advisory databases to use -db-urls = ["https://github.com/rustsec/advisory-db"] -# The lint level for security vulnerabilities -vulnerability = "deny" -# The lint level for unmaintained crates -unmaintained = "warn" -# The lint level for crates that have been yanked from their source registry -yanked = "warn" -# The lint level for crates with security notices. Note that as of -# 2019-12-17 there are no security notice advisories in -# https://github.com/rustsec/advisory-db -notice = "warn" -# A list of advisory IDs to ignore. Note that ignored advisories will still -# output a note when they are encountered. - -# RUSTSEC-2020-0071 is related to time crate, which is used only by chrono in our deps tree, remove when https://github.com/chronotope/chrono/issues/700 is resolved -# RUSTSEC-2022-0040 is related to owning-ref, which seems unmaintained. We need to find a way to get rid of it. https://github.com/KomodoPlatform/atomicDEX-API/issues/1429 -ignore = [ - "RUSTSEC-2020-0071", - "RUSTSEC-2022-0040", - "RUSTSEC-2022-0041", - "RUSTSEC-2022-0070", - "RUSTSEC-2021-0145", - "RUSTSEC-2020-0056", - "RUSTSEC-2022-0080", - "RUSTSEC-2021-0059", - "RUSTSEC-2021-0060", - "RUSTSEC-2022-0090" -] -# Threshold for security vulnerabilities, any vulnerability with a CVSS score -# lower than the range specified will be ignored. Note that ignored advisories -# will still output a note when they are encountered. -# * None - CVSS Score 0.0 -# * Low - CVSS Score 0.1 - 3.9 -# * Medium - CVSS Score 4.0 - 6.9 -# * High - CVSS Score 7.0 - 8.9 -# * Critical - CVSS Score 9.0 - 10.0 -#severity-threshold = - -# This section is considered when running `cargo deny check licenses` -# More documentation for the licenses section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html -[licenses] -# The lint level for crates which do not have a detectable license -unlicensed = "deny" -# List of explictly allowed licenses -# See https://spdx.org/licenses/ for list of possible licenses -# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. -allow = [ - #"MIT", - #"Apache-2.0", - #"Apache-2.0 WITH LLVM-exception", -] -# List of explictly disallowed licenses -# See https://spdx.org/licenses/ for list of possible licenses -# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. -deny = [ - #"Nokia", -] -# Lint level for licenses considered copyleft -copyleft = "warn" -# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses -# * both - The license will be approved if it is both OSI-approved *AND* FSF -# * either - The license will be approved if it is either OSI-approved *OR* FSF -# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF -# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved -# * neither - This predicate is ignored and the default lint level is used -allow-osi-fsf-free = "neither" -# Lint level used when no other predicates are matched -# 1. License isn't in the allow or deny lists -# 2. License isn't copyleft -# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither" -default = "deny" -# The confidence threshold for detecting a license from license text. -# The higher the value, the more closely the license text must be to the -# canonical license text of a valid SPDX license file. -# [possible values: any between 0.0 and 1.0]. -confidence-threshold = 0.8 -# Allow 1 or more licenses on a per-crate basis, so that particular licenses -# aren't accepted for every possible crate as with the normal allow list -exceptions = [ - # Each entry is the crate and version constraint, and its specific allow - # list - #{ allow = ["Zlib"], name = "adler32", version = "*" }, -] - -# Some crates don't have (easily) machine readable licensing information, -# adding a clarification entry for it allows you to manually specify the -# licensing information -#[[licenses.clarify]] -# The name of the crate the clarification applies to -#name = "ring" -# The optional version constraint for the crate -#version = "*" -# The SPDX expression for the license requirements of the crate -#expression = "MIT AND ISC AND OpenSSL" -# One or more files in the crate's source used as the "source of truth" for -# the license expression. If the contents match, the clarification will be used -# when running the license check, otherwise the clarification will be ignored -# and the crate will be checked normally, which may produce warnings or errors -# depending on the rest of your configuration -#license-files = [ - # Each entry is a crate relative path, and the (opaque) hash of its contents - #{ path = "LICENSE", hash = 0xbd0eed23 } -#] - -[licenses.private] -# If true, ignores workspace crates that aren't published, or are only -# published to private registries -ignore = false -# One or more private registries that you might publish crates to, if a crate -# is only published to private registries, and ignore is true, the crate will -# not have its license(s) checked -registries = [ - #"https://sekretz.com/registry -] - -# This section is considered when running `cargo deny check bans`. -# More documentation about the 'bans' section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html -[bans] -# Lint level for when multiple versions of the same crate are detected -multiple-versions = "deny" -# Lint level for when a crate version requirement is `*` -wildcards = "allow" -# The graph highlighting used when creating dotgraphs for crates -# with multiple versions -# * lowest-version - The path to the lowest versioned duplicate is highlighted -# * simplest-path - The path to the version with the fewest edges is highlighted -# * all - Both lowest-version and simplest-path are used -highlight = "all" -# List of crates that are allowed. Use with care! -allow = [ - #{ name = "ansi_term", version = "=0.11.0" }, -] -# List of crates to deny -deny = [ - # Each entry the name of a crate and a version range. If version is - # not specified, all versions will be matched. - #{ name = "ansi_term", version = "=0.11.0" }, - # - # Wrapper crates can optionally be specified to allow the crate when it - # is a direct dependency of the otherwise banned crate - #{ name = "ansi_term", version = "=0.11.0", wrappers = [] }, -] -# Certain crates/versions that will be skipped when doing duplicate detection. -# The goal is to reduce this list as much as possible -skip = [ - { name = "aes", version = "*" }, - { name = "adler", version = "*" }, - { name = "ahash", version = "*" }, - { name = "arrayvec", version = "*" }, - { name = "autocfg", version = "*" }, - { name = "base64", version = "*" }, - { name = "bitvec", version = "*" }, - { name = "block-buffer", version = "*" }, - { name = "block-padding", version = "*" }, - { name = "byteorder", version = "*" }, - { name = "bytes", version = "*" }, - { name = "cfg-if", version = "*" }, - { name = "cipher", version = "*" }, - { name = "cloudabi", version = "*" }, - { name = "cpufeatures", version = "*" }, - { name = "crossbeam-channel", version = "*" }, - { name = "crossbeam-deque", version = "*" }, - { name = "crossbeam-epoch", version = "*" }, - { name = "crossbeam-utils", version = "*" }, - { name = "crunchy", version = "*" }, - { name = "crypto-mac", version = "*" }, - { name = "cuckoofilter", version = "*" }, - { name = "curve25519-dalek", version = "*" }, - { name = "derivation-path", version = "*" }, - { name = "digest", version = "*" }, - { name = "ed25519-dalek-bip32", version = "*" }, - { name = "env_logger", version = "*" }, - { name = "ethbloom", version = "*" }, - { name = "ethereum-types", version = "*" }, - { name = "ff", version = "*" }, - { name = "fixed-hash", version = "*" }, - { name = "funty", version = "*" }, - { name = "futures", version = "*" }, - { name = "futures-rustls", version = "*" }, - { name = "generic-array", version = "*" }, - { name = "getrandom", version = "*" }, - { name = "group", version = "*" }, - { name = "hashbrown", version = "*" }, - { name = "hex", version = "*" }, - { name = "hmac", version = "*" }, - { name = "http", version = "*" }, - { name = "http-body", version = "*" }, - { name = "humantime", version = "*" }, - { name = "idna", version = "*" }, - { name = "impl-codec", version = "*" }, - { name = "itoa", version = "*" }, - { name = "jsonrpc-core", version = "*" }, - { name = "libp2p-floodsub", version = "*" }, - { name = "libsecp256k1", version = "*" }, - { name = "libsecp256k1-core", version = "*" }, - { name = "libsecp256k1-gen-ecmult", version = "*" }, - { name = "libsecp256k1-gen-genmult", version = "*" }, - { name = "lock_api", version = "*" }, - { name = "log", version = "*" }, - { name = "memoffset", version = "*" }, - { name = "miniz_oxide", version = "*" }, - { name = "mio", version = "*" }, - { name = "num-bigint", version = "*" }, - { name = "opaque-debug", version = "*" }, - { name = "parking_lot", version = "*" }, - { name = "parking_lot_core", version = "*" }, - { name = "pbkdf2", version = "*" }, - { name = "percent-encoding", version = "*" }, - { name = "petgraph", version = "*" }, - { name = "pin-project", version = "*" }, - { name = "pin-project-internal", version = "*" }, - { name = "pin-project-lite", version = "*" }, - { name = "proc-macro-crate", version = "*" }, - { name = "proc-macro2", version = "*" }, - { name = "quote", version = "*" }, - { name = "radium", version = "*" }, - { name = "rand", version = "*" }, - { name = "rand_chacha", version = "*" }, - { name = "rand_core", version = "*" }, - { name = "rand_hc", version = "*" }, - { name = "rand_pcg", version = "*" }, - { name = "redox_syscall", version = "*" }, - { name = "redox_users", version = "*" }, - { name = "rlp", version = "*" }, - { name = "rustc-hex", version = "*" }, - { name = "rustc_version", version = "*" }, - { name = "rustls", version = "*" }, - { name = "rustls-pemfile", version = "*" }, - { name = "scopeguard", version = "*" }, - { name = "sct", version = "*" }, - { name = "secp256k1", version = "*" }, - { name = "secp256k1-sys", version = "*" }, - { name = "semver", version = "*" }, - { name = "send_wrapper", version = "*" }, - { name = "sha2", version = "*" }, - { name = "slab", version = "*" }, - { name = "smallvec", version = "*" }, - { name = "socket2", version = "*" }, - { name = "subtle", version = "*" }, - { name = "syn", version = "*" }, - { name = "time", version = "*" }, - { name = "time-macros", version = "*" }, - { name = "tiny-keccak", version = "*" }, - { name = "tokio-util", version = "*" }, - { name = "trie-root", version = "*" }, - { name = "unicode-xid", version = "*" }, - { name = "unsigned-varint", version = "*" }, - { name = "url", version = "*" }, - { name = "uuid", version = "*" }, - { name = "wasi", version = "*" }, - { name = "webpki", version = "*" }, - { name = "wyz", version = "*" }, -] -# Similarly to `skip` allows you to skip certain crates during duplicate -# detection. Unlike skip, it also includes the entire tree of transitive -# dependencies starting at the specified crate, up to a certain depth, which is -# by default infinite -skip-tree = [ - #{ name = "ansi_term", version = "=0.11.0", depth = 20 }, -] - -# This section is considered when running `cargo deny check sources`. -# More documentation about the 'sources' section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html -[sources] -# Lint level for what to happen when a crate from a crate registry that is not -# in the allow list is encountered -unknown-registry = "warn" -# Lint level for what to happen when a crate from a git repository that is not -# in the allow list is encountered -unknown-git = "warn" -# List of URLs for allowed crate registries. Defaults to the crates.io index -# if not specified. If it is specified but empty, no registries are allowed. -allow-registry = ["https://github.com/rust-lang/crates.io-index"] -# List of URLs for allowed Git repositories -allow-git = [] - -[sources.allow-org] -# 1 or more github.com organizations to allow git sources for -github = [""] -# 1 or more gitlab.com organizations to allow git sources for -gitlab = [""] -# 1 or more bitbucket.org organizations to allow git sources for -bitbucket = [""] diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 8c55c5c366..4f5e25cf34 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -43,7 +43,7 @@ use ethereum_types::{Address, H160, H256, U256}; use ethkey::{public_to_address, KeyPair, Public, Signature}; use ethkey::{sign, verify_address}; use futures::compat::Future01CompatExt; -use futures::future::{join_all, Either, FutureExt, TryFutureExt}; +use futures::future::{join_all, select_ok, Either, FutureExt, TryFutureExt}; use futures01::Future; use http::StatusCode; use mm2_core::mm_ctx::{MmArc, MmWeak}; @@ -775,7 +775,7 @@ async fn withdraw_impl(coin: EthCoin, req: WithdrawRequest) -> WithdrawResult { let (tx_hash, tx_hex) = match coin.priv_key_policy { EthPrivKeyPolicy::KeyPair(ref key_pair) => { let _nonce_lock = coin.nonce_lock.lock().await; - let nonce = get_addr_nonce(coin.my_address, coin.web3_instances.clone()) + let (nonce, _) = get_addr_nonce(coin.my_address, coin.web3_instances.clone()) .compat() .timeout_secs(30.) .await? @@ -924,7 +924,7 @@ pub async fn withdraw_erc1155(ctx: MmArc, req: WithdrawErc1155) -> WithdrawNftRe let (gas, gas_price) = get_eth_gas_details(ð_coin, req.fee, eth_value, data.clone().into(), call_addr, false).await?; let _nonce_lock = eth_coin.nonce_lock.lock().await; - let nonce = get_addr_nonce(eth_coin.my_address, eth_coin.web3_instances.clone()) + let (nonce, _) = get_addr_nonce(eth_coin.my_address, eth_coin.web3_instances.clone()) .compat() .timeout_secs(30.) .await? @@ -992,7 +992,7 @@ pub async fn withdraw_erc721(ctx: MmArc, req: WithdrawErc721) -> WithdrawNftResu let (gas, gas_price) = get_eth_gas_details(ð_coin, req.fee, eth_value, data.clone().into(), call_addr, false).await?; let _nonce_lock = eth_coin.nonce_lock.lock().await; - let nonce = get_addr_nonce(eth_coin.my_address, eth_coin.web3_instances.clone()) + let (nonce, _) = get_addr_nonce(eth_coin.my_address, eth_coin.web3_instances.clone()) .compat() .timeout_secs(30.) .await? @@ -2005,7 +2005,7 @@ async fn sign_and_send_transaction_with_keypair( } let _nonce_lock = coin.nonce_lock.lock().await; status.status(tags!(), "get_addr_nonce…"); - let nonce = try_tx_s!( + let (nonce, web3_instances_with_latest_nonce) = try_tx_s!( get_addr_nonce(coin.my_address, coin.web3_instances.clone()) .compat() .await @@ -2026,14 +2026,10 @@ async fn sign_and_send_transaction_with_keypair( let bytes = Bytes(rlp::encode(&signed).to_vec()); status.status(tags!(), "send_raw_transaction…"); - try_tx_s!( - coin.web3 - .eth() - .send_raw_transaction(bytes) - .await - .map_err(|e| ERRL!("{}", e)), - signed - ); + let futures = web3_instances_with_latest_nonce + .into_iter() + .map(|web3_instance| web3_instance.web3.eth().send_raw_transaction(bytes.clone())); + try_tx_s!(select_ok(futures).await.map_err(|e| ERRL!("{}", e)), signed); status.status(tags!(), "get_addr_nonce…"); coin.wait_for_addr_nonce_increase(coin.my_address, nonce).await; @@ -4012,7 +4008,7 @@ impl EthCoin { Box::new(fut.boxed().compat()) } - /// Checks every second till ETH nodes recognize that nonce is increased. + /// Checks every second till at least one ETH node recognizes that nonce is increased. /// Parity has reliable "nextNonce" method that always returns correct nonce for address. /// But we can't expect that all nodes will always be Parity. /// Some of ETH forks use Geth only so they don't have Parity nodes at all. @@ -4025,8 +4021,8 @@ impl EthCoin { async fn wait_for_addr_nonce_increase(&self, addr: Address, prev_nonce: U256) { repeatable!(async { match get_addr_nonce(addr, self.web3_instances.clone()).compat().await { - Ok(new_nonce) if new_nonce > prev_nonce => Ready(()), - Ok(_nonce) => Retry(()), + Ok((new_nonce, _)) if new_nonce > prev_nonce => Ready(()), + Ok((_nonce, _)) => Retry(()), Err(e) => { error!("Error getting {} {} nonce: {}", self.ticker(), self.my_address, e); Retry(()) @@ -4324,7 +4320,7 @@ impl MmCoin for EthCoin { }) } - fn get_receiver_trade_fee(&self, _send_amount: BigDecimal, stage: FeeApproxStage) -> TradePreimageFut { + fn get_receiver_trade_fee(&self, stage: FeeApproxStage) -> TradePreimageFut { let coin = self.clone(); let fut = async move { let gas_price = coin.get_gas_price().compat().await?; @@ -5015,31 +5011,37 @@ fn checksum_address(addr: &str) -> String { /// The input must be 0x prefixed hex string fn is_valid_checksum_addr(addr: &str) -> bool { addr == checksum_address(addr) } -/// Requests the nonce from all available nodes and checks that returned results equal. -/// Nodes might need some time to sync and there can be other coins that use same nodes in different order. -/// We need to be sure that nonce is updated on all of them before and after transaction is sent. +/// Requests the nonce from all available nodes and returns the highest nonce available with the list of nodes that returned the highest nonce. +/// Transactions will be sent using the nodes that returned the highest nonce. #[cfg_attr(test, mockable)] -fn get_addr_nonce(addr: Address, web3s: Vec) -> Box + Send> { +fn get_addr_nonce( + addr: Address, + web3s: Vec, +) -> Box), Error = String> + Send> { let fut = async move { let mut errors: u32 = 0; loop { - let futures: Vec<_> = web3s + let (futures, web3s): (Vec<_>, Vec<_>) = web3s .iter() .map(|web3| { if web3.is_parity { let parity: ParityNonce<_> = web3.web3.api(); - Either::Left(parity.parity_next_nonce(addr)) + (Either::Left(parity.parity_next_nonce(addr)), web3.clone()) } else { - Either::Right(web3.web3.eth().transaction_count(addr, Some(BlockNumber::Pending))) + ( + Either::Right(web3.web3.eth().transaction_count(addr, Some(BlockNumber::Pending))), + web3.clone(), + ) } }) - .collect(); + .unzip(); let nonces: Vec<_> = join_all(futures) .await .into_iter() - .filter_map(|nonce_res| match nonce_res { - Ok(n) => Some(n), + .zip(web3s.into_iter()) + .filter_map(|(nonce_res, web3)| match nonce_res { + Ok(n) => Some((n, web3)), Err(e) => { error!("Error getting nonce for addr {:?}: {}", addr, e); None @@ -5053,13 +5055,18 @@ fn get_addr_nonce(addr: Address, web3s: Vec) -> Box TradePreimageFut { + fn get_receiver_trade_fee(&self, _stage: FeeApproxStage) -> TradePreimageFut { Box::new(futures01::future::ok(TradeFee { coin: self.ticker().to_owned(), amount: Default::default(), diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 78118f54b7..042238fb59 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -2190,7 +2190,7 @@ pub trait MmCoin: ) -> TradePreimageResult; /// Get fee to be paid by receiver per whole swap and check if the wallet has sufficient balance to pay the fee. - fn get_receiver_trade_fee(&self, send_amount: BigDecimal, stage: FeeApproxStage) -> TradePreimageFut; + fn get_receiver_trade_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; /// Get transaction fee the Taker has to pay to send a `TakerFee` transaction and check if the wallet has sufficient balance to pay the fee. async fn get_fee_to_send_taker_fee( diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 54219400cf..5064ae483c 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -1375,7 +1375,7 @@ impl MmCoin for Qrc20Coin { }) } - fn get_receiver_trade_fee(&self, _send_amount: BigDecimal, stage: FeeApproxStage) -> TradePreimageFut { + fn get_receiver_trade_fee(&self, stage: FeeApproxStage) -> TradePreimageFut { let selfi = self.clone(); let fut = async move { // pass the dummy params diff --git a/mm2src/coins/qrc20/qrc20_tests.rs b/mm2src/coins/qrc20/qrc20_tests.rs index 2835752f0c..60d8a93527 100644 --- a/mm2src/coins/qrc20/qrc20_tests.rs +++ b/mm2src/coins/qrc20/qrc20_tests.rs @@ -916,7 +916,7 @@ fn test_receiver_trade_preimage() { check_tx_fee(&coin, ActualTxFee::FixedPerKb(EXPECTED_TX_FEE as u64)); let actual = coin - .get_receiver_trade_fee(Default::default(), FeeApproxStage::WithoutApprox) + .get_receiver_trade_fee(FeeApproxStage::WithoutApprox) .wait() .expect("!get_receiver_trade_fee"); // only one contract call should be included into the expected trade fee diff --git a/mm2src/coins/solana.rs b/mm2src/coins/solana.rs index ef3cc38c49..6652d5c704 100644 --- a/mm2src/coins/solana.rs +++ b/mm2src/coins/solana.rs @@ -46,9 +46,9 @@ pub mod solana_common; mod solana_decode_tx_helpers; pub mod spl; -mod solana_common_tests; -mod solana_tests; -mod spl_tests; +#[cfg(test)] mod solana_common_tests; +#[cfg(test)] mod solana_tests; +#[cfg(test)] mod spl_tests; pub const SOLANA_DEFAULT_DECIMALS: u64 = 9; pub const LAMPORTS_DUMMY_AMOUNT: u64 = 10; @@ -727,9 +727,7 @@ impl MmCoin for SolanaCoin { unimplemented!() } - fn get_receiver_trade_fee(&self, _send_amount: BigDecimal, _stage: FeeApproxStage) -> TradePreimageFut { - unimplemented!() - } + fn get_receiver_trade_fee(&self, _stage: FeeApproxStage) -> TradePreimageFut { unimplemented!() } async fn get_fee_to_send_taker_fee( &self, diff --git a/mm2src/coins/solana/solana_common_tests.rs b/mm2src/coins/solana/solana_common_tests.rs index 6a332a462b..32b030b425 100644 --- a/mm2src/coins/solana/solana_common_tests.rs +++ b/mm2src/coins/solana/solana_common_tests.rs @@ -32,7 +32,6 @@ pub fn generate_key_pair_from_seed(seed: String) -> Keypair { .unwrap() .derive(&derivation_path) .unwrap(); - let ref priv_key = ext.secret_key; let pub_key = ext.public_key(); let pair = ed25519_dalek::Keypair { secret: ext.secret_key, @@ -59,7 +58,7 @@ pub fn spl_coin_for_test( decimals: u8, token_contract_address: Pubkey, ) -> SplToken { - let spl_coin = SplToken { + SplToken { conf: Arc::new(SplTokenFields { decimals, ticker, @@ -67,8 +66,7 @@ pub fn spl_coin_for_test( abortable_system: AbortableQueue::default(), }), platform_coin: solana_coin, - }; - spl_coin + } } pub fn solana_coin_for_test(seed: String, net_type: SolanaNet) -> (MmArc, SolanaCoin) { @@ -81,7 +79,7 @@ pub fn solana_coin_for_test(seed: String, net_type: SolanaNet) -> (MmArc, Solana {"coin":"SOL","name":"solana","protocol":{"type":"SOL"},"rpcport":80,"mm2":1} ] }); - let ctx = MmCtxBuilder::new().with_conf(conf.clone()).into_mm_arc(); + let ctx = MmCtxBuilder::new().with_conf(conf).into_mm_arc(); let (ticker, decimals) = ("SOL".to_string(), 8); let key_pair = generate_key_pair_from_iguana_seed(seed); let my_address = key_pair.pubkey().to_string(); diff --git a/mm2src/coins/solana/solana_tests.rs b/mm2src/coins/solana/solana_tests.rs index 5004d05dd8..05939b68c5 100644 --- a/mm2src/coins/solana/solana_tests.rs +++ b/mm2src/coins/solana/solana_tests.rs @@ -75,7 +75,7 @@ fn solana_prerequisites() { #[cfg(not(target_arch = "wasm32"))] fn solana_coin_creation() { let passphrase = "federal stay trigger hour exist success game vapor become comfort action phone bright ill target wild nasty crumble dune close rare fabric hen iron".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); assert_eq!( sol_coin.my_address().unwrap(), "FJktmyjV9aBHEShT4hfnLpr9ELywdwVtEL1w1rSWgbVf" @@ -86,7 +86,7 @@ fn solana_coin_creation() { #[cfg(not(target_arch = "wasm32"))] fn solana_my_balance() { let passphrase = "federal stay trigger hour exist success game vapor become comfort action phone bright ill target wild nasty crumble dune close rare fabric hen iron".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); let res = block_on(sol_coin.my_balance().compat()).unwrap(); assert_ne!(res.spendable, BigDecimal::from(0)); } @@ -95,7 +95,7 @@ fn solana_my_balance() { #[cfg(not(target_arch = "wasm32"))] fn solana_block_height() { let passphrase = "federal stay trigger hour exist success game vapor become comfort action phone bright ill target wild nasty crumble dune close rare fabric hen iron".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); let res = block_on(sol_coin.current_block().compat()).unwrap(); println!("block is : {}", res); assert!(res > 0); @@ -105,29 +105,28 @@ fn solana_block_height() { #[cfg(not(target_arch = "wasm32"))] fn solana_validate_address() { let passphrase = "federal stay trigger hour exist success game vapor become comfort action phone bright ill target wild nasty crumble dune close rare fabric hen iron".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); // invalid len let res = sol_coin.validate_address("invalidaddressobviously"); - assert_eq!(res.is_valid, false); - + assert!(!res.is_valid); let res = sol_coin.validate_address("GMtMFbuVgjDnzsBd3LLBfM4X8RyYcDGCM92tPq2PG6B2"); - assert_eq!(res.is_valid, true); + assert!(res.is_valid); // Typo let res = sol_coin.validate_address("Fr8fraJXAe1cFU81mF7NhHTrUzXjZAJkQE1gUQ11riH"); - assert_eq!(res.is_valid, false); + assert!(!res.is_valid); // invalid len let res = sol_coin.validate_address("r8fraJXAe1cFU81mF7NhHTrUzXjZAJkQE1gUQ11riHn"); - assert_eq!(res.is_valid, false); + assert!(!res.is_valid); } #[test] #[cfg(not(target_arch = "wasm32"))] fn test_sign_message() { let passphrase = "spice describe gravity federal blast come thank unfair canal monkey style afraid".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); let signature = sol_coin.sign_message("test").unwrap(); assert_eq!( signature, @@ -139,7 +138,7 @@ fn test_sign_message() { #[cfg(not(target_arch = "wasm32"))] fn test_verify_message() { let passphrase = "spice describe gravity federal blast come thank unfair canal monkey style afraid".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); let is_valid = sol_coin .verify_message( "4dzKwEteN8nch76zPMEjPX19RsaQwGTxsbtfg2bwGTkGenLfrdm31zvn9GH5rvaJBwivp6ESXx1KYR672ngs3UfF", @@ -154,7 +153,7 @@ fn test_verify_message() { #[cfg(not(target_arch = "wasm32"))] fn solana_transaction_simulations() { let passphrase = "federal stay trigger hour exist success game vapor become comfort action phone bright ill target wild nasty crumble dune close rare fabric hen iron".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Devnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Devnet); let request_amount = BigDecimal::try_from(0.0001).unwrap(); let valid_tx_details = block_on( sol_coin @@ -183,7 +182,7 @@ fn solana_transaction_simulations() { #[cfg(not(target_arch = "wasm32"))] fn solana_transaction_zero_balance() { let passphrase = "fake passphrase".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Devnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Devnet); let invalid_tx_details = block_on( sol_coin .withdraw(WithdrawRequest { @@ -204,7 +203,7 @@ fn solana_transaction_zero_balance() { WithdrawError::NotSufficientBalance { required, .. } => { assert_eq!(required, sol_required); }, - e @ _ => panic!("Unexpected err {:?}", e), + e => panic!("Unexpected err {:?}", e), }; } @@ -212,7 +211,7 @@ fn solana_transaction_zero_balance() { #[cfg(not(target_arch = "wasm32"))] fn solana_transaction_simulations_not_enough_for_fees() { let passphrase = "non existent passphrase".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Devnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Devnet); let invalid_tx_details = block_on( sol_coin .withdraw(WithdrawRequest { @@ -238,7 +237,7 @@ fn solana_transaction_simulations_not_enough_for_fees() { assert_eq!(available, 0.into()); assert_eq!(required, sol_required); }, - e @ _ => panic!("Unexpected err {:?}", e), + e => panic!("Unexpected err {:?}", e), }; } @@ -246,7 +245,7 @@ fn solana_transaction_simulations_not_enough_for_fees() { #[cfg(not(target_arch = "wasm32"))] fn solana_transaction_simulations_max() { let passphrase = "federal stay trigger hour exist success game vapor become comfort action phone bright ill target wild nasty crumble dune close rare fabric hen iron".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Devnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Devnet); let valid_tx_details = block_on( sol_coin .withdraw(WithdrawRequest { @@ -275,7 +274,7 @@ fn solana_transaction_simulations_max() { #[cfg(not(target_arch = "wasm32"))] fn solana_test_transactions() { let passphrase = "federal stay trigger hour exist success game vapor become comfort action phone bright ill target wild nasty crumble dune close rare fabric hen iron".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Devnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Devnet); let valid_tx_details = block_on( sol_coin .withdraw(WithdrawRequest { @@ -295,7 +294,7 @@ fn solana_test_transactions() { let tx_str = hex::encode(&*valid_tx_details.tx_hex.0); let res = block_on(sol_coin.send_raw_tx(&tx_str).compat()).unwrap(); - let res2 = block_on(sol_coin.send_raw_tx_bytes(&*valid_tx_details.tx_hex.0).compat()).unwrap(); + let res2 = block_on(sol_coin.send_raw_tx_bytes(&valid_tx_details.tx_hex.0).compat()).unwrap(); assert_eq!(res, res2); //println!("{:?}", res); @@ -307,7 +306,7 @@ fn solana_test_transactions() { #[cfg(not(target_arch = "wasm32"))] fn solana_test_tx_history() { let passphrase = "federal stay trigger hour exist success game vapor become comfort action phone bright ill target wild nasty crumble dune close rare fabric hen iron".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); let res = sol_coin .client .get_signatures_for_address(&sol_coin.key_pair.pubkey()) diff --git a/mm2src/coins/solana/spl.rs b/mm2src/coins/solana/spl.rs index 8aa917aed0..fc97512f77 100644 --- a/mm2src/coins/solana/spl.rs +++ b/mm2src/coins/solana/spl.rs @@ -520,9 +520,7 @@ impl MmCoin for SplToken { unimplemented!() } - fn get_receiver_trade_fee(&self, _send_amount: BigDecimal, _stage: FeeApproxStage) -> TradePreimageFut { - unimplemented!() - } + fn get_receiver_trade_fee(&self, _stage: FeeApproxStage) -> TradePreimageFut { unimplemented!() } async fn get_fee_to_send_taker_fee( &self, diff --git a/mm2src/coins/solana/spl_tests.rs b/mm2src/coins/solana/spl_tests.rs index 22af85ef5c..c405f99b05 100644 --- a/mm2src/coins/solana/spl_tests.rs +++ b/mm2src/coins/solana/spl_tests.rs @@ -9,9 +9,9 @@ use std::str::FromStr; #[cfg(not(target_arch = "wasm32"))] fn spl_coin_creation() { let passphrase = "federal stay trigger hour exist success game vapor become comfort action phone bright ill target wild nasty crumble dune close rare fabric hen iron".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); let sol_spl_usdc_coin = spl_coin_for_test( - sol_coin.clone(), + sol_coin, "USDC".to_string(), 6, solana_sdk::pubkey::Pubkey::from_str("CpMah17kQEL2wqyMKt3mZBdTnZbkbfx4nqmQMFDP5vwp").unwrap(), @@ -28,9 +28,9 @@ fn spl_coin_creation() { #[cfg(not(target_arch = "wasm32"))] fn test_sign_message() { let passphrase = "spice describe gravity federal blast come thank unfair canal monkey style afraid".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); let sol_spl_usdc_coin = spl_coin_for_test( - sol_coin.clone(), + sol_coin, "USDC".to_string(), 6, solana_sdk::pubkey::Pubkey::from_str("CpMah17kQEL2wqyMKt3mZBdTnZbkbfx4nqmQMFDP5vwp").unwrap(), @@ -46,9 +46,9 @@ fn test_sign_message() { #[cfg(not(target_arch = "wasm32"))] fn test_verify_message() { let passphrase = "spice describe gravity federal blast come thank unfair canal monkey style afraid".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); let sol_spl_usdc_coin = spl_coin_for_test( - sol_coin.clone(), + sol_coin, "USDC".to_string(), 6, solana_sdk::pubkey::Pubkey::from_str("CpMah17kQEL2wqyMKt3mZBdTnZbkbfx4nqmQMFDP5vwp").unwrap(), @@ -67,7 +67,7 @@ fn test_verify_message() { #[cfg(not(target_arch = "wasm32"))] fn spl_my_balance() { let passphrase = "federal stay trigger hour exist success game vapor become comfort action phone bright ill target wild nasty crumble dune close rare fabric hen iron".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); let sol_spl_usdc_coin = spl_coin_for_test( sol_coin.clone(), "USDC".to_string(), @@ -80,7 +80,7 @@ fn spl_my_balance() { assert!(res.spendable < BigDecimal::from(10)); let sol_spl_wsol_coin = spl_coin_for_test( - sol_coin.clone(), + sol_coin, "WSOL".to_string(), 8, solana_sdk::pubkey::Pubkey::from_str("So11111111111111111111111111111111111111112").unwrap(), @@ -95,9 +95,9 @@ fn spl_my_balance() { #[cfg(not(target_arch = "wasm32"))] fn test_spl_transactions() { let passphrase = "federal stay trigger hour exist success game vapor become comfort action phone bright ill target wild nasty crumble dune close rare fabric hen iron".to_string(); - let (_, sol_coin) = solana_coin_for_test(passphrase.clone(), SolanaNet::Testnet); + let (_, sol_coin) = solana_coin_for_test(passphrase, SolanaNet::Testnet); let usdc_sol_coin = spl_coin_for_test( - sol_coin.clone(), + sol_coin, "USDC".to_string(), 6, solana_sdk::pubkey::Pubkey::from_str("CpMah17kQEL2wqyMKt3mZBdTnZbkbfx4nqmQMFDP5vwp").unwrap(), @@ -127,6 +127,6 @@ fn test_spl_transactions() { let res = block_on(usdc_sol_coin.send_raw_tx(&tx_str).compat()).unwrap(); println!("{:?}", res); - let res2 = block_on(usdc_sol_coin.send_raw_tx_bytes(&*valid_tx_details.tx_hex.0).compat()).unwrap(); + let res2 = block_on(usdc_sol_coin.send_raw_tx_bytes(&valid_tx_details.tx_hex.0).compat()).unwrap(); assert_eq!(res, res2); } diff --git a/mm2src/coins/tendermint/iris/ethermint_account.rs b/mm2src/coins/tendermint/iris/ethermint_account.rs new file mode 100644 index 0000000000..7fd88ffcfb --- /dev/null +++ b/mm2src/coins/tendermint/iris/ethermint_account.rs @@ -0,0 +1,9 @@ +use cosmrs::proto::cosmos::auth::v1beta1::BaseAccount; + +#[derive(prost::Message)] +pub struct EthermintAccount { + #[prost(message, optional, tag = "1")] + pub base_account: core::option::Option, + #[prost(string, tag = "2")] + pub code_hash: prost::alloc::string::String, +} diff --git a/mm2src/coins/tendermint/iris/mod.rs b/mm2src/coins/tendermint/iris/mod.rs index 00c493c504..03331ac181 100644 --- a/mm2src/coins/tendermint/iris/mod.rs +++ b/mm2src/coins/tendermint/iris/mod.rs @@ -1,2 +1,3 @@ +pub(crate) mod ethermint_account; pub(crate) mod htlc; pub(crate) mod htlc_proto; diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 594508a3af..2ae9ba07fe 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -1,5 +1,6 @@ use super::ibc::transfer_v1::MsgTransfer; use super::ibc::IBC_GAS_LIMIT_DEFAULT; +use super::iris::ethermint_account::EthermintAccount; use super::iris::htlc::{IrisHtlc, MsgClaimHtlc, MsgCreateHtlc, HTLC_STATE_COMPLETED, HTLC_STATE_OPEN, HTLC_STATE_REFUNDED}; use super::iris::htlc_proto::{CreateHtlcProtoRep, QueryHtlcRequestProto, QueryHtlcResponseProto}; @@ -62,7 +63,6 @@ use mm2_number::MmNumber; use parking_lot::Mutex as PaMutex; use primitives::hash::H256; use prost::{DecodeError, Message}; -use rand::{thread_rng, Rng}; use rpc::v1::types::Bytes as BytesJson; use serde_json::{self as json, Value as Json}; use std::collections::HashMap; @@ -92,7 +92,7 @@ const ABCI_REQUEST_PROVE: bool = false; /// 0.25 is good average gas price on atom and iris const DEFAULT_GAS_PRICE: f64 = 0.25; pub(super) const TIMEOUT_HEIGHT_DELTA: u64 = 100; -pub const GAS_LIMIT_DEFAULT: u64 = 100_000; +pub const GAS_LIMIT_DEFAULT: u64 = 125_000; pub(crate) const TX_DEFAULT_MEMO: &str = ""; // https://github.com/irisnet/irismod/blob/5016c1be6fdbcffc319943f33713f4a057622f0a/modules/htlc/types/validation.go#L19-L22 @@ -995,7 +995,22 @@ impl TendermintCoin { let account = account_response .account .or_mm_err(|| TendermintCoinRpcError::InvalidResponse("Account is None".into()))?; - Ok(BaseAccount::decode(account.value.as_slice())?) + + let base_account = match BaseAccount::decode(account.value.as_slice()) { + Ok(account) => account, + Err(err) if &self.account_prefix == "iaa" => { + let ethermint_account = EthermintAccount::decode(account.value.as_slice())?; + + ethermint_account + .base_account + .or_mm_err(|| TendermintCoinRpcError::Prost(err))? + }, + Err(err) => { + return MmError::err(TendermintCoinRpcError::Prost(err)); + }, + }; + + Ok(base_account) } pub(super) async fn balance_for_denom(&self, denom: String) -> MmResult { @@ -1461,7 +1476,11 @@ impl TendermintCoin { amount: BigDecimal, ) -> TradePreimageResult { const TIME_LOCK: u64 = 1750; - let sec: [u8; 32] = thread_rng().gen(); + + let mut sec = [0u8; 32]; + common::os_rng(&mut sec).map_err(|e| MmError::new(TradePreimageError::InternalError(e.to_string())))?; + drop_mutability!(sec); + let to_address = account_id_from_pubkey_hex(&self.account_prefix, DEX_FEE_ADDR_PUBKEY) .map_err(|e| MmError::new(TradePreimageError::InternalError(e.into_inner().to_string())))?; @@ -1988,13 +2007,18 @@ impl MmCoin for TendermintCoin { .await } - fn get_receiver_trade_fee(&self, send_amount: BigDecimal, stage: FeeApproxStage) -> TradePreimageFut { + fn get_receiver_trade_fee(&self, stage: FeeApproxStage) -> TradePreimageFut { let coin = self.clone(); let fut = async move { // We can't simulate Claim Htlc without having information about broadcasted htlc tx. // Since create and claim htlc fees are almost same, we can simply simulate create htlc tx. - coin.get_sender_trade_fee_for_denom(coin.ticker.clone(), coin.denom.clone(), coin.decimals, send_amount) - .await + coin.get_sender_trade_fee_for_denom( + coin.ticker.clone(), + coin.denom.clone(), + coin.decimals, + coin.min_tx_amount(), + ) + .await }; Box::new(fut.boxed().compat()) } @@ -2627,7 +2651,6 @@ pub mod tendermint_coin_tests { use common::{block_on, DEX_FEE_ADDR_RAW_PUBKEY}; use cosmrs::proto::cosmos::tx::v1beta1::{GetTxRequest, GetTxResponse, GetTxsEventResponse}; use crypto::privkey::key_pair_from_seed; - use rand::{thread_rng, Rng}; use std::mem::discriminant; pub const IRIS_TESTNET_HTLC_PAIR1_SEED: &str = "iris test seed"; @@ -2731,7 +2754,11 @@ pub mod tendermint_coin_tests { const UAMOUNT: u64 = 1; let amount: cosmrs::Decimal = UAMOUNT.into(); let amount_dec = big_decimal_from_sat_unsigned(UAMOUNT, coin.decimals); - let sec: [u8; 32] = thread_rng().gen(); + + let mut sec = [0u8; 32]; + common::os_rng(&mut sec).unwrap(); + drop_mutability!(sec); + let time_lock = 1000; let create_htlc_tx = coin diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index 54dc2dbc28..9088e4e12c 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -739,14 +739,19 @@ impl MmCoin for TendermintToken { .await } - fn get_receiver_trade_fee(&self, send_amount: BigDecimal, _stage: FeeApproxStage) -> TradePreimageFut { + fn get_receiver_trade_fee(&self, _stage: FeeApproxStage) -> TradePreimageFut { let token = self.clone(); let fut = async move { // We can't simulate Claim Htlc without having information about broadcasted htlc tx. // Since create and claim htlc fees are almost same, we can simply simulate create htlc tx. token .platform_coin - .get_sender_trade_fee_for_denom(token.ticker.clone(), token.denom.clone(), token.decimals, send_amount) + .get_sender_trade_fee_for_denom( + token.ticker.clone(), + token.denom.clone(), + token.decimals, + token.min_tx_amount(), + ) .await }; Box::new(fut.boxed().compat()) diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index 01e4dda0cc..54bef3a6ba 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -318,9 +318,7 @@ impl MmCoin for TestCoin { unimplemented!() } - fn get_receiver_trade_fee(&self, _send_amount: BigDecimal, _stage: FeeApproxStage) -> TradePreimageFut { - unimplemented!() - } + fn get_receiver_trade_fee(&self, _stage: FeeApproxStage) -> TradePreimageFut { unimplemented!() } async fn get_fee_to_send_taker_fee( &self, diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index 896600d0a3..7ccf3c7bac 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -1234,7 +1234,7 @@ impl MmCoin for BchCoin { utxo_common::get_sender_trade_fee(self, value, stage).await } - fn get_receiver_trade_fee(&self, _send_amount: BigDecimal, _stage: FeeApproxStage) -> TradePreimageFut { + fn get_receiver_trade_fee(&self, _stage: FeeApproxStage) -> TradePreimageFut { utxo_common::get_receiver_trade_fee(self.clone()) } diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index 8fa047cfa1..772bf78575 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -924,7 +924,7 @@ impl MmCoin for QtumCoin { utxo_common::get_sender_trade_fee(self, value, stage).await } - fn get_receiver_trade_fee(&self, _send_amount: BigDecimal, _stage: FeeApproxStage) -> TradePreimageFut { + fn get_receiver_trade_fee(&self, _stage: FeeApproxStage) -> TradePreimageFut { utxo_common::get_receiver_trade_fee(self.clone()) } diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index b5d1731169..1f1053a20b 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -1788,7 +1788,7 @@ impl MmCoin for SlpToken { }) } - fn get_receiver_trade_fee(&self, _send_amount: BigDecimal, _stage: FeeApproxStage) -> TradePreimageFut { + fn get_receiver_trade_fee(&self, _stage: FeeApproxStage) -> TradePreimageFut { let coin = self.clone(); let fut = async move { diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index b21b2fda80..28c5ca0280 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -687,7 +687,7 @@ impl MmCoin for UtxoStandardCoin { utxo_common::get_sender_trade_fee(self, value, stage).await } - fn get_receiver_trade_fee(&self, _send_amount: BigDecimal, _stage: FeeApproxStage) -> TradePreimageFut { + fn get_receiver_trade_fee(&self, _stage: FeeApproxStage) -> TradePreimageFut { utxo_common::get_receiver_trade_fee(self.clone()) } diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 416b6292c1..5816f8231b 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -284,6 +284,11 @@ impl ZCoin { #[inline] pub fn consensus_params_ref(&self) -> &ZcoinConsensusParams { &self.z_fields.consensus_params } + #[inline] + pub async fn is_sapling_state_synced(&self) -> bool { + matches!(self.sync_status().await, Ok(SyncStatus::Finished { block_number: _ })) + } + #[inline] pub async fn sync_status(&self) -> Result> { self.z_fields @@ -1618,7 +1623,7 @@ impl MmCoin for ZCoin { }) } - fn get_receiver_trade_fee(&self, _send_amount: BigDecimal, _stage: FeeApproxStage) -> TradePreimageFut { + fn get_receiver_trade_fee(&self, _stage: FeeApproxStage) -> TradePreimageFut { utxo_common::get_receiver_trade_fee(self.clone()) } diff --git a/mm2src/coins/z_coin/z_coin_native_tests.rs b/mm2src/coins/z_coin/z_coin_native_tests.rs index fca156d0f7..07e5831d58 100644 --- a/mm2src/coins/z_coin/z_coin_native_tests.rs +++ b/mm2src/coins/z_coin/z_coin_native_tests.rs @@ -1,91 +1,96 @@ -use super::*; -use crate::z_coin::z_htlc::z_send_dex_fee; -use common::block_on; -use common::now_ms; +use bitcrypto::dhash160; +use common::{block_on, now_ms}; use mm2_core::mm_ctx::MmCtxBuilder; +use mm2_test_helpers::for_tests::zombie_conf; +use std::path::PathBuf; use std::time::Duration; use zcash_client_backend::encoding::decode_extended_spending_key; +use super::{z_coin_from_conf_and_params_with_z_key, z_mainnet_constants, Future, PrivKeyBuildPolicy, + RefundPaymentArgs, SendPaymentArgs, SpendPaymentArgs, SwapOps, ValidateFeeArgs, ValidatePaymentError, + ZTransaction}; +use crate::z_coin::{z_htlc::z_send_dex_fee, ZcoinActivationParams, ZcoinRpcMode}; +use crate::CoinProtocol; + #[test] fn zombie_coin_send_and_refund_maker_payment() { - let conf = json!({ - "coin": "ZOMBIE", - "asset": "ZOMBIE", - "fname": "ZOMBIE (TESTCOIN)", - "txversion": 4, - "overwintered": 1, - "mm2": 1, - }); - let req = json!({ - "method": "enable", - "coin": "ZOMBIE" - }); - let ctx = MmCtxBuilder::default().into_mm_arc(); - let priv_key = [1; 32]; + let mut conf = zombie_conf(); + let params = default_zcoin_activation_params(); + let pk_data = [1; 32]; + let db_dir = PathBuf::from("./for_tests"); let z_key = decode_extended_spending_key(z_mainnet_constants::HRP_SAPLING_EXTENDED_SPENDING_KEY, "secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe").unwrap().unwrap(); + let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { + CoinProtocol::ZHTLC(protocol_info) => protocol_info, + other_protocol => panic!("Failed to get protocol from config: {:?}", other_protocol), + }; - let db_dir = PathBuf::from("./for_tests"); - let params = UtxoActivationParams::from_legacy_req(&req).unwrap(); let coin = block_on(z_coin_from_conf_and_params_with_z_key( - &ctx, "ZOMBIE", &conf, ¶ms, &priv_key, db_dir, z_key, + &ctx, + "ZOMBIE", + &conf, + ¶ms, + PrivKeyBuildPolicy::IguanaPrivKey(pk_data.into()), + db_dir, + z_key, + protocol_info, )) .unwrap(); - let lock_time = (now_ms() / 1000) as u32 - 3600; + let time_lock = (now_ms() / 1000) as u32 - 3600; let taker_pub = coin.utxo_arc.priv_key_policy.key_pair_or_err().unwrap().public(); let secret_hash = [0; 20]; - let tx = coin - .send_maker_payment( - lock_time, - taker_pub, - taker_pub, - &secret_hash, - "0.01".parse().unwrap(), - &None, - &None, - ) - .wait() - .unwrap(); - println!("swap tx {}", hex::encode(&tx.tx_hash().0)); - - let refund_tx = coin - .send_maker_refunds_payment( - &tx.tx_hex().unwrap(), - lock_time, - &*taker_pub, - &secret_hash, - &priv_key, - &None, - ) - .wait() - .unwrap(); - println!("refund tx {}", hex::encode(&refund_tx.tx_hash().0)); + + let args = SendPaymentArgs { + time_lock_duration: 0, + time_lock, + other_pubkey: taker_pub, + secret_hash: &secret_hash, + amount: "0.01".parse().unwrap(), + swap_contract_address: &None, + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: None, + wait_for_confirmation_until: 0, + }; + let tx = coin.send_maker_payment(args).wait().unwrap(); + println!("swap tx {}", hex::encode(tx.tx_hash().0)); + + let refund_args = RefundPaymentArgs { + payment_tx: &tx.tx_hex(), + time_lock, + other_pubkey: taker_pub, + secret_hash: &secret_hash, + swap_contract_address: &None, + swap_unique_data: pk_data.as_slice(), + watcher_reward: false, + }; + let refund_tx = coin.send_maker_refunds_payment(refund_args).wait().unwrap(); + println!("refund tx {}", hex::encode(refund_tx.tx_hash().0)); } #[test] fn zombie_coin_send_and_spend_maker_payment() { - let conf = json!({ - "coin": "ZOMBIE", - "asset": "ZOMBIE", - "fname": "ZOMBIE (TESTCOIN)", - "txversion": 4, - "overwintered": 1, - "mm2": 1, - }); - let req = json!({ - "method": "enable", - "coin": "ZOMBIE" - }); - let ctx = MmCtxBuilder::default().into_mm_arc(); - let priv_key = [1; 32]; + let mut conf = zombie_conf(); + let params = default_zcoin_activation_params(); + let pk_data = [1; 32]; + let db_dir = PathBuf::from("./for_tests"); let z_key = decode_extended_spending_key(z_mainnet_constants::HRP_SAPLING_EXTENDED_SPENDING_KEY, "secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe").unwrap().unwrap(); + let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { + CoinProtocol::ZHTLC(protocol_info) => protocol_info, + other_protocol => panic!("Failed to get protocol from config: {:?}", other_protocol), + }; - let db_dir = PathBuf::from("./for_tests"); - let params = UtxoActivationParams::from_legacy_req(&req).unwrap(); let coin = block_on(z_coin_from_conf_and_params_with_z_key( - &ctx, "ZOMBIE", &conf, ¶ms, &priv_key, db_dir, z_key, + &ctx, + "ZOMBIE", + &conf, + ¶ms, + PrivKeyBuildPolicy::IguanaPrivKey(pk_data.into()), + db_dir, + z_key, + protocol_info, )) .unwrap(); @@ -93,51 +98,64 @@ fn zombie_coin_send_and_spend_maker_payment() { let taker_pub = coin.utxo_arc.priv_key_policy.key_pair_or_err().unwrap().public(); let secret = [0; 32]; let secret_hash = dhash160(&secret); - let tx = coin - .send_maker_payment( - lock_time, - taker_pub, - taker_pub, - &*secret_hash, - "0.01".parse().unwrap(), - &None, - &None, - ) - .wait() - .unwrap(); - println!("swap tx {}", hex::encode(&tx.tx_hash().0)); + + let maker_payment_args = SendPaymentArgs { + time_lock_duration: 0, + time_lock: lock_time, + other_pubkey: taker_pub, + secret_hash: secret_hash.as_slice(), + amount: "0.01".parse().unwrap(), + swap_contract_address: &None, + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: None, + wait_for_confirmation_until: 0, + }; + + let tx = coin.send_maker_payment(maker_payment_args).wait().unwrap(); + println!("swap tx {}", hex::encode(tx.tx_hash().0)); let maker_pub = taker_pub; + + let spends_payment_args = SpendPaymentArgs { + other_payment_tx: &tx.tx_hex(), + time_lock: lock_time, + other_pubkey: maker_pub, + secret: &secret, + secret_hash: &[], + swap_contract_address: &None, + swap_unique_data: pk_data.as_slice(), + watcher_reward: false, + }; let spend_tx = coin - .send_taker_spends_maker_payment(&tx.tx_hex(), lock_time, &*maker_pub, &secret, &priv_key, &None) + .send_taker_spends_maker_payment(spends_payment_args) .wait() .unwrap(); - println!("spend tx {}", hex::encode(&spend_tx.tx_hash().0)); + println!("spend tx {}", hex::encode(spend_tx.tx_hash().0)); } #[test] fn zombie_coin_send_dex_fee() { - let conf = json!({ - "coin": "ZOMBIE", - "asset": "ZOMBIE", - "fname": "ZOMBIE (TESTCOIN)", - "txversion": 4, - "overwintered": 1, - "mm2": 1, - }); - let req = json!({ - "method": "enable", - "coin": "ZOMBIE" - }); - let ctx = MmCtxBuilder::default().into_mm_arc(); - let priv_key = [1; 32]; + let mut conf = zombie_conf(); + let params = default_zcoin_activation_params(); + let priv_key = PrivKeyBuildPolicy::IguanaPrivKey([1; 32].into()); + let db_dir = PathBuf::from("./for_tests"); let z_key = decode_extended_spending_key(z_mainnet_constants::HRP_SAPLING_EXTENDED_SPENDING_KEY, "secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe").unwrap().unwrap(); + let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { + CoinProtocol::ZHTLC(protocol_info) => protocol_info, + other_protocol => panic!("Failed to get protocol from config: {:?}", other_protocol), + }; - let db_dir = PathBuf::from("./for_tests"); - let params = UtxoActivationParams::from_legacy_req(&req).unwrap(); let coin = block_on(z_coin_from_conf_and_params_with_z_key( - &ctx, "ZOMBIE", &conf, ¶ms, &priv_key, db_dir, z_key, + &ctx, + "ZOMBIE", + &conf, + ¶ms, + priv_key, + db_dir, + z_key, + protocol_info, )) .unwrap(); @@ -147,58 +165,56 @@ fn zombie_coin_send_dex_fee() { #[test] fn prepare_zombie_sapling_cache() { - let conf = json!({ - "coin": "ZOMBIE", - "asset": "ZOMBIE", - "fname": "ZOMBIE", - "txversion": 4, - "overwintered": 1, - "mm2": 1, - }); - let req = json!({ - "method": "enable", - "coin": "ZOMBIE" - }); - let ctx = MmCtxBuilder::default().into_mm_arc(); - let priv_key = [1; 32]; + let mut conf = zombie_conf(); + let params = default_zcoin_activation_params(); + let priv_key = PrivKeyBuildPolicy::IguanaPrivKey([1; 32].into()); + let db_dir = PathBuf::from("./for_tests"); let z_key = decode_extended_spending_key(z_mainnet_constants::HRP_SAPLING_EXTENDED_SPENDING_KEY, "secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe").unwrap().unwrap(); + let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { + CoinProtocol::ZHTLC(protocol_info) => protocol_info, + other_protocol => panic!("Failed to get protocol from config: {:?}", other_protocol), + }; - let db_dir = PathBuf::from("./for_tests"); - let params = UtxoActivationParams::from_legacy_req(&req).unwrap(); let coin = block_on(z_coin_from_conf_and_params_with_z_key( - &ctx, "ZOMBIE", &conf, ¶ms, &priv_key, db_dir, z_key, + &ctx, + "ZOMBIE", + &conf, + ¶ms, + priv_key, + db_dir, + z_key, + protocol_info, )) .unwrap(); - while !coin.is_sapling_state_synced() { + while !block_on(coin.is_sapling_state_synced()) { std::thread::sleep(Duration::from_secs(1)); } } #[test] fn zombie_coin_validate_dex_fee() { - let conf = json!({ - "coin": "ZOMBIE", - "asset": "ZOMBIE", - "fname": "ZOMBIE (TESTCOIN)", - "txversion": 4, - "overwintered": 1, - "mm2": 1, - }); - let req = json!({ - "method": "enable", - "coin": "ZOMBIE" - }); - let ctx = MmCtxBuilder::default().into_mm_arc(); - let priv_key = [1; 32]; + let mut conf = zombie_conf(); + let params = default_zcoin_activation_params(); + let priv_key = PrivKeyBuildPolicy::IguanaPrivKey([1; 32].into()); + let db_dir = PathBuf::from("./for_tests"); let z_key = decode_extended_spending_key(z_mainnet_constants::HRP_SAPLING_EXTENDED_SPENDING_KEY, "secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe").unwrap().unwrap(); + let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { + CoinProtocol::ZHTLC(protocol_info) => protocol_info, + other_protocol => panic!("Failed to get protocol from config: {:?}", other_protocol), + }; - let db_dir = PathBuf::from("./for_tests"); - let params = UtxoActivationParams::from_legacy_req(&req).unwrap(); let coin = block_on(z_coin_from_conf_and_params_with_z_key( - &ctx, "ZOMBIE", &conf, ¶ms, &priv_key, db_dir, z_key, + &ctx, + "ZOMBIE", + &conf, + ¶ms, + priv_key, + db_dir, + z_key, + protocol_info, )) .unwrap(); @@ -208,32 +224,70 @@ fn zombie_coin_validate_dex_fee() { let tx = ZTransaction::read(tx_bytes.as_slice()).unwrap(); let tx = tx.into(); + let validate_fee_args = ValidateFeeArgs { + fee_tx: &tx, + expected_sender: &[], + fee_addr: &[], + amount: &"0.001".parse().unwrap(), + min_block_number: 12000, + uuid: &[1; 16], + }; // Invalid amount should return an error - let err = coin - .validate_fee(&tx, &[], &[], &"0.001".parse().unwrap(), 12000, &[1; 16]) - .wait() - .unwrap_err(); - println!("{}", err); - assert!(err.contains("Dex fee has invalid amount")); + let err = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + match err { + ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("Dex fee has invalid amount")), + _ => panic!("Expected `WrongPaymentTx`: {:?}", err), + } // Invalid memo should return an error - let err = coin - .validate_fee(&tx, &[], &[], &"0.01".parse().unwrap(), 12000, &[2; 16]) - .wait() - .unwrap_err(); - println!("{}", err); - assert!(err.contains("Dex fee has invalid memo")); + let validate_fee_args = ValidateFeeArgs { + fee_tx: &tx, + expected_sender: &[], + fee_addr: &[], + amount: &"0.01".parse().unwrap(), + min_block_number: 12000, + uuid: &[2; 16], + }; + let err = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + match err { + ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("Dex fee has invalid memo")), + _ => panic!("Expected `WrongPaymentTx`: {:?}", err), + } // Confirmed before min block - let err = coin - .validate_fee(&tx, &[], &[], &"0.01".parse().unwrap(), 14000, &[1; 16]) - .wait() - .unwrap_err(); - println!("{}", err); - assert!(err.contains("confirmed before min block")); + let validate_fee_args = ValidateFeeArgs { + fee_tx: &tx, + expected_sender: &[], + fee_addr: &[], + amount: &"0.01".parse().unwrap(), + min_block_number: 14000, + uuid: &[1; 16], + }; + let err = coin.validate_fee(validate_fee_args).wait().unwrap_err().into_inner(); + match err { + ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("confirmed before min block")), + _ => panic!("Expected `WrongPaymentTx`: {:?}", err), + } // Success validation - coin.validate_fee(&tx, &[], &[], &"0.01".parse().unwrap(), 12000, &[1; 16]) - .wait() - .unwrap(); + let validate_fee_args = ValidateFeeArgs { + fee_tx: &tx, + expected_sender: &[], + fee_addr: &[], + amount: &"0.01".parse().unwrap(), + min_block_number: 12000, + uuid: &[1; 16], + }; + coin.validate_fee(validate_fee_args).wait().unwrap(); +} + +fn default_zcoin_activation_params() -> ZcoinActivationParams { + ZcoinActivationParams { + mode: ZcoinRpcMode::Native, + required_confirmations: None, + requires_notarization: None, + zcash_params_path: None, + scan_blocks_per_iteration: 0, + scan_interval_ms: 0, + } } diff --git a/mm2src/common/common.rs b/mm2src/common/common.rs index 67e7ff7ce8..6f23003fa3 100644 --- a/mm2src/common/common.rs +++ b/mm2src/common/common.rs @@ -138,6 +138,7 @@ use futures01::{future, Future}; use http::header::CONTENT_TYPE; use http::Response; use parking_lot::{Mutex as PaMutex, MutexGuard as PaMutexGuard}; +use rand::RngCore; use rand::{rngs::SmallRng, SeedableRng}; use serde::{de, ser}; use serde_json::{self as json, Value as Json}; @@ -747,6 +748,9 @@ pub fn writeln(line: &str) { pub fn small_rng() -> SmallRng { SmallRng::seed_from_u64(now_ms()) } +#[inline(always)] +pub fn os_rng(dest: &mut [u8]) -> Result<(), rand::Error> { rand::rngs::OsRng.try_fill_bytes(dest) } + #[derive(Debug, Clone)] /// Ordered from low to height inclusive range. pub struct OrdRange(RangeInclusive); diff --git a/mm2src/mm2_bin_lib/Cargo.toml b/mm2src/mm2_bin_lib/Cargo.toml index c216278742..3ed3fdcc61 100644 --- a/mm2src/mm2_bin_lib/Cargo.toml +++ b/mm2src/mm2_bin_lib/Cargo.toml @@ -5,7 +5,7 @@ [package] name = "mm2_bin_lib" -version = "1.0.2-beta" +version = "1.0.3-beta" authors = ["James Lee", "Artem Pikulin", "Artem Grinblat", "Omar S.", "Onur Ozkan", "Alina Sharon", "Caglar Kaya", "Cipi", "Sergey Boiko", "Samuel Onoja", "Roman Sztergbaum", "Kadan Stadelmann "] edition = "2018" default-run = "mm2" diff --git a/mm2src/mm2_libp2p/src/lib.rs b/mm2src/mm2_libp2p/src/lib.rs index 8027121c8f..a99841329e 100644 --- a/mm2src/mm2_libp2p/src/lib.rs +++ b/mm2src/mm2_libp2p/src/lib.rs @@ -16,7 +16,7 @@ use secp256k1::{Message as SecpMessage, PublicKey as Secp256k1Pubkey, Secp256k1, use sha2::{Digest, Sha256}; pub use atomicdex_behaviour::{spawn_gossipsub, AdexBehaviourError, NodeType, WssCerts}; -pub use atomicdex_gossipsub::{GossipsubEvent, GossipsubMessage, MessageId}; +pub use atomicdex_gossipsub::{GossipsubEvent, GossipsubMessage, MessageId, TopicHash}; pub use libp2p::identity::error::DecodingError; pub use libp2p::identity::secp256k1::PublicKey as Libp2pSecpPublic; pub use libp2p::identity::PublicKey as Libp2pPublic; diff --git a/mm2src/mm2_main/src/lp_network.rs b/mm2src/mm2_main/src/lp_network.rs index ba10ee46c3..c1c58a722c 100644 --- a/mm2src/mm2_main/src/lp_network.rs +++ b/mm2src/mm2_main/src/lp_network.rs @@ -30,7 +30,7 @@ use mm2_libp2p::atomicdex_behaviour::{AdexBehaviourCmd, AdexBehaviourEvent, Adex AdexResponseChannel}; use mm2_libp2p::peers_exchange::PeerAddresses; use mm2_libp2p::{decode_message, encode_message, DecodingError, GossipsubMessage, Libp2pPublic, Libp2pSecpPublic, - MessageId, NetworkPorts, PeerId, TOPIC_SEPARATOR}; + MessageId, NetworkPorts, PeerId, TopicHash, TOPIC_SEPARATOR}; use mm2_metrics::{mm_label, mm_timing}; #[cfg(test)] use mocktopus::macros::*; use parking_lot::Mutex as PaMutex; @@ -39,7 +39,8 @@ use std::net::ToSocketAddrs; use std::sync::Arc; use wasm_timer::Instant; -use crate::mm2::{lp_ordermatch, lp_stats, lp_swap}; +use crate::mm2::lp_ordermatch; +use crate::mm2::{lp_stats, lp_swap}; pub type P2PRequestResult = Result>; @@ -138,36 +139,99 @@ async fn process_p2p_message( mut message: GossipsubMessage, i_am_relay: bool, ) { + fn is_valid(topics: &[TopicHash]) -> Result<(), String> { + if topics.is_empty() { + return Err("At least one topic must be provided.".to_string()); + } + + let first_topic_prefix = topics[0].as_str().split(TOPIC_SEPARATOR).next().unwrap_or_default(); + for item in topics.iter().skip(1) { + if !item.as_str().starts_with(first_topic_prefix) { + return Err(format!( + "Topics are invalid, received more than one topic kind. Topics '{:?}", + topics + )); + } + } + + Ok(()) + } + let mut to_propagate = false; - let mut orderbook_pairs = vec![]; message.topics.dedup(); drop_mutability!(message); - for topic in message.topics { + if let Err(err) = is_valid(&message.topics) { + log::error!("{}", err); + return; + } + + let inform_about_break = |used: &str, all: &[TopicHash]| { + log::debug!( + "Topic '{}' proceed and loop is killed. Whole topic list was '{:?}'", + used, + all + ); + }; + + for topic in message.topics.iter() { let mut split = topic.as_str().split(TOPIC_SEPARATOR); + match split.next() { Some(lp_ordermatch::ORDERBOOK_PREFIX) => { - if let Some(pair) = split.next() { - orderbook_pairs.push(pair.to_string()); + let fut = lp_ordermatch::handle_orderbook_msg( + ctx.clone(), + &message.topics, + peer_id.to_string(), + &message.data, + i_am_relay, + ); + + if let Err(e) = fut.await { + if e.get_inner().is_warning() { + log::warn!("{}", e); + } else { + log::error!("{}", e); + } + return; } + + to_propagate = true; + break; }, Some(lp_swap::SWAP_PREFIX) => { - lp_swap::process_msg(ctx.clone(), split.next().unwrap_or_default(), &message.data).await; + if let Err(e) = + lp_swap::process_swap_msg(ctx.clone(), split.next().unwrap_or_default(), &message.data).await + { + log::error!("{}", e); + return; + } + to_propagate = true; + + inform_about_break(topic.as_str(), &message.topics); + break; }, Some(lp_swap::WATCHER_PREFIX) => { if ctx.is_watcher() { - lp_swap::process_watcher_msg(ctx.clone(), &message.data).await; + if let Err(e) = lp_swap::process_watcher_msg(ctx.clone(), &message.data) { + log::error!("{}", e); + return; + } } + to_propagate = true; + + inform_about_break(topic.as_str(), &message.topics); + break; }, Some(lp_swap::TX_HELPER_PREFIX) => { if let Some(pair) = split.next() { if let Ok(Some(coin)) = lp_coinfind(&ctx, pair).await { if let Err(e) = coin.tx_enum_from_bytes(&message.data) { log::error!("Message cannot continue the process due to: {:?}", e); - continue; + return; }; let fut = coin.send_raw_tx_bytes(&message.data); @@ -182,25 +246,14 @@ async fn process_p2p_message( }) } } + + inform_about_break(topic.as_str(), &message.topics); + break; }, None | Some(_) => (), } } - if !orderbook_pairs.is_empty() { - let process_fut = lp_ordermatch::process_msg( - ctx.clone(), - orderbook_pairs, - peer_id.to_string(), - &message.data, - i_am_relay, - ); - - if process_fut.await { - to_propagate = true; - } - } - if to_propagate && i_am_relay { propagate_message(&ctx, message_id, peer_id); } diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 5fc9d248db..0827b40f24 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -42,7 +42,8 @@ use http::Response; use keys::{AddressFormat, KeyPair}; use mm2_core::mm_ctx::{from_ctx, MmArc, MmWeak}; use mm2_err_handle::prelude::*; -use mm2_libp2p::{decode_signed, encode_and_sign, encode_message, pub_sub_topic, TopicPrefix, TOPIC_SEPARATOR}; +use mm2_libp2p::{decode_signed, encode_and_sign, encode_message, pub_sub_topic, TopicHash, TopicPrefix, + TOPIC_SEPARATOR}; use mm2_metrics::mm_gauge; use mm2_number::{construct_detailed, BigDecimal, BigRational, Fraction, MmNumber, MmNumberMultiRepr}; #[cfg(test)] use mocktopus::macros::*; @@ -61,7 +62,8 @@ use std::time::Duration; use trie_db::NodeCodec as NodeCodecT; use uuid::Uuid; -use crate::mm2::lp_network::{broadcast_p2p_msg, request_any_relay, request_one_peer, subscribe_to_topic, P2PRequest}; +use crate::mm2::lp_network::{broadcast_p2p_msg, request_any_relay, request_one_peer, subscribe_to_topic, P2PRequest, + P2PRequestError}; use crate::mm2::lp_swap::{calc_max_maker_vol, check_balance_for_maker_swap, check_balance_for_taker_swap, check_other_coin_balance_for_swap, get_max_maker_vol, insert_new_swap_to_db, is_pubkey_banned, lp_atomic_locktime, p2p_keypair_and_peer_id_to_broadcast, @@ -123,6 +125,39 @@ const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 300; #[cfg(test)] const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 3; +pub type OrderbookP2PHandlerResult = Result<(), MmError>; + +#[derive(Display)] +pub enum OrderbookP2PHandlerError { + #[display(fmt = "'{}' is an invalid topic for the orderbook handler.", _0)] + InvalidTopic(String), + + #[display(fmt = "Message decoding was failed. Error: {}", _0)] + DecodeError(String), + + #[display(fmt = "Pubkey '{}' is not allowed.", _0)] + PubkeyNotAllowed(String), + + #[display(fmt = "P2P request error: {}", _0)] + P2PRequestError(String), + + #[display( + fmt = "Couldn't find an order {}, ignoring, it will be synced upon pubkey keep alive", + _0 + )] + OrderNotFound(Uuid), + + Internal(String), +} + +impl OrderbookP2PHandlerError { + pub(crate) fn is_warning(&self) -> bool { matches!(self, OrderbookP2PHandlerError::OrderNotFound(_)) } +} + +impl From for OrderbookP2PHandlerError { + fn from(e: P2PRequestError) -> Self { OrderbookP2PHandlerError::P2PRequestError(e.to_string()) } +} + /// Alphabetically ordered orderbook pair type AlbOrderedOrderbookPair = String; type PubkeyOrders = Vec<(Uuid, OrderbookP2PItem)>; @@ -247,7 +282,7 @@ async fn process_orders_keep_alive( from_pubkey: String, keep_alive: new_protocol::PubkeyKeepAlive, i_am_relay: bool, -) -> bool { +) -> OrderbookP2PHandlerResult { let ordermatch_ctx = OrdermatchContext::from_ctx(&ctx).expect("from_ctx failed"); let to_request = ordermatch_ctx .orderbook @@ -257,17 +292,21 @@ async fn process_orders_keep_alive( let req = match to_request { Some(req) => req, // The message was processed, simply forward it - None => return true, + None => return Ok(()), }; - let resp = - request_one_peer::(ctx.clone(), P2PRequest::Ordermatch(req), propagated_from_peer) - .await; - - let response = match resp { - Ok(Some(resp)) => resp, - _ => return false, - }; + let response = request_one_peer::( + ctx.clone(), + P2PRequest::Ordermatch(req), + propagated_from_peer.clone(), + ) + .await? + .ok_or_else(|| { + MmError::new(OrderbookP2PHandlerError::P2PRequestError(format!( + "No response was received from peer {} for SyncPubkeyOrderbookState request!", + propagated_from_peer + ))) + })?; let mut orderbook = ordermatch_ctx.orderbook.lock(); for (pair, diff) in response.pair_orders_diff { @@ -282,27 +321,27 @@ async fn process_orders_keep_alive( DeltaOrFullTrie::FullTrie(values) => process_pubkey_full_trie(&mut orderbook, values, params), }; } - true + + Ok(()) } -fn process_maker_order_updated(ctx: MmArc, from_pubkey: String, updated_msg: new_protocol::MakerOrderUpdated) -> bool { +fn process_maker_order_updated( + ctx: MmArc, + from_pubkey: String, + updated_msg: new_protocol::MakerOrderUpdated, +) -> OrderbookP2PHandlerResult { let ordermatch_ctx = OrdermatchContext::from_ctx(&ctx).expect("from_ctx failed"); let uuid = updated_msg.uuid(); let mut orderbook = ordermatch_ctx.orderbook.lock(); - match orderbook.find_order_by_uuid_and_pubkey(&uuid, &from_pubkey) { - Some(mut order) => { - order.apply_updated(&updated_msg); - orderbook.insert_or_update_order_update_trie(order); - true - }, - None => { - log::warn!( - "Couldn't find an order {}, ignoring, it will be synced upon pubkey keep alive", - uuid - ); - false - }, - } + + let mut order = orderbook + .find_order_by_uuid_and_pubkey(&uuid, &from_pubkey) + .ok_or_else(|| MmError::new(OrderbookP2PHandlerError::OrderNotFound(uuid)))?; + order.apply_updated(&updated_msg); + drop_mutability!(order); + orderbook.insert_or_update_order_update_trie(order); + + Ok(()) } // fn verify_pubkey_orderbook(orderbook: &GetOrderbookPubkeyItem) -> Result<(), String> { @@ -468,19 +507,52 @@ fn remove_pubkey_pair_orders(orderbook: &mut Orderbook, pubkey: &str, alb_pair: pubkey_state.trie_roots.remove(alb_pair); } +pub async fn handle_orderbook_msg( + ctx: MmArc, + topics: &[TopicHash], + from_peer: String, + msg: &[u8], + i_am_relay: bool, +) -> OrderbookP2PHandlerResult { + if let Err(e) = decode_signed::(msg) { + return MmError::err(OrderbookP2PHandlerError::DecodeError(e.to_string())); + }; + + let mut orderbook_pairs = vec![]; + + for topic in topics { + let mut split = topic.as_str().split(TOPIC_SEPARATOR); + match (split.next(), split.next()) { + (Some(ORDERBOOK_PREFIX), Some(pair)) => { + orderbook_pairs.push(pair.to_string()); + }, + _ => { + return MmError::err(OrderbookP2PHandlerError::InvalidTopic(topic.as_str().to_owned())); + }, + }; + } + + drop_mutability!(orderbook_pairs); + + if !orderbook_pairs.is_empty() { + process_msg(ctx, from_peer, msg, i_am_relay).await?; + } + + Ok(()) +} + /// Attempts to decode a message and process it returning whether the message is valid and worth rebroadcasting -pub async fn process_msg(ctx: MmArc, _topics: Vec, from_peer: String, msg: &[u8], i_am_relay: bool) -> bool { +pub async fn process_msg(ctx: MmArc, from_peer: String, msg: &[u8], i_am_relay: bool) -> OrderbookP2PHandlerResult { match decode_signed::(msg) { Ok((message, _sig, pubkey)) => { if is_pubkey_banned(&ctx, &pubkey.unprefixed().into()) { - log::warn!("Pubkey {} is banned", pubkey.to_hex()); - return false; + return MmError::err(OrderbookP2PHandlerError::PubkeyNotAllowed(pubkey.to_hex())); } match message { new_protocol::OrdermatchMessage::MakerOrderCreated(created_msg) => { let order: OrderbookItem = (created_msg, hex::encode(pubkey.to_bytes().as_slice())).into(); insert_or_update_order(&ctx, order); - true + Ok(()) }, new_protocol::OrdermatchMessage::PubkeyKeepAlive(keep_alive) => { process_orders_keep_alive(ctx, from_peer, pubkey.to_hex(), keep_alive, i_am_relay).await @@ -488,36 +560,33 @@ pub async fn process_msg(ctx: MmArc, _topics: Vec, from_peer: String, ms new_protocol::OrdermatchMessage::TakerRequest(taker_request) => { let msg = TakerRequest::from_new_proto_and_pubkey(taker_request, pubkey.unprefixed().into()); process_taker_request(ctx, pubkey.unprefixed().into(), msg).await; - true + Ok(()) }, new_protocol::OrdermatchMessage::MakerReserved(maker_reserved) => { let msg = MakerReserved::from_new_proto_and_pubkey(maker_reserved, pubkey.unprefixed().into()); // spawn because process_maker_reserved may take significant time to run let spawner = ctx.spawner(); spawner.spawn(process_maker_reserved(ctx, pubkey.unprefixed().into(), msg)); - true + Ok(()) }, new_protocol::OrdermatchMessage::TakerConnect(taker_connect) => { process_taker_connect(ctx, pubkey.unprefixed().into(), taker_connect.into()).await; - true + Ok(()) }, new_protocol::OrdermatchMessage::MakerConnected(maker_connected) => { process_maker_connected(ctx, pubkey.unprefixed().into(), maker_connected.into()).await; - true + Ok(()) }, new_protocol::OrdermatchMessage::MakerOrderCancelled(cancelled_msg) => { delete_order(&ctx, &pubkey.to_hex(), cancelled_msg.uuid.into()); - true + Ok(()) }, new_protocol::OrdermatchMessage::MakerOrderUpdated(updated_msg) => { process_maker_order_updated(ctx, pubkey.to_hex(), updated_msg) }, } }, - Err(e) => { - error!("Error {} while decoding signed message", e); - false - }, + Err(e) => MmError::err(OrderbookP2PHandlerError::DecodeError(e.to_string())), } } @@ -2923,6 +2992,15 @@ fn lp_connect_start_bob(ctx: MmArc, maker_match: MakerMatch, maker_order: MakerO if let Err(e) = insert_new_swap_to_db(ctx.clone(), maker_coin.ticker(), taker_coin.ticker(), uuid, now).await { error!("Error {} on new swap insertion", e); } + + let secret = match MakerSwap::generate_secret() { + Ok(s) => s.into(), + Err(e) => { + error!("Error {} on secret generation", e); + return; + }, + }; + let maker_swap = MakerSwap::new( ctx.clone(), alice, @@ -2936,7 +3014,7 @@ fn lp_connect_start_bob(ctx: MmArc, maker_match: MakerMatch, maker_order: MakerO taker_coin, lock_time, maker_order.p2p_privkey.map(SerializableSecp256k1Keypair::into_inner), - MakerSwap::generate_secret().into(), + secret, ); run_maker_swap(RunMakerSwapInput::StartNew(maker_swap), ctx).await; }; @@ -4476,13 +4554,9 @@ async fn cancel_orders_on_error(ctx: &MmArc, req: &SetPriceReq, error: E) Err(error) } -pub async fn check_other_coin_balance_for_order_issue( - ctx: &MmArc, - other_coin: &MmCoinEnum, - my_coin_volume: BigDecimal, -) -> CheckBalanceResult<()> { +pub async fn check_other_coin_balance_for_order_issue(ctx: &MmArc, other_coin: &MmCoinEnum) -> CheckBalanceResult<()> { let trade_fee = other_coin - .get_receiver_trade_fee(my_coin_volume, FeeApproxStage::OrderIssue) + .get_receiver_trade_fee(FeeApproxStage::OrderIssue) .compat() .await .mm_err(|e| CheckBalanceError::from_trade_preimage_error(e, other_coin.ticker()))?; @@ -4536,7 +4610,7 @@ pub async fn create_maker_order(ctx: &MmArc, req: SetPriceReq) -> Result Result // Calculate order volume and add to update_msg if new_volume is found in the request let new_volume = if req.max.unwrap_or(false) { let max_volume = try_s!(get_max_maker_vol(ctx, &base_coin).await).volume + reserved_amount.clone(); - try_s!(check_other_coin_balance_for_order_issue(ctx, &rel_coin, max_volume.to_decimal()).await); + try_s!(check_other_coin_balance_for_order_issue(ctx, &rel_coin).await); update_msg.with_new_max_volume(max_volume.clone().into()); max_volume } else if Option::is_some(&req.volume_delta) { diff --git a/mm2src/mm2_main/src/lp_swap.rs b/mm2src/mm2_main/src/lp_swap.rs index 53d5c1a1e2..280ed7babc 100644 --- a/mm2src/mm2_main/src/lp_swap.rs +++ b/mm2src/mm2_main/src/lp_swap.rs @@ -57,7 +57,8 @@ // marketmaker // -use crate::mm2::lp_network::{broadcast_p2p_msg, Libp2pPeerId}; +use super::lp_network::P2PRequestResult; +use crate::mm2::lp_network::{broadcast_p2p_msg, Libp2pPeerId, P2PRequestError}; use bitcrypto::{dhash160, sha256}; use coins::eth::Web3RpcError; use coins::{lp_coinfind, lp_coinfind_or_err, CoinFindError, MmCoinEnum, TradeFee, TransactionEnum}; @@ -97,7 +98,7 @@ use std::sync::atomic::{AtomicU64, Ordering}; #[path = "lp_swap/recreate_swap_data.rs"] mod recreate_swap_data; #[path = "lp_swap/saved_swap.rs"] mod saved_swap; #[path = "lp_swap/swap_lock.rs"] mod swap_lock; -#[path = "lp_swap/swap_watcher.rs"] mod swap_watcher; +#[path = "lp_swap/swap_watcher.rs"] pub(crate) mod swap_watcher; #[path = "lp_swap/taker_swap.rs"] mod taker_swap; #[path = "lp_swap/trade_preimage.rs"] mod trade_preimage; @@ -236,31 +237,35 @@ pub fn broadcast_p2p_tx_msg(ctx: &MmArc, topic: String, msg: &TransactionEnum, p broadcast_p2p_msg(ctx, vec![topic], encoded_msg, from); } -pub async fn process_msg(ctx: MmArc, topic: &str, msg: &[u8]) { - let uuid = match Uuid::from_str(topic) { - Ok(u) => u, - Err(_) => return, - }; +pub async fn process_swap_msg(ctx: MmArc, topic: &str, msg: &[u8]) -> P2PRequestResult<()> { + let uuid = Uuid::from_str(topic).map_to_mm(|e| P2PRequestError::DecodeError(e.to_string()))?; let msg = match decode_signed::(msg) { Ok(m) => m, Err(swap_msg_err) => { #[cfg(not(target_arch = "wasm32"))] - match json::from_slice::(msg) { + return match json::from_slice::(msg) { Ok(mut status) => { status.data.fetch_and_set_usd_prices().await; if let Err(e) = save_stats_swap(&ctx, &status.data).await { error!("Error saving the swap {} status: {}", status.data.uuid(), e); } + Ok(()) }, Err(swap_status_err) => { - error!("Couldn't deserialize 'SwapMsg': {:?}", swap_msg_err); - error!("Couldn't deserialize 'SwapStatus': {:?}", swap_status_err); + let error = format!( + "Couldn't deserialize swap msg to either 'SwapMsg': {} or to 'SwapStatus': {}", + swap_msg_err, swap_status_err + ); + MmError::err(P2PRequestError::DecodeError(error)) }, }; - // Drop it to avoid dead_code warning - drop(swap_msg_err); - return; + + #[cfg(target_arch = "wasm32")] + return MmError::err(P2PRequestError::DecodeError(format!( + "Couldn't deserialize 'SwapMsg': {}", + swap_msg_err + ))); }, }; @@ -280,7 +285,9 @@ pub async fn process_msg(ctx: MmArc, topic: &str, msg: &[u8]) { } else { warn!("Received message from unexpected sender for swap {}", uuid); } - } + }; + + Ok(()) } pub fn swap_topic(uuid: &Uuid) -> String { pub_sub_topic(SWAP_PREFIX, &uuid.to_string()) } diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 320a65ff97..c2ba8bce37 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -31,7 +31,6 @@ use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, MmNumber}; use parking_lot::Mutex as PaMutex; use primitives::hash::{H256, H264}; -use rand::Rng; use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json, H264 as H264Json}; use std::any::TypeId; use std::path::PathBuf; @@ -238,8 +237,11 @@ impl MakerSwap { #[inline] fn r(&self) -> RwLockReadGuard { self.mutable.read().unwrap() } - #[inline] - pub fn generate_secret() -> [u8; 32] { rand::thread_rng().gen() } + pub fn generate_secret() -> Result<[u8; 32], rand::Error> { + let mut sec = [0u8; 32]; + common::os_rng(&mut sec)?; + Ok(sec) + } #[inline] fn secret_hash(&self) -> Vec { @@ -475,9 +477,7 @@ impl MakerSwap { )])) }, }; - let taker_payment_spend_trade_fee_fut = self - .taker_coin - .get_receiver_trade_fee(self.maker_amount.clone(), stage.clone()); + let taker_payment_spend_trade_fee_fut = self.taker_coin.get_receiver_trade_fee(stage.clone()); let taker_payment_spend_trade_fee = match taker_payment_spend_trade_fee_fut.compat().await { Ok(fee) => fee, Err(e) => { @@ -2149,7 +2149,7 @@ pub async fn check_balance_for_maker_swap( .await .mm_err(|e| CheckBalanceError::from_trade_preimage_error(e, my_coin.ticker()))?; let taker_payment_spend_trade_fee = other_coin - .get_receiver_trade_fee(volume.to_decimal(), stage) + .get_receiver_trade_fee(stage) .compat() .await .mm_err(|e| CheckBalanceError::from_trade_preimage_error(e, other_coin.ticker()))?; @@ -2203,7 +2203,7 @@ pub async fn maker_swap_trade_preimage( .await .mm_err(|e| TradePreimageRpcError::from_trade_preimage_error(e, base_coin_ticker))?; let rel_coin_fee = rel_coin - .get_receiver_trade_fee(volume.to_decimal(), FeeApproxStage::TradePreimage) + .get_receiver_trade_fee(FeeApproxStage::TradePreimage) .compat() .await .mm_err(|e| TradePreimageRpcError::from_trade_preimage_error(e, rel_coin_ticker))?; diff --git a/mm2src/mm2_main/src/lp_swap/swap_watcher.rs b/mm2src/mm2_main/src/lp_swap/swap_watcher.rs index 7441a4a855..536e8fc691 100644 --- a/mm2src/mm2_main/src/lp_swap/swap_watcher.rs +++ b/mm2src/mm2_main/src/lp_swap/swap_watcher.rs @@ -1,5 +1,6 @@ use super::{broadcast_p2p_tx_msg, get_payment_locktime, lp_coinfind, min_watcher_reward, taker_payment_spend_deadline, tx_helper_topic, H256Json, SwapsContext, WAIT_CONFIRM_INTERVAL}; +use crate::mm2::lp_network::{P2PRequestError, P2PRequestResult}; use crate::mm2::MmError; use async_trait::async_trait; use coins::{CanRefundHtlc, ConfirmPaymentInput, FoundSwapTxSpend, MmCoinEnum, RefundPaymentArgs, @@ -11,6 +12,7 @@ use common::state_machine::prelude::*; use common::{now_ms, DEX_FEE_ADDR_RAW_PUBKEY}; use futures::compat::Future01CompatExt; use mm2_core::mm_ctx::MmArc; +use mm2_err_handle::prelude::MapToMmResult; use mm2_libp2p::{decode_signed, pub_sub_topic, TopicPrefix}; use serde::{Deserialize, Serialize}; use serde_json as json; @@ -513,16 +515,8 @@ impl LastState for Stopped { async fn on_changed(self: Box, _watcher_ctx: &mut Self::Ctx) -> Self::Result {} } -pub async fn process_watcher_msg(ctx: MmArc, msg: &[u8]) { - let msg = match decode_signed::(msg) { - Ok(m) => m, - Err(watcher_msg_err) => { - error!("Couldn't deserialize 'SwapWatcherMsg': {:?}", watcher_msg_err); - // Drop it to avoid dead_code warning - drop(watcher_msg_err); - return; - }, - }; +pub fn process_watcher_msg(ctx: MmArc, msg: &[u8]) -> P2PRequestResult<()> { + let msg = decode_signed::(msg).map_to_mm(|e| P2PRequestError::DecodeError(e.to_string()))?; let watcher_data = msg.0; let verified_pubkey = msg.2; @@ -530,7 +524,9 @@ pub async fn process_watcher_msg(ctx: MmArc, msg: &[u8]) { SwapWatcherMsg::TakerSwapWatcherMsg(watcher_data) => { spawn_taker_swap_watcher(ctx, watcher_data, verified_pubkey.to_bytes()) }, - } + }; + + Ok(()) } /// Currently, Taker Swap Watcher is supported only. diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 1a41f1128b..96ad3532e2 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -971,9 +971,7 @@ impl TakerSwap { )])) }, }; - let maker_payment_spend_trade_fee_fut = self - .maker_coin - .get_receiver_trade_fee(self.taker_amount.to_decimal(), stage.clone()); + let maker_payment_spend_trade_fee_fut = self.maker_coin.get_receiver_trade_fee(stage.clone()); let maker_payment_spend_trade_fee = match maker_payment_spend_trade_fee_fut.compat().await { Ok(fee) => fee, Err(e) => { @@ -2257,7 +2255,7 @@ pub async fn check_balance_for_taker_swap( .await .mm_err(|e| CheckBalanceError::from_trade_preimage_error(e, my_coin.ticker()))?; let maker_payment_spend_trade_fee = other_coin - .get_receiver_trade_fee(volume.to_decimal(), stage) + .get_receiver_trade_fee(stage) .compat() .await .mm_err(|e| CheckBalanceError::from_trade_preimage_error(e, other_coin.ticker()))?; @@ -2352,7 +2350,7 @@ pub async fn taker_swap_trade_preimage( .await .mm_err(|e| TradePreimageRpcError::from_trade_preimage_error(e, my_coin_ticker))?; let other_coin_trade_fee = other_coin - .get_receiver_trade_fee(my_coin_volume.to_decimal(), stage.clone()) + .get_receiver_trade_fee(stage.clone()) .compat() .await .mm_err(|e| TradePreimageRpcError::from_trade_preimage_error(e, other_coin_ticker))?; diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index 40a6514c88..050e628dbe 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -332,7 +332,7 @@ pub fn utxo_asset_docker_node<'a>(docker: &'a Cli, ticker: &'static str, port: u "-v".into(), format!("{}:/root/.zcash-params", zcash_params_path().display()), "-p".into(), - format!("{}:{}", port, port).into(), + format!("{}:{}", port, port), ]; let image = GenericImage::new(UTXO_ASSET_DOCKER_IMAGE) .with_args(args) @@ -399,19 +399,13 @@ where pub fn qrc20_coin_from_privkey(ticker: &str, priv_key: Secp256k1Secret) -> (MmArc, Qrc20Coin) { let (contract_address, swap_contract_address) = unsafe { let contract_address = match ticker { - "QICK" => QICK_TOKEN_ADDRESS - .expect("QICK_TOKEN_ADDRESS must be set already") - .clone(), - "QORTY" => QORTY_TOKEN_ADDRESS - .expect("QORTY_TOKEN_ADDRESS must be set already") - .clone(), + "QICK" => QICK_TOKEN_ADDRESS.expect("QICK_TOKEN_ADDRESS must be set already"), + "QORTY" => QORTY_TOKEN_ADDRESS.expect("QORTY_TOKEN_ADDRESS must be set already"), _ => panic!("Expected QICK or QORTY ticker"), }; ( contract_address, - QRC20_SWAP_CONTRACT_ADDRESS - .expect("QRC20_SWAP_CONTRACT_ADDRESS must be set already") - .clone(), + QRC20_SWAP_CONTRACT_ADDRESS.expect("QRC20_SWAP_CONTRACT_ADDRESS must be set already"), ) }; let platform = "QTUM"; @@ -454,12 +448,8 @@ pub fn qrc20_coin_from_privkey(ticker: &str, priv_key: Secp256k1Secret) -> (MmAr fn qrc20_coin_conf_item(ticker: &str) -> Json { let contract_address = unsafe { match ticker { - "QICK" => QICK_TOKEN_ADDRESS - .expect("QICK_TOKEN_ADDRESS must be set already") - .clone(), - "QORTY" => QORTY_TOKEN_ADDRESS - .expect("QORTY_TOKEN_ADDRESS must be set already") - .clone(), + "QICK" => QICK_TOKEN_ADDRESS.expect("QICK_TOKEN_ADDRESS must be set already"), + "QORTY" => QORTY_TOKEN_ADDRESS.expect("QORTY_TOKEN_ADDRESS must be set already"), _ => panic!("Expected either QICK or QORTY ticker, found {}", ticker), } }; @@ -561,7 +551,7 @@ pub fn fill_qrc20_address(coin: &Qrc20Coin, amount: BigDecimal, timeout: u64) { let tx_bytes = client.get_transaction_bytes(&hash).wait().unwrap(); log!("{:02x}", tx_bytes); let confirm_payment_input = ConfirmPaymentInput { - payment_tx: tx_bytes.clone().0, + payment_tx: tx_bytes.0, confirmations: 1, requires_nota: false, wait_until: timeout, @@ -741,11 +731,8 @@ pub fn wait_for_estimate_smart_fee(timeout: u64) -> Result<(), String> { } pub async fn enable_qrc20_native(mm: &MarketMakerIt, coin: &str) -> Json { - let swap_contract_address = unsafe { - QRC20_SWAP_CONTRACT_ADDRESS - .expect("QRC20_SWAP_CONTRACT_ADDRESS must be set already") - .clone() - }; + let swap_contract_address = + unsafe { QRC20_SWAP_CONTRACT_ADDRESS.expect("QRC20_SWAP_CONTRACT_ADDRESS must be set already") }; let native = mm .rpc(&json! ({ @@ -984,7 +971,7 @@ pub fn solana_supplied_node() -> MarketMakerIt { {"coin":"ADEX-SOL-DEVNET","protocol":{"type":"SPLTOKEN","protocol_data":{"decimals":9,"token_contract_address":"5tSm6PqMosy1rz1AqV3kD28yYT5XqZW3QYmZommuFiPJ","platform":"SOL-DEVNET"}},"mm2": 1}, ]); - let mm = MarketMakerIt::start( + MarketMakerIt::start( json! ({ "gui": "nogui", "netid": 9000, @@ -997,9 +984,7 @@ pub fn solana_supplied_node() -> MarketMakerIt { "pass".to_string(), None, ) - .unwrap(); - - mm + .unwrap() } pub fn get_balance(mm: &MarketMakerIt, coin: &str) -> MyBalanceResponse { diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs index 6a46d62661..83e53f87c4 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs @@ -74,7 +74,7 @@ fn test_search_for_swap_tx_spend_native_was_refunded_taker() { let search_input = SearchForSwapTxSpendInput { time_lock, - other_pub: &*coin.my_public_key().unwrap(), + other_pub: coin.my_public_key().unwrap(), secret_hash: &[0; 20], tx: &tx.tx_hex(), search_from_block: 0, @@ -162,7 +162,7 @@ fn test_search_for_swap_tx_spend_native_was_refunded_maker() { let search_input = SearchForSwapTxSpendInput { time_lock, - other_pub: &*coin.my_public_key().unwrap(), + other_pub: coin.my_public_key().unwrap(), secret_hash: &[0; 20], tx: &tx.tx_hex(), search_from_block: 0, @@ -233,7 +233,7 @@ fn test_search_for_taker_swap_tx_spend_native_was_spent_by_maker() { let search_input = SearchForSwapTxSpendInput { time_lock, - other_pub: &*coin.my_public_key().unwrap(), + other_pub: coin.my_public_key().unwrap(), secret_hash: &*dhash160(&secret), tx: &tx.tx_hex(), search_from_block: 0, @@ -304,7 +304,7 @@ fn test_search_for_maker_swap_tx_spend_native_was_spent_by_taker() { let search_input = SearchForSwapTxSpendInput { time_lock, - other_pub: &*coin.my_public_key().unwrap(), + other_pub: coin.my_public_key().unwrap(), secret_hash: &*dhash160(&secret), tx: &tx.tx_hex(), search_from_block: 0, @@ -2955,7 +2955,7 @@ fn test_utxo_merge() { thread::sleep(Duration::from_secs(2)); let (unspents, _) = - block_on(coin.get_unspent_ordered_list(&coin.as_ref().derivation_method.unwrap_single_addr())).unwrap(); + block_on(coin.get_unspent_ordered_list(coin.as_ref().derivation_method.unwrap_single_addr())).unwrap(); assert_eq!(unspents.len(), 1); } @@ -3009,7 +3009,7 @@ fn test_utxo_merge_max_merge_at_once() { thread::sleep(Duration::from_secs(2)); let (unspents, _) = - block_on(coin.get_unspent_ordered_list(&coin.as_ref().derivation_method.unwrap_single_addr())).unwrap(); + block_on(coin.get_unspent_ordered_list(coin.as_ref().derivation_method.unwrap_single_addr())).unwrap(); // 4 utxos are merged of 5 so the resulting unspents len must be 2 assert_eq!(unspents.len(), 2); } diff --git a/mm2src/mm2_main/tests/docker_tests/mod.rs b/mm2src/mm2_main/tests/docker_tests/mod.rs index 300ebbc63c..4ac4e6541d 100644 --- a/mm2src/mm2_main/tests/docker_tests/mod.rs +++ b/mm2src/mm2_main/tests/docker_tests/mod.rs @@ -12,4 +12,5 @@ mod swaps_file_lock_tests; // dummy test helping IDE to recognize this as test module #[test] +#[allow(clippy::assertions_on_constants)] fn dummy() { assert!(true) } diff --git a/mm2src/mm2_main/tests/docker_tests/qrc20_tests.rs b/mm2src/mm2_main/tests/docker_tests/qrc20_tests.rs index 3601baa886..ba3cbb5fe9 100644 --- a/mm2src/mm2_main/tests/docker_tests/qrc20_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/qrc20_tests.rs @@ -1199,7 +1199,7 @@ fn test_trade_preimage_not_sufficient_base_coin_balance_for_ticker() { // fill QTUM balance with 0.005 QTUM which is will be than expected transaction fee just to get our desired output for this test. let qick_balance = MmNumber::from("10").to_decimal(); let qtum_balance = MmNumber::from("0.005").to_decimal(); - let (_, _, priv_key) = generate_qrc20_coin_with_random_privkey("QICK", qtum_balance.clone(), qick_balance.clone()); + let (_, _, priv_key) = generate_qrc20_coin_with_random_privkey("QICK", qtum_balance.clone(), qick_balance); let qick_contract_address = format!("{:#02x}", unsafe { QICK_TOKEN_ADDRESS.expect("!QICK_TOKEN_ADDRESS") }); let confpath = unsafe { QTUM_CONF_PATH.as_ref().expect("Qtum config is not set yet") }; @@ -1569,7 +1569,7 @@ fn test_search_for_segwit_swap_tx_spend_native_was_refunded_maker() { let search_input = SearchForSwapTxSpendInput { time_lock, - other_pub: &*coin.my_public_key().unwrap(), + other_pub: coin.my_public_key().unwrap(), secret_hash: &[0; 20], tx: &tx.tx_hex(), search_from_block: 0, @@ -1638,7 +1638,7 @@ fn test_search_for_segwit_swap_tx_spend_native_was_refunded_taker() { let search_input = SearchForSwapTxSpendInput { time_lock, - other_pub: &*coin.my_public_key().unwrap(), + other_pub: coin.my_public_key().unwrap(), secret_hash: &[0; 20], tx: &tx.tx_hex(), search_from_block: 0, diff --git a/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs b/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs index 223b4f215c..c6493c1dfb 100644 --- a/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs @@ -95,7 +95,7 @@ fn test_watcher_spends_maker_payment_spend_eth_erc20() { block_on(mm_watcher.wait_for_log(180., |log| log.contains(MAKER_PAYMENT_SPEND_SENT_LOG))).unwrap(); thread::sleep(Duration::from_secs(25)); - let mm_alice = MarketMakerIt::start(alice_conf.conf.clone(), alice_conf.rpc_password.clone(), None).unwrap(); + let mm_alice = MarketMakerIt::start(alice_conf.conf.clone(), alice_conf.rpc_password, None).unwrap(); enable_eth_and_jst(&mm_alice); let alice_eth_balance_after = block_on(my_balance(&mm_alice, "ETH")).balance.with_scale(2); @@ -108,7 +108,7 @@ fn test_watcher_spends_maker_payment_spend_eth_erc20() { assert_eq!(alice_jst_balance_before - volume.clone(), alice_jst_balance_after); assert_eq!(bob_jst_balance_before + volume.clone(), bob_jst_balance_after); assert_eq!(alice_eth_balance_before + volume.clone(), alice_eth_balance_after); - assert_eq!(bob_eth_balance_before - volume.clone(), bob_eth_balance_after); + assert_eq!(bob_eth_balance_before - volume, bob_eth_balance_after); assert!(watcher_eth_balance_after > watcher_eth_balance_before); } @@ -176,7 +176,7 @@ fn test_two_watchers_spend_maker_payment_eth_erc20() { block_on(mm_watcher2.wait_for_log(180., |log| log.contains(MAKER_PAYMENT_SPEND_SENT_LOG))).unwrap(); thread::sleep(Duration::from_secs(25)); - let mm_alice = MarketMakerIt::start(alice_conf.conf.clone(), alice_conf.rpc_password.clone(), None).unwrap(); + let mm_alice = MarketMakerIt::start(alice_conf.conf.clone(), alice_conf.rpc_password, None).unwrap(); enable_eth_and_jst(&mm_alice); let alice_eth_balance_after = block_on(my_balance(&mm_alice, "ETH")).balance.with_scale(2); @@ -190,7 +190,7 @@ fn test_two_watchers_spend_maker_payment_eth_erc20() { assert_eq!(alice_jst_balance_before - volume.clone(), alice_jst_balance_after); assert_eq!(bob_jst_balance_before + volume.clone(), bob_jst_balance_after); assert_eq!(alice_eth_balance_before + volume.clone(), alice_eth_balance_after); - assert_eq!(bob_eth_balance_before - volume.clone(), bob_eth_balance_after); + assert_eq!(bob_eth_balance_before - volume, bob_eth_balance_after); if watcher1_eth_balance_after > watcher1_eth_balance_before { assert_eq!(watcher2_eth_balance_after, watcher2_eth_balance_after); } @@ -248,7 +248,7 @@ fn test_watcher_spends_maker_payment_spend_erc20_eth() { block_on(mm_watcher.wait_for_log(180., |log| log.contains(MAKER_PAYMENT_SPEND_SENT_LOG))).unwrap(); thread::sleep(Duration::from_secs(25)); - let mm_alice = MarketMakerIt::start(alice_conf.conf.clone(), alice_conf.rpc_password.clone(), None).unwrap(); + let mm_alice = MarketMakerIt::start(alice_conf.conf.clone(), alice_conf.rpc_password, None).unwrap(); enable_eth_and_jst(&mm_alice); let alice_eth_balance_after = block_on(my_balance(&mm_alice, "ETH")).balance.with_scale(2); @@ -262,7 +262,7 @@ fn test_watcher_spends_maker_payment_spend_erc20_eth() { assert_eq!(alice_jst_balance_before + volume.clone(), alice_jst_balance_after); assert_eq!(bob_jst_balance_before - volume.clone(), bob_jst_balance_after); assert_eq!(alice_eth_balance_before - volume.clone(), alice_eth_balance_after); - assert_eq!(bob_eth_balance_before + volume.clone(), bob_eth_balance_after); + assert_eq!(bob_eth_balance_before + volume, bob_eth_balance_after); assert!(watcher_eth_balance_after > watcher_eth_balance_before); } @@ -274,7 +274,7 @@ fn test_watcher_waits_for_taker_eth() { let alice_passphrase = String::from("spice describe gravity federal blast come thank unfair canal monkey style afraid"); let alice_conf = Mm2TestConf::seednode_using_watchers(&alice_passphrase, &coins); - let mut mm_alice = MarketMakerIt::start(alice_conf.conf.clone(), alice_conf.rpc_password.clone(), None).unwrap(); + let mut mm_alice = MarketMakerIt::start(alice_conf.conf.clone(), alice_conf.rpc_password, None).unwrap(); let (_alice_dump_log, _alice_dump_dashboard) = mm_alice.mm_dump(); log!("Alice log path: {}", mm_alice.log_path.display()); @@ -464,11 +464,7 @@ fn test_watcher_validate_taker_fee_eth() { let taker_amount = MmNumber::from((10, 1)); let fee_amount = dex_fee_amount_from_taker_coin(&MmCoinEnum::EthCoin(taker_coin.clone()), "ETH", &taker_amount); let taker_fee = taker_coin - .send_taker_fee( - &DEX_FEE_ADDR_RAW_PUBKEY, - fee_amount.clone().into(), - Uuid::new_v4().as_bytes(), - ) + .send_taker_fee(&DEX_FEE_ADDR_RAW_PUBKEY, fee_amount.into(), Uuid::new_v4().as_bytes()) .wait() .unwrap(); @@ -572,11 +568,7 @@ fn test_watcher_validate_taker_fee_erc20() { let taker_amount = MmNumber::from((10, 1)); let fee_amount = dex_fee_amount_from_taker_coin(&MmCoinEnum::EthCoin(taker_coin.clone()), "ETH", &taker_amount); let taker_fee = taker_coin - .send_taker_fee( - &DEX_FEE_ADDR_RAW_PUBKEY, - fee_amount.clone().into(), - Uuid::new_v4().as_bytes(), - ) + .send_taker_fee(&DEX_FEE_ADDR_RAW_PUBKEY, fee_amount.into(), Uuid::new_v4().as_bytes()) .wait() .unwrap(); @@ -683,7 +675,7 @@ fn test_watcher_validate_taker_payment_eth() { let wait_for_confirmation_until = now_ms() / 1000 + time_lock_duration; let time_lock = wait_for_confirmation_until as u32; let amount = BigDecimal::from_str("0.01").unwrap(); - let secret_hash = dhash160(&MakerSwap::generate_secret()); + let secret_hash = dhash160(&MakerSwap::generate_secret().unwrap()); let watcher_reward = Some( block_on(watcher_reward_amount( &MmCoinEnum::from(taker_coin.clone()), @@ -809,7 +801,7 @@ fn test_watcher_validate_taker_payment_eth() { } // Used to get wrong swap id - let wrong_secret_hash = dhash160(&MakerSwap::generate_secret()); + let wrong_secret_hash = dhash160(&MakerSwap::generate_secret().unwrap()); let error = taker_coin .watcher_validate_taker_payment(coins::WatcherValidatePaymentInput { payment_tx: taker_payment.tx_hex(), @@ -957,7 +949,7 @@ fn test_watcher_validate_taker_payment_erc20() { let wait_for_confirmation_until = now_ms() / 1000 + time_lock_duration; let time_lock = wait_for_confirmation_until as u32; - let secret_hash = dhash160(&MakerSwap::generate_secret()); + let secret_hash = dhash160(&MakerSwap::generate_secret().unwrap()); let watcher_reward = Some( block_on(watcher_reward_amount( &MmCoinEnum::from(taker_coin.clone()), @@ -1082,7 +1074,7 @@ fn test_watcher_validate_taker_payment_erc20() { } // Used to get wrong swap id - let wrong_secret_hash = dhash160(&MakerSwap::generate_secret()); + let wrong_secret_hash = dhash160(&MakerSwap::generate_secret().unwrap()); let error = taker_coin .watcher_validate_taker_payment(WatcherValidatePaymentInput { payment_tx: taker_payment.tx_hex(), @@ -1306,7 +1298,7 @@ fn test_watcher_waits_for_taker_utxo() { let coins = json!([mycoin_conf(1000), mycoin1_conf(1000)]); let alice_conf = Mm2TestConf::seednode_using_watchers(&format!("0x{}", hex::encode(alice_priv_key)), &coins).conf; - let mut mm_alice = MarketMakerIt::start(alice_conf.clone(), DEFAULT_RPC_PASSWORD.to_string(), None).unwrap(); + let mut mm_alice = MarketMakerIt::start(alice_conf, DEFAULT_RPC_PASSWORD.to_string(), None).unwrap(); let (_alice_dump_log, _alice_dump_dashboard) = mm_dump(&mm_alice.log_path); let bob_conf = @@ -1452,11 +1444,7 @@ fn test_watcher_validate_taker_fee_utxo() { ); let taker_fee = taker_coin - .send_taker_fee( - &DEX_FEE_ADDR_RAW_PUBKEY, - fee_amount.clone().into(), - Uuid::new_v4().as_bytes(), - ) + .send_taker_fee(&DEX_FEE_ADDR_RAW_PUBKEY, fee_amount.into(), Uuid::new_v4().as_bytes()) .wait() .unwrap(); @@ -1577,7 +1565,7 @@ fn test_watcher_validate_taker_payment_utxo() { let (_ctx, maker_coin, _) = generate_utxo_coin_with_random_privkey("MYCOIN", 1000u64.into()); let maker_pubkey = maker_coin.my_public_key().unwrap(); - let secret_hash = dhash160(&MakerSwap::generate_secret()); + let secret_hash = dhash160(&MakerSwap::generate_secret().unwrap()); let taker_payment = taker_coin .send_taker_payment(SendPaymentArgs { @@ -1654,7 +1642,7 @@ fn test_watcher_validate_taker_payment_utxo() { _ => panic!("Expected `WrongPaymentTx` {INVALID_SENDER_ERR_LOG}, found {:?}", error), } - let wrong_secret_hash = dhash160(&MakerSwap::generate_secret()); + let wrong_secret_hash = dhash160(&MakerSwap::generate_secret().unwrap()); let error = taker_coin .watcher_validate_taker_payment(WatcherValidatePaymentInput { payment_tx: taker_payment.tx_hex(), @@ -1809,7 +1797,7 @@ fn test_send_taker_payment_refund_preimage_utxo() { let search_input = SearchForSwapTxSpendInput { time_lock, - other_pub: &*coin.my_public_key().unwrap(), + other_pub: coin.my_public_key().unwrap(), secret_hash: &[0; 20], tx: &tx.tx_hex(), search_from_block: 0, diff --git a/mm2src/mm2_main/tests/docker_tests/swaps_file_lock_tests.rs b/mm2src/mm2_main/tests/docker_tests/swaps_file_lock_tests.rs index 1ef18a8ed3..e69733cbff 100644 --- a/mm2src/mm2_main/tests/docker_tests/swaps_file_lock_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/swaps_file_lock_tests.rs @@ -25,7 +25,7 @@ fn swap_file_lock_prevents_double_swap_start_on_kick_start(swap_json: &str) { let swap_path = swaps_db_folder.join("5acb0e63-8b26-469e-81df-7dd9e4a9ad15.json"); let swap_lock_path = swaps_db_folder.join("5acb0e63-8b26-469e-81df-7dd9e4a9ad15.lock"); let lock = FileLock::lock(swap_lock_path, 10.).unwrap().unwrap(); - std::fs::write(&swap_path, swap_json).unwrap(); + std::fs::write(swap_path, swap_json).unwrap(); thread::spawn(move || loop { // touch the lock file to simulate that other process is running the swap already lock.touch().unwrap(); @@ -176,12 +176,12 @@ fn test_swaps_should_kick_start_if_process_was_killed() { fn addr_hash_for_privkey(priv_key: Secp256k1Secret) -> String { let private = Private { prefix: 1, - secret: priv_key.into(), + secret: priv_key, compressed: true, checksum_type: ChecksumType::DSHA256, }; let key_pair = KeyPair::from_private(private).unwrap(); - hex::encode(&*key_pair.public().address_hash()) + hex::encode(key_pair.public().address_hash()) } fn swap_should_not_kick_start_if_finished_during_waiting_for_file_lock( diff --git a/mm2src/mm2_main/tests/docker_tests_main.rs b/mm2src/mm2_main/tests/docker_tests_main.rs index 6ef9cba2d5..70b31bf0d3 100644 --- a/mm2src/mm2_main/tests/docker_tests_main.rs +++ b/mm2src/mm2_main/tests/docker_tests_main.rs @@ -89,7 +89,7 @@ pub fn docker_tests_runner(tests: &[&TestDescAndFn]) { }) .collect(); let args: Vec = std::env::args().collect(); - let _exit_code = test_main(&args, owned_tests, None); + test_main(&args, owned_tests, None); } fn pull_docker_image(name: &str) { diff --git a/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs b/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs index 0685731781..26bb064ed5 100644 --- a/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs @@ -1019,13 +1019,16 @@ fn best_orders_must_return_duplicate_for_orderbook_tickers() { assert_eq!(best_orders[0].coin, "tBTC-Segwit"); } -#[cfg(feature = "zhtlc-native-tests")] #[test] +#[cfg(feature = "zhtlc-native-tests")] fn zhtlc_best_orders() { + use super::enable_z_coin; use mm2_test_helpers::for_tests::zombie_conf; - let bob_passphrase = get_passphrase!(".env.seed", "BOB_PASSPHRASE").unwrap(); - let alice_passphrase = get_passphrase!(".env.client", "ALICE_PASSPHRASE").unwrap(); + use mm2_test_helpers::electrums::rick_electrums; + + let bob_passphrase = get_passphrase(&".env.seed", "BOB_PASSPHRASE").unwrap(); + let alice_passphrase = get_passphrase(&".env.client", "ALICE_PASSPHRASE").unwrap(); let coins = json!([rick_conf(), zombie_conf()]); @@ -1042,10 +1045,7 @@ fn zhtlc_best_orders() { "i_am_seed": true, }), "pass".into(), - match var("LOCAL_THREAD_MM") { - Ok(ref e) if e == "bob" => Some(local_start()), - _ => None, - }, + None, ) .unwrap(); @@ -1087,10 +1087,7 @@ fn zhtlc_best_orders() { "rpc_password": "pass", }), "pass".into(), - match var("LOCAL_THREAD_MM") { - Ok(ref e) if e == "alice" => Some(local_start()), - _ => None, - }, + None, ) .unwrap(); diff --git a/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs b/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs index 345b4960bf..01ed93849c 100644 --- a/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs +++ b/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs @@ -1,3 +1,5 @@ +#[cfg(all(feature = "zhtlc-native-tests", not(target_arch = "wasm32")))] +use super::enable_z_coin; use crate::integration_tests_common::*; use common::executor::Timer; use common::{cfg_native, cfg_wasm32, get_utc_timestamp, log, new_uuid}; @@ -7,19 +9,19 @@ use mm2_main::mm2::lp_ordermatch::MIN_ORDER_KEEP_ALIVE_INTERVAL; use mm2_metrics::{MetricType, MetricsJson}; use mm2_number::{BigDecimal, BigRational, Fraction, MmNumber}; use mm2_test_helpers::electrums::*; -#[cfg(all(feature = "zhtlc-native-tests", not(target_arch = "wasm32")))] -use mm2_test_helpers::for_tests::init_z_coin_native; use mm2_test_helpers::for_tests::{btc_segwit_conf, btc_with_spv_conf, btc_with_sync_starting_header, - check_recent_swaps, check_stats_swap_status, enable_eth_coin, enable_qrc20, - eth_jst_testnet_conf, eth_testnet_conf, find_metrics_in_json, from_env_file, - get_shared_db_id, mm_spat, morty_conf, rick_conf, sign_message, start_swaps, - tbtc_with_spv_conf, test_qrc20_history_impl, tqrc20_conf, verify_message, + check_recent_swaps, enable_eth_coin, enable_qrc20, eth_jst_testnet_conf, + eth_testnet_conf, find_metrics_in_json, from_env_file, get_shared_db_id, mm_spat, + morty_conf, rick_conf, sign_message, start_swaps, tbtc_with_spv_conf, + test_qrc20_history_impl, tqrc20_conf, verify_message, wait_for_swap_contract_negotiation, wait_for_swap_negotiation_failure, wait_for_swaps_finish_and_check_status, wait_till_history_has_records, MarketMakerIt, Mm2InitPrivKeyPolicy, Mm2TestConf, Mm2TestConfForSwap, RaiiDump, ETH_DEV_NODES, ETH_DEV_SWAP_CONTRACT, ETH_MAINNET_NODE, ETH_MAINNET_SWAP_CONTRACT, - MAKER_SUCCESS_EVENTS, MORTY, QRC20_ELECTRUMS, RICK, RICK_ELECTRUM_ADDRS, - TAKER_SUCCESS_EVENTS}; + MORTY, QRC20_ELECTRUMS, RICK, RICK_ELECTRUM_ADDRS}; +#[cfg(all(not(target_arch = "wasm32"), not(feature = "zhtlc-native-tests")))] +use mm2_test_helpers::for_tests::{check_stats_swap_status, MAKER_SUCCESS_EVENTS, TAKER_SUCCESS_EVENTS}; + use mm2_test_helpers::get_passphrase; use mm2_test_helpers::structs::*; use serde_json::{self as json, json, Value as Json}; @@ -43,30 +45,6 @@ cfg_wasm32! { wasm_bindgen_test_configure!(run_in_browser); } -#[cfg(all(feature = "zhtlc-native-tests", not(target_arch = "wasm32")))] -async fn enable_z_coin(mm: &MarketMakerIt, coin: &str) -> CoinActivationResult { - use common::now_ms; - use mm2_test_helpers::for_tests::init_z_coin_status; - - let init = init_z_coin_native(mm, coin).await; - let init: RpcV2Response = json::from_value(init).unwrap(); - let timeout = now_ms() + 120000; - - loop { - if gstuff::now_ms() > timeout { - panic!("{} initialization timed out", coin); - } - - let status = init_z_coin_status(mm, init.result.task_id).await; - let status: RpcV2Response = json::from_value(status).unwrap(); - match status.result { - InitZcoinStatus::Ok(result) => break result, - InitZcoinStatus::Error(e) => panic!("{} initialization error {:?}", coin, e), - _ => Timer::sleep(1.).await, - } - } -} - /// Integration test for RPC server. /// Check that MM doesn't crash in case of invalid RPC requests #[test] @@ -788,12 +766,14 @@ async fn trade_base_rel_electrum( #[cfg(all(feature = "zhtlc-native-tests", not(target_arch = "wasm32")))] { + let bob_passphrase = get_passphrase!(".env.seed", "BOB_PASSPHRASE").unwrap(); Timer::sleep(1.).await; let rmd = rmd160_from_passphrase(&bob_passphrase); let bob_zombie_cache_path = mm_bob.folder.join("DB").join(hex::encode(rmd)).join("ZOMBIE_CACHE.db"); log!("bob_zombie_cache_path {}", bob_zombie_cache_path.display()); std::fs::copy("./mm2src/coins/for_tests/ZOMBIE_CACHE.db", bob_zombie_cache_path).unwrap(); + let alice_passphrase = get_passphrase!(".env.client", "ALICE_PASSPHRASE").unwrap(); let rmd = rmd160_from_passphrase(&alice_passphrase); let alice_zombie_cache_path = mm_alice .folder @@ -894,7 +874,14 @@ fn trade_test_electrum_and_eth_coins() { let bob_policy = Mm2InitPrivKeyPolicy::Iguana; let alice_policy = Mm2InitPrivKeyPolicy::GlobalHDAccount(0); let pairs = &[("ETH", "JST")]; - block_on(trade_base_rel_electrum(bob_policy, alice_policy, pairs, 1., 2., 0.1)); + block_on(trade_base_rel_electrum( + bob_policy, + alice_policy, + pairs, + 1., + 2., + 0.000001, + )); } #[test] diff --git a/mm2src/mm2_main/tests/mm2_tests/mod.rs b/mm2src/mm2_main/tests/mm2_tests/mod.rs index d331a269c6..9c6cdd35e3 100644 --- a/mm2src/mm2_main/tests/mm2_tests/mod.rs +++ b/mm2src/mm2_main/tests/mm2_tests/mod.rs @@ -10,6 +10,38 @@ mod tendermint_ibc_asset_tests; mod tendermint_tests; mod z_coin_tests; +mod zhtlc_native_reexport { + pub use common::executor::Timer; + pub use common::now_ms; + pub use mm2_test_helpers::for_tests::MarketMakerIt; + pub use mm2_test_helpers::for_tests::{init_z_coin_native, init_z_coin_status}; + pub use mm2_test_helpers::structs::{CoinActivationResult, InitTaskResult, InitZcoinStatus, RpcV2Response}; +} + +#[cfg(all(feature = "zhtlc-native-tests", not(target_arch = "wasm32")))] +use zhtlc_native_reexport::*; + +#[cfg(all(feature = "zhtlc-native-tests", not(target_arch = "wasm32")))] +async fn enable_z_coin(mm: &MarketMakerIt, coin: &str) -> CoinActivationResult { + let init = init_z_coin_native(mm, coin).await; + let init: RpcV2Response = serde_json::from_value(init).unwrap(); + let timeout = now_ms() + 120000; + + loop { + if gstuff::now_ms() > timeout { + panic!("{} initialization timed out", coin); + } + + let status = init_z_coin_status(mm, init.result.task_id).await; + let status: RpcV2Response = serde_json::from_value(status).unwrap(); + match status.result { + InitZcoinStatus::Ok(result) => break result, + InitZcoinStatus::Error(e) => panic!("{} initialization error {:?}", coin, e), + _ => Timer::sleep(1.).await, + } + } +} + // dummy test helping IDE to recognize this as test module #[test] #[allow(clippy::assertions_on_constants)] diff --git a/mm2src/mm2_test_helpers/dummy_files/iris_nimda_history.json b/mm2src/mm2_test_helpers/dummy_files/iris_nimda_history.json index c3a6ff1580..e75d8aaf5a 100644 --- a/mm2src/mm2_test_helpers/dummy_files/iris_nimda_history.json +++ b/mm2src/mm2_test_helpers/dummy_files/iris_nimda_history.json @@ -16,7 +16,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.027385", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-NIMDA", "internal_id": "3930374535314439384537304239343431413230443630420000000000000000", @@ -45,7 +45,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.028433", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-NIMDA", "internal_id": "4138433845353931363133303743353941344143374536320000000000000000", @@ -74,7 +74,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.026403", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-NIMDA", "internal_id": "3436313245464444363537373544434341433838463935340000000000000000", @@ -103,7 +103,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.028433", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-NIMDA", "internal_id": "3931453345363544374341333833394331463141394435320000000000000000", @@ -134,7 +134,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.025763", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-NIMDA", "internal_id": "3643343243423346353232433844414333343138443338440000000000000000", @@ -162,7 +162,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.022114", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-NIMDA", "internal_id": "4631313139343742323142303344373639303343333441370000000000000000", @@ -190,7 +190,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.026861", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-NIMDA", "internal_id": "3236413546344639343144434531363135373046373530330000000000000000", @@ -218,7 +218,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.026861", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-NIMDA", "internal_id": "4344413036444433353735413332323330363430414634310000000000000000", @@ -246,7 +246,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.022114", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-NIMDA", "internal_id": "4339384239303045393643333738453237333945314344330000000000000000", @@ -274,7 +274,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.02316", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-NIMDA", "internal_id": "4136303630343838314237323638453734433246453537450000000000000000", diff --git a/mm2src/mm2_test_helpers/dummy_files/iris_test_history.json b/mm2src/mm2_test_helpers/dummy_files/iris_test_history.json index 6577282ea3..a5cc44de43 100644 --- a/mm2src/mm2_test_helpers/dummy_files/iris_test_history.json +++ b/mm2src/mm2_test_helpers/dummy_files/iris_test_history.json @@ -18,7 +18,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.022145", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "3338384245443830413744344633314337443043303141460000000000000000", @@ -42,7 +42,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.027215", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "3644333931323846453142423238354542363542413237300000000000000000", @@ -71,7 +71,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.027385", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "0000000000000000423036443032413134343942303745383944313545373039", @@ -95,7 +95,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.028433", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "0000000000000000323645374341344139354337303331363139354538433841", @@ -119,7 +119,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.026403", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "0000000000000000343539463838434143434435373735364444464532313634", @@ -143,7 +143,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.02856", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "3533313331314334433333384341323539443144423441380000000000000000", @@ -174,7 +174,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.022085", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "3332313535443541424134344134343736463332363433370000000000000000", @@ -198,7 +198,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.026446", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "3945383530394438433442384645464138413133443235320000000000000000", @@ -227,7 +227,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.026426", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "4538314545353844354538344630413743344437364142360000000000000000", @@ -256,7 +256,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.028455", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "4135353530353436314138373531433631443333364331460000000000000000", @@ -285,7 +285,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.02648", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "4444394136304639344533383037313336353232394430310000000000000000", @@ -314,7 +314,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.028433", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "0000000000000000323544394131463143393338334143374435364533453139", @@ -338,7 +338,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.025763", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "0000000000000000443833443831343343414438433232354633424332344336", @@ -364,7 +364,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.026861", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "3236413546344639343144434531363135373046373530330000000000000001", @@ -390,7 +390,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.026861", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "4344413036444433353735413332323330363430414634310000000000000001", @@ -416,7 +416,7 @@ "type": "Tendermint", "coin": "IRIS-TEST", "amount": "0.2", - "gas_limit": 100000 + "gas_limit": 125000 }, "coin": "IRIS-TEST", "internal_id": "3846394537344334443745414531314244303741424145410000000000000000", diff --git a/mm2src/mm2_test_helpers/src/for_tests.rs b/mm2src/mm2_test_helpers/src/for_tests.rs index 910837c666..68c3ba4eaf 100644 --- a/mm2src/mm2_test_helpers/src/for_tests.rs +++ b/mm2src/mm2_test_helpers/src/for_tests.rs @@ -126,8 +126,8 @@ pub const ZOMBIE_TICKER: &str = "ZOMBIE"; pub const ARRR: &str = "ARRR"; pub const ZOMBIE_ELECTRUMS: &[&str] = &["zombie.dragonhound.info:10033"]; pub const ZOMBIE_LIGHTWALLETD_URLS: &[&str] = &["http://zombie.dragonhound.info:443"]; -pub const PIRATE_ELECTRUMS: &[&str] = &["pirate.dragonhound.info:10032"]; -pub const PIRATE_LIGHTWALLETD_URLS: &[&str] = &["http://pirate.dragonhound.info:443"]; +pub const PIRATE_ELECTRUMS: &[&str] = &["node1.chainkeeper.pro:10132"]; +pub const PIRATE_LIGHTWALLETD_URLS: &[&str] = &["http://node1.chainkeeper.pro:443"]; pub const DEFAULT_RPC_PASSWORD: &str = "pass"; pub const QRC20_ELECTRUMS: &[&str] = &[ "electrum1.cipig.net:10071",