From a79e644102f5974f0533fa9628da61aa4e14f51b Mon Sep 17 00:00:00 2001 From: jorgeantonio21 Date: Wed, 12 Oct 2022 23:07:14 +0100 Subject: [PATCH] squase commits --- .github/workflows/coverage.yml | 60 +- .github/workflows/integration_tests.yml | 2 +- Cargo.lock | 843 +++++++++--------- applications/tari_app_grpc/Cargo.toml | 11 +- .../src/authentication/basic_auth.rs | 4 +- applications/tari_app_utilities/Cargo.toml | 8 +- .../tari_app_utilities/src/utilities.rs | 26 +- applications/tari_base_node/Cargo.toml | 6 +- .../src/commands/command/status.rs | 15 +- applications/tari_base_node/src/config.rs | 5 +- applications/tari_base_node/src/main.rs | 18 +- applications/tari_console_wallet/Cargo.toml | 9 +- .../src/automation/commands.rs | 162 +++- .../src/automation/error.rs | 3 + applications/tari_console_wallet/src/cli.rs | 43 +- .../tari_console_wallet/src/init/mod.rs | 31 +- applications/tari_console_wallet/src/main.rs | 18 +- .../tari_console_wallet/src/wallet_modes.rs | 36 +- .../tari_merge_mining_proxy/Cargo.toml | 8 +- applications/tari_miner/Cargo.toml | 8 +- base_layer/common_types/Cargo.toml | 8 +- base_layer/core/Cargo.toml | 8 +- .../src/chain_storage/blockchain_database.rs | 69 +- base_layer/core/src/consensus/emission.rs | 47 +- base_layer/core/src/iterators/chunk.rs | 2 +- .../transaction_output.rs | 3 +- .../unblinded_output.rs | 47 + base_layer/key_manager/Cargo.toml | 8 +- base_layer/mmr/Cargo.toml | 7 +- base_layer/p2p/Cargo.toml | 10 +- base_layer/p2p/examples/gen_node_identity.rs | 2 +- base_layer/service_framework/Cargo.toml | 2 +- base_layer/tari_mining_helper_ffi/Cargo.toml | 8 +- base_layer/wallet/Cargo.toml | 10 +- base_layer/wallet/src/config.rs | 4 +- .../wallet/src/key_manager_service/handle.rs | 14 +- .../src/key_manager_service/interface.rs | 5 +- .../wallet/src/key_manager_service/mock.rs | 5 +- .../src/output_manager_service/handle.rs | 53 +- .../src/output_manager_service/service.rs | 171 +++- .../storage/sqlite_db/mod.rs | 2 +- .../wallet/src/storage/sqlite_db/wallet.rs | 2 +- .../wallet/src/transaction_service/handle.rs | 135 ++- .../wallet/src/transaction_service/service.rs | 290 +++++- .../transaction_service/storage/sqlite_db.rs | 2 +- base_layer/wallet/src/util/encryption.rs | 2 +- .../key_manager_service_tests/service.rs | 2 +- .../output_manager_service_tests/storage.rs | 2 +- .../transaction_service_tests/storage.rs | 2 +- base_layer/wallet_ffi/Cargo.toml | 8 +- base_layer/wallet_ffi/src/lib.rs | 2 +- changelog.md | 43 + common/Cargo.toml | 4 +- common/config/presets/c_base_node.toml | 13 +- common/src/configuration/bootstrap.rs | 24 + common_sqlite/Cargo.toml | 2 +- comms/core/Cargo.toml | 8 +- comms/core/src/connectivity/manager.rs | 23 +- comms/core/src/connectivity/test.rs | 52 +- comms/core/src/lib.rs | 2 +- comms/core/src/message/mod.rs | 13 + comms/core/src/peer_manager/migrations.rs | 13 +- comms/core/src/peer_manager/migrations/v7.rs | 78 ++ comms/core/src/protocol/rpc/body.rs | 2 +- comms/dht/Cargo.toml | 11 +- comms/dht/examples/memory_net/utilities.rs | 2 +- comms/dht/examples/memorynet.rs | 4 +- comms/dht/examples/propagation_stress.rs | 2 +- comms/dht/src/crypt.rs | 299 ++++--- comms/dht/src/dedup/mod.rs | 8 +- comms/dht/src/dht.rs | 11 +- comms/dht/src/envelope.rs | 5 +- comms/dht/src/inbound/decryption.rs | 51 +- comms/dht/src/inbound/deserialize.rs | 4 +- comms/dht/src/inbound/dht_handler/task.rs | 2 +- comms/dht/src/inbound/forward.rs | 20 +- comms/dht/src/outbound/broadcast.rs | 24 +- comms/dht/src/outbound/message.rs | 9 +- comms/dht/src/outbound/mock.rs | 37 +- comms/dht/src/outbound/requester.rs | 20 +- comms/dht/src/outbound/serialize.rs | 2 +- .../dht/src/store_forward/saf_handler/task.rs | 51 +- comms/dht/src/store_forward/store.rs | 8 +- comms/dht/src/test_utils/makers.rs | 58 +- comms/dht/src/test_utils/mod.rs | 2 + comms/dht/tests/dht.rs | 25 +- comms/rpc_macros/Cargo.toml | 2 +- infrastructure/derive/Cargo.toml | 2 +- infrastructure/libtor/Cargo.toml | 2 +- infrastructure/shutdown/Cargo.toml | 2 +- infrastructure/storage/Cargo.toml | 6 +- infrastructure/tari_script/Cargo.toml | 8 +- infrastructure/tari_script/src/lib.rs | 2 +- infrastructure/tari_script/src/op_codes.rs | 133 ++- infrastructure/tari_script/src/script.rs | 111 ++- infrastructure/tari_script/src/stack.rs | 88 +- infrastructure/test_utils/Cargo.toml | 4 +- integration_tests/features/WalletCli.feature | 3 +- .../features/WalletTransactions.feature | 18 +- integration_tests/helpers/walletProcess.js | 1 + package-lock.json | 2 +- 101 files changed, 2519 insertions(+), 1045 deletions(-) create mode 100644 comms/core/src/peer_manager/migrations/v7.rs diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 94d6d9d042..7b8fb38bff 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,8 +1,7 @@ --- name: Source Coverage -on: - workflow_dispatch: +'on': push: branches: - development @@ -13,53 +12,38 @@ env: jobs: coverage: - name: test and generate cov + name: test and generate coverage runs-on: [ self-hosted, ubuntu18.04-high-mem ] steps: + - name: checkout source code + uses: actions/checkout@v3 + - name: ubuntu dependencies run: | - sudo apt-get update && \ - sudo apt-get -y install \ - openssl \ - libssl-dev \ - pkg-config \ - libsqlite3-dev \ - clang-10 \ - git \ - cmake \ - libc++-dev \ - libc++abi-dev \ - libprotobuf-dev \ - protobuf-compiler \ - libncurses5-dev \ - libncursesw5-dev \ - zip \ - build-essential \ - libgtk-3-dev \ - libwebkit2gtk-4.0-dev \ - libsoup2.4-dev \ - curl \ - wget \ - libappindicator3-dev \ - patchelf \ - librsvg2-dev - - name: checkout - uses: actions/checkout@v2 + sudo apt-get update + sudo bash scripts/install_ubuntu_dependencies.sh + - uses: actions-rs/toolchain@v1 with: toolchain: nightly override: true components: llvm-tools-preview - - uses: actions-rs/cargo@v1 + + - name: cache cargo files and outputs + uses: Swatinem/rust-cache@v2 with: - command: test - args: --all-features --no-fail-fast + cache-on-failure: true + + - uses: actions-rs/cargo@v1 env: RUSTFLAGS: "-C instrument-coverage" RUSTDOCFLAGS: "-C instrument-coverage" LLVM_PROFILE_FILE: "coverage_data-%p-%m.profraw" - - id: coverage - name: Prepare coverage data + with: + command: test + args: --all-features --no-fail-fast + + - name: prepare coverage data env: COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} run: | @@ -72,13 +56,15 @@ jobs: --vcs-branch $GITHUB_REF_NAME \ --service-name github \ --service-job-id ${GITHUB_RUN_ID} - - id: archive-coverage - name: archive-coverage + + - name: archive coverage data uses: actions/upload-artifact@v3 with: path: target/coveralls_coverage.json name: coveralls-coverage + - name: Coveralls upload + continue-on-error: true uses: toshke/github-action@master with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index 34469137aa..5f48a53e40 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -133,7 +133,7 @@ jobs: npm run check-fmt npm run lint npm ci - cd ../clients/base_node_grpc_client + cd ../clients/nodejs/base_node_grpc_client npm install cd ../wallet_grpc_client npm install diff --git a/Cargo.lock b/Cargo.lock index 577db90300..0997c208ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,13 +18,14 @@ dependencies = [ ] [[package]] -name = "aead" -version = "0.5.1" +name = "aes" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" dependencies = [ - "crypto-common", - "generic-array", + "aes-soft", + "aesni", + "cipher 0.2.5", ] [[package]] @@ -45,14 +46,34 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" dependencies = [ - "aead 0.4.3", - "aes", + "aead", + "aes 0.7.5", "cipher 0.3.0", "ctr", "ghash", "subtle", ] +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher 0.2.5", + "opaque-debug", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher 0.2.5", + "opaque-debug", +] + [[package]] name = "ahash" version = "0.7.6" @@ -188,6 +209,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "autocfg" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.1.0", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -203,6 +233,12 @@ dependencies = [ "cc", ] +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base58-monero" version = "0.3.2" @@ -230,6 +266,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "base64" version = "0.13.0" @@ -331,7 +373,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" dependencies = [ - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -353,14 +395,23 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-cipher" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f337a3e6da609650eb74e02bc9fac7b735049f7623ab12f2e4c719316fcc7e80" +dependencies = [ + "generic-array", +] + [[package]] name = "block-modes" -version = "0.8.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" +checksum = "0c9b14fd8a4739e6548d4b6018696cf991dcf8c6effd9ef9eb33b29b8a650972" dependencies = [ + "block-cipher", "block-padding", - "cipher 0.3.0", ] [[package]] @@ -371,12 +422,12 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "blowfish" -version = "0.8.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe3ff3fc1de48c1ac2e3341c4df38b0d1bfb8fdf04632a187c8b75aaa319a7ab" +checksum = "32fa6a061124e37baba002e496d203e23ba3d7b73750be82dbfbc92913048a5b" dependencies = [ "byteorder", - "cipher 0.3.0", + "cipher 0.2.5", "opaque-debug", ] @@ -459,7 +510,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" dependencies = [ - "rustc_version", + "rustc_version 0.4.0", ] [[package]] @@ -470,12 +521,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cast5" -version = "0.10.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f69790da27038b52ffcf09e7874e1aae353c674d65242549a733ad9372e7281f" +checksum = "1285caf81ea1f1ece6b24414c521e625ad0ec94d880625c20f2e65d8d3f78823" dependencies = [ "byteorder", - "cipher 0.3.0", + "cipher 0.2.5", "opaque-debug", ] @@ -504,7 +555,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6358dedf60f4d9b8db43ad187391afe959746101346fe51bb978126bec61dfb" dependencies = [ - "clap 3.2.21", + "clap 3.2.22", "heck 0.4.0", "indexmap", "log", @@ -534,11 +585,11 @@ dependencies = [ [[package]] name = "cfb-mode" -version = "0.7.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "750dfbb1b1f84475c1a92fed10fa5e76cb11adc0cda5225f137c5cac84e80860" +checksum = "1d6975e91054798d325f85f50115056d7deccf6817fe7f947c438ee45b119632" dependencies = [ - "cipher 0.3.0", + "cipher 0.2.5", ] [[package]] @@ -576,40 +627,16 @@ dependencies = [ "zeroize", ] -[[package]] -name = "chacha20" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fc89c7c5b9e7a02dfe45cd2367bae382f9ed31c61ca8debe5f827c420a2f08" -dependencies = [ - "cfg-if 1.0.0", - "cipher 0.4.3", - "cpufeatures", -] - [[package]] name = "chacha20poly1305" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" dependencies = [ - "aead 0.4.3", + "aead", "chacha20 0.8.2", "cipher 0.3.0", - "poly1305 0.7.2", - "zeroize", -] - -[[package]] -name = "chacha20poly1305" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" -dependencies = [ - "aead 0.5.1", - "chacha20 0.9.0", - "cipher 0.4.3", - "poly1305 0.8.0", + "poly1305", "zeroize", ] @@ -647,22 +674,20 @@ dependencies = [ [[package]] name = "cipher" -version = "0.3.0" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" dependencies = [ "generic-array", ] [[package]] name = "cipher" -version = "0.4.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ - "crypto-common", - "inout", - "zeroize", + "generic-array", ] [[package]] @@ -673,9 +698,9 @@ checksum = "b0fc239e0f6cb375d2402d48afb92f76f5404fd1df208a41930ec81eda078bea" [[package]] name = "clang-sys" -version = "1.3.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a050e2153c5be08febd6734e29298e844fdb0fa21aeddd63b4eb7baa106c69b" +checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" dependencies = [ "glob", "libc", @@ -699,9 +724,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.21" +version = "3.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed5341b2301a26ab80be5cbdced622e80ed808483c52e45e3310a877d3b37d7" +checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" dependencies = [ "atty", "bitflags 1.3.2", @@ -711,7 +736,7 @@ dependencies = [ "once_cell", "strsim 0.10.0", "termcolor", - "textwrap 0.15.0", + "textwrap 0.15.1", ] [[package]] @@ -800,12 +825,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "const-oid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" - [[package]] name = "convert_case" version = "0.4.0" @@ -899,7 +918,7 @@ dependencies = [ "clap 2.34.0", "criterion-plot 0.4.5", "csv", - "itertools 0.10.4", + "itertools 0.10.5", "lazy_static", "num-traits", "oorandom", @@ -932,7 +951,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" dependencies = [ "cast 0.3.0", - "itertools 0.10.4", + "itertools 0.10.5", ] [[package]] @@ -994,15 +1013,14 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" +checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348" dependencies = [ - "autocfg", + "autocfg 1.1.0", "cfg-if 1.0.0", "crossbeam-utils", "memoffset", - "once_cell", "scopeguard", ] @@ -1018,12 +1036,11 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" dependencies = [ "cfg-if 1.0.0", - "once_cell", ] [[package]] @@ -1108,16 +1125,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -1125,7 +1132,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core 0.6.3", "typenum", ] @@ -1187,12 +1193,13 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" dependencies = [ "byteorder", "digest 0.9.0", + "packed_simd_2", "rand_core 0.5.1", "serde", "subtle", @@ -1201,32 +1208,17 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-pre.1" +version = "4.0.0-pre.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4033478fbf70d6acf2655ac70da91ee65852d69daf7a67bf7a2f518fb47aafcf" +checksum = "12dc3116fe595d7847c701796ac1b189bd86b81f4f593c6f775f9d80fb2e29f4" dependencies = [ "byteorder", - "digest 0.9.0", - "rand_core 0.6.3", + "digest 0.10.5", + "rand_core 0.6.4", "subtle", "zeroize", ] -[[package]] -name = "curve25519-dalek-ng" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" -dependencies = [ - "byteorder", - "digest 0.9.0", - "packed_simd_2", - "rand_core 0.6.3", - "serde", - "subtle-ng", - "zeroize", -] - [[package]] name = "darling" version = "0.10.2" @@ -1287,17 +1279,6 @@ dependencies = [ "log", ] -[[package]] -name = "der" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" -dependencies = [ - "const-oid", - "crypto-bigint", - "pem-rfc7468", -] - [[package]] name = "derivative" version = "2.2.0" @@ -1343,18 +1324,18 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version", + "rustc_version 0.4.0", "syn", ] [[package]] name = "des" -version = "0.7.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac41dd49fb554432020d52c875fc290e110113f864c6b1b525cd62c7e7747a5d" +checksum = "b24e7c748888aa2fa8bce21d8c64a52efc810663285315ac7476f7197a982fae" dependencies = [ "byteorder", - "cipher 0.3.0", + "cipher 0.2.5", "opaque-debug", ] @@ -1408,9 +1389,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ "block-buffer 0.10.3", "crypto-common", @@ -1448,6 +1429,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + [[package]] name = "dlv-list" version = "0.3.0" @@ -1469,7 +1456,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek 3.2.0", + "curve25519-dalek 3.2.1", "ed25519", "rand 0.7.3", "serde", @@ -1556,9 +1543,9 @@ dependencies = [ [[package]] name = "ethnum" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e4a7b7dde9ed6aed8eb4dd7474d22fb1713a4b05ac5071cdb60d9903248ad3" +checksum = "2eac3c0b9fa6eb75255ebb42c0ba3e2210d102a66d2795afef6fed668f373311" [[package]] name = "fast-float" @@ -1802,8 +1789,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", + "stdweb", "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1886,9 +1876,9 @@ dependencies = [ [[package]] name = "hdrhistogram" -version = "7.5.1" +version = "7.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea9fe3952d32674a14e0975009a3547af9ea364995b5ec1add2e23c2ae523ab" +checksum = "7f19b9f54f7c7f55e31401bb647626ce0cf0f67b0004982ce815b3ee72a02aa8" dependencies = [ "byteorder", "num-traits", @@ -1907,7 +1897,7 @@ dependencies = [ "http", "httpdate", "mime", - "sha1 0.10.4", + "sha1 0.10.5", ] [[package]] @@ -2055,14 +2045,13 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.48" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a0714f28b1ee39ccec0770ccb544eb02c9ef2c82bb096230eefcffa6468b0" +checksum = "fd911b35d940d2bd0bea0f9100068e5b97b51a1cbe13d13382f132e0365257a0" dependencies = [ "android_system_properties", "core-foundation-sys", "js-sys", - "once_cell", "wasm-bindgen", "winapi", ] @@ -2125,19 +2114,10 @@ version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ - "autocfg", + "autocfg 1.1.0", "hashbrown", ] -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - [[package]] name = "instant" version = "0.1.12" @@ -2182,9 +2162,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.4" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8bf247779e67a9082a4790b45e71ac7cfd1321331a5c856a74a9faebdab78d0" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] @@ -2267,9 +2247,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.132" +version = "0.2.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" [[package]] name = "libgit2-sys" @@ -2426,11 +2406,11 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ - "autocfg", + "autocfg 1.1.0", "scopeguard", ] @@ -2514,7 +2494,19 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ - "autocfg", + "autocfg 1.1.0", +] + +[[package]] +name = "merlin" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e261cf0f8b3c42ded9f7d2bb59dea03aa52bc8a1cbc7482f9fc3fd1229d3b42" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.5.1", + "zeroize", ] [[package]] @@ -2525,7 +2517,7 @@ checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", "keccak", - "rand_core 0.6.3", + "rand_core 0.6.4", "zeroize", ] @@ -2621,7 +2613,7 @@ version = "0.17.2" source = "git+https://github.com/tari-project/monero-rs.git?branch=main#7aebfd0aa037025cac6cbded3f72d73bf3c18123" dependencies = [ "base58-monero 1.0.0", - "curve25519-dalek 3.2.0", + "curve25519-dalek 3.2.1", "fixed-hash", "hex", "hex-literal", @@ -2784,24 +2776,25 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ - "autocfg", + "autocfg 1.1.0", "num-integer", "num-traits", ] [[package]] name = "num-bigint-dig" -version = "0.8.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566d173b2f9406afbc5510a90925d5a2cd80cae4605631f1212303df265de011" +checksum = "5d51546d704f52ef14b3c962b5776e53d5b862e5790e40a350d366c209bd7f7a" dependencies = [ + "autocfg 0.1.8", "byteorder", "lazy_static", "libm 0.2.5", "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand 0.7.3", "serde", "smallvec", "zeroize", @@ -2834,7 +2827,7 @@ version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ - "autocfg", + "autocfg 1.1.0", "num-traits", ] @@ -2844,7 +2837,7 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" dependencies = [ - "autocfg", + "autocfg 1.1.0", "num-integer", "num-traits", ] @@ -2855,7 +2848,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" dependencies = [ - "autocfg", + "autocfg 1.1.0", "num-integer", "num-traits", ] @@ -2866,8 +2859,7 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ - "autocfg", - "libm 0.2.5", + "autocfg 1.1.0", ] [[package]] @@ -2891,9 +2883,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" [[package]] name = "oorandom" @@ -2909,9 +2901,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.41" +version = "0.10.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" +checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" dependencies = [ "bitflags 1.3.2", "cfg-if 1.0.0", @@ -2950,11 +2942,11 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.75" +version = "0.9.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f" +checksum = "5230151e44c0f05157effb743e8d517472843121cf9243e8b81393edb5acd9ce" dependencies = [ - "autocfg", + "autocfg 1.1.0", "cc", "libc", "openssl-src", @@ -3084,7 +3076,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", - "lock_api 0.4.8", + "lock_api 0.4.9", "parking_lot_core 0.8.5", ] @@ -3094,7 +3086,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "lock_api 0.4.8", + "lock_api 0.4.9", "parking_lot_core 0.9.3", ] @@ -3146,7 +3138,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77e0b28ace46c5a396546bcf443bf422b57049617433d8854227352a4a9b24e7" dependencies = [ "base64ct", - "rand_core 0.6.3", + "rand_core 0.6.4", "subtle", ] @@ -3157,7 +3149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" dependencies = [ "base64ct", - "rand_core 0.6.3", + "rand_core 0.6.4", "subtle", ] @@ -3180,12 +3172,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] -name = "pem-rfc7468" -version = "0.3.1" +name = "pem" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01de5d978f34aa4b2296576379fcc416034702fd94117c56ffd8a1a767cefb30" +checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" dependencies = [ - "base64ct", + "base64 0.13.0", + "once_cell", + "regex", ] [[package]] @@ -3202,9 +3196,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb779fcf4bb850fbbb0edc96ff6cf34fd90c4b1a112ce042653280d9a7364048" +checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a" dependencies = [ "thiserror", "ucd-trie", @@ -3212,9 +3206,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502b62a6d0245378b04ffe0a7fb4f4419a4815fce813bd8a0ec89a56e07d67b1" +checksum = "60b75706b9642ebcb34dab3bc7750f811609a0eb1dd8b88c2d15bf628c1c65b2" dependencies = [ "pest", "pest_generator", @@ -3222,9 +3216,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451e629bf49b750254da26132f1a5a9d11fd8a95a3df51d15c4abd1ba154cb6c" +checksum = "f4f9272122f5979a6511a749af9db9bfc810393f63119970d7085fed1c4ea0db" dependencies = [ "pest", "pest_meta", @@ -3235,13 +3229,13 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcec162c71c45e269dfc3fc2916eaeb97feab22993a21bcce4721d08cd7801a6" +checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d" dependencies = [ "once_cell", "pest", - "sha1 0.10.4", + "sha1 0.10.5", ] [[package]] @@ -3266,12 +3260,12 @@ dependencies = [ [[package]] name = "pgp" -version = "0.8.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0c63db779c3f090b540dfa0484f8adc2d380e3aa60cdb0f3a7a97454e22edc5" +checksum = "856124b4d0a95badd3e1ad353edd7157fc6c6995767b78ef62848f3b296405ff" dependencies = [ - "aes", - "base64 0.13.0", + "aes 0.6.0", + "base64 0.12.3", "bitfield", "block-modes", "block-padding", @@ -3281,7 +3275,7 @@ dependencies = [ "cast5", "cfb-mode", "chrono", - "cipher 0.3.0", + "cipher 0.2.5", "circular", "clear_on_drop", "crc24", @@ -3299,7 +3293,7 @@ dependencies = [ "num-bigint-dig", "num-derive", "num-traits", - "rand 0.8.5", + "rand 0.7.3", "ripemd160", "rsa", "sha-1", @@ -3308,6 +3302,7 @@ dependencies = [ "signature", "smallvec", "thiserror", + "try_from", "twofish", "x25519-dalek", "zeroize", @@ -3365,28 +3360,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs1" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78f66c04ccc83dd4486fd46c33896f4e17b24a7a3a6400dedc48ed0ddd72320" -dependencies = [ - "der", - "pkcs8", - "zeroize", -] - -[[package]] -name = "pkcs8" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" -dependencies = [ - "der", - "spki", - "zeroize", -] - [[package]] name = "pkg-config" version = "0.3.25" @@ -3429,18 +3402,7 @@ checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ "cpufeatures", "opaque-debug", - "universal-hash 0.4.1", -] - -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash 0.5.0", + "universal-hash", ] [[package]] @@ -3452,7 +3414,7 @@ dependencies = [ "cfg-if 1.0.0", "cpufeatures", "opaque-debug", - "universal-hash 0.4.1", + "universal-hash", ] [[package]] @@ -3498,9 +3460,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" dependencies = [ "unicode-ident", ] @@ -3538,7 +3500,7 @@ checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" dependencies = [ "bytes 1.2.1", "heck 0.3.3", - "itertools 0.10.4", + "itertools 0.10.5", "lazy_static", "log", "multimap", @@ -3557,7 +3519,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" dependencies = [ "anyhow", - "itertools 0.10.4", + "itertools 0.10.5", "proc-macro2", "quote", "syn", @@ -3575,9 +3537,9 @@ dependencies = [ [[package]] name = "protobuf" -version = "2.27.1" +version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf7e6d18738ecd0902d30d1ad232c9125985a3422929b16c65517b38adc14f96" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" [[package]] name = "qrcode" @@ -3646,7 +3608,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -3666,7 +3628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -3695,9 +3657,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom 0.2.7", ] @@ -3751,7 +3713,7 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" dependencies = [ - "autocfg", + "autocfg 1.1.0", "crossbeam-deque", "either", "rayon-core", @@ -3925,21 +3887,23 @@ dependencies = [ [[package]] name = "rsa" -version = "0.6.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf22754c49613d2b3b119f0e5d46e34a2c628a937e3024b8762de4e7d8c710b" +checksum = "3648b669b10afeab18972c105e284a7b953a669b0be3514c27f9b17acab2f9cd" dependencies = [ "byteorder", - "digest 0.10.3", + "digest 0.9.0", + "lazy_static", "num-bigint-dig", "num-integer", "num-iter", "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.3", - "smallvec", + "pem", + "rand 0.7.3", + "sha2 0.9.9", + "simple_asn1", "subtle", + "thiserror", "zeroize", ] @@ -3965,20 +3929,29 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.14", ] [[package]] name = "rustix" -version = "0.35.9" +version = "0.35.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c825b8aa8010eb9ee99b75f05e10180b9278d161583034d7574c9d617aeada" +checksum = "fbb2fda4666def1433b1b05431ab402e42a1084285477222b72d6c564c417cef" dependencies = [ "bitflags 1.3.2", "errno", @@ -4000,6 +3973,15 @@ dependencies = [ "webpki 0.22.0", ] +[[package]] +name = "rustls-pemfile" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +dependencies = [ + "base64 0.13.0", +] + [[package]] name = "rustls-pemfile" version = "0.3.0" @@ -4140,17 +4122,32 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" dependencies = [ "serde_derive", ] @@ -4186,9 +4183,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", @@ -4262,13 +4259,13 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" [[package]] name = "sha1" -version = "0.10.4" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -4286,13 +4283,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9db03534dff993187064c4e0c05a5708d2a9728ace9a8959b77bedf415dac5" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -4366,9 +4363,20 @@ dependencies = [ [[package]] name = "signature" -version = "1.6.1" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb766570a2825fa972bceff0d195727876a9cdf2460ab2e52d455dc2de47fd9" + +[[package]] +name = "simple_asn1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90531723b08e4d6d71b791108faf51f03e1b4a7784f96b2b87f852ebc247228" +checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" +dependencies = [ + "chrono", + "num-bigint", + "num-traits", +] [[package]] name = "slab" @@ -4376,14 +4384,14 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" dependencies = [ - "autocfg", + "autocfg 1.1.0", ] [[package]] name = "smallvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "snow" @@ -4393,11 +4401,11 @@ checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d" dependencies = [ "aes-gcm", "blake2 0.10.4", - "chacha20poly1305 0.9.1", - "curve25519-dalek 4.0.0-pre.1", - "rand_core 0.6.3", - "rustc_version", - "sha2 0.10.5", + "chacha20poly1305", + "curve25519-dalek 4.0.0-pre.2", + "rand_core 0.6.4", + "rustc_version 0.4.0", + "sha2 0.10.6", "subtle", ] @@ -4417,16 +4425,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "spki" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" -dependencies = [ - "base64ct", - "der", -] - [[package]] name = "stack-buf" version = "0.1.6" @@ -4439,6 +4437,57 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "serde", + "serde_json", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1 0.6.0", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + [[package]] name = "str-buf" version = "1.0.6" @@ -4514,12 +4563,6 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" -[[package]] -name = "subtle-ng" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" - [[package]] name = "supercow" version = "0.1.0" @@ -4528,9 +4571,9 @@ checksum = "171758edb47aa306a78dfa4ab9aeb5167405bd4e3dc2b64e88f6a84bbe98bd63" [[package]] name = "syn" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ "proc-macro2", "quote", @@ -4551,7 +4594,7 @@ dependencies = [ [[package]] name = "tari_app_grpc" -version = "0.38.4" +version = "0.38.5" dependencies = [ "argon2 0.4.1", "base64 0.13.0", @@ -4576,15 +4619,15 @@ dependencies = [ [[package]] name = "tari_app_utilities" -version = "0.38.4" +version = "0.38.5" dependencies = [ - "clap 3.2.21", + "clap 3.2.22", "config", "dirs-next 1.0.2", "futures 0.3.24", "json5 0.2.8", "log", - "rand 0.8.5", + "rand 0.7.3", "serde", "structopt", "tari_common", @@ -4598,13 +4641,13 @@ dependencies = [ [[package]] name = "tari_base_node" -version = "0.38.4" +version = "0.38.5" dependencies = [ "anyhow", "async-trait", "bincode", "chrono", - "clap 3.2.21", + "clap 3.2.22", "config", "crossterm 0.23.2", "derive_more", @@ -4658,38 +4701,39 @@ dependencies = [ [[package]] name = "tari_bulletproofs" -version = "4.2.1" -source = "git+https://github.com/tari-project/bulletproofs?tag=v4.2.1#b7118625aeaf1a5f42301ca293fd89e5e783a2a8" +version = "4.3.0" +source = "git+https://github.com/tari-project/bulletproofs?tag=v4.3.0#02d5cb51d7fdaabf0e2523d45afed8b3d206c402" dependencies = [ "blake2 0.9.2", "byteorder", - "curve25519-dalek-ng", + "curve25519-dalek 3.2.1", "digest 0.9.0", - "merlin", - "rand 0.8.5", - "rand_core 0.6.3", + "merlin 2.0.1", + "rand 0.7.3", + "rand_core 0.5.1", "serde", "serde_derive", "sha3", - "subtle-ng", + "subtle", "thiserror", "zeroize", ] [[package]] name = "tari_bulletproofs_plus" -version = "0.0.6" -source = "git+https://github.com/tari-project/bulletproofs-plus?tag=v0.0.6#1af8e5102cca178f7de0f0c4ed73e8f31f00e95c" +version = "0.0.7" +source = "git+https://github.com/tari-project/bulletproofs-plus?tag=v0.1.0#6c221ff1661b776c26217d4b1c3605d77cbf3d43" dependencies = [ "blake2 0.9.2", "byteorder", - "curve25519-dalek-ng", + "curve25519-dalek 3.2.1", "derivative", "derive_more", "digest 0.9.0", "lazy_static", - "merlin", - "rand 0.8.5", + "merlin 3.0.0", + "rand 0.7.3", + "rand_core 0.5.1", "serde", "sha3", "thiserror", @@ -4698,7 +4742,7 @@ dependencies = [ [[package]] name = "tari_common" -version = "0.38.4" +version = "0.38.5" dependencies = [ "anyhow", "blake2 0.9.2", @@ -4726,7 +4770,7 @@ dependencies = [ [[package]] name = "tari_common_sqlite" -version = "0.38.4" +version = "0.38.5" dependencies = [ "diesel", "log", @@ -4735,12 +4779,12 @@ dependencies = [ [[package]] name = "tari_common_types" -version = "0.38.4" +version = "0.38.5" dependencies = [ "base64 0.13.0", "digest 0.9.0", "lazy_static", - "rand 0.8.5", + "rand 0.7.3", "serde", "tari_crypto", "tari_utilities", @@ -4751,7 +4795,7 @@ dependencies = [ [[package]] name = "tari_comms" -version = "0.38.4" +version = "0.38.5" dependencies = [ "anyhow", "async-trait", @@ -4776,7 +4820,7 @@ dependencies = [ "pin-project 1.0.12", "prost", "prost-types", - "rand 0.8.5", + "rand 0.7.3", "serde", "serde_derive", "serde_json", @@ -4801,13 +4845,12 @@ dependencies = [ [[package]] name = "tari_comms_dht" -version = "0.38.4" +version = "0.38.5" dependencies = [ "anyhow", "bitflags 1.3.2", - "bytes 0.5.6", "chacha20 0.7.3", - "chacha20poly1305 0.9.1", + "chacha20poly1305", "chrono", "clap 2.34.0", "diesel", @@ -4826,7 +4869,7 @@ dependencies = [ "pin-project 0.4.30", "prost", "prost-types", - "rand 0.8.5", + "rand 0.7.3", "serde", "serde_derive", "tari_common", @@ -4848,7 +4891,7 @@ dependencies = [ [[package]] name = "tari_comms_rpc_macros" -version = "0.38.4" +version = "0.38.5" dependencies = [ "futures 0.3.24", "proc-macro2", @@ -4863,12 +4906,12 @@ dependencies = [ [[package]] name = "tari_console_wallet" -version = "0.38.4" +version = "0.38.5" dependencies = [ "base64 0.13.0", "bitflags 1.3.2", "chrono", - "clap 3.2.21", + "clap 3.2.22", "config", "crossterm 0.17.7", "digest 0.9.0", @@ -4877,7 +4920,7 @@ dependencies = [ "opentelemetry", "opentelemetry-jaeger", "qrcode", - "rand 0.8.5", + "rand 0.7.3", "regex", "rpassword", "rustyline", @@ -4909,18 +4952,19 @@ dependencies = [ "tui", "unicode-segmentation", "unicode-width", + "zeroize", ] [[package]] name = "tari_core" -version = "0.38.4" +version = "0.38.5" dependencies = [ "async-trait", "bincode", "bitflags 1.3.2", "blake2 0.9.2", "bytes 0.5.6", - "chacha20poly1305 0.9.1", + "chacha20poly1305", "chrono", "config", "criterion 0.3.6", @@ -4944,7 +4988,7 @@ dependencies = [ "once_cell", "prost", "prost-types", - "rand 0.8.5", + "rand 0.7.3", "randomx-rs", "serde", "serde_json", @@ -4976,19 +5020,19 @@ dependencies = [ [[package]] name = "tari_crypto" -version = "0.15.5" -source = "git+https://github.com/tari-project/tari-crypto.git?tag=v0.15.5#a531063441b51415b9bafad6e8dbeea31247fc4a" +version = "0.15.6" +source = "git+https://github.com/tari-project/tari-crypto.git?tag=v0.15.6#d4f645403c6165534474338328582979a73d2b15" dependencies = [ "base64 0.10.1", "blake2 0.9.2", "cbindgen 0.17.0", - "curve25519-dalek-ng", + "curve25519-dalek 3.2.1", "digest 0.9.0", "lazy_static", "log", - "merlin", + "merlin 2.0.1", "once_cell", - "rand 0.8.5", + "rand 0.7.3", "serde", "serde_json", "sha3", @@ -5001,7 +5045,7 @@ dependencies = [ [[package]] name = "tari_key_manager" -version = "0.38.4" +version = "0.38.5" dependencies = [ "argon2 0.2.4", "arrayvec 0.7.2", @@ -5014,7 +5058,7 @@ dependencies = [ "digest 0.9.0", "getrandom 0.2.7", "js-sys", - "rand 0.8.5", + "rand 0.7.3", "serde", "serde_derive", "serde_json", @@ -5038,7 +5082,7 @@ dependencies = [ "log", "log4rs", "multiaddr", - "rand 0.8.5", + "rand 0.7.3", "tari_common", "tari_p2p", "tari_shutdown", @@ -5048,13 +5092,13 @@ dependencies = [ [[package]] name = "tari_merge_mining_proxy" -version = "0.38.4" +version = "0.38.5" dependencies = [ "anyhow", "bincode", "bytes 1.2.1", "chrono", - "clap 3.2.21", + "clap 3.2.22", "config", "crossterm 0.17.7", "derivative", @@ -5063,7 +5107,7 @@ dependencies = [ "hyper", "jsonrpc", "log", - "rand 0.8.5", + "rand 0.7.3", "reqwest", "serde", "serde_json", @@ -5100,12 +5144,12 @@ dependencies = [ [[package]] name = "tari_miner" -version = "0.38.4" +version = "0.38.5" dependencies = [ "base64 0.13.0", "bufstream", "chrono", - "clap 3.2.21", + "clap 3.2.22", "config", "crossbeam", "crossterm 0.17.7", @@ -5116,7 +5160,7 @@ dependencies = [ "native-tls", "num_cpus", "prost-types", - "rand 0.8.5", + "rand 0.7.3", "reqwest", "serde", "serde_json", @@ -5136,11 +5180,11 @@ dependencies = [ [[package]] name = "tari_mining_helper_ffi" -version = "0.38.4" +version = "0.38.5" dependencies = [ "hex", "libc", - "rand 0.8.5", + "rand 0.7.3", "serde", "serde_json", "tari_common", @@ -5153,7 +5197,7 @@ dependencies = [ [[package]] name = "tari_mmr" -version = "0.38.4" +version = "0.38.5" dependencies = [ "bincode", "blake2 0.9.2", @@ -5172,7 +5216,7 @@ dependencies = [ [[package]] name = "tari_p2p" -version = "0.38.4" +version = "0.38.5" dependencies = [ "anyhow", "bytes 0.5.6", @@ -5186,10 +5230,10 @@ dependencies = [ "log", "pgp", "prost", - "rand 0.8.5", + "rand 0.7.3", "reqwest", "rustls", - "semver", + "semver 1.0.14", "serde", "serde_derive", "tari_common", @@ -5218,7 +5262,7 @@ dependencies = [ "blake2 0.9.2", "digest 0.9.0", "integer-encoding 3.0.4", - "rand 0.8.5", + "rand 0.7.3", "serde", "sha2 0.9.9", "sha3", @@ -5229,7 +5273,7 @@ dependencies = [ [[package]] name = "tari_service_framework" -version = "0.38.4" +version = "0.38.5" dependencies = [ "anyhow", "async-trait", @@ -5246,7 +5290,7 @@ dependencies = [ [[package]] name = "tari_shutdown" -version = "0.38.4" +version = "0.38.5" dependencies = [ "futures 0.3.24", "tokio", @@ -5254,12 +5298,12 @@ dependencies = [ [[package]] name = "tari_storage" -version = "0.38.4" +version = "0.38.5" dependencies = [ "bincode", "lmdb-zero", "log", - "rand 0.8.5", + "rand 0.7.3", "serde", "serde_derive", "tari_utilities", @@ -5268,11 +5312,11 @@ dependencies = [ [[package]] name = "tari_test_utils" -version = "0.38.4" +version = "0.38.5" dependencies = [ "futures 0.3.24", "futures-test", - "rand 0.8.5", + "rand 0.7.3", "tari_shutdown", "tempfile", "tokio", @@ -5280,8 +5324,8 @@ dependencies = [ [[package]] name = "tari_utilities" -version = "0.4.5" -source = "git+https://github.com/tari-project/tari_utilities.git?tag=v0.4.5#a9e059ba84f8d931aeaa2b88a52a1ce6503b2deb" +version = "0.4.7" +source = "git+https://github.com/tari-project/tari_utilities.git?tag=v0.4.7#890a67140f56d9948ba64e8b0be981589875e75c" dependencies = [ "base58-monero 0.3.2", "base64 0.13.0", @@ -5295,13 +5339,13 @@ dependencies = [ [[package]] name = "tari_wallet" -version = "0.38.4" +version = "0.38.5" dependencies = [ "argon2 0.2.4", "async-trait", "bincode", "blake2 0.9.2", - "chacha20poly1305 0.10.1", + "chacha20poly1305", "chrono", "clear_on_drop", "derivative", @@ -5311,13 +5355,13 @@ dependencies = [ "env_logger", "fs2", "futures 0.3.24", - "itertools 0.10.4", + "itertools 0.10.5", "libsqlite3-sys", "lmdb-zero", "log", "log4rs", "prost", - "rand 0.8.5", + "rand 0.7.3", "serde", "serde_json", "sha2 0.9.9", @@ -5346,19 +5390,19 @@ dependencies = [ [[package]] name = "tari_wallet_ffi" -version = "0.38.4" +version = "0.38.5" dependencies = [ "cbindgen 0.24.3", "chrono", "futures 0.3.24", - "itertools 0.10.4", + "itertools 0.10.5", "lazy_static", "libc", "log", "log4rs", "num-traits", "openssl", - "rand 0.8.5", + "rand 0.7.3", "security-framework", "tari_common", "tari_common_types", @@ -5424,24 +5468,24 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" [[package]] name = "thiserror" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", @@ -5503,9 +5547,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3f9a28b618c3a6b9251b6908e9c99e04b9e5c02e6581ccbb67d59c34ef7f9b" +checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" dependencies = [ "libc", "num_threads", @@ -5547,17 +5591,16 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.21.1" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0020c875007ad96677dcc890298f4b942882c5d4eb7cc8f439fc3bf813dc9c95" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ - "autocfg", + "autocfg 1.1.0", "bytes 1.2.1", "libc", "memchr", "mio 0.8.4", "num_cpus", - "once_cell", "pin-project-lite", "signal-hook-registry", "socket2", @@ -5609,9 +5652,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" +checksum = "f6edf2d6bc038a43d31353570e27270603f4648d18f5ed10c0e179abe43255af" dependencies = [ "futures-core", "pin-project-lite", @@ -5869,7 +5912,7 @@ dependencies = [ "ring", "rustls", "thiserror", - "time 0.3.14", + "time 0.3.15", "tokio", "trust-dns-proto", "webpki 0.22.0", @@ -5895,7 +5938,7 @@ dependencies = [ "rand 0.8.5", "ring", "rustls", - "rustls-pemfile", + "rustls-pemfile 0.3.0", "smallvec", "thiserror", "tinyvec", @@ -5911,6 +5954,15 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +[[package]] +name = "try_from" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" +dependencies = [ + "cfg-if 0.1.10", +] + [[package]] name = "tui" version = "0.16.0" @@ -5926,12 +5978,12 @@ dependencies = [ [[package]] name = "twofish" -version = "0.6.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728f6b7e784825d272fe9d2a77e44063f4197a570cbedc6fdcc90a6ddac91296" +checksum = "0028f5982f23ecc9a1bc3008ead4c664f843ed5d78acd3d213b99ff50c441bc2" dependencies = [ "byteorder", - "cipher 0.3.0", + "cipher 0.2.5", "opaque-debug", ] @@ -5958,9 +6010,9 @@ checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "uint" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" +checksum = "a45526d29728d135c2900b0d30573fe3ee79fceb12ef534c7bb30e810a91b601" dependencies = [ "byteorder", "crunchy", @@ -5991,9 +6043,9 @@ checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" [[package]] name = "unicode-normalization" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] @@ -6012,9 +6064,9 @@ checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" @@ -6026,16 +6078,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "universal-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" -dependencies = [ - "crypto-common", - "subtle", -] - [[package]] name = "unsafe-any" version = "0.4.2" @@ -6138,9 +6180,9 @@ dependencies = [ [[package]] name = "warp" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cef4e1e9114a4b7f1ac799f16ce71c14de5778500c5450ec6b7b920c55b587e" +checksum = "ed7b8be92646fc3d18b06147664ebc5f48d222686cb11a8755e561a735aacc6d" dependencies = [ "bytes 1.2.1", "futures-channel", @@ -6153,13 +6195,14 @@ dependencies = [ "mime_guess", "percent-encoding 2.2.0", "pin-project 1.0.12", + "rustls-pemfile 0.2.1", "scoped-tls", "serde", "serde_json", "serde_urlencoded", "tokio", "tokio-stream", - "tokio-util 0.6.10", + "tokio-util 0.7.4", "tower-service", "tracing", ] @@ -6400,11 +6443,11 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" +checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077" dependencies = [ - "curve25519-dalek 3.2.0", + "curve25519-dalek 3.2.1", "rand_core 0.5.1", "zeroize", ] @@ -6434,9 +6477,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.5.7" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" dependencies = [ "zeroize_derive", ] diff --git a/applications/tari_app_grpc/Cargo.toml b/applications/tari_app_grpc/Cargo.toml index 935cacd755..f60e707bcb 100644 --- a/applications/tari_app_grpc/Cargo.toml +++ b/applications/tari_app_grpc/Cargo.toml @@ -4,16 +4,16 @@ authors = ["The Tari Development Community"] description = "This crate is to provide a single source for all cross application grpc files and conversions to and from tari::core" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [dependencies] tari_common_types = { version = "^0.38", path = "../../base_layer/common_types" } tari_comms = { path = "../../comms/core" } tari_core = { path = "../../base_layer/core" } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } tari_script = { path = "../../infrastructure/tari_script" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } argon2 = { version = "0.4.1", features = ["std"] } base64 = "0.13.0" @@ -23,11 +23,10 @@ log = "0.4" num-traits = "0.2.15" prost = "0.9" prost-types = "0.9" -rand = "0.8" +rand = "0.8.5" thiserror = "1" tonic = "0.6.2" -zeroize = "1.5" +zeroize = "1.3" [build-dependencies] tonic-build = "0.6.2" - diff --git a/applications/tari_app_grpc/src/authentication/basic_auth.rs b/applications/tari_app_grpc/src/authentication/basic_auth.rs index 4bd5efe30d..0a2a99a24f 100644 --- a/applications/tari_app_grpc/src/authentication/basic_auth.rs +++ b/applications/tari_app_grpc/src/authentication/basic_auth.rs @@ -20,7 +20,7 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{borrow::Cow, string::FromUtf8Error}; +use std::{borrow::Cow, ops::Deref, string::FromUtf8Error}; use argon2::{password_hash::Encoding, Argon2, PasswordHash, PasswordVerifier}; use tari_utilities::SafePassword; @@ -93,7 +93,7 @@ impl BasicAuthCredentials { pub fn generate_header(username: &str, password: &[u8]) -> Result, BasicAuthError> { let password_str = String::from_utf8_lossy(password); let token_str = Zeroizing::new(format!("{}:{}", username, password_str)); - let mut token = base64::encode(token_str); + let mut token = base64::encode(token_str.deref()); let header = format!("Basic {}", token); token.zeroize(); match password_str { diff --git a/applications/tari_app_utilities/Cargo.toml b/applications/tari_app_utilities/Cargo.toml index e32ee75216..3ada64c646 100644 --- a/applications/tari_app_utilities/Cargo.toml +++ b/applications/tari_app_utilities/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "tari_app_utilities" -version = "0.38.4" +version = "0.38.5" authors = ["The Tari Development Community"] edition = "2018" license = "BSD-3-Clause" [dependencies] tari_comms = { path = "../../comms/core" } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } tari_common = { path = "../../common" } tari_common_types = { path = "../../base_layer/common_types" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } clap = { version = "3.2.0", features = ["derive", "env"] } config = { version = "0.13.0" } @@ -18,7 +18,7 @@ futures = { version = "^0.3.16", default-features = false, features = ["alloc"] dirs-next = "1.0.2" json5 = "0.2.2" log = { version = "0.4.8", features = ["std"] } -rand = "0.8" +rand = "0.7.3" tokio = { version = "1.20", features = ["signal"] } serde = "1.0.126" structopt = { version = "0.3.13", default_features = false } diff --git a/applications/tari_app_utilities/src/utilities.rs b/applications/tari_app_utilities/src/utilities.rs index f098ce2044..8de9a8b0b6 100644 --- a/applications/tari_app_utilities/src/utilities.rs +++ b/applications/tari_app_utilities/src/utilities.rs @@ -27,10 +27,10 @@ use log::*; use tari_common::exit_codes::{ExitCode, ExitError}; use tari_common_types::{ emoji::EmojiId, - types::{BlockHash, PublicKey}, + types::{BlockHash, PrivateKey, PublicKey, Signature}, }; use tari_comms::{peer_manager::NodeId, types::CommsPublicKey}; -use tari_utilities::hex::Hex; +use tari_utilities::hex::{Hex, HexError}; use thiserror::Error; use tokio::{runtime, runtime::Runtime}; @@ -96,6 +96,28 @@ impl From for PublicKey { } } +#[derive(Debug, Clone)] +pub struct UniSignature(Signature); + +impl FromStr for UniSignature { + type Err = HexError; + + fn from_str(s: &str) -> Result { + let data = s.split(',').collect::>(); + let signature = PrivateKey::from_hex(data[0])?; + let public_nonce = PublicKey::from_hex(data[1])?; + + let signature = Signature::new(public_nonce, signature); + Ok(Self(signature)) + } +} + +impl From for Signature { + fn from(id: UniSignature) -> Self { + id.0 + } +} + #[derive(Debug)] pub enum UniNodeId { PublicKey(PublicKey), diff --git a/applications/tari_base_node/Cargo.toml b/applications/tari_base_node/Cargo.toml index 2df4a644b1..2ff991ef58 100644 --- a/applications/tari_base_node/Cargo.toml +++ b/applications/tari_base_node/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "The tari full base node implementation" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [dependencies] @@ -15,14 +15,14 @@ tari_comms = { path = "../../comms/core", features = ["rpc"] } tari_common_types = { path = "../../base_layer/common_types" } tari_comms_dht = { path = "../../comms/dht" } tari_core = { path = "../../base_layer/core", default-features = false, features = ["transactions"] } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } tari_libtor = { path = "../../infrastructure/libtor", optional = true } tari_mmr = { path = "../../base_layer/mmr", features = ["native_bitmap"] } tari_p2p = { path = "../../base_layer/p2p", features = ["auto-update"] } tari_storage = {path="../../infrastructure/storage"} tari_service_framework = { path = "../../base_layer/service_framework" } tari_shutdown = { path = "../../infrastructure/shutdown" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } anyhow = "1.0.53" async-trait = "0.1.52" diff --git a/applications/tari_base_node/src/commands/command/status.rs b/applications/tari_base_node/src/commands/command/status.rs index df293775bc..f499b55059 100644 --- a/applications/tari_base_node/src/commands/command/status.rs +++ b/applications/tari_base_node/src/commands/command/status.rs @@ -27,7 +27,6 @@ use async_trait::async_trait; use chrono::{DateTime, NaiveDateTime, Utc}; use clap::Parser; use tari_app_utilities::consts; -use tari_comms::connectivity::ConnectivitySelection; use tokio::time; use super::{CommandContext, HandleCommand}; @@ -103,11 +102,15 @@ impl CommandContext { status_line.add_field("Mempool", "query timed out"); }; - let conns = self - .connectivity - .select_connections(ConnectivitySelection::all_nodes(vec![])) - .await?; - status_line.add_field("Connections", conns.len()); + let conns = self.connectivity.get_active_connections().await?; + let (num_nodes, num_clients) = conns.iter().fold((0usize, 0usize), |(nodes, clients), conn| { + if conn.peer_features().is_node() { + (nodes + 1, clients) + } else { + (nodes, clients + 1) + } + }); + status_line.add_field("Connections", format!("{}|{}", num_nodes, num_clients)); let banned_peers = self.fetch_banned_peers().await?; status_line.add_field("Banned", banned_peers.len()); diff --git a/applications/tari_base_node/src/config.rs b/applications/tari_base_node/src/config.rs index 21fd61dfe2..184ff83e9a 100644 --- a/applications/tari_base_node/src/config.rs +++ b/applications/tari_base_node/src/config.rs @@ -83,6 +83,8 @@ pub struct BaseNodeConfig { override_from: Option, /// Selected network pub network: Network, + /// Enable the base node GRPC server + pub grpc_enabled: bool, /// GRPC address of base node pub grpc_address: Option, /// A path to the file that stores the base node identity and secret key @@ -144,7 +146,8 @@ impl Default for BaseNodeConfig { Self { override_from: None, network: Network::default(), - grpc_address: Some("/ip4/127.0.0.1/tcp/18142".parse().unwrap()), + grpc_enabled: true, + grpc_address: None, identity_file: PathBuf::from("config/base_node_id.json"), use_libtor: false, tor_identity_file: PathBuf::from("config/base_node_tor_id.json"), diff --git a/applications/tari_base_node/src/main.rs b/applications/tari_base_node/src/main.rs index 9a63982e7e..a9b0e399e3 100644 --- a/applications/tari_base_node/src/main.rs +++ b/applications/tari_base_node/src/main.rs @@ -94,7 +94,10 @@ use log::*; use opentelemetry::{self, global, KeyValue}; use tari_app_utilities::{consts, identity_management::setup_node_identity, utilities::setup_runtime}; use tari_common::{ - configuration::{bootstrap::ApplicationType, Network}, + configuration::{ + bootstrap::{grpc_default_port, ApplicationType}, + Network, + }, exit_codes::{ExitCode, ExitError}, initialize_logging, load_configuration, @@ -145,7 +148,6 @@ fn main_inner() -> Result<(), ExitError> { include_str!("../log4rs_sample.yml"), )?; - #[cfg_attr(not(all(unix, feature = "libtor")), allow(unused_mut))] let mut config = ApplicationConfig::load_from(&cfg)?; if let Some(network) = &cli.network { config.base_node.network = Network::from_str(network)?; @@ -229,10 +231,14 @@ async fn run_node( // Build, node, build! let ctx = builder::configure_and_initialize_node(config.clone(), node_identity, shutdown.to_signal()).await?; - if let Some(address) = config.base_node.grpc_address.clone() { + if config.base_node.grpc_enabled { + let grpc_address = config.base_node.grpc_address.clone().unwrap_or_else(|| { + let port = grpc_default_port(ApplicationType::BaseNode, config.base_node.network); + format!("/ip4/127.0.0.1/tcp/{}", port).parse().unwrap() + }); // Go, GRPC, go go - let grpc = crate::grpc::base_node_grpc_server::BaseNodeGrpcServer::from_base_node_context(&ctx); - task::spawn(run_grpc(grpc, address, shutdown.to_signal())); + let grpc = grpc::base_node_grpc_server::BaseNodeGrpcServer::from_base_node_context(&ctx); + task::spawn(run_grpc(grpc, grpc_address, shutdown.to_signal())); } // Run, node, run! @@ -288,7 +294,7 @@ fn enable_tracing() { /// Runs the gRPC server async fn run_grpc( - grpc: crate::grpc::base_node_grpc_server::BaseNodeGrpcServer, + grpc: grpc::base_node_grpc_server::BaseNodeGrpcServer, grpc_address: Multiaddr, interrupt_signal: ShutdownSignal, ) -> Result<(), anyhow::Error> { diff --git a/applications/tari_console_wallet/Cargo.toml b/applications/tari_console_wallet/Cargo.toml index 906ffa9f28..1b0f1d5ea2 100644 --- a/applications/tari_console_wallet/Cargo.toml +++ b/applications/tari_console_wallet/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "tari_console_wallet" -version = "0.38.4" +version = "0.38.5" authors = ["The Tari Development Community"] edition = "2018" license = "BSD-3-Clause" [dependencies] tari_wallet = { path = "../../base_layer/wallet", features = ["bundled_sqlite"] } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } tari_common = { path = "../../common" } tari_app_utilities = { path = "../tari_app_utilities" } tari_comms = { path = "../../comms/core" } @@ -18,7 +18,7 @@ tari_p2p = { path = "../../base_layer/p2p", features = ["auto-update"] } tari_app_grpc = { path = "../tari_app_grpc" } tari_shutdown = { path = "../../infrastructure/shutdown" } tari_key_manager = { path = "../../base_layer/key_manager" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.7" } # Uncomment for tokio tracing via tokio-console (needs "tracing" featurs) #console-subscriber = "0.1.3" @@ -36,7 +36,7 @@ digest = "0.9.0" futures = { version = "^0.3.16", default-features = false, features = ["alloc"] } log = { version = "0.4.8", features = ["std"] } qrcode = { version = "0.12" } -rand = "0.8" +rand = "0.7.3" regex = "1.5.4" rpassword = "5.0" rustyline = "9.0" @@ -52,6 +52,7 @@ tracing-opentelemetry = "0.15.0" tracing-subscriber = "0.2.20" unicode-segmentation = "1.6.0" unicode-width = "0.1" +zeroize = "1.3" # network tracing, rt-tokio for async batch export opentelemetry = { version = "0.16", default-features = false, features = ["trace", "rt-tokio"] } diff --git a/applications/tari_console_wallet/src/automation/commands.rs b/applications/tari_console_wallet/src/automation/commands.rs index 49e22948c2..f265bd6d4b 100644 --- a/applications/tari_console_wallet/src/automation/commands.rs +++ b/applications/tari_console_wallet/src/automation/commands.rs @@ -21,7 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use std::{ - convert::TryInto, + convert::{From, TryInto}, fs, fs::File, io, @@ -34,6 +34,7 @@ use chrono::{DateTime, Utc}; use digest::Digest; use futures::FutureExt; use log::*; +use rand::rngs::OsRng; use serde::{de::DeserializeOwned, Serialize}; use sha2::Sha256; use strum_macros::{Display, EnumIter, EnumString}; @@ -41,7 +42,7 @@ use tari_app_grpc::authentication::salted_password::create_salted_hashed_passwor use tari_common_types::{ emoji::EmojiId, transaction::TxId, - types::{CommitmentFactory, FixedHash, PrivateKey, PublicKey}, + types::{Commitment, CommitmentFactory, FixedHash, PrivateKey, PublicKey, Signature}, }; use tari_comms::{ connectivity::{ConnectivityEvent, ConnectivityRequester}, @@ -53,11 +54,12 @@ use tari_core::transactions::{ tari_amount::{uT, MicroTari, Tari}, transaction_components::{OutputFeatures, TransactionOutput, UnblindedOutput}, }; +use tari_crypto::keys::SecretKey; use tari_utilities::{hex::Hex, ByteArray}; use tari_wallet::{ connectivity_service::WalletConnectivityInterface, error::WalletError, - key_manager_service::{storage::database::KeyManagerBackend, KeyManagerHandle, KeyManagerInterface, NextKeyResult}, + key_manager_service::{KeyManagerInterface, NextKeyResult}, output_manager_service::{handle::OutputManagerHandle, UtxoSelectionCriteria}, transaction_service::handle::{TransactionEvent, TransactionServiceHandle}, TransactionStage, @@ -68,6 +70,7 @@ use tokio::{ sync::{broadcast, mpsc}, time::{sleep, timeout}, }; +use zeroize::Zeroizing; use super::error::CommandError; use crate::{ @@ -84,7 +87,10 @@ pub enum WalletCommand { GetBalance, SendTari, SendOneSided, - CreateKeyCombo, + CreateKeyPair, + CreateAggregateSignatureUtxo, + SignMessage, + EncumberAggregateUtxo, MakeItRain, CoinSplit, DiscoverPeer, @@ -140,14 +146,49 @@ pub async fn burn_tari( .map_err(CommandError::TransactionServiceError) } -pub async fn create_key_combo( - key_manager_service: KeyManagerHandle, - key_seed: String, -) -> Result<(PrivateKey, PublicKey), CommandError> { - key_manager_service - .create_key_combo(key_seed) +pub async fn create_aggregate_signature_utxo( + mut wallet_transaction_service: TransactionServiceHandle, + amount: MicroTari, + fee_per_gram: MicroTari, + n: u8, + m: u8, + public_keys: Vec, + message: String, +) -> Result<(TxId, FixedHash), CommandError> { + let mut msg = [0u8; 32]; + msg.copy_from_slice(message.as_bytes()); + + wallet_transaction_service + .create_aggregate_signature_utxo(amount, fee_per_gram, n, m, public_keys, msg) .await - .map_err(CommandError::KeyManagerError) + .map_err(CommandError::TransactionServiceError) +} + +/// creates a metadata signature utxo +async fn encumber_aggregate_utxo( + mut wallet_transaction_service: TransactionServiceHandle, + fee_per_gram: MicroTari, + output_hash: String, + signatures: Vec, + total_script_pubkey: PublicKey, + total_offset_pubkey: PublicKey, + total_signature_nonce: PublicKey, + metadata_signature_nonce: PublicKey, + wallet_script_secret_key: String, +) -> Result<(TxId, Commitment, FixedHash, Commitment, String, String, PublicKey), CommandError> { + wallet_transaction_service + .encumber_aggregate_utxo( + fee_per_gram, + output_hash, + signatures, + total_script_pubkey, + total_offset_pubkey, + total_signature_nonce, + metadata_signature_nonce, + wallet_script_secret_key, + ) + .await + .map_err(CommandError::TransactionServiceError) } /// publishes a tari-SHA atomic swap HTLC transaction @@ -262,6 +303,17 @@ pub async fn coin_split( Ok(tx_id) } +pub fn sign_message(private_key: String, challenge: String) -> Result { + let private_key = + PrivateKey::from_hex(private_key.as_str()).map_err(|e| CommandError::InvalidArgument(e.to_string()))?; + let challenge = challenge.as_bytes(); + + let nonce = PrivateKey::random(&mut OsRng); + let signature = Signature::sign(private_key, nonce, challenge).map_err(CommandError::FailedSignature)?; + + Ok(signature) +} + async fn wait_for_comms(connectivity_requester: &ConnectivityRequester) -> Result<(), CommandError> { let mut connectivity = connectivity_requester.get_event_subscription(); print!("Waiting for connectivity... "); @@ -649,17 +701,95 @@ pub async fn command_runner( Err(e) => eprintln!("BurnTari error! {}", e), } }, - CreateKeyCombo(args) => match create_key_combo(key_manager_service.clone(), args.key_seed).await { + CreateKeyPair(args) => match key_manager_service.create_key_pair(args.key_branch).await { Ok((sk, pk)) => { println!( - "create new key combo pair: + "New key pair: 1. secret key: {}, - 2. public key {}", - sk.to_hex(), + 2. public key: {}", + *Zeroizing::new(sk.to_hex()), pk.to_hex() ) }, - Err(e) => eprintln!("CreateKeyCombo error! {}", e), + Err(e) => eprintln!("CreateKeyPair error! {}", e), + }, + CreateAggregateSignatureUtxo(args) => match create_aggregate_signature_utxo( + transaction_service.clone(), + args.amount, + args.fee_per_gram, + args.n, + args.m, + args.public_keys + .iter() + .map(|pk| PublicKey::from(pk.clone())) + .collect::>(), + args.message, + ) + .await + { + Ok((tx_id, output_hash)) => { + println!( + "Create a utxo with n-of-m aggregate public key, with: + 1. n = {}, + 2. m = {}, + 3. tx id = {}, + 4. output hash = {}", + args.n, args.m, tx_id, output_hash + ) + }, + Err(e) => eprintln!("CreateAggregateSignatureUtxo error! {}", e), + }, + SignMessage(args) => match sign_message(args.private_key, args.challenge) { + Ok(sgn) => { + println!( + "Sign message: + 1. signature: {}, + 2. public key: {}", + sgn.get_signature().to_hex(), + sgn.get_public_nonce().to_hex(), + ) + }, + Err(e) => eprintln!("SignMessage error! {}", e), + }, + EncumberAggregateUtxo(args) => match encumber_aggregate_utxo( + transaction_service.clone(), + args.fee_per_gram, + args.output_hash, + args.signatures.iter().map(|sgn| sgn.clone().into()).collect::>(), + args.total_script_pubkey.into(), + args.total_offset_pubkey.into(), + args.total_signature_nonce.into(), + args.metadata_signature_nonce.into(), + args.wallet_script_secret_key, + ) + .await + { + Ok(( + _tx_id, + output_commitment, + output_hash, + input_commitment, + input_script_hex, + input_commitment_hex, + total_public_offset, + )) => { + println!( + "Encumber aggregate utxo: + 1. output_commitment: {}, + 2. output_hash: {}, + 3. input_commitment: {}, + 4. input_stack_hex: {}, + 5. input_script_hex: {}, + 6. total_public_offes: {}", + output_commitment.to_hex(), + output_hash.to_hex(), + input_commitment.to_hex(), + input_script_hex, + input_commitment_hex, + total_public_offset.to_hex(), + ) + }, + Err(e) => eprintln!("Encumber aggregate utxo! {}", e), }, SendTari(args) => { match send_tari( diff --git a/applications/tari_console_wallet/src/automation/error.rs b/applications/tari_console_wallet/src/automation/error.rs index 06ab26f57b..79f15842af 100644 --- a/applications/tari_console_wallet/src/automation/error.rs +++ b/applications/tari_console_wallet/src/automation/error.rs @@ -29,6 +29,7 @@ use log::*; use tari_common::exit_codes::{ExitCode, ExitError}; use tari_common_types::types::FixedHashSizeError; use tari_core::transactions::{tari_amount::MicroTariError, transaction_components::TransactionError}; +use tari_crypto::signatures::SchnorrSignatureError; use tari_utilities::hex::HexError; use tari_wallet::{ error::{WalletError, WalletStorageError}, @@ -82,6 +83,8 @@ pub enum CommandError { General(String), #[error("FixedHash size error `{0}`")] FixedHashSizeError(#[from] FixedHashSizeError), + #[error("Invalid signature: `{0}`")] + FailedSignature(#[from] SchnorrSignatureError), } impl From for ExitError { diff --git a/applications/tari_console_wallet/src/cli.rs b/applications/tari_console_wallet/src/cli.rs index 891b0511ff..d2ce7b237a 100644 --- a/applications/tari_console_wallet/src/cli.rs +++ b/applications/tari_console_wallet/src/cli.rs @@ -28,7 +28,10 @@ use std::{ use chrono::{DateTime, Utc}; use clap::{Args, Parser, Subcommand}; -use tari_app_utilities::{common_cli_args::CommonCliArgs, utilities::UniPublicKey}; +use tari_app_utilities::{ + common_cli_args::CommonCliArgs, + utilities::{UniPublicKey, UniSignature}, +}; use tari_common::configuration::{ConfigOverrideProvider, Network}; use tari_comms::multiaddr::Multiaddr; use tari_core::transactions::{tari_amount, tari_amount::MicroTari}; @@ -116,7 +119,10 @@ pub enum CliCommands { GetBalance, SendTari(SendTariArgs), BurnTari(BurnTariArgs), - CreateKeyCombo(CreateKeyComboArgs), + CreateAggregateSignatureUtxo(CreateAggregateSignatureUtxoArgs), + CreateKeyPair(CreateKeyPairArgs), + EncumberAggregateUtxo(EncumberAggregateUtxoArgs), + SignMessage(SignMessageArgs), SendOneSided(SendTariArgs), SendOneSidedToStealthAddress(SendTariArgs), MakeItRain(MakeItRainArgs), @@ -157,8 +163,37 @@ pub struct BurnTariArgs { } #[derive(Debug, Args, Clone)] -pub struct CreateKeyComboArgs { - pub key_seed: String, +pub struct CreateKeyPairArgs { + pub key_branch: String, +} + +#[derive(Debug, Args, Clone)] +pub struct CreateAggregateSignatureUtxoArgs { + pub amount: MicroTari, + pub fee_per_gram: MicroTari, + pub n: u8, + pub m: u8, + pub message: String, + #[clap(long)] + pub public_keys: Vec, +} + +#[derive(Debug, Args, Clone)] +pub struct SignMessageArgs { + pub private_key: String, + pub challenge: String, +} + +#[derive(Debug, Args, Clone)] +pub struct EncumberAggregateUtxoArgs { + pub fee_per_gram: MicroTari, + pub output_hash: String, + pub signatures: Vec, + pub total_script_pubkey: UniPublicKey, + pub total_offset_pubkey: UniPublicKey, + pub total_signature_nonce: UniPublicKey, + pub metadata_signature_nonce: UniPublicKey, + pub wallet_script_secret_key: String, } #[derive(Debug, Args, Clone)] diff --git a/applications/tari_console_wallet/src/init/mod.rs b/applications/tari_console_wallet/src/init/mod.rs index 97ce4105f4..f00b788e31 100644 --- a/applications/tari_console_wallet/src/init/mod.rs +++ b/applications/tari_console_wallet/src/init/mod.rs @@ -27,7 +27,10 @@ use rpassword::prompt_password_stdout; use rustyline::Editor; use tari_app_utilities::identity_management::setup_node_identity; use tari_common::{ - configuration::bootstrap::prompt, + configuration::{ + bootstrap::{grpc_default_port, prompt, ApplicationType}, + Network, + }, exit_codes::{ExitCode, ExitError}, }; use tari_comms::{ @@ -41,7 +44,7 @@ use tari_crypto::keys::PublicKey; use tari_key_manager::{cipher_seed::CipherSeed, mnemonic::MnemonicLanguage}; use tari_p2p::{peer_seeds::SeedPeer, TransportType}; use tari_shutdown::ShutdownSignal; -use tari_utilities::{ByteArray, SafePassword}; +use tari_utilities::{hex::Hex, ByteArray, SafePassword}; use tari_wallet::{ error::{WalletError, WalletStorageError}, output_manager_service::storage::database::OutputManagerDatabase, @@ -164,7 +167,7 @@ pub async fn get_base_node_peer_config( // If the user has not explicitly set a base node in the config, we try detect one if !non_interactive_mode && config.wallet.custom_base_node.is_none() { - if let Some(detected_node) = detect_local_base_node().await { + if let Some(detected_node) = detect_local_base_node(config.wallet.network).await { match selected_base_node { Some(ref base_node) if base_node.public_key == detected_node.public_key => { // Skip asking because it's already set @@ -407,15 +410,31 @@ pub async fn init_wallet( Ok(wallet) } -async fn detect_local_base_node() -> Option { +async fn detect_local_base_node(network: Network) -> Option { use tari_app_grpc::tari_rpc::{base_node_client::BaseNodeClient, Empty}; - const COMMON_BASE_NODE_GRPC_ADDRESS: &str = "http://127.0.0.1:18142"; + let addr = format!( + "http://127.0.0.1:{}", + grpc_default_port(ApplicationType::BaseNode, network) + ); + debug!(target: LOG_TARGET, "Checking for local base node at {}", addr); - let mut node_conn = BaseNodeClient::connect(COMMON_BASE_NODE_GRPC_ADDRESS).await.ok()?; + let mut node_conn = match BaseNodeClient::connect(addr).await.ok() { + Some(conn) => conn, + None => { + debug!(target: LOG_TARGET, "No local base node detected"); + return None; + }, + }; let resp = node_conn.identify(Empty {}).await.ok()?; let identity = resp.get_ref(); let public_key = CommsPublicKey::from_bytes(&identity.public_key).ok()?; let address = Multiaddr::from_str(&identity.public_address).ok()?; + debug!( + target: LOG_TARGET, + "Local base node found with pk={} and addr={}", + public_key.to_hex(), + address + ); Some(SeedPeer::new(public_key, vec![address])) } diff --git a/applications/tari_console_wallet/src/main.rs b/applications/tari_console_wallet/src/main.rs index e8f0b4060c..cbeebbcf4c 100644 --- a/applications/tari_console_wallet/src/main.rs +++ b/applications/tari_console_wallet/src/main.rs @@ -38,7 +38,7 @@ use opentelemetry::{self, global, KeyValue}; use recovery::prompt_private_key_from_seed_words; use tari_app_utilities::consts; use tari_common::{ - configuration::bootstrap::ApplicationType, + configuration::bootstrap::{grpc_default_port, ApplicationType}, exit_codes::{ExitCode, ExitError}, initialize_logging, load_configuration, @@ -99,9 +99,10 @@ fn main_inner() -> Result<(), ExitError> { include_str!("../log4rs_sample.yml"), )?; - #[cfg_attr(not(all(unix, feature = "libtor")), allow(unused_mut))] let mut config = ApplicationConfig::load_from(&cfg)?; + setup_grpc_config(&mut config); + let runtime = tokio::runtime::Builder::new_multi_thread() .enable_all() .build() @@ -270,3 +271,16 @@ fn enable_tracing() { tracing::subscriber::set_global_default(subscriber) .expect("Tracing could not be set. Try running without `--tracing-enabled`"); } + +fn setup_grpc_config(config: &mut ApplicationConfig) { + if config.wallet.grpc_address.is_none() { + config.wallet.grpc_address = Some( + format!( + "/ip4/127.0.0.1/tcp/{}", + grpc_default_port(ApplicationType::ConsoleWallet, config.wallet.network) + ) + .parse() + .unwrap(), + ); + } +} diff --git a/applications/tari_console_wallet/src/wallet_modes.rs b/applications/tari_console_wallet/src/wallet_modes.rs index c410769f5f..f8afc8bbec 100644 --- a/applications/tari_console_wallet/src/wallet_modes.rs +++ b/applications/tari_console_wallet/src/wallet_modes.rs @@ -267,12 +267,10 @@ pub fn tui_mode( ) -> Result<(), ExitError> { let (events_broadcaster, _events_listener) = broadcast::channel(100); if config.grpc_enabled { - let grpc = WalletGrpcServer::new(wallet.clone()); - handle.spawn(run_grpc( - grpc, - config.grpc_address.clone(), - config.grpc_authentication.clone(), - )); + if let Some(address) = config.grpc_address.clone() { + let grpc = WalletGrpcServer::new(wallet.clone()); + handle.spawn(run_grpc(grpc, address, config.grpc_authentication.clone())); + } } let notifier = Notifier::new( @@ -369,11 +367,11 @@ pub fn recovery_mode( pub fn grpc_mode(handle: Handle, config: &WalletConfig, wallet: WalletSqlite) -> Result<(), ExitError> { info!(target: LOG_TARGET, "Starting grpc server"); - if config.grpc_enabled { + if let Some(address) = config.grpc_address.as_ref().filter(|_| config.grpc_enabled).cloned() { let grpc = WalletGrpcServer::new(wallet); let auth = config.grpc_authentication.clone(); handle - .block_on(run_grpc(grpc, config.grpc_address.clone(), auth)) + .block_on(run_grpc(grpc, address, auth)) .map_err(|e| ExitError::new(ExitCode::GrpcError, e))?; } else { println!("GRPC server is disabled"); @@ -429,7 +427,13 @@ mod test { burn-tari --message Ups_these_funds_will_be_burned! 100T - create-key-combo pie + create-key-pair pie + + create-aggregate-signature-utxo 125T 100 10 1 ff \ + --public-keys=5c4f2a4b3f3f84e047333218a84fd24f581a9d7e4f23b78e3714e9d174427d61 \ + --public-keys=f6b2ca781342a3ebe30ee1643655c96f1d7c14f4d49f077695395de98ae73665 + + sign-message 5c4f2a4b3f3f84e047333218a84fd24f581a9d7e4f23b78e3714e9d174427d61 my_challenge! coin-split --message Make_many_dust_UTXOs! --fee-per-gram 2 0.001T 499 @@ -446,7 +450,10 @@ mod test { let mut get_balance = false; let mut send_tari = false; let mut burn_tari = false; - let mut create_key_combo = false; + let mut create_key_pair = false; + let mut create_aggregate_signature_utxo = false; + let mut sign_message = false; + let mut encumbered_aggregate_utxo = false; let mut make_it_rain = false; let mut coin_split = false; let mut discover_peer = false; @@ -456,7 +463,10 @@ mod test { CliCommands::GetBalance => get_balance = true, CliCommands::SendTari(_) => send_tari = true, CliCommands::BurnTari(_) => burn_tari = true, - CliCommands::CreateKeyCombo(_) => create_key_combo = true, + CliCommands::CreateKeyPair(_) => create_key_pair = true, + CliCommands::CreateAggregateSignatureUtxo(_) => create_aggregate_signature_utxo = true, + CliCommands::SignMessage(_) => sign_message = true, + CliCommands::EncumberAggregateUtxo(_) => encumbered_aggregate_utxo = true, CliCommands::SendOneSided(_) => {}, CliCommands::SendOneSidedToStealthAddress(_) => {}, CliCommands::MakeItRain(_) => make_it_rain = true, @@ -480,7 +490,9 @@ mod test { get_balance && send_tari && burn_tari && - create_key_combo && + create_key_pair && + create_aggregate_signature_utxo && + sign_message && make_it_rain && coin_split && discover_peer && diff --git a/applications/tari_merge_mining_proxy/Cargo.toml b/applications/tari_merge_mining_proxy/Cargo.toml index e3c3e307eb..d0bac48767 100644 --- a/applications/tari_merge_mining_proxy/Cargo.toml +++ b/applications/tari_merge_mining_proxy/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "The Tari merge mining proxy for xmrig" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [features] @@ -15,8 +15,8 @@ tari_common = { path = "../../common" } tari_comms = { path = "../../comms/core" } tari_core = { path = "../../base_layer/core", default-features = false, features = ["transactions"] } tari_app_utilities = { path = "../tari_app_utilities" } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } tari_base_node_grpc_client = {path="../../clients/rust/base_node_grpc_client" } tari_wallet_grpc_client = {path="../../clients/rust/wallet_grpc_client" } @@ -33,7 +33,7 @@ hex = "0.4.2" hyper = "0.14.12" jsonrpc = "0.12.0" log = { version = "0.4.8", features = ["std"] } -rand = "0.8" +rand = "0.7.3" reqwest = { version = "0.11.4", features = ["json"] } serde = { version = "1.0.106", features = ["derive"] } serde_json = "1.0.57" diff --git a/applications/tari_miner/Cargo.toml b/applications/tari_miner/Cargo.toml index 4512306889..f63f4f7291 100644 --- a/applications/tari_miner/Cargo.toml +++ b/applications/tari_miner/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "The tari miner implementation" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [dependencies] @@ -14,8 +14,8 @@ tari_common_types = { path = "../../base_layer/common_types" } tari_comms = { path = "../../comms/core" } tari_app_utilities = { path = "../tari_app_utilities" } tari_app_grpc = { path = "../tari_app_grpc" } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } crossterm = { version = "0.17" } clap = { version = "3.1.1", features = ["derive"] } @@ -24,7 +24,7 @@ futures = "0.3" log = { version = "0.4", features = ["std"] } num_cpus = "1.13" prost-types = "0.9" -rand = "0.8" +rand = "0.7.3" sha3 = "0.9" serde = { version = "1.0", default_features = false, features = ["derive"] } tonic = { version = "0.6.2", features = ["transport"] } diff --git a/base_layer/common_types/Cargo.toml b/base_layer/common_types/Cargo.toml index b16b97d684..e22cf81ef7 100644 --- a/base_layer/common_types/Cargo.toml +++ b/base_layer/common_types/Cargo.toml @@ -3,17 +3,17 @@ name = "tari_common_types" authors = ["The Tari Development Community"] description = "Tari cryptocurrency common types" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [dependencies] -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } base64 = "0.13.0" digest = "0.9.0" lazy_static = "1.4.0" -rand = "0.8" +rand = "0.7.3" serde = { version = "1.0.106", features = ["derive"] } thiserror = "1.0.29" tokio = { version = "1.20", features = ["time", "sync"] } diff --git a/base_layer/core/Cargo.toml b/base_layer/core/Cargo.toml index e81b617a58..863f6e0513 100644 --- a/base_layer/core/Cargo.toml +++ b/base_layer/core/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [features] @@ -24,7 +24,7 @@ tari_common_types = { version = "^0.38", path = "../../base_layer/common_types" tari_comms = { version = "^0.38", path = "../../comms/core" } tari_comms_dht = { version = "^0.38", path = "../../comms/dht" } tari_comms_rpc_macros = { version = "^0.38", path = "../../comms/rpc_macros" } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } tari_metrics = { path = "../../infrastructure/metrics" } tari_mmr = { version = "^0.38", path = "../../base_layer/mmr", optional = true, features = ["native_bitmap"] } tari_p2p = { version = "^0.38", path = "../../base_layer/p2p" } @@ -33,7 +33,7 @@ tari_service_framework = { version = "^0.38", path = "../service_framework" } tari_shutdown = { version = "^0.38", path = "../../infrastructure/shutdown" } tari_storage = { version = "^0.38", path = "../../infrastructure/storage" } tari_test_utils = { version = "^0.38", path = "../../infrastructure/test_utils" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } async-trait = "0.1.50" bincode = "1.1.4" @@ -62,7 +62,7 @@ num-format = "0.4.0" once_cell = "1.8.0" prost = "0.9" prost-types = "0.9" -rand = "0.8" +rand = "0.7.3" randomx-rs = { git = "https://github.com/tari-project/randomx-rs", tag = "v1.1.13", optional = true } serde = { version = "1.0.106", features = ["derive"] } serde_json = "1.0" diff --git a/base_layer/core/src/chain_storage/blockchain_database.rs b/base_layer/core/src/chain_storage/blockchain_database.rs index 2b7d4c5da8..d73cc0795c 100644 --- a/base_layer/core/src/chain_storage/blockchain_database.rs +++ b/base_layer/core/src/chain_storage/blockchain_database.rs @@ -1647,18 +1647,12 @@ fn check_for_valid_height(db: &T, height: u64) -> Result<( /// Removes blocks from the db from current tip to specified height. /// Returns the blocks removed, ordered from tip to height. -fn rewind_to_height( - db: &mut T, - mut height: u64, -) -> Result>, ChainStorageError> { +fn rewind_to_height(db: &mut T, height: u64) -> Result>, ChainStorageError> { let last_header = db.fetch_last_header()?; - let mut txn = DbTransaction::new(); - // Delete headers let last_header_height = last_header.height; let metadata = db.fetch_chain_metadata()?; - let expected_block_hash = *metadata.best_block(); let last_block_height = metadata.height_of_longest_chain(); // We use the cmp::max value here because we'll only delete headers here and leave remaining headers to be deleted // with the whole block @@ -1681,20 +1675,20 @@ fn rewind_to_height( ); } // We might have more headers than blocks, so we first see if we need to delete the extra headers. - (0..steps_back).for_each(|h| { + for h in 0..steps_back { + let mut txn = DbTransaction::new(); info!( target: LOG_TARGET, "Rewinding headers at height {}", last_header_height - h ); txn.delete_header(last_header_height - h); - }); - + db.write(txn)?; + } // Delete blocks let mut steps_back = last_block_height.saturating_sub(height); // No blocks to remove, no need to update the best block if steps_back == 0 { - db.write(txn)?; return Ok(vec![]); } @@ -1715,22 +1709,45 @@ fn rewind_to_height( effective_pruning_horizon ); steps_back = effective_pruning_horizon; - height = 0; } - for h in 0..steps_back { + let mut txn = DbTransaction::new(); info!(target: LOG_TARGET, "Deleting block {}", last_block_height - h,); let block = fetch_block(db, last_block_height - h, false)?; let block = Arc::new(block.try_into_chain_block()?); txn.delete_block(*block.hash()); txn.delete_header(last_block_height - h); if !prune_past_horizon && !db.contains(&DbKey::OrphanBlock(*block.hash()))? { - // Because we know we will remove blocks we can't recover, this will be a destructive rewind, so we can't - // recover from this apart from resync from another peer. Failure here should not be common as - // this chain has a valid proof of work that has been tested at this point in time. + // Because we know we will remove blocks we can't recover, this will be a destructive rewind, so we + // can't recover from this apart from resync from another peer. Failure here + // should not be common as this chain has a valid proof of work that has been + // tested at this point in time. txn.insert_chained_orphan(block.clone()); } removed_blocks.push(block); + // Set best block to one before, to keep DB consistent. Or if we reached pruned horizon, set best block to 0. + let chain_header = db.fetch_chain_header_by_height(if prune_past_horizon && h + 1 == steps_back { + 0 + } else { + last_block_height - h - 1 + })?; + let metadata = db.fetch_chain_metadata()?; + let expected_block_hash = *metadata.best_block(); + txn.set_best_block( + chain_header.height(), + chain_header.accumulated_data().hash, + chain_header.accumulated_data().total_accumulated_difficulty, + expected_block_hash, + chain_header.timestamp(), + ); + // Update metadata + debug!( + target: LOG_TARGET, + "Updating best block to height (#{}), total accumulated difficulty: {}", + chain_header.height(), + chain_header.accumulated_data().total_accumulated_difficulty + ); + db.write(txn)?; } if prune_past_horizon { @@ -1739,6 +1756,7 @@ fn rewind_to_height( // We don't have these complete blocks, so we don't push them to the channel for further processing such as the // mempool add reorg'ed tx. for h in 0..(last_block_height - steps_back) { + let mut txn = DbTransaction::new(); debug!( target: LOG_TARGET, "Deleting blocks and utxos {}", @@ -1746,27 +1764,10 @@ fn rewind_to_height( ); let header = fetch_header(db, last_block_height - h - steps_back)?; txn.delete_block(header.hash()); + db.write(txn)?; } } - let chain_header = db.fetch_chain_header_by_height(height)?; - // Update metadata - debug!( - target: LOG_TARGET, - "Updating best block to height (#{}), total accumulated difficulty: {}", - chain_header.height(), - chain_header.accumulated_data().total_accumulated_difficulty - ); - - txn.set_best_block( - chain_header.height(), - chain_header.accumulated_data().hash, - chain_header.accumulated_data().total_accumulated_difficulty, - expected_block_hash, - chain_header.timestamp(), - ); - db.write(txn)?; - Ok(removed_blocks) } diff --git a/base_layer/core/src/consensus/emission.rs b/base_layer/core/src/consensus/emission.rs index 710a02922d..9fc2ecae95 100644 --- a/base_layer/core/src/consensus/emission.rs +++ b/base_layer/core/src/consensus/emission.rs @@ -48,7 +48,7 @@ impl EmissionSchedule { /// a constant tail emission rate. /// /// The block reward is given by - /// $$ r_n = r_{n-1} * (1 - \epsilon) + t, n > 0 $$ + /// $$ r_n = \mathrm{MAX}(\mathrm(intfloor(r_{n-1} * (1 - \epsilon)), t) n > 0 $$ /// $$ r_0 = A_0 $$ /// /// where @@ -56,11 +56,42 @@ impl EmissionSchedule { /// * $$1 - \epsilon$$ is the decay rate /// * $$t$$ is the constant tail emission rate /// - /// The decay in this constructor is calculated as follows: - /// $$ \epsilon = \sum 2^{-k} \foreach k \in decay $$ + /// The `intfloor` function is an integer-math-based multiplication of an integer by a fraction that's very close + /// to one (e.g. 0.998,987,123,432)` that + /// 1. provides the same result regardless of the CPU architecture (e.g. x86, ARM, etc.) + /// 2. Has minimal rounding error given the very high precision of the decay factor. /// - /// So for example, if the decay rate is 0.25, then $$\epsilon$$ is 0.75 or 1/2 + 1/4 i.e. `1 >> 1 + 1 >> 2` - /// and the decay array is `&[1, 2]`. + /// Firstly, the decay factor is represented in an array of its binary coefficients. In the same way that 65.4 in + /// decimal can be represented as `6 x 10 + 5 x 1 + 4 x 0.1`, we can write 0.75 in binary as `2^(-1) + 2^(-2)`. + /// The decay function is always less than one, so we dispense with signs and just represent the array as the set + /// of negative powers of 2 that most closely represent the decay factor. + /// + /// We can then apply a very fast multiplication using bitwise operations. If the decay factor, ϵ, is represented + /// in the array `**k**` then + /// ```ignore + /// intfloor(x, (1 - ϵ)) = x - sum(x >> k_i) + /// ``` + /// + /// Now, why use (1 - ϵ), and not the decay rate, `f` directly? + /// + /// The reason is to reduce rounding error. Every SHR operation is a "round down" operation. E.g. `7 >> 2` is 1, + /// whereas 7 / 4 = 1.75. So, we lose 0.75 there due to rounding. In general, the maximum error due to rounding + /// when doing integer division, `a / b` is `a % b`, which has a maximum of `b-1`. In binary terms, the maximum + /// error of the operation ` a >> b` is `2^-(b+1)`. + /// + /// Now compare the operation `x.f` where `f ~ 1` vs. `x.(1 - ϵ) = x - x.ϵ`, where `ϵ ~ 0`. + /// In both cases, the maximum error is $$ \sum_i 2^{k_i} = 1 - 2^{-(n+1)} $$ + /// + /// Since `f` is close to one, `k` is something like 0.9989013671875, or `[1,2,3,4,5,6,7,8,9,11,12,13]`, with a + /// maximum error of 0.49945 μT per block. Too high. + /// + /// However, using the ϵ representation (1 - `f`) is `[10,14,15,...,64]`, which has a maximum error of + /// 0.0005493 μT per block, which is more than accurate enough for our purposes (1 μT difference over 2,000 + /// blocks). + /// + /// **Note:** The word "error" has been used here, since this is technically what it is compared to an infinite + /// precision floating point operation. However, to be clear, the results given by `intfloor` are, by + /// **definition**, the correct and official emission values. /// /// ## Panics /// @@ -78,10 +109,12 @@ impl EmissionSchedule { /// is provided as a convenience and for the record, but is kept as a separate step. For performance reasons the /// parameters are 'hard-coded' as a static array rather than a heap allocation. /// + /// See [`EmissionSchedule::new`] for more details on how the parameters are derived. + /// /// Input : `k`: A string representing a floating point number of (nearly) arbitrary precision, and less than one. /// - /// Returns: An array of powers of negative two when when applied as a shift right and sum operation is equal to - /// (1-k)*n (to 1/2^64 precision). + /// Returns: An array of powers of negative two when when applied as a shift right and sum operation is very + /// close to (1-k)*n. /// /// None - If k is not a valid floating point number less than one. pub fn decay_params(k: &str) -> Option> { diff --git a/base_layer/core/src/iterators/chunk.rs b/base_layer/core/src/iterators/chunk.rs index 9d31477995..50cc3c3627 100644 --- a/base_layer/core/src/iterators/chunk.rs +++ b/base_layer/core/src/iterators/chunk.rs @@ -286,7 +286,7 @@ mod test { #[test] fn iterator_symmetry() { - let size = OsRng.gen_range(3usize..=10); + let size = OsRng.gen_range(3usize, 10 + 1); let rand_start = OsRng.gen::(); let rand_end = OsRng.gen::().saturating_add(rand_start); diff --git a/base_layer/core/src/transactions/transaction_components/transaction_output.rs b/base_layer/core/src/transactions/transaction_components/transaction_output.rs index ca75c3ba42..34efcf7282 100644 --- a/base_layer/core/src/transactions/transaction_components/transaction_output.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_output.rs @@ -298,8 +298,7 @@ impl TransactionOutput { } // Create commitment signature for the metadata - - fn create_metadata_signature( + pub fn create_metadata_signature( version: TransactionOutputVersion, value: MicroTari, spending_key: &BlindingFactor, diff --git a/base_layer/core/src/transactions/transaction_components/unblinded_output.rs b/base_layer/core/src/transactions/transaction_components/unblinded_output.rs index 132d143cb2..72186d2a78 100644 --- a/base_layer/core/src/transactions/transaction_components/unblinded_output.rs +++ b/base_layer/core/src/transactions/transaction_components/unblinded_output.rs @@ -201,6 +201,53 @@ impl UnblindedOutput { )) } + /// it creates a transaction input given a partial script signature. The public keys + /// partial_script_public_key and partial_total_nonce exclude callers private keys use + pub fn as_transaction_input_with_partial_signature( + &self, + factory: &CommitmentFactory, + partial_script_public_key: PublicKey, + partial_total_nonce: PublicKey, + ) -> Result { + let commitment = factory.commit(&self.spending_key, &self.value.into()); + let script_nonce_a = PrivateKey::random(&mut OsRng); + let script_nonce_b = PrivateKey::random(&mut OsRng); + let nonce_commitment = factory.commit(&script_nonce_b, &script_nonce_a); + + let challenge = TransactionInput::build_script_challenge( + TransactionInputVersion::get_current_version(), + &(&nonce_commitment + &partial_total_nonce), + &self.script, + &self.input_data, + &(&PublicKey::from_secret_key(&self.script_private_key) + &partial_script_public_key), + &commitment, + ); + let script_signature = ComSignature::sign( + &self.value.into(), + &(&self.script_private_key + &self.spending_key), + &script_nonce_a, + &script_nonce_b, + &challenge, + factory, + ) + .map_err(|_| TransactionError::InvalidSignatureError("Generating script signature".to_string()))?; + + Ok(TransactionInput::new_current_version( + SpentOutput::OutputData { + features: self.features.clone(), + commitment, + script: self.script.clone(), + sender_offset_public_key: self.sender_offset_public_key.clone(), + covenant: self.covenant.clone(), + version: self.version, + encrypted_value: self.encrypted_value.clone(), + minimum_value_promise: self.minimum_value_promise, + }, + self.input_data.clone(), + script_signature, + )) + } + /// Commits an UnblindedOutput into a TransactionInput that only contains the hash of the spent output data pub fn as_compact_transaction_input( &self, diff --git a/base_layer/key_manager/Cargo.toml b/base_layer/key_manager/Cargo.toml index 0db8a96d52..75d69a695f 100644 --- a/base_layer/key_manager/Cargo.toml +++ b/base_layer/key_manager/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet key management" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2021" [lib] @@ -13,8 +13,8 @@ crate-type = ["lib", "cdylib"] # NB: All dependencies must support or be gated for the WASM target. [dependencies] tari_common_types = { version = "^0.38", path = "../../base_layer/common_types", optional = true } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } arrayvec = "0.7.1" argon2 = { version = "0.2", features = ["std"] } @@ -27,7 +27,7 @@ derivative = "2.2.0" digest = "0.9.0" getrandom = { version = "0.2.3", optional = true } js-sys = { version = "0.3.55", optional = true } -rand = "0.8" +rand = "0.7.3" serde = "1.0.89" serde_derive = "1.0.89" serde_json = "1.0.39" diff --git a/base_layer/mmr/Cargo.toml b/base_layer/mmr/Cargo.toml index 279fd31e95..5774c5b1ea 100644 --- a/base_layer/mmr/Cargo.toml +++ b/base_layer/mmr/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "A Merkle Mountain Range implementation" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [features] @@ -13,8 +13,8 @@ native_bitmap = ["croaring"] benches = ["criterion"] [dependencies] -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } tari_common = {path = "../../common"} thiserror = "1.0.26" digest = "0.9.0" @@ -26,7 +26,6 @@ criterion = { version="0.2", optional = true } [dev-dependencies] rand="0.8.0" blake2 = "0.9.0" -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } serde_json = "1.0" bincode = "1.1" [lib] diff --git a/base_layer/p2p/Cargo.toml b/base_layer/p2p/Cargo.toml index 1b1ed8425e..665991d18a 100644 --- a/base_layer/p2p/Cargo.toml +++ b/base_layer/p2p/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_p2p" -version = "0.38.4" +version = "0.38.5" authors = ["The Tari Development community"] description = "Tari base layer-specific peer-to-peer communication features" repository = "https://github.com/tari-project/tari" @@ -13,11 +13,11 @@ edition = "2018" tari_comms = { version = "^0.38", path = "../../comms/core" } tari_comms_dht = { version = "^0.38", path = "../../comms/dht" } tari_common = { version = "^0.38", path = "../../common" } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } tari_service_framework = { version = "^0.38", path = "../service_framework" } tari_shutdown = { version = "^0.38", path = "../../infrastructure/shutdown" } tari_storage = { version = "^0.38", path = "../../infrastructure/storage" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } anyhow = "1.0.53" bytes = "0.5" @@ -26,9 +26,9 @@ fs2 = "0.4.0" futures = { version = "^0.3.1" } lmdb-zero = "0.4.4" log = "0.4.6" -pgp = { version = "0.8.0", optional = true } +pgp = { version = "0.7.2", optional = true } prost = "=0.9.0" -rand = "0.8" +rand = "0.7.3" reqwest = { version = "0.11", optional = true, default-features = false } rustls = "0.20.2" semver = { version = "1.0.1", optional = true } diff --git a/base_layer/p2p/examples/gen_node_identity.rs b/base_layer/p2p/examples/gen_node_identity.rs index 89ba2912fc..bd4ff37bed 100644 --- a/base_layer/p2p/examples/gen_node_identity.rs +++ b/base_layer/p2p/examples/gen_node_identity.rs @@ -40,7 +40,7 @@ use tari_comms::{ use tari_utilities::message_format::MessageFormat; fn random_address() -> Multiaddr { - let port = OsRng.gen_range(9000..std::u16::MAX); + let port = OsRng.gen_range(9000, std::u16::MAX); let socket_addr: SocketAddr = (Ipv4Addr::LOCALHOST, port).into(); socketaddr_to_multiaddr(&socket_addr) } diff --git a/base_layer/service_framework/Cargo.toml b/base_layer/service_framework/Cargo.toml index 825bbcd0e0..f70eb71d7a 100644 --- a/base_layer/service_framework/Cargo.toml +++ b/base_layer/service_framework/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_service_framework" -version = "0.38.4" +version = "0.38.5" authors = ["The Tari Development Community"] description = "The Tari communication stack service framework" repository = "https://github.com/tari-project/tari" diff --git a/base_layer/tari_mining_helper_ffi/Cargo.toml b/base_layer/tari_mining_helper_ffi/Cargo.toml index dcc33fe618..53072f6487 100644 --- a/base_layer/tari_mining_helper_ffi/Cargo.toml +++ b/base_layer/tari_mining_helper_ffi/Cargo.toml @@ -3,15 +3,15 @@ name = "tari_mining_helper_ffi" authors = ["The Tari Development Community"] description = "Tari cryptocurrency miningcore C FFI bindings" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [dependencies] tari_comms = { version = "^0.38", path = "../../comms/core" } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } tari_common = { path = "../../common" } tari_core = { path = "../core", default-features = false, features = ["transactions"]} -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } libc = "0.2.65" thiserror = "1.0.26" hex = "0.4.2" @@ -21,7 +21,7 @@ serde_json = "1.0.57" [dev-dependencies] tari_core = { path = "../core", features = ["transactions", "base_node"]} -rand = "0.8.1" +rand = "0.7.3" [lib] crate-type = ["staticlib","cdylib"] diff --git a/base_layer/wallet/Cargo.toml b/base_layer/wallet/Cargo.toml index b4ede8ba67..cf62400004 100644 --- a/base_layer/wallet/Cargo.toml +++ b/base_layer/wallet/Cargo.toml @@ -3,7 +3,7 @@ name = "tari_wallet" authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet library" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [dependencies] @@ -11,7 +11,7 @@ tari_common = { path = "../../common" } tari_common_types = { version = "^0.38", path = "../../base_layer/common_types" } tari_comms = { version = "^0.38", path = "../../comms/core" } tari_comms_dht = { version = "^0.38", path = "../../comms/dht" } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } tari_key_manager = { version = "^0.38", path = "../key_manager" } tari_p2p = { version = "^0.38", path = "../p2p", features = ["auto-update"] } tari_script = { path = "../../infrastructure/tari_script" } @@ -19,7 +19,7 @@ tari_service_framework = { version = "^0.38", path = "../service_framework" } tari_shutdown = { version = "^0.38", path = "../../infrastructure/shutdown" } tari_storage = { version = "^0.38", path = "../../infrastructure/storage" } tari_common_sqlite = { path = "../../common_sqlite" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } # Uncomment for tokio tracing via tokio-console (needs "tracing" featurs) #console-subscriber = "0.1.3" @@ -44,7 +44,7 @@ libsqlite3-sys = { version = "0.22.2", features = ["bundled"], optional = true } lmdb-zero = "0.4.4" log = "0.4.6" log4rs = { version = "1.0.0", features = ["console_appender", "file_appender", "yaml_format"] } -rand = "0.8" +rand = "0.7.3" serde = { version = "1.0.89", features = ["derive"] } serde_json = "1.0.39" strum = "0.22" @@ -54,7 +54,7 @@ thiserror = "1.0.26" tower = "0.4" prost = "0.9" itertools = "0.10.3" -chacha20poly1305 = "0.10.1" +chacha20poly1305 = "0.9.1" [dependencies.tari_core] path = "../../base_layer/core" diff --git a/base_layer/wallet/src/config.rs b/base_layer/wallet/src/config.rs index 6d0997fa6e..ca5a472efe 100644 --- a/base_layer/wallet/src/config.rs +++ b/base_layer/wallet/src/config.rs @@ -99,7 +99,7 @@ pub struct WalletConfig { /// If true, a GRPC server will bind to the configured address and listen for incoming GRPC requests. pub grpc_enabled: bool, /// GRPC bind address of the wallet - pub grpc_address: Multiaddr, + pub grpc_address: Option, /// GRPC authentication mode pub grpc_authentication: GrpcAuthentication, /// A custom base node peer that will be used to obtain metadata from @@ -144,7 +144,7 @@ impl Default for WalletConfig { command_send_wait_timeout: Duration::from_secs(300), notify_file: None, grpc_enabled: false, - grpc_address: "/ip4/127.0.0.1/tcp/18143".parse().unwrap(), + grpc_address: None, grpc_authentication: GrpcAuthentication::default(), custom_base_node: None, base_node_service_peers: StringList::default(), diff --git a/base_layer/wallet/src/key_manager_service/handle.rs b/base_layer/wallet/src/key_manager_service/handle.rs index 2a6e8d237a..d53be0e37b 100644 --- a/base_layer/wallet/src/key_manager_service/handle.rs +++ b/base_layer/wallet/src/key_manager_service/handle.rs @@ -73,16 +73,20 @@ where TBackend: KeyManagerBackend + 'static (*self.key_manager_inner).write().await.apply_encryption(cipher) } - async fn create_key_combo(&self, key_seed: String) -> Result<(PrivateKey, PublicKey), KeyManagerServiceError> { - (*self.key_manager_inner) + async fn create_key_pair + Send>( + &self, + branch: T, + ) -> Result<(PrivateKey, PublicKey), KeyManagerServiceError> { + let branch: String = branch.into(); + + self.key_manager_inner .write() .await - .add_key_manager_branch(key_seed.clone())?; + .add_key_manager_branch(branch.clone())?; - let next_key = self.get_next_key(key_seed).await?; + let next_key = self.get_next_key(branch).await?; let sk = next_key.key.clone(); let pk = next_key.to_public_key(); - // (*self.key_manager_inner).read().await.get_next_key(branch).await; Ok((sk, pk)) } diff --git a/base_layer/wallet/src/key_manager_service/interface.rs b/base_layer/wallet/src/key_manager_service/interface.rs index 9719c7b882..fed1c2d680 100644 --- a/base_layer/wallet/src/key_manager_service/interface.rs +++ b/base_layer/wallet/src/key_manager_service/interface.rs @@ -73,7 +73,10 @@ pub trait KeyManagerInterface: Clone + Send + Sync + 'static { ) -> Result; /// Gets new key combo pair out of a key seed - async fn create_key_combo(&self, key_seed: String) -> Result<(PrivateKey, PublicKey), KeyManagerServiceError>; + async fn create_key_pair + Send>( + &self, + branch: T, + ) -> Result<(PrivateKey, PublicKey), KeyManagerServiceError>; /// Searches the branch to find the index used to generated the key, O(N) where N = index used. async fn find_key_index + Send>( diff --git a/base_layer/wallet/src/key_manager_service/mock.rs b/base_layer/wallet/src/key_manager_service/mock.rs index dde4ae1db3..c1f737126d 100644 --- a/base_layer/wallet/src/key_manager_service/mock.rs +++ b/base_layer/wallet/src/key_manager_service/mock.rs @@ -162,7 +162,10 @@ impl KeyManagerInterface for KeyManagerMock { unimplemented!("Not supported"); } - async fn create_key_combo(&self, _key_seed: String) -> Result<(PrivateKey, PublicKey), KeyManagerServiceError> { + async fn create_key_pair + Send>( + &self, + _branch: T, + ) -> Result<(PrivateKey, PublicKey), KeyManagerServiceError> { unimplemented!("Not supported"); } diff --git a/base_layer/wallet/src/output_manager_service/handle.rs b/base_layer/wallet/src/output_manager_service/handle.rs index d881deb656..1977bff63c 100644 --- a/base_layer/wallet/src/output_manager_service/handle.rs +++ b/base_layer/wallet/src/output_manager_service/handle.rs @@ -25,7 +25,7 @@ use std::{fmt, fmt::Formatter, sync::Arc}; use chacha20poly1305::XChaCha20Poly1305; use tari_common_types::{ transaction::TxId, - types::{Commitment, HashOutput, PublicKey}, + types::{Commitment, HashOutput, PublicKey, Signature}, }; use tari_core::{ covenants::Covenant, @@ -75,6 +75,17 @@ pub enum OutputManagerRequest { GetRecipientTransaction(TransactionSenderMessage), GetCoinbaseTransaction((TxId, MicroTari, MicroTari, u64)), ConfirmPendingTransaction(TxId), + EncumberAggregateUtxo { + tx_id: TxId, + fee_per_gram: MicroTari, + output_hash: String, + signatures: Vec, + total_script_pubkey: PublicKey, + total_offset_pubkey: PublicKey, + total_signature_nonce: PublicKey, + metadata_signature_nonce: PublicKey, + wallet_script_secret_key: String, + }, PrepareToSendTransaction { tx_id: TxId, amount: MicroTari, @@ -142,6 +153,7 @@ pub enum OutputManagerRequest { } impl fmt::Display for OutputManagerRequest { + #[allow(clippy::too_many_lines)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[allow(clippy::enum_glob_use)] use OutputManagerRequest::*; @@ -162,6 +174,11 @@ impl fmt::Display for OutputManagerRequest { v.metadata_signature.u().to_hex(), v.metadata_signature.v().to_hex() ), + EncumberAggregateUtxo { tx_id, output_hash, .. } => write!( + f, + "Encumber aggregate utxo with tx_id: {} and output_hash: {}", + tx_id, output_hash + ), GetRecipientTransaction(_) => write!(f, "GetRecipientTransaction"), ConfirmPendingTransaction(v) => write!(f, "ConfirmPendingTransaction ({})", v), PrepareToSendTransaction { message, .. } => write!(f, "PrepareToSendTransaction ({})", message), @@ -241,8 +258,10 @@ pub enum OutputManagerResponse { Balance(Balance), OutputAdded, ConvertedToTransactionOutput(Box), + ConvertedToTransaction(Box), OutputMetadataSignatureUpdated, RecipientTransactionGenerated(ReceiverTransactionProtocol), + EncumberAggregateUtxo(Transaction), CoinbaseTransaction(Transaction), OutputConfirmed, PendingTransactionConfirmed, @@ -850,6 +869,38 @@ impl OutputManagerHandle { } } + pub async fn encumber_aggregate_utxo( + &mut self, + tx_id: TxId, + fee_per_gram: MicroTari, + output_hash: String, + signatures: Vec, + total_script_pubkey: PublicKey, + total_offset_pubkey: PublicKey, + total_signature_nonce: PublicKey, + metadata_signature_nonce: PublicKey, + wallet_script_secret_key: String, + ) -> Result { + match self + .handle + .call(OutputManagerRequest::EncumberAggregateUtxo { + tx_id, + fee_per_gram, + output_hash, + signatures, + total_script_pubkey, + total_offset_pubkey, + total_signature_nonce, + metadata_signature_nonce, + wallet_script_secret_key, + }) + .await?? + { + OutputManagerResponse::EncumberAggregateUtxo(transaction) => Ok(transaction), + _ => Err(OutputManagerError::UnexpectedApiResponse), + } + } + pub async fn create_pay_to_self_transaction( &mut self, tx_id: TxId, diff --git a/base_layer/wallet/src/output_manager_service/service.rs b/base_layer/wallet/src/output_manager_service/service.rs index 711259652b..1fbf9d6013 100644 --- a/base_layer/wallet/src/output_manager_service/service.rs +++ b/base_layer/wallet/src/output_manager_service/service.rs @@ -30,7 +30,7 @@ use rand::{rngs::OsRng, RngCore}; use strum::IntoEnumIterator; use tari_common_types::{ transaction::TxId, - types::{BlockHash, Commitment, HashOutput, PrivateKey, PublicKey}, + types::{BlockHash, Commitment, FixedHash, HashOutput, PrivateKey, PublicKey, Signature}, }; use tari_comms::{types::CommsPublicKey, NodeIdentity}; use tari_core::{ @@ -65,7 +65,7 @@ use tari_crypto::{ keys::{DiffieHellmanSharedSecret, PublicKey as PublicKeyTrait, SecretKey}, ristretto::RistrettoSecretKey, }; -use tari_script::{inputs, script, Opcode, TariScript}; +use tari_script::{inputs, script, Opcode, StackItem, TariScript}; use tari_service_framework::reply_channel; use tari_shutdown::ShutdownSignal; use tari_utilities::{hex::Hex, ByteArray}; @@ -257,6 +257,34 @@ where transaction_output, ))) }, + OutputManagerRequest::EncumberAggregateUtxo { + tx_id, + fee_per_gram, + output_hash, + signatures, + total_script_pubkey, + total_offset_pubkey, + total_signature_nonce, + metadata_signature_nonce, + wallet_script_secret_key, + } => { + let transaction_output = self + .encumber_aggregate_utxo( + tx_id, + fee_per_gram, + output_hash, + signatures, + total_script_pubkey, + total_offset_pubkey, + total_signature_nonce, + metadata_signature_nonce, + wallet_script_secret_key, + ) + .await?; + Ok(OutputManagerResponse::ConvertedToTransaction(Box::new( + transaction_output, + ))) + }, OutputManagerRequest::AddUnvalidatedOutput((tx_id, uo, spend_priority)) => self .add_unvalidated_output(tx_id, *uo, spend_priority) .map(|_| OutputManagerResponse::OutputAdded), @@ -1231,6 +1259,145 @@ where Ok((tx_id, stp.take_transaction()?)) } + #[allow(clippy::too_many_lines)] + pub async fn encumber_aggregate_utxo( + &mut self, + tx_id: TxId, + fee_per_gram: MicroTari, + output_hash: String, + signatures: Vec, + total_script_pubkey: PublicKey, + total_offset_pubkey: PublicKey, + total_signature_nonce: PublicKey, + metadata_signature_nonce: PublicKey, + wallet_script_secret_key: String, + ) -> Result { + let script = script!(Nop); + let covenant = Covenant::default(); + let output_features = OutputFeatures::default(); + + let metadata_byte_size = self + .resources + .consensus_constants + .transaction_weight() + .round_up_metadata_size( + output_features.consensus_encode_exact_size() + + script.consensus_encode_exact_size() + + covenant.consensus_encode_exact_size(), + ); + + let output_hash = + FixedHash::from_hex(&output_hash).map_err(|e| OutputManagerError::ConversionError(e.to_string()))?; + let db_input = self.resources.db.get_unspent_output(output_hash)?; + let mut input: UnblindedOutput = db_input.clone().into(); + + for signature in &signatures { + input.input_data.push(StackItem::from(signature.clone()))?; + } + + let wallet_script_secret_key = PrivateKey::from_hex(&wallet_script_secret_key) + .map_err(|e| OutputManagerError::ConversionError(e.to_string()))?; + input.script_private_key = wallet_script_secret_key; + + let offset = PrivateKey::random(&mut OsRng); + let nonce = PrivateKey::random(&mut OsRng); + let sender_offset_private_key = PrivateKey::random(&mut OsRng); + + // Create builder with no recipients (other than ourselves) + let mut builder = SenderTransactionProtocol::builder(0, self.resources.consensus_constants.clone()); + builder + .with_fee_per_gram(fee_per_gram) + .with_offset(offset.clone()) + .with_private_nonce(nonce.clone()) + .with_rewindable_outputs(self.resources.rewind_data.clone()) + .with_prevent_fee_gt_amount(self.resources.config.prevent_fee_gt_amount) + .with_kernel_features(KernelFeatures::empty()) + .with_tx_id(tx_id) + .with_input( + input.clone().as_transaction_input_with_partial_signature( + &self.resources.factories.commitment, + total_script_pubkey, + total_signature_nonce, + )?, + input.clone(), + ); + + let fee = self.get_fee_calc(); + let fee = fee.calculate(fee_per_gram, 1, 1, 1, metadata_byte_size); + let amount = input.value - fee; + + let (spending_key, script_private_key) = self.get_spend_and_script_keys().await?; + let commitment = self + .resources + .factories + .commitment + .commit_value(&spending_key, amount.into()); + let encrypted_value = + EncryptedValue::encrypt_value(&self.resources.rewind_data.encryption_key, &commitment, amount)?; + let minimum_amount_promise = MicroTari::zero(); + let metadata_signature = TransactionOutput::create_metadata_signature( + TransactionOutputVersion::get_current_version(), + amount, + &spending_key, + &script, + &output_features, + &(&total_offset_pubkey + &PublicKey::from_secret_key(&sender_offset_private_key)), + Some(&metadata_signature_nonce), + Some(&sender_offset_private_key), + &covenant, + &encrypted_value, + minimum_amount_promise, + )?; + let utxo = DbUnblindedOutput::rewindable_from_unblinded_output( + UnblindedOutput::new_current_version( + amount, + spending_key, + output_features, + script, + inputs!(PublicKey::from_secret_key(&script_private_key)), + script_private_key, + PublicKey::from_secret_key(&sender_offset_private_key), + metadata_signature, + 0, + covenant, + encrypted_value, + minimum_amount_promise, + ), + &self.resources.factories, + &self.resources.rewind_data, + None, + None, + OutputSource::default(), + )?; + builder + .with_output(utxo.unblinded_output.clone(), sender_offset_private_key.clone()) + .map_err(|e| OutputManagerError::BuildError(e.message))?; + + let factories = CryptoFactories::default(); + let mut stp = builder + .build( + &self.resources.factories, + None, + self.last_seen_tip_height.unwrap_or(u64::MAX), + ) + .map_err(|e| OutputManagerError::BuildError(e.message))?; + + trace!( + target: LOG_TARGET, + "Encumber send to self transaction ({}) outputs.", + tx_id + ); + self.resources.db.encumber_outputs(tx_id, vec![db_input], vec![utxo])?; + self.confirm_encumberance(tx_id)?; + + trace!(target: LOG_TARGET, "Finalize send-to-self transaction ({}).", tx_id); + + stp.finalize(&factories, None, self.last_seen_tip_height.unwrap_or(u64::MAX))?; + let tx = stp.take_transaction()?; + + Ok(tx) + } + #[allow(clippy::too_many_lines)] async fn create_pay_to_self_transaction( &mut self, diff --git a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs index c855c26bc4..0710212f94 100644 --- a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs +++ b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/mod.rs @@ -1455,7 +1455,7 @@ impl Encryptable for KnownOneSidedPaymentScriptSql { mod test { use std::{mem::size_of, time::Duration}; - use chacha20poly1305::{Key, KeyInit, XChaCha20Poly1305}; + use chacha20poly1305::{aead::NewAead, Key, XChaCha20Poly1305}; use diesel::{Connection, SqliteConnection}; use rand::{rngs::OsRng, RngCore}; use tari_common_sqlite::sqlite_connection_pool::SqliteConnectionPool; diff --git a/base_layer/wallet/src/storage/sqlite_db/wallet.rs b/base_layer/wallet/src/storage/sqlite_db/wallet.rs index 8c50660a19..ec95ddc820 100644 --- a/base_layer/wallet/src/storage/sqlite_db/wallet.rs +++ b/base_layer/wallet/src/storage/sqlite_db/wallet.rs @@ -31,7 +31,7 @@ use argon2::{ password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, Argon2, }; -use chacha20poly1305::{Key, KeyInit, Tag, XChaCha20Poly1305, XNonce}; +use chacha20poly1305::{aead::NewAead, Key, Tag, XChaCha20Poly1305, XNonce}; use diesel::{prelude::*, SqliteConnection}; use log::*; use tari_common_types::chain_metadata::ChainMetadata; diff --git a/base_layer/wallet/src/transaction_service/handle.rs b/base_layer/wallet/src/transaction_service/handle.rs index fda68fc370..9a6b53ee4e 100644 --- a/base_layer/wallet/src/transaction_service/handle.rs +++ b/base_layer/wallet/src/transaction_service/handle.rs @@ -31,7 +31,7 @@ use chacha20poly1305::XChaCha20Poly1305; use chrono::NaiveDateTime; use tari_common_types::{ transaction::{ImportStatus, TxId}, - types::PublicKey, + types::{Commitment, FixedHash, PublicKey, Signature}, }; use tari_comms::types::CommsPublicKey; use tari_core::{ @@ -88,6 +88,24 @@ pub enum TransactionServiceRequest { fee_per_gram: MicroTari, message: String, }, + CreateNMUtxo { + amount: MicroTari, + fee_per_gram: MicroTari, + n: u8, + m: u8, + public_keys: Vec, + message: [u8; 32], + }, + EncumberAggregateUtxo { + fee_per_gram: MicroTari, + output_hash: String, + signatures: Vec, + total_script_pubkey: PublicKey, + total_offset_pubkey: PublicKey, + total_signature_nonce: PublicKey, + metadata_signature_nonce: PublicKey, + wallet_script_secret_key: String, + }, SendOneSidedTransaction { dest_pubkey: CommsPublicKey, amount: MicroTari, @@ -135,6 +153,7 @@ pub enum TransactionServiceRequest { } impl fmt::Display for TransactionServiceRequest { + #[allow(clippy::too_many_lines)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::GetPendingInboundTransactions => f.write_str("GetPendingInboundTransactions"), @@ -156,6 +175,38 @@ impl fmt::Display for TransactionServiceRequest { message )), Self::BurnTari { amount, message, .. } => f.write_str(&format!("Burning Tari ({}, {})", amount, message)), + Self::CreateNMUtxo { + amount, + fee_per_gram: _, + n, + m, + public_keys: _, + message: _, + } => f.write_str(&format!( + "Creating a new n-of-m aggregate uxto with: amount = {}, n = {}, m = {}", + amount, n, m + )), + Self::EncumberAggregateUtxo { + fee_per_gram, + output_hash, + signatures, + total_script_pubkey, + total_offset_pubkey, + total_signature_nonce, + metadata_signature_nonce, + .. + } => f.write_str(&format!( + "Metadata signature utxto with: fee_per_gram = {}, output_hash = {}, signatures = {:?}, \ + total_script_pubkey = {}, total_offset_pubkey = {}, total_signature_nonce = {}, \ + metadata_signature_nonce = {}", + fee_per_gram, + output_hash, + signatures, + total_script_pubkey.to_hex(), + total_offset_pubkey.to_hex(), + total_signature_nonce.to_hex(), + metadata_signature_nonce.to_hex(), + )), Self::SendOneSidedTransaction { dest_pubkey, amount, @@ -228,6 +279,16 @@ impl fmt::Display for TransactionServiceRequest { #[derive(Debug)] pub enum TransactionServiceResponse { TransactionSent(TxId), + TransactionSentWithOutputHash(TxId, FixedHash), + TransactionSentWithEncumberAggregateUtxo( + TxId, + Box, + FixedHash, + Box, + String, + String, + Box, + ), TransactionCancelled, PendingInboundTransactions(HashMap), PendingOutboundTransactions(HashMap), @@ -504,6 +565,78 @@ impl TransactionServiceHandle { } } + pub async fn create_aggregate_signature_utxo( + &mut self, + amount: MicroTari, + fee_per_gram: MicroTari, + n: u8, + m: u8, + public_keys: Vec, + message: [u8; 32], + ) -> Result<(TxId, FixedHash), TransactionServiceError> { + match self + .handle + .call(TransactionServiceRequest::CreateNMUtxo { + amount, + fee_per_gram, + n, + m, + public_keys, + message, + }) + .await?? + { + TransactionServiceResponse::TransactionSentWithOutputHash(tx_id, output_hash) => Ok((tx_id, output_hash)), + _ => Err(TransactionServiceError::UnexpectedApiResponse), + } + } + + pub async fn encumber_aggregate_utxo( + &mut self, + fee_per_gram: MicroTari, + output_hash: String, + signatures: Vec, + total_script_pubkey: PublicKey, + total_offset_pubkey: PublicKey, + total_signature_nonce: PublicKey, + metadata_signature_nonce: PublicKey, + wallet_script_secret_key: String, + ) -> Result<(TxId, Commitment, FixedHash, Commitment, String, String, PublicKey), TransactionServiceError> { + match self + .handle + .call(TransactionServiceRequest::EncumberAggregateUtxo { + fee_per_gram, + output_hash, + signatures, + total_script_pubkey, + total_offset_pubkey, + total_signature_nonce, + metadata_signature_nonce, + wallet_script_secret_key, + }) + .await?? + { + TransactionServiceResponse::TransactionSentWithEncumberAggregateUtxo( + tx_id, + output_commitment, + output_hash, + input_commitment, + input_stack_hex, + input_script_hex, + total_public_offset, + ) => Ok(( + tx_id, + *output_commitment, + output_hash, + *input_commitment, + input_stack_hex, + input_script_hex, + *total_public_offset, + )), + _ => Err(TransactionServiceError::UnexpectedApiResponse), + } + } + pub async fn send_one_sided_to_stealth_address_transaction( &mut self, dest_pubkey: CommsPublicKey, diff --git a/base_layer/wallet/src/transaction_service/service.rs b/base_layer/wallet/src/transaction_service/service.rs index 33f484398b..5880c35864 100644 --- a/base_layer/wallet/src/transaction_service/service.rs +++ b/base_layer/wallet/src/transaction_service/service.rs @@ -35,7 +35,7 @@ use rand::rngs::OsRng; use sha2::Sha256; use tari_common_types::{ transaction::{ImportStatus, TransactionDirection, TransactionStatus, TxId}, - types::{PrivateKey, PublicKey}, + types::{Commitment, FixedHash, PrivateKey, PublicKey, Signature}, }; use tari_comms::{peer_manager::NodeIdentity, types::CommsPublicKey}; use tari_comms_dht::outbound::OutboundMessageRequester; @@ -70,9 +70,10 @@ use tari_crypto::{ tari_utilities::ByteArray, }; use tari_p2p::domain_message::DomainMessage; -use tari_script::{inputs, script, TariScript}; +use tari_script::{inputs, script, slice_to_boxed_message, TariScript}; use tari_service_framework::{reply_channel, reply_channel::Receiver}; use tari_shutdown::ShutdownSignal; +use tari_utilities::hex::Hex; use tokio::{ sync::{mpsc, mpsc::Sender, oneshot, Mutex}, task::JoinHandle, @@ -649,6 +650,47 @@ where ) .await .map(TransactionServiceResponse::TransactionSent), + TransactionServiceRequest::CreateNMUtxo { + amount, + fee_per_gram, + n, + m, + public_keys, + message, + } => self + .create_aggregate_signature_utxo( + amount, + fee_per_gram, + n, + m, + public_keys, + message, + transaction_broadcast_join_handles, + ) + .await + .map(|(tx_id, _)| TransactionServiceResponse::TransactionSent(tx_id)), + TransactionServiceRequest::EncumberAggregateUtxo { + fee_per_gram, + output_hash, + signatures, + total_script_pubkey, + total_offset_pubkey, + total_signature_nonce, + metadata_signature_nonce, + wallet_script_secret_key, + } => self + .encumber_aggregate_utxo( + fee_per_gram, + output_hash, + signatures, + total_script_pubkey, + total_offset_pubkey, + total_signature_nonce, + metadata_signature_nonce, + wallet_script_secret_key, + ) + .await + .map(|(tx_id, ..)| TransactionServiceResponse::TransactionSent(tx_id)), TransactionServiceRequest::SendShaAtomicSwapTransaction( dest_pubkey, amount, @@ -986,6 +1028,237 @@ where Ok(()) } + /// Creates a utxo with aggregate public key out of m-of-n public keys + #[allow(clippy::too_many_lines)] + pub async fn create_aggregate_signature_utxo( + &mut self, + amount: MicroTari, + fee_per_gram: MicroTari, + n: u8, + m: u8, + public_keys: Vec, + message: [u8; 32], + transaction_broadcast_join_handles: &mut FuturesUnordered< + JoinHandle>>, + >, + ) -> Result<(TxId, FixedHash), TransactionServiceError> { + let tx_id = TxId::new_random(); + + let msg = slice_to_boxed_message(message.as_bytes()); + let script = script!(CheckMultiSigVerifyAggregatePubKey(n, m, public_keys, msg)); + + // Empty covenant + let covenant = Covenant::default(); + + // Default range proof + let minimum_value_promise = MicroTari::zero(); + + // Prepare sender part of transaction + let mut stp = self + .output_manager_service + .prepare_transaction_to_send( + tx_id, + amount, + UtxoSelectionCriteria::default(), + OutputFeatures::default(), + fee_per_gram, + TransactionMetadata::default(), + "".to_string(), + script.clone(), + covenant, + minimum_value_promise, + ) + .await?; + + // This call is needed to advance the state from `SingleRoundMessageReady` to `CollectingSingleSignature`, + // but the returned value is not used + let _single_round_sender_data = stp + .build_single_round_message() + .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?; + + self.output_manager_service + .confirm_pending_transaction(tx_id) + .await + .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?; + + // Prepare receiver part of the transaction + + // In generating an aggregate public key utxo, we can use a randomly generated spend key + let spend_key = PrivateKey::random(&mut OsRng); + + let sender_message = TransactionSenderMessage::new_single_round_message(stp.get_single_round_message()?); + let rewind_blinding_key = PrivateKey::from_bytes(&hash_secret_key(&spend_key))?; + let encryption_key = PrivateKey::from_bytes(&hash_secret_key(&rewind_blinding_key))?; + + let rewind_data = RewindData { + rewind_blinding_key: rewind_blinding_key.clone(), + encryption_key: encryption_key.clone(), + }; + + let rtp = ReceiverTransactionProtocol::new_with_rewindable_output( + sender_message, + PrivateKey::random(&mut OsRng), + spend_key.clone(), + &self.resources.factories, + &rewind_data, + ); + + // we don't want the given utxo to be spendable as an input to a later transaction, so we set + // spendable height of the current utxo to be u64::MAx + let height = u64::MAX; + + let recipient_reply = rtp.get_signed_data()?.clone(); + let output = recipient_reply.output.clone(); + let commitment = self + .resources + .factories + .commitment + .commit_value(&spend_key.clone(), amount.into()); + + let encrypted_value = EncryptedValue::encrypt_value(&rewind_data.encryption_key, &commitment, amount)?; + let minimum_value_promise = MicroTari::zero(); + + let covenant = Covenant::default(); + + let unblinded_output = UnblindedOutput::new_current_version( + amount, + spend_key.clone(), + output.features.clone(), + script, + inputs!(PublicKey::from_secret_key(&spend_key)), /* TODO: refactor this, when we have implemented the + * necessary logic */ + self.node_identity.secret_key().clone(), + output.sender_offset_public_key.clone(), + output.metadata_signature.clone(), + height, + covenant, + encrypted_value, + minimum_value_promise, + ); + + // Start finalize + stp.add_single_recipient_info(recipient_reply, &self.resources.factories.range_proof) + .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?; + + // Finalize + stp.finalize(&self.resources.factories, None, height).map_err(|e| { + error!( + target: LOG_TARGET, + "Transaction (TxId: {}) could not be finalized. Failure error: {:?}", tx_id, e, + ); + TransactionServiceProtocolError::new(tx_id, e.into()) + })?; + info!( + target: LOG_TARGET, + "Finalized create n of m transaction TxId: {}", tx_id + ); + + // This event being sent is important, but not critical to the protocol being successful. Send only fails if + // there are no subscribers. + let _size = self + .event_publisher + .send(Arc::new(TransactionEvent::TransactionCompletedImmediately(tx_id))); + + // Broadcast create n of m aggregate public key transaction + let tx = stp + .get_transaction() + .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?; + let fee = stp + .get_fee_amount() + .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?; + self.output_manager_service + .add_rewindable_output_with_tx_id( + tx_id, + unblinded_output, + Some(SpendingPriority::Normal), + Some(rewind_data), + ) + .await?; + self.submit_transaction( + transaction_broadcast_join_handles, + CompletedTransaction::new( + tx_id, + self.resources.node_identity.public_key().clone(), + self.resources.node_identity.public_key().clone(), + amount, + fee, + tx.clone(), + TransactionStatus::Completed, + "".to_string(), + Utc::now().naive_utc(), + TransactionDirection::Outbound, + None, + None, + None, + ), + )?; + + let output_hash = output.hash(); + + // we want to print out the hash of the utxo + Ok((tx_id, output_hash)) + } + + /// Creates a metadata signature utxo + pub async fn encumber_aggregate_utxo( + &mut self, + fee_per_gram: MicroTari, + output_hash: String, + signatures: Vec, + total_script_pubkey: PublicKey, + total_offset_pubkey: PublicKey, + total_signature_nonce: PublicKey, + metadata_signature_nonce: PublicKey, + wallet_script_secret_key: String, + ) -> Result<(TxId, Commitment, FixedHash, Commitment, String, String, PublicKey), TransactionServiceError> { + let tx_id = TxId::new_random(); + + match self + .output_manager_service + .encumber_aggregate_utxo( + tx_id, + fee_per_gram, + output_hash, + signatures, + total_script_pubkey, + total_offset_pubkey, + total_signature_nonce, + metadata_signature_nonce, + wallet_script_secret_key, + ) + .await + { + Ok(transaction) => { + let output = transaction + .body + .outputs() + .first() + .ok_or(TransactionServiceError::UnexpectedApiResponse)?; + let input = transaction + .body + .inputs() + .first() + .ok_or(TransactionServiceError::UnexpectedApiResponse)?; + let output_commitment = output.commitment().clone(); + let output_hash = output.hash(); + let input_commitment = input.commitment()?.clone(); + let input_stack_hex = input.input_data.to_hex(); + let input_script_hex = input.script_signature.to_vec().to_hex(); + let total_public_offset = PublicKey::from_secret_key(&transaction.offset); + Ok(( + tx_id, + output_commitment, + output_hash, + input_commitment, + input_stack_hex, + input_script_hex, + total_public_offset, + )) + }, + Err(_) => Err(TransactionServiceError::UnexpectedApiResponse), + } + } + /// broadcasts a SHA-XTR atomic swap transaction /// # Arguments /// 'dest_pubkey': The Comms pubkey of the recipient node @@ -1043,7 +1316,7 @@ where ) .await?; - // This call is needed to advance the state from `SingleRoundMessageReady` to `SingleRoundMessageReady`, + // This call is needed to advance the state from `SingleRoundMessageReady` to `CollectingSingleSignature`, // but the returned value is not used let _single_round_sender_data = stp .build_single_round_message() @@ -1127,7 +1400,10 @@ where ); TransactionServiceProtocolError::new(tx_id, e.into()) })?; - info!(target: LOG_TARGET, "Finalized one-side transaction TxId: {}", tx_id); + info!( + target: LOG_TARGET, + "Finalized sha atomic swap transaction TxId: {}", tx_id + ); // This event being sent is important, but not critical to the protocol being successful. Send only fails if // there are no subscribers. @@ -1135,7 +1411,7 @@ where .event_publisher .send(Arc::new(TransactionEvent::TransactionCompletedImmediately(tx_id))); - // Broadcast one-sided transaction + // Broadcast sha atomic swap transaction let tx = stp .get_transaction() @@ -1205,7 +1481,7 @@ where ) .await?; - // This call is needed to advance the state from `SingleRoundMessageReady` to `SingleRoundMessageReady`, + // This call is needed to advance the state from `SingleRoundMessageReady` to `CollectingSingleSignature`, // but the returned value is not used let _single_round_sender_data = stp .build_single_round_message() @@ -1373,7 +1649,7 @@ where ) .await?; - // This call is needed to advance the state from `SingleRoundMessageReady` to `SingleRoundMessageReady`, + // This call is needed to advance the state from `SingleRoundMessageReady` to `CollectingSingleSignature`, // but the returned value is not used let _single_round_sender_data = stp .build_single_round_message() diff --git a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs index 46c96aca8c..92a101cadc 100644 --- a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs +++ b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs @@ -2202,7 +2202,7 @@ impl UnconfirmedTransactionInfoSql { mod test { use std::{convert::TryFrom, mem::size_of, time::Duration}; - use chacha20poly1305::{Key, KeyInit, XChaCha20Poly1305}; + use chacha20poly1305::{aead::NewAead, Key, XChaCha20Poly1305}; use chrono::Utc; use diesel::{Connection, SqliteConnection}; use rand::{rngs::OsRng, RngCore}; diff --git a/base_layer/wallet/src/util/encryption.rs b/base_layer/wallet/src/util/encryption.rs index b826ad5839..915fa163e1 100644 --- a/base_layer/wallet/src/util/encryption.rs +++ b/base_layer/wallet/src/util/encryption.rs @@ -104,7 +104,7 @@ pub fn encrypt_bytes_integral_nonce( mod test { use std::mem::size_of; - use chacha20poly1305::{Key, KeyInit, Tag, XChaCha20Poly1305, XNonce}; + use chacha20poly1305::{aead::NewAead, Key, Tag, XChaCha20Poly1305, XNonce}; use rand::{rngs::OsRng, RngCore}; use tari_utilities::ByteArray; diff --git a/base_layer/wallet/tests/key_manager_service_tests/service.rs b/base_layer/wallet/tests/key_manager_service_tests/service.rs index 0898c69459..7e286b461e 100644 --- a/base_layer/wallet/tests/key_manager_service_tests/service.rs +++ b/base_layer/wallet/tests/key_manager_service_tests/service.rs @@ -22,7 +22,7 @@ use std::mem::size_of; -use chacha20poly1305::{Key, KeyInit, XChaCha20Poly1305}; +use chacha20poly1305::{aead::NewAead, Key, XChaCha20Poly1305}; use rand::{rngs::OsRng, RngCore}; use tari_key_manager::cipher_seed::CipherSeed; use tari_wallet::key_manager_service::{ diff --git a/base_layer/wallet/tests/output_manager_service_tests/storage.rs b/base_layer/wallet/tests/output_manager_service_tests/storage.rs index 4cbe99b096..6e2aad5863 100644 --- a/base_layer/wallet/tests/output_manager_service_tests/storage.rs +++ b/base_layer/wallet/tests/output_manager_service_tests/storage.rs @@ -22,7 +22,7 @@ use std::mem::size_of; -use chacha20poly1305::{Key, KeyInit, XChaCha20Poly1305}; +use chacha20poly1305::{aead::NewAead, Key, XChaCha20Poly1305}; use rand::{rngs::OsRng, RngCore}; use tari_common_types::{transaction::TxId, types::FixedHash}; use tari_core::transactions::{tari_amount::MicroTari, CryptoFactories}; diff --git a/base_layer/wallet/tests/transaction_service_tests/storage.rs b/base_layer/wallet/tests/transaction_service_tests/storage.rs index 236e9e2ca3..1cc9272fdb 100644 --- a/base_layer/wallet/tests/transaction_service_tests/storage.rs +++ b/base_layer/wallet/tests/transaction_service_tests/storage.rs @@ -22,7 +22,7 @@ use std::mem::size_of; -use chacha20poly1305::{Key, KeyInit, XChaCha20Poly1305}; +use chacha20poly1305::{aead::NewAead, Key, XChaCha20Poly1305}; use chrono::{NaiveDateTime, Utc}; use rand::{rngs::OsRng, RngCore}; use tari_common_types::{ diff --git a/base_layer/wallet_ffi/Cargo.toml b/base_layer/wallet_ffi/Cargo.toml index 14555aebdd..66bc653af3 100644 --- a/base_layer/wallet_ffi/Cargo.toml +++ b/base_layer/wallet_ffi/Cargo.toml @@ -3,7 +3,7 @@ name = "tari_wallet_ffi" authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet C FFI bindings" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [dependencies] @@ -12,12 +12,12 @@ tari_common = {path="../../common"} tari_common_types = {path="../common_types"} tari_comms = { version = "^0.38", path = "../../comms/core", features = ["c_integration"]} tari_comms_dht = { version = "^0.38", path = "../../comms/dht", default-features = false } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } tari_key_manager = { version = "^0.38", path = "../key_manager" } tari_p2p = { version = "^0.38", path = "../p2p" } tari_script = { path = "../../infrastructure/tari_script" } tari_shutdown = { version = "^0.38", path = "../../infrastructure/shutdown" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } tari_wallet = { version = "^0.38", path = "../wallet", features = ["c_integration"]} chrono = { version = "0.4.19", default-features = false, features = ["serde"] } @@ -27,7 +27,7 @@ log = "0.4.6" log4rs = {version = "1.0.0", features = ["console_appender", "file_appender", "yaml_format"]} # Needs to be higher than 0.10.41 to address a security issue openssl = { version = "0.10.41", features = ["vendored"] } -rand = "0.8" +rand = "0.7.3" thiserror = "1.0.26" tokio = "1.20" num-traits = "0.2.15" diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index ee47b34f15..0b31851f5a 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -4232,7 +4232,7 @@ pub unsafe extern "C" fn wallet_create( let network = CStr::from_ptr(network_str) .to_str() .expect("A non-null network should be able to be converted to string"); - error!(target: LOG_TARGET, "network set to {}", network); + info!(target: LOG_TARGET, "network set to {}", network); // eprintln!("network set to {}", network); match Network::from_str(&*network) { Ok(n) => n, diff --git a/changelog.md b/changelog.md index b8dbf5bcc7..1c8d231881 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,49 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [0.38.5](https://github.com/tari-project/tari/compare/v0.38.4...v0.38.5) (2022-10-03) + + +### Features + +* add sql transactions to encumbering queries ([#4716](https://github.com/tari-project/tari/issues/4716)) ([a25d216](https://github.com/tari-project/tari/commit/a25d21678e9863bf1d708ca425e9ca0951cda782)) +* change priority in mempool to take into account age ([#4737](https://github.com/tari-project/tari/issues/4737)) ([0dad9e8](https://github.com/tari-project/tari/commit/0dad9e805d83a6647bb3bc159869852e58de32c6)) +* **clients:** add base node and wallet client crates ([#4722](https://github.com/tari-project/tari/issues/4722)) ([9d06408](https://github.com/tari-project/tari/commit/9d064080bd01a104cda3fae6204f0acd8b56a426)) +* **core/sync:** add sync error status ([#4705](https://github.com/tari-project/tari/issues/4705)) ([6178548](https://github.com/tari-project/tari/commit/6178548b89084ea6a2a39dfe0df45bbf1b4c48d3)) +* **core/sync:** adds `connecting` sync status ([#4698](https://github.com/tari-project/tari/issues/4698)) ([abde8e8](https://github.com/tari-project/tari/commit/abde8e8706ddb62341647d9e8648acf039ea3f69)) +* different default grpc ports for different networks ([#4755](https://github.com/tari-project/tari/issues/4755)) ([933126e](https://github.com/tari-project/tari/commit/933126eb6f99e3842d68809edd1f907be27899db)) +* improve bn command mode timeouts ([#4712](https://github.com/tari-project/tari/issues/4712)) ([e7b0b8f](https://github.com/tari-project/tari/commit/e7b0b8f0a3b5b5683b99f2fdf4b67e0345a7ad3d)) +* improve the TMS validation process ([#4694](https://github.com/tari-project/tari/issues/4694)) ([030bece](https://github.com/tari-project/tari/commit/030becec8ad1479f394a1bc4b1285b5ee3c9d17b)) +* improve txo validation logic ([#4689](https://github.com/tari-project/tari/issues/4689)) ([2b5afcf](https://github.com/tari-project/tari/commit/2b5afcfda7563da75831b9c579a1a415eb716bc5)) +* **tariscript:** adds ToRistrettoPoint op-code ([#4749](https://github.com/tari-project/tari/issues/4749)) ([8f872a1](https://github.com/tari-project/tari/commit/8f872a1d5e154cb8f134474da56e917b512e18d5)) +* trigger mempool sync on lag ([#4730](https://github.com/tari-project/tari/issues/4730)) ([1e22a03](https://github.com/tari-project/tari/commit/1e22a036bf965f89def9a5ae3514ee4e86886e2b)) +* wallet optimize output manager db operations ([#4663](https://github.com/tari-project/tari/issues/4663)) ([25c4d99](https://github.com/tari-project/tari/commit/25c4d99699438526725701dff167e3c608af7ad5)) + + +### Bug Fixes + +* add a macos dependency to compile libtor ([#4720](https://github.com/tari-project/tari/issues/4720)) ([b41226c](https://github.com/tari-project/tari/commit/b41226c52c74d5e053e0a366931f558afb78c483)) +* **base_node/grpc:** audit of error handling ([#4704](https://github.com/tari-project/tari/issues/4704)) ([595e334](https://github.com/tari-project/tari/commit/595e334ee3a7ab0d885680c6245c88e08c14a5e5)) +* **base-node/grpc:** fixes panic if invalid kernel mr is given ([#4693](https://github.com/tari-project/tari/issues/4693)) ([80af7fa](https://github.com/tari-project/tari/commit/80af7fa32a37f51718f7f15113dce3f7d708dd41)) +* burned reorg ([#4697](https://github.com/tari-project/tari/issues/4697)) ([08773f4](https://github.com/tari-project/tari/commit/08773f4a4522169e80d06f684e5235b61491d404)) +* **ci:** add cargo cache, reduce Ubuntu dependencies and action on pull_request ([#4757](https://github.com/tari-project/tari/issues/4757)) ([33e0dc2](https://github.com/tari-project/tari/commit/33e0dc24222a24e95fbed1d5d66eaa1a340423eb)) +* cli wallet cucumber ([#4739](https://github.com/tari-project/tari/issues/4739)) ([62384f9](https://github.com/tari-project/tari/commit/62384f9fc491d9fe87cfc05c659ef6002a00c8e8)) +* **clients:** fix tari nodejs client proto paths ([#4743](https://github.com/tari-project/tari/issues/4743)) ([88b75dc](https://github.com/tari-project/tari/commit/88b75dc29b129ee083fa1408a6a65270d0444512)) +* **comms/peer_manager:** add migration to remove onionv2 addresses ([#4748](https://github.com/tari-project/tari/issues/4748)) ([a92f205](https://github.com/tari-project/tari/commit/a92f205ff60ea47d1b58da9ec60ee9d2e0249c15)) +* **comms/rpc:** increase max frame size limit for rpc requests ([#4724](https://github.com/tari-project/tari/issues/4724)) ([239b64b](https://github.com/tari-project/tari/commit/239b64bc9935b873a646c8b93a8e3011c3a4d483)) +* **comms:** fixes edge case where online status event does not get published ([#4756](https://github.com/tari-project/tari/issues/4756)) ([aab729a](https://github.com/tari-project/tari/commit/aab729a139f8fa31cb43eab22abaf16bbad8f3b2)) +* **core/mempool:** improve perf of retrieve transactions ([#4710](https://github.com/tari-project/tari/issues/4710)) ([f55762e](https://github.com/tari-project/tari/commit/f55762ea05e54f7711e893f1c7df4d7b670ddabd)) +* **core:** broken doctests ([#4763](https://github.com/tari-project/tari/issues/4763)) ([4cbb378](https://github.com/tari-project/tari/commit/4cbb37853281615dd5c8d7009c5ab2b44f7ab0a5)) +* **core:** improve logging of dropped reply channels ([#4702](https://github.com/tari-project/tari/issues/4702)) ([9768f02](https://github.com/tari-project/tari/commit/9768f02935f4fe5c84dd5fc2f9058e58251c5ff0)) +* **core:** use compact inputs for block propagation ([#4714](https://github.com/tari-project/tari/issues/4714)) ([c659275](https://github.com/tari-project/tari/commit/c65927500c0792f84953274d9036d6c8d1bec72f)) +* **dht/encryption:** greatly reduce heap allocations for encrypted messaging ([#4753](https://github.com/tari-project/tari/issues/4753)) ([195df85](https://github.com/tari-project/tari/commit/195df85172a22fe710e6ce082dbe82db5f6c8d19)) +* ffi tests ([#4713](https://github.com/tari-project/tari/issues/4713)) ([4551ac3](https://github.com/tari-project/tari/commit/4551ac393f205f83db2e9d0faba54ed236e71400)) +* fixes cargo check ([#4729](https://github.com/tari-project/tari/issues/4729)) ([851ba1d](https://github.com/tari-project/tari/commit/851ba1d4d1d6140b14f761d3e3868c9cea90d131)) +* mined tx being invalid ([#4735](https://github.com/tari-project/tari/issues/4735)) ([24e396d](https://github.com/tari-project/tari/commit/24e396d9d6073b6b4b7355bb6f2558a73a0560f2)) +* refactor incorrect cucumber test on burn funds via cli ([#4679](https://github.com/tari-project/tari/issues/4679)) ([cd183ef](https://github.com/tari-project/tari/commit/cd183ef44f43cb1400716b10cee6d2e76fd9f81a)) +* sync handling and increase reorg speed in mempool ([#4706](https://github.com/tari-project/tari/issues/4706)) ([a3b529a](https://github.com/tari-project/tari/commit/a3b529ad52e9654cecac76667bc748796e5573bf)) +* **wallet:** fixes bug in fetch_by_commitment ([#4703](https://github.com/tari-project/tari/issues/4703)) ([97b01c2](https://github.com/tari-project/tari/commit/97b01c2b70f02ded466c866841a5d03ba49fad02)) + ### [0.38.4](https://github.com/tari-project/tari/compare/v0.38.3...v0.38.4) (2022-09-16) diff --git a/common/Cargo.toml b/common/Cargo.toml index a4d4841f8c..61350b5cb9 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [features] @@ -14,7 +14,7 @@ build = ["toml", "prost-build"] static-application-info = ["git2"] [dependencies] -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } anyhow = "1.0.53" config = { version = "0.13.0", default_features = false, features = ["toml"] } diff --git a/common/config/presets/c_base_node.toml b/common/config/presets/c_base_node.toml index fc98a0d3c3..bb2dad874e 100644 --- a/common/config/presets/c_base_node.toml +++ b/common/config/presets/c_base_node.toml @@ -17,15 +17,22 @@ identity_file = "config/base_node_id_dibbler.json" # A path to the file that stores your node identity and secret key (default = "config/base_node_id.json") identity_file = "config/base_node_id_igor.json" +# The socket to expose for the gRPC base node server (default = "/ip4/127.0.0.1/tcp/18152") +#grpc_address = "/ip4/127.0.0.1/tcp/18152" + [esmeralda.base_node] # A path to the file that stores your node identity and secret key (default = "config/base_node_id.json") identity_file = "config/base_node_id_esmeralda.json" +# The socket to expose for the gRPC base node server (default = "/ip4/127.0.0.1/tcp/18142") +#grpc_address = "/ip4/127.0.0.1/tcp/18142" + [base_node] # Selected network (Note: Not implemented properly, please specify on the command line) (default = "emseralda") #network = "emseralda" -# The socket to expose for the gRPC base node server (default = "/ip4/127.0.0.1/tcp/18142") -#grpc_address = "/ip4/127.0.0.1/tcp/18142" + +# Set to false to disable the base node GRPC server (default = true) +#grpc_enabled = true # A path to the file that stores your node identity and secret key (default = "config/base_node_id.json") #identity_file = "config/base_node_id.json" @@ -111,7 +118,7 @@ track_reorgs = true # The maximum number of transactions to sync in a single sync session Default: 10_000 #service.initial_sync_max_transactions = 10_000 # The maximum number of blocks added via sync or re-org to triggering a sync -#block_sync_trigger = 5 +#service.block_sync_trigger = 5 [base_node.state_machine] # The initial max sync latency. If a peer fails to stream a header/block within this deadline another sync peer will be diff --git a/common/src/configuration/bootstrap.rs b/common/src/configuration/bootstrap.rs index 26dcf14edc..75d65cc0f0 100644 --- a/common/src/configuration/bootstrap.rs +++ b/common/src/configuration/bootstrap.rs @@ -10,6 +10,7 @@ use std::{ }; use super::error::ConfigError; +use crate::configuration::Network; pub fn prompt(question: &str) -> bool { println!("{}", question); @@ -97,6 +98,29 @@ impl Display for ApplicationType { } } +/// Gets the default grpc port for the given application and network +pub fn grpc_default_port(app_type: ApplicationType, network: Network) -> u16 { + match app_type { + ApplicationType::BaseNode => match network { + Network::MainNet => 18102u16, + Network::Weatherwax => 18112, + Network::Dibbler => 18122, + Network::Esmeralda => 18142, + Network::Igor => 18152, + _ => unreachable!("Network {} not supported", network), + }, + ApplicationType::ConsoleWallet => match network { + Network::MainNet => 18103u16, + Network::Weatherwax => 18113, + Network::Dibbler => 18123, + Network::Esmeralda => 18143, + Network::Igor => 18153, + _ => unreachable!("Network {} not supported", network), + }, + _ => unreachable!("Application {} not supported", app_type), + } +} + #[cfg(test)] mod test { use super::*; diff --git a/common_sqlite/Cargo.toml b/common_sqlite/Cargo.toml index 3e8652df1b..0101cba1bf 100644 --- a/common_sqlite/Cargo.toml +++ b/common_sqlite/Cargo.toml @@ -3,7 +3,7 @@ name = "tari_common_sqlite" authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet library" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/comms/core/Cargo.toml b/comms/core/Cargo.toml index b3e4c88a81..bfab6a6a11 100644 --- a/comms/core/Cargo.toml +++ b/comms/core/Cargo.toml @@ -6,16 +6,16 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [dependencies] -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } tari_common = {path = "../../common"} tari_metrics = { path = "../../infrastructure/metrics" } tari_storage = { version = "^0.38", path = "../../infrastructure/storage" } tari_shutdown = { version = "^0.38", path = "../../infrastructure/shutdown" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } anyhow = "1.0.53" async-trait = "0.1.36" @@ -39,7 +39,7 @@ once_cell = "1.8.0" pin-project = "1.0.8" prost = "=0.9.0" prost-types = "0.9.0" -rand = "0.8" +rand = "0.7.3" serde = "1.0.119" serde_derive = "1.0.119" snow = { version = "=0.9.0", features = ["default-resolver"] } diff --git a/comms/core/src/connectivity/manager.rs b/comms/core/src/connectivity/manager.rs index 1cf1c41b41..a9e916a842 100644 --- a/comms/core/src/connectivity/manager.rs +++ b/comms/core/src/connectivity/manager.rs @@ -480,7 +480,7 @@ impl ConnectivityManagerActor { entry.failed_attempts() } - async fn handle_peer_connection_failure(&mut self, node_id: &NodeId) -> Result<(), ConnectivityError> { + async fn on_peer_connection_failure(&mut self, node_id: &NodeId) -> Result<(), ConnectivityError> { if self.status.is_offline() { debug!( target: LOG_TARGET, @@ -532,12 +532,22 @@ impl ConnectivityManagerActor { async fn handle_connection_manager_event( &mut self, event: &ConnectionManagerEvent, + ) -> Result<(), ConnectivityError> { + self.update_state_on_connectivity_event(event).await?; + self.update_connectivity_status(); + self.update_connectivity_metrics(); + Ok(()) + } + + async fn update_state_on_connectivity_event( + &mut self, + event: &ConnectionManagerEvent, ) -> Result<(), ConnectivityError> { use ConnectionManagerEvent::{PeerConnectFailed, PeerConnected, PeerDisconnected}; debug!(target: LOG_TARGET, "Received event: {}", event); match event { PeerConnected(new_conn) => { - match self.handle_new_connection_tie_break(new_conn).await { + match self.on_new_connection(new_conn).await { TieBreak::KeepExisting => { // Ignore event, we discarded the new connection and keeping the current one return Ok(()); @@ -572,6 +582,7 @@ impl ConnectivityManagerActor { target: LOG_TARGET, "Ignoring DialCancelled({}) event because an inbound connection already exists", node_id ); + return Ok(()); } } @@ -586,7 +597,7 @@ impl ConnectivityManagerActor { target: LOG_TARGET, "Connection to peer '{}' failed because '{:?}'", node_id, err ); - self.handle_peer_connection_failure(node_id).await?; + self.on_peer_connection_failure(node_id).await?; (&*node_id, ConnectionStatus::Failed, None) }, _ => return Ok(()), @@ -635,12 +646,10 @@ impl ConnectivityManagerActor { }, } - self.update_connectivity_status(); - self.update_connectivity_metrics(); Ok(()) } - async fn handle_new_connection_tie_break(&mut self, new_conn: &PeerConnection) -> TieBreak { + async fn on_new_connection(&mut self, new_conn: &PeerConnection) -> TieBreak { match self.pool.get_connection(new_conn.peer_node_id()).cloned() { Some(existing_conn) if !existing_conn.is_connected() => { debug!( @@ -749,6 +758,8 @@ impl ConnectivityManagerActor { n if n == 0 => { if num_connected_clients == 0 { self.transition(ConnectivityStatus::Offline, min_peers); + } else { + self.transition(ConnectivityStatus::Degraded(n), min_peers); } }, _ => unreachable!("num_connected is unsigned and only negative pattern covered on this branch"), diff --git a/comms/core/src/connectivity/test.rs b/comms/core/src/connectivity/test.rs index 8e3743e460..7dc7840fa0 100644 --- a/comms/core/src/connectivity/test.rs +++ b/comms/core/src/connectivity/test.rs @@ -1,10 +1,10 @@ // Copyright 2020, The Tari Project // -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that +// the following conditions are met: // -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the +// following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the // following disclaimer in the documentation and/or other materials provided with the distribution. @@ -12,13 +12,14 @@ // 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote // products derived from this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. use std::{sync::Arc, time::Duration}; use futures::{future, StreamExt}; @@ -137,8 +138,9 @@ async fn connecting_peers() { } } +#[allow(clippy::too_many_lines)] #[runtime::test] -async fn online_then_offline() { +async fn online_then_offline_then_online() { let (mut connectivity, mut event_stream, node_identity, peer_manager, cm_mock_state, _shutdown) = setup_connectivity_manager(ConnectivityConfig { min_connectivity: 2, @@ -239,6 +241,32 @@ async fn online_then_offline() { let is_offline = connectivity.get_connectivity_status().await.unwrap().is_offline(); assert!(is_offline); + + // Create a fresh set of connections since the previous connections are now in a disconnected state + let connections = future::join_all( + (0..5) + .map(|i| peers[i].clone()) + .map(|peer| create_peer_connection_mock_pair(node_identity.to_peer(), peer)), + ) + .await + .into_iter() + .map(|(conn, _, _, _)| conn) + .collect::>(); + for conn in connections.iter().skip(1) { + cm_mock_state.publish_event(ConnectionManagerEvent::PeerConnected(conn.clone())); + } + + streams::assert_in_broadcast( + &mut event_stream, + |item| match item { + ConnectivityEvent::ConnectivityStateOnline(2) => Some(()), + _ => None, + }, + Duration::from_secs(10), + ) + .await; + + assert!(connectivity.get_connectivity_status().await.unwrap().is_online()); } #[runtime::test] diff --git a/comms/core/src/lib.rs b/comms/core/src/lib.rs index d72b52585a..570794feb7 100644 --- a/comms/core/src/lib.rs +++ b/comms/core/src/lib.rs @@ -66,6 +66,6 @@ pub mod multiaddr { } pub use async_trait::async_trait; -pub use bytes::{Bytes, BytesMut}; +pub use bytes::{Buf, BufMut, Bytes, BytesMut}; #[cfg(feature = "rpc")] pub use tower::make::MakeService; diff --git a/comms/core/src/message/mod.rs b/comms/core/src/message/mod.rs index d5a2718797..99172105fc 100644 --- a/comms/core/src/message/mod.rs +++ b/comms/core/src/message/mod.rs @@ -26,6 +26,8 @@ #[macro_use] mod envelope; + +use bytes::BytesMut; pub use envelope::EnvelopeBody; mod error; @@ -52,5 +54,16 @@ pub trait MessageExt: prost::Message { ); buf } + + /// Encodes a message into a BytesMut, allocating the buffer on the heap as necessary. + fn encode_into_bytes_mut(&self) -> BytesMut + where Self: Sized { + let mut buf = BytesMut::with_capacity(self.encoded_len()); + self.encode(&mut buf).expect( + "prost::Message::encode documentation says it is infallible unless the buffer has insufficient capacity. \ + This buffer's capacity was set with encoded_len", + ); + buf + } } impl MessageExt for T {} diff --git a/comms/core/src/peer_manager/migrations.rs b/comms/core/src/peer_manager/migrations.rs index 9118874bc8..41a17455cc 100644 --- a/comms/core/src/peer_manager/migrations.rs +++ b/comms/core/src/peer_manager/migrations.rs @@ -22,6 +22,7 @@ mod v5; mod v6; +mod v7; use log::*; use tari_storage::lmdb_store::{LMDBDatabase, LMDBError}; @@ -32,7 +33,7 @@ pub(super) const MIGRATION_VERSION_KEY: u64 = u64::MAX; pub fn migrate(database: &LMDBDatabase) -> Result<(), LMDBError> { // Add migrations here in version order - let migrations = vec![v5::Migration.boxed(), v6::Migration.boxed()]; + let migrations = vec![v5::Migration.boxed(), v6::Migration.boxed(), v7::Migration.boxed()]; if migrations.is_empty() { return Ok(()); } @@ -81,10 +82,12 @@ pub fn migrate(database: &LMDBDatabase) -> Result<(), LMDBError> { debug!(target: LOG_TARGET, "Migration {} complete", version); }, None => { - error!( - target: LOG_TARGET, - "Migration {} not found. Unable to migrate peer db", version - ); + if version - 1 != latest_version { + error!( + target: LOG_TARGET, + "Migration {} not found. Unable to migrate peer db", version + ); + } return Ok(()); }, } diff --git a/comms/core/src/peer_manager/migrations/v7.rs b/comms/core/src/peer_manager/migrations/v7.rs new file mode 100644 index 0000000000..c6e15ce197 --- /dev/null +++ b/comms/core/src/peer_manager/migrations/v7.rs @@ -0,0 +1,78 @@ +// Copyright 2020, The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use log::*; +use tari_storage::{ + lmdb_store::{LMDBDatabase, LMDBError}, + IterationResult, +}; + +use crate::peer_manager::{migrations::MIGRATION_VERSION_KEY, Peer, PeerId}; + +const LOG_TARGET: &str = "comms::peer_manager::migrations::v7"; + +/// No structural changes, removes peers with onionv2 addresses +pub struct Migration; + +impl super::Migration for Migration { + type Error = LMDBError; + + fn get_version(&self) -> u32 { + 7 + } + + fn migrate(&self, db: &LMDBDatabase) -> Result<(), Self::Error> { + db.for_each::(|old_peer| { + let result = old_peer.and_then(|(key, peer)| { + if key == MIGRATION_VERSION_KEY { + return Ok(()); + } + if peer.addresses.iter().any(|a| { + // Starts with /onion/ + a.iter() + .next() + .map(|p| matches!(p, multiaddr::Protocol::Onion(_, _))) + .unwrap_or(false) + }) { + debug!( + target: LOG_TARGET, + "Removing onionv2 peer `{}`", + peer.node_id.short_str() + ); + db.remove(&key)?; + } + + Ok(()) + }); + + if let Err(err) = result { + error!( + target: LOG_TARGET, + "Failed to deserialize peer: {} ** Database may be corrupt **", err + ); + } + IterationResult::Continue + })?; + + Ok(()) + } +} diff --git a/comms/core/src/protocol/rpc/body.rs b/comms/core/src/protocol/rpc/body.rs index 0790712e0e..a93ce23e8d 100644 --- a/comms/core/src/protocol/rpc/body.rs +++ b/comms/core/src/protocol/rpc/body.rs @@ -177,7 +177,7 @@ impl BodyBytes { } pub fn into_vec(self) -> Vec { - self.0.map(|bytes| bytes.to_vec()).unwrap_or_else(Vec::new) + self.0.map(|bytes| bytes.into()).unwrap_or_else(Vec::new) } pub fn into_bytes(self) -> Option { diff --git a/comms/dht/Cargo.toml b/comms/dht/Cargo.toml index 25d0590575..b644c51565 100644 --- a/comms/dht/Cargo.toml +++ b/comms/dht/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_comms_dht" -version = "0.38.4" +version = "0.38.5" authors = ["The Tari Development Community"] description = "Tari comms DHT module" repository = "https://github.com/tari-project/tari" @@ -13,15 +13,14 @@ edition = "2018" tari_comms = { version = "^0.38", path = "../core", features = ["rpc"] } tari_common = { path = "../../common" } tari_comms_rpc_macros = { version = "^0.38", path = "../rpc_macros" } -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } tari_shutdown = { version = "^0.38", path = "../../infrastructure/shutdown" } tari_storage = { version = "^0.38", path = "../../infrastructure/storage" } tari_common_sqlite = { path = "../../common_sqlite" } anyhow = "1.0.53" bitflags = "1.2.0" -bytes = "0.5" chacha20 = "0.7.1" chacha20poly1305 = "0.9.1" chrono = { version = "0.4.19", default-features = false } @@ -34,12 +33,12 @@ log = "0.4.8" log-mdc = "0.1.0" prost = "=0.9.0" prost-types = "=0.9.0" -rand = "0.8" +rand = "0.7.3" serde = "1.0.90" serde_derive = "1.0.90" thiserror = "1.0.26" tower = { version = "0.4", features = ["full"] } -zeroize = "1.4.0" +zeroize = "1.3.0" # Uncomment for tokio tracing via tokio-console (needs "tracing" features) #console-subscriber = "0.1.3" diff --git a/comms/dht/examples/memory_net/utilities.rs b/comms/dht/examples/memory_net/utilities.rs index 35271742dd..4156abd79e 100644 --- a/comms/dht/examples/memory_net/utilities.rs +++ b/comms/dht/examples/memory_net/utilities.rs @@ -260,7 +260,7 @@ pub async fn network_connectivity_stats(nodes: &[TestNode], wallets: &[TestNode] pub async fn do_network_wide_propagation(nodes: &mut [TestNode], origin_node_index: Option) -> (usize, usize) { let random_node = match origin_node_index { Some(n) if n < nodes.len() => &nodes[n], - Some(_) | None => &nodes[OsRng.gen_range(0..nodes.len() - 1)], + Some(_) | None => &nodes[OsRng.gen_range(0, nodes.len() - 1)], }; let random_node_id = random_node.comms.node_identity().node_id().clone(); diff --git a/comms/dht/examples/memorynet.rs b/comms/dht/examples/memorynet.rs index 5633f3ba23..83f1eb46de 100644 --- a/comms/dht/examples/memorynet.rs +++ b/comms/dht/examples/memorynet.rs @@ -116,7 +116,7 @@ async fn main() { repeat_with(|| { make_node( PeerFeatures::COMMUNICATION_CLIENT, - vec![nodes[OsRng.gen_range(0..NUM_NODES - 1)].node_identity()], + vec![nodes[OsRng.gen_range(0, NUM_NODES - 1)].node_identity()], node_message_tx.clone(), NUM_NEIGHBOURING_NODES, NUM_RANDOM_NODES, @@ -225,7 +225,7 @@ async fn main() { let mut total_saf_timeouts = 0; let total_saf_done = 5; for _ in 0..5 { - let random_wallet = wallets.remove(OsRng.gen_range(0..wallets.len() - 1)); + let random_wallet = wallets.remove(OsRng.gen_range(0, wallets.len() - 1)); let (num_msgs, random_wallet, num_successes, num_attempts) = do_store_and_forward_message_propagation( random_wallet, &wallets, diff --git a/comms/dht/examples/propagation_stress.rs b/comms/dht/examples/propagation_stress.rs index 865a5b45d1..f49b22e94c 100644 --- a/comms/dht/examples/propagation_stress.rs +++ b/comms/dht/examples/propagation_stress.rs @@ -61,7 +61,7 @@ async fn main() -> anyhow::Result<()> { Multiaddr::empty(), PeerFeatures::COMMUNICATION_CLIENT, )); - let port = OsRng.gen_range(9000u16..55000); + let port = OsRng.gen_range(9000u16, 55000); let seed_peers = &[ "c2eca9cf32261a1343e21ed718e79f25bfc74386e9305350b06f62047f519347::/onion3/\ 6yxqk2ybo43u73ukfhyc42qn25echn4zegjpod2ccxzr2jd5atipwzqd:18141", diff --git a/comms/dht/src/crypt.rs b/comms/dht/src/crypt.rs index 518cace315..e37012db45 100644 --- a/comms/dht/src/crypt.rs +++ b/comms/dht/src/crypt.rs @@ -20,7 +20,7 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::mem::size_of; +use std::{iter, mem::size_of}; use chacha20::{ cipher::{NewCipher, StreamCipher}, @@ -34,8 +34,13 @@ use chacha20poly1305::{ ChaCha20Poly1305, }; use digest::Digest; +use prost::bytes::BytesMut; use rand::{rngs::OsRng, RngCore}; -use tari_comms::types::{CommsPublicKey, CommsSecretKey}; +use tari_comms::{ + message::MessageExt, + types::{CommsPublicKey, CommsSecretKey}, + BufMut, +}; use tari_crypto::{ keys::DiffieHellmanSharedSecret, tari_utilities::{epoch_time::EpochTime, ByteArray}, @@ -69,31 +74,39 @@ pub fn generate_ecdh_secret(secret_key: &CommsSecretKey, public_key: &CommsPubli output } -fn pad_message_to_base_length_multiple(message: &[u8]) -> Result, DhtEncryptError> { - // We require a 32-bit length representation, and also don't want to overflow after including this encoding - if message.len() > ((u32::max_value() - (size_of::() as u32)) as usize) { - return Err(DhtEncryptError::PaddingError("Message is too long".to_string())); +fn get_message_padding_length(message_length: usize) -> usize { + if message_length == 0 { + return MESSAGE_BASE_LENGTH; } - let message_length = message.len(); - let encoded_length = (message_length as u32).to_le_bytes(); - // Pad the message (if needed) to the next multiple of the base length - let padding_length = if ((message_length + size_of::()) % MESSAGE_BASE_LENGTH) == 0 { + if message_length % MESSAGE_BASE_LENGTH == 0 { 0 } else { - MESSAGE_BASE_LENGTH - ((message_length + size_of::()) % MESSAGE_BASE_LENGTH) - }; - - // The padded message is the encoded length, message, and zero padding - let mut padded_message = Vec::with_capacity(size_of::() + message_length + padding_length); - padded_message.extend_from_slice(&encoded_length); - padded_message.extend_from_slice(message); - padded_message.extend(std::iter::repeat(0u8).take(padding_length)); + MESSAGE_BASE_LENGTH - (message_length % MESSAGE_BASE_LENGTH) + } +} - Ok(padded_message) +/// Pads a message to a multiple of MESSAGE_BASE_LENGTH excluding the additional prefix space +fn pad_message_to_base_length_multiple( + message: &mut BytesMut, + additional_prefix_space: usize, +) -> Result<(), DhtEncryptError> { + // We require a 32-bit length representation, and also don't want to overflow after including this encoding + if message.len() > u32::MAX as usize { + return Err(DhtEncryptError::PaddingError("Message is too long".to_string())); + } + let padding_length = + get_message_padding_length(message.len().checked_sub(additional_prefix_space).ok_or_else(|| { + DhtEncryptError::PaddingError("Message length shorter than the additional_prefix_space".to_string()) + })?); + message.reserve(message.len() + padding_length); + message.extend(iter::repeat(0u8).take(padding_length)); + + Ok(()) } -fn get_original_message_from_padded_text(padded_message: &[u8]) -> Result, DhtEncryptError> { +/// Returns the unpadded message. The messages must have the length prefixed to it and the nonce is removec. +fn get_original_message_from_padded_text(padded_message: &mut BytesMut) -> Result<(), DhtEncryptError> { // NOTE: This function can return errors relating to message length // It is important not to leak error types to an adversary, or to have timing differences @@ -112,25 +125,22 @@ fn get_original_message_from_padded_text(padded_message: &[u8]) -> Result()); let mut encoded_length = [0u8; size_of::()]; - encoded_length.copy_from_slice(&padded_message[0..size_of::()]); + encoded_length.copy_from_slice(&len[..]); let message_length = u32::from_le_bytes(encoded_length) as usize; // The padded message is too short for the decoded length - let end = message_length - .checked_add(size_of::()) - .ok_or_else(|| DhtEncryptError::PaddingError("Claimed unpadded message length is too large".to_string()))?; - if end > padded_message.len() { + if message_length > padded_message.len() { return Err(DhtEncryptError::CipherError( "Claimed unpadded message length is too large".to_string(), )); } // Remove the padding (we don't check for valid padding, as this is offloaded to authentication) - let start = size_of::(); - let unpadded_message = &padded_message[start..end]; + padded_message.truncate(message_length); - Ok(unpadded_message.to_vec()) + Ok(()) } pub fn generate_key_message(data: &[u8]) -> CipherKey { @@ -150,21 +160,20 @@ pub fn generate_key_signature_for_authenticated_encryption(data: &[u8]) -> Authe } /// Decrypts cipher text using ChaCha20 stream cipher given the cipher key and cipher text with integral nonce. -pub fn decrypt(cipher_key: &CipherKey, cipher_text: &[u8]) -> Result, DhtEncryptError> { +pub fn decrypt(cipher_key: &CipherKey, cipher_text: &mut BytesMut) -> Result<(), DhtEncryptError> { if cipher_text.len() < size_of::() { return Err(DhtEncryptError::InvalidDecryptionNonceNotIncluded); } - let (nonce, cipher_text) = cipher_text.split_at(size_of::()); - let nonce = Nonce::from_slice(nonce); - let mut cipher_text = cipher_text.to_vec(); + let nonce = cipher_text.split_to(size_of::()); + let nonce = Nonce::from_slice(&nonce); let mut cipher = ChaCha20::new(&cipher_key.0, nonce); - cipher.apply_keystream(cipher_text.as_mut_slice()); + cipher.apply_keystream(cipher_text); // get original message, from decrypted padded cipher text - let cipher_text = get_original_message_from_padded_text(cipher_text.as_slice())?; - Ok(cipher_text) + get_original_message_from_padded_text(cipher_text)?; + Ok(()) } pub fn decrypt_with_chacha20_poly1305( @@ -183,23 +192,49 @@ pub fn decrypt_with_chacha20_poly1305( Ok(decrypted_signature) } -/// Encrypt the plain text using the ChaCha20 stream cipher -pub fn encrypt(cipher_key: &CipherKey, plain_text: &[u8]) -> Result, DhtEncryptError> { - // pad plain_text to avoid message length leaks - let plain_text = pad_message_to_base_length_multiple(plain_text)?; - +/// Encrypt the plain text using the ChaCha20 stream cipher. The message is assumed to have a 32-bit length prepended +/// onto it. +pub fn encrypt(cipher_key: &CipherKey, plain_text: &mut BytesMut) -> Result<(), DhtEncryptError> { + if plain_text.len() < size_of::() { + return Err(DhtEncryptError::PaddingError( + "Message is not long enough to include a nonce".to_string(), + )); + } + // add nonce let mut nonce = [0u8; size_of::()]; OsRng.fill_bytes(&mut nonce); + let nonce = Nonce::from(nonce); + plain_text[..size_of::()].copy_from_slice(&nonce[..]); + + // pad plain_text to avoid message length leaks + // Excludes the nonce in the padded message length - this is mostly for backwards compatibility + pad_message_to_base_length_multiple(plain_text, size_of::())?; - let nonce_ga = Nonce::from_slice(&nonce); - let mut cipher = ChaCha20::new(&cipher_key.0, nonce_ga); + let mut cipher = ChaCha20::new(&cipher_key.0, &nonce); - let mut buf = vec![0u8; plain_text.len() + nonce.len()]; - buf[..nonce.len()].copy_from_slice(&nonce[..]); + cipher.apply_keystream(&mut plain_text[size_of::()..]); + Ok(()) +} - buf[nonce.len()..].copy_from_slice(plain_text.as_slice()); - cipher.apply_keystream(&mut buf[nonce.len()..]); - Ok(buf) +/// Encodes a prost Message, efficiently prepending the little-endian 32-bit length to the encoding +fn encode_with_prepended_length(msg: &T, additional_prefix_space: usize) -> BytesMut { + let len = msg.encoded_len(); + let mut buf = BytesMut::with_capacity(size_of::() + additional_prefix_space + len); + buf.extend(iter::repeat(0).take(additional_prefix_space)); + buf.put_u32_le(len as u32); + msg.encode(&mut buf).expect( + "prost::Message::encode documentation says it is infallible unless the buffer has insufficient capacity. This \ + buffer's capacity was set with encoded_len", + ); + buf +} + +pub fn prepare_message(is_encrypted: bool, message: &T) -> BytesMut { + if is_encrypted { + encode_with_prepended_length(message, size_of::()) + } else { + message.encode_into_bytes_mut() + } } /// Produces authenticated encryption of the signature using the ChaCha20-Poly1305 stream cipher, @@ -276,6 +311,8 @@ pub fn create_message_domain_separated_hash_parts( #[cfg(test)] mod test { + use prost::Message; + use tari_comms::message::MessageExt; use tari_crypto::keys::PublicKey; use tari_utilities::hex::from_hex; @@ -285,10 +322,11 @@ mod test { fn encrypt_decrypt() { let pk = CommsPublicKey::default(); let key = CipherKey(*chacha20::Key::from_slice(pk.as_bytes())); - let plain_text = "Last enemy position 0830h AJ 9863".as_bytes().to_vec(); - let encrypted = encrypt(&key, &plain_text).unwrap(); - let decrypted = decrypt(&key, &encrypted).unwrap(); - assert_eq!(decrypted, plain_text); + let plain_text = "Last enemy position 0830h AJ 9863".to_string(); + let mut msg = prepare_message(true, &plain_text); + encrypt(&key, &mut msg).unwrap(); + decrypt(&key, &mut msg).unwrap(); + assert_eq!(String::decode(&msg[..]).unwrap(), plain_text); } #[test] @@ -299,9 +337,11 @@ mod test { "6063cd49c7b871c0fc9785e9b959fda553fadbb10bcaaced0958e88eb6858e05fe310b4401a78d03b52a81be49db2bffcce13765e1a64460063d33289b1a3527af3df8e292c79abca71aa9a87baa1a0a6c23532a3297dda9e0c22d4b60606db1ed02a75e7a7d21fafe1214cbf8a3a66ec319a6aafeeb0e7b06375370c52b2abe63170ce50552a697f1ff87dc03ae1df574ed8e7abf915aec6959808ec526d6da78f08f2bed24268028baeba3ebd52d0fde34b145267ced68a08c4d480c213d0ab8b9c55a1630e956ed9531d6db600537f3997d612bec5905bd3ce72f5eace475e9793e6e316349f9cbd49022e401870af357605a1c7d279d5f414a5cae13e378711f345eabf46eb7fabc9465376f027a8d2d69448243cf2d70223c2430f6ce1ff55b8c2f54e27ccf77040f70c9eb84c9da9f8176a867ebcf8cbb9dfbb9256d688a76ec02af3afe3fa8221a4876462a754bc65a15c584b8c132a48dd955821961e47d5fdce62668b8f11a42b9127d5d98414bbd026eed0b5511628b96eb8435880f38d28bad6573f90611397b7f0df46d371e29a1de3591a3aa221623a540693941d6fc22d4fa57bc612282868f024613c2f69224141ad623eb49cb2b151ff79b36ec30f9a2842c696fd94f3092989ba3f8f5136850ed1f970a559e3fe19c24b84f650da4d46a5abc3514a242e3088cae15b6012e2a3cd878a7b988cc6183e81a27fc263d3be1ef07403262b22972b4f78a38d930f3e4ec1f5c9f1a1639cd138f24c665fc39b808dfbed81f8888e8e23aac1cdd980dcd0f7d95dc71fb02abcf532be17208b8d86a5fd501c18f2b18234956617797ea78523907c46a7b558cde76d1d034d6ab36ca33c4c17ea617929e3e40af011417f9b3983912fd0ed60685261532bcca5f3b3863d92cf2e4eb33a97613d9ca55112d1bd63df9d591042f972e2da3bde7b5a572f9f4cd2633330fdb3250430f27d3a40a30a996d5a41d61dafc3fe96a1fb63e2cab5c3ec0f1084e778f303da498fc970fe3117b8513166a6c8798e00a82a6c96a61b419e12717fac57dd1c989d3a10b3ab798ee0c15a5cd04dbe83667523ad4b7587ff331513b63f15c72f1844d67c7830f723fa754969d3f4254895e71d7087617ded071a797ee5791b7a95abcb360ef504bdaa85191b09b2345c0d0096fafa85b10d1675f0c4a1fe45231fd88c715c32c38d9697cebfb712e1ce57645c8faa08b4983ab8f537b017c9898b7907c06b25c01ea0f9d736d573ec7e3b14efa84d84258131ddc11a9696e12234ab65fb4e653d8dcdf4c6ce51e0104aedf2b8089593c4b5d665ed885c2d798843cf80041657ba9d800bbb9eee7076c212cfdc56df1d63e3eb4de5c6f132376c39b0272fc35e4729988eeaf9f7748142b68b10a72a948f6db24baebe3323c11002edfbe878972f02920a9ca536ff917c37a20eb0d984ee230885950fb271e56a8640d5fff75cef501cc82a46244eca5bfed4ab180b4c4d61abb209f38dabddcb4a82581bf4990631e11cc670507f8ce88c10a7fcc06ed824d7a1aab0b4dc4a2b984f45c7447b077262dc6b90f04516a5598193e95a40e982f092a2b61fcf5203379e6b042715792915adfd0edc66a69bb7fbacf64b9c86f3b15da66f8d8eecfc373204ad10f2c666181f0facd972be208c620bb0539e396c6254f2efcc2934ae6265fdc0b8172577435758e7da46df6f175f2867e6bd734fe70416b70b643b9e4b0e0e844ccfa019c699f85313f94cc6a1bb371bb14fd65a1599355ec8cdd71a555d98a900b8cbd2b1de3378f42a137eb95b473d62be3559ed687583d6963b6857d3be5f7acc12f5f5b04b26b5c582ce6dd8d1bee6322b02c2c1dc29fcba20899d529df4fd6c1edbfd1081d6cf10b20b9451ad935da2c4cef66c160550b180ba1b668029ed15448cd288427aca7f6e6505fdfc69b8111a2a071601d78484e857705a4bc7f9423800ded4eba46e0f22ee85c48fc9e8a191355edc0868df350d627a7f1120d79ba4aa1dde1ec97f8daeb0a07be914d5f6d2e74270666d03e4ca92845957b85982761dc1ee6f7603e31681dd323a045c0ac3b06b515d7bd485bfe7f6abe31e35aac7d8536b3f9c572121fcdd44c505ccfffe514e498732cab4e70524a5281b0942f5ae861b535764f056df6a1951b3c1c261f21b3b5f0a276ed05e32879ede428683b34ac8e7ebc88c9c767bf5e7cfb0cf444c1f9fd5be9041f69f6ae9772b0e035c6a2a7d9c1c614858a506a4a4bc00cee0577561b96e98c973edfa43d52471db9c716699e52260a20150aa99f8adea872c999b66fb4395d5b8c717a2c97eb7638a1d92da2ef8b2ec80db3afa3ce83445aaccae09f38c0b84c85a8983ba4c3b9a13fed4c65fd8899333da4dbca549cd2a487eb58841881f3571dfa4821bc522b56993d657bce51dfb41caf6c2cb78e8b6beceddc44febdea144da13ae9ccd9465b3ac96b06dfe79baced35ad51763d05090dc7620c89f448134507f41828be8703fd2ab1f53370e75e55366eba1e903311313707279d5965e3343476c0a8aeef2001ad88d5e452d648dd2029a6f549809c4177d1871c88abcd1404d52ebee2dd97dc52ad1a9c018428a1a64fda6773a6ea967d4124a6cf98c7e6dc4c4d9c051a376d3e3fe2e17f6cd044dd60ee32e9d6bdbdfdcbdecc4e7306092186a7ad8ab87328f9fedb6ee8ab9417968fbaa0e582205a660fa55e1ba3c5b0c84b67017f250338125894d162c400be8d563c9f0416dc5641d31bad577543cba8c6c9a7c04064e412597d47c6272d8e087bc11397533cb1bd7feebea9feee44e1b6a5f49b937594da3b719e1982a90594277f43798a39e419c204f18a6920e5ac1a751eddeaef9392a6f84d68d73aabc6ba68750d47ad4da8bd842662226225a764661ea11ff9f13d328e0242a0b513aa5ad9fbe9d484b3d28a41890e4fc62820ef2342a90c0837b30c831eb78213e7e2cd6dfbda26a7e6103ab8b4219462ca70ca57c79638b2c49f0469ea6f68335071294257c5337ccf452ca1bfedf81610f353e7576f02a2b32aba64a4252946fda330de11990f51207817860e0d8b7c9cb58a5858155db61376a01c02aaedb7017fd3c36adf4f3c07f29f352330c6d78ab6bbb7d4aabf3725833e86523b755094273465ba57545162623036a7786f426d0a63e13bebf2205a6b488bd6da3c93469a4df4b3811e9c63d62c61e0cdd263df821adc0d1b751c1314be9fd93761b447931e425db7e09baac9083aed472de5fe6172c8e8f729ade8faa96d131e86204462e14e0411b4b7629de25a0c5dbf848c9ca8c42376f5d54bff34bf36074136bbe98228745dbc9d411d891553f0af00240e1729ce7757fba2775fa5b700e95460910008584a833fb9edc073cd4d8333643631e193040d850f87cd50d9ca2e2e5c3943787dc4a4677ac7e130c2d6739945fd3b059ebe040abb38a20d73a7669516cf8503f40642217c8580a27b127f1f33eaa7adff44c922afac813c870795563fac79d139d5b5233a26728328f88f1f9daaaea1c4e1ee64ded0b006ce46015d512e8c4a411ab788a5383563949c95846202250c5b9e0baab0bc8620327ed2aacd36e1bdc9d3a4d6b4e22627d75bd088cdd47ca204f1ce44357d1b471b37581c820f6bbdfe3da1f4f90dc353833731703b7b9bb87ff2d0cae1e2f0321994759d1a21b2075a620b58b814cd65812092891261dd7e879b65843480382f59e20d6b6c67b2fb750ff0cfce897891f976b0fae7ac31e02384b251bcbecce6ff98819cf0cd6d41fdab9ba6907742394732ed5e74bcd13aad1a188855c020f09e62540be9b2992a397b30107ad730ebe183504226b303f30032f4c0a683812d05be57961430504866bd2ee6993423ebe34ba4d2d022ce6d5b2345bbed34d6807aec473ad0701b9b8fe2db1cef57748dfcb29ddb3b253a865dd7383d04253cd70c350d02ccd2371cecfd74aae820fa91eddd89d27925c33183e03d44c7f88f8068c64d223d2d5f4ab18fae6d209e1e267395576f4f48ae056da7d6e91f94991659b4c07f44aa1c45aaf75b7274b7668753f968d5e6635f4abf238e5d44ffc38e68cad8237f7e7a25d5fc0dcd5afc2bedbac6b42e8bc8064118c9042d1159f70dfac73d65c8a9782c264445af11c878591d49d49ad46f4e6d086d55232afd234c3bceab2eef0e22e5c2875670c5125e8a172f5f2168e59fe0cb5e9e1a81bf645a2c45d115b9a3efe9fe2d1799f12b0c11f50ae5540ff4e90e6220eb62451e10ce1418929e03c751d9019d47b87847595333feb6ab4af40662d04c3ece4f93b4c2c2f2ee2078724090336f16a4f33801095036a31b557960b5d8d2552f0aadfa3dc9dcfe8f1dd6a61631b6a69ee6ce8433153f8b1ea99a9a5ac688026d6ef408f2aa958ada8baf0193b3989f359c7a913fcb9eec230568584bcda3a759c824884c9febff518c7cf312360d2c1ffd2bbdd0b2e9346cbe1bf383446bd2fec431475ec509474ef9eb06817f53d3c4ca74fba08c3b434eabf3ae9fcc2287c588fc5574bff37066705ca9a39d088cd5cbb83b385b5cf647ced0c23885295d2b24f37e4098be82edccc23e1c973b1855e2009de63408c78e570b3cec65c6d236d81adb1bc298436a1e125b99bb995a5c6df5b2a4e70b8cf1db5de38120134527ce349c32f8e35fa43837aa38cdb1d5695a34d12d27bd5ee4536d9a20e62b55e59cdc7ecca1f4398dac7a4b756d9e131a7d2c8bde32c20ef0424154c88c8276fdf3c75f08f3cd423bd648ff3520680a1f1dd956451881f6d31238c11c99a20e1d9170410c8d8eb88ce90e179fc80e23e36a28b1810383a4d0d1ef0f2db94206aa1fb25498b425e5ad1f0f0bd3eed22ca5545ef541880f37f8fea82fecd59d8c94765d3a454e81775844701412e3c01a6dcdbf277428969a7f08d67313cdd2ce3b531addee28733552ee1bf4124ad8b3e40e04b94599e04cce60f5676307b0605ad7dc73b03cc26227eab60196d37c312a01858f5ad6a901e0f1c796c52cb9690da5c712a2d36c74e65ec9a60ea41387b8a0f79697cdfd93e40ab569d6a55361be97fb7ac8d80b5a5482908d44af94df2fb09a777978f4d911008d528ff44aef960cfd25fb56e26c341850721f020f9fd112cd52fc28dd129ffc2f9a12a829dcb69b54a894d4b3d1ac3b63bc9bcd39e30a00e419c8f4d2b630c224880a7d3af9c19c8a79262818b368589e7ad03b722021306fbcbcf7bc87ad418a3eb6616e7d4ce286264554be6040e8e4cd0c5a9bbdd2367e47d1fe0a9c3eeaf2455c4f6f779bab3d5bea5284a244fc3e804fb6d0e50fec91f85b71c6ba91f43a240fa48900229e5f3038b0806f70a1cb72fdea58b664f06c04bf688183a4f22255d6976f2102aafb669ee117fa1e44ae325ad52001469fed9d26e4f8592f56e42bf5e7195f521c0beaf891e47a703075fa1948ee07add55a765346b94ae498fa96145ad8460f23248222e329398fec6ad7f323c448ce82bb706b24e07adc0681901a63d5d1c7b871a9df8009ed7bb10be4e39a987c1bf039554a016ac8693284a7248fb8a9aa440dde213c2414447727c1556d25f1fbce057652044e2350b9ef5627584d403a934dd33e8c26e20799f1dbf915705b70d66256d31ca7c407307fa18e163917635d67f742828deba4b942b5f0d916b5e737b5811d3c3b4ac386c7ebaad1a6c465ce9fb229bc6ce7ae62f8efd8632e5312db8ba213d28d19843ac7fbae105a1433921b34c216c3c2ab247080a629c7ac5507129b27ce0d38ddde06722a5a0a979894d6140c31a82bfc517adf0b57c761f75bc14d65d8701e0dea92a06584f2d877dc5fb0b32496754e6b0115e99a9623ad631ea0a76b4e7893bf0982151e1c5ed6d64a305393f6f715de333653ace204c2f03de8f36c463c937f7f23326a88337624fc606317d7c0ea2badf69e40602c2ff1e2dcc9cfca1ccef566381712af157c5e458335c8a283733a617a75fd7cef52c515c754443c8e9e1930994805e6f0b2a9a2ccbd848f6580896317dd9dbfda17d00e80d35bc58a704fbe7d6d6d45752811130f682ea9471903c9af9b5c95d074ec87b32c86dc5b29a186a60a7a03e630c7a5cd38e6ab1a2f561642d5662658fc20239233505727575e75dbbc5be630f9ebc9485f03bbf0569554a87bfb5cfd397daf5d8d92a38fc4b24b1a433edad26a12c4e29506362dec83fb9b1f31158e834cde319d40bd283f0a1f3995b3ade08bcc01c794d656583b928300a6f2be57e5bf1586a123cf28ac8e2287e0b7ab67419dc4f527f714fdee8c47088cc1857a39825524dc3f5a3777c1f906cf496dac43e3f8304ebe5d5696da5b7e5d79f176a391736ba46bc718356e1713a00ea754a52b5899ba7eb71b10bbd211cead7d1890f2d8bb981a2549e2cd53bf895f96f628c4d00061275c87f4dcbadcb5944f912d27aaa4124cadd0e2a1d82ee4d3a8b977bd1a03fc6f79caf4c306addea0bd72b754c113350655324dec3dcbb1f1de66e3e7a9f06ba0e04de0cae7af7d6e31298bf5be706038e0d8477a79ea5f8e21decdf6f5ff71090d8cb2dabb9d1a87ee526b0ec84be81ad9585b09f165cfff7a4a63e30ac7341a3a42e3e02bfc34486a2a5492a39dd31dc233c74f454584e5bd2524382a08357ba2d3ef46833551ed3fa6f672d5ba0ec75258430738c16989840b6ae6909f10340d1845bd975cf2933047a1c22c332606f76681dae8727921d4f1345f0457700b8622ea72a50c17cda201f7019d4af9dc0b67bd95317d98c2fe38ab8e12dbefe236b463014caf9c3cdd390dfcff034e90e4f51e1233bb8b341bba6f922d1b0629e261844018f39d054b26cb82592e33466354f552a14f9e6175d418cb9724fa045e723b5ab9ece5aa45800f1202b3d174fe4e129e7320a9063039f8bdea8601762ff45933503e0bd10944893e565d641a39289da67e5269dc7cfc22dc3d5f5011b66b25340cea4055bd66a7752c69e624bfc12e5cc68cd0b5cab3242860b7f40541303e228e666a6500e1e739b0b6d853b5715cf3a668facc135d133d4eefa035f36c16838f25ab4a0d2f20d18f05c0fae1a705370162cfe6f7fcf1c69654c2ce73e3820b48568c25a6d9d036c2386dee6ef14e5fc967ffccde38bf263c8c0f924bcfcdf54669dcf872724280cc4f81bb2aa993998f6312d0c6084ed823e5e6bff0ed25cc4e82b749dc11f4cf55290344d9c307d634793e81b9d3d457765dc6f81b66f1a6aaaa1079558a4892edfc342fe24856200b5dcc65c9e7809b655d3cc7bb26bcda91933f590bc61099fd0b83e04bad2174150645afd7c3ccac5417234e30da4e7574af953f8d9b7a5029417d439f1d13c4390bed2bc05d73821ff2355c33da5f95623c73abd826614572841e4777a9a0b538cef4a2c6327c75116977322a8c488f466178cdcaf3f0e10df86dbd1827ba2cc4c8fba90a1d64ad783a77704c5b1262cd11cb010f09ab04377d6e5ebed4d5dfe8eaa0cc2535a0be69bdf5e1987167b8135428ef84287aa4424c35c7a7bc94cabd553df4840121403b2ba3479e1a7f86085cce49c245af944a2ed78b77784309d05d5f5587a6e589baa6e7d279b0ab43afb5497b6d5954b3a8f66dd547d3b72565437ead511c9d5342406aace95e5cc31f2c6d618a24c219d0298f980a571ce29b999d20b3ed94a60e286ed7ddc647c439e3d421814da6d91c8b7d5b3fa70ec6a3c261ab9ee4ac779545edcc7db6df3345db26b91c5a997dac5e62b75dc05358821bab4fe65a049fe9ce8e537ae81a10dfcca0ef97c6cb95e3ff1573e5461f7b505e1678fbe97a41ab696b53f6ea09038ecda09eed34247251424b766306c0c64fd836274cf85fe0e0c19638127c2210b580c9194fe0cccac7ac80e3dde38e9cccd6a194ee923f4e73800bec0c77f60553f9c7c8413ea87d20c114d7b415fdd87fc55f273b1b3a9f9c71c4462d5b3f300daf0fc6c338278e5991e0c6de07a3c288d237df00325230be204f7b2bb7a127ac28b001e4225e910eeb9521f5af6cfeae1f18c08bf8ac9d1513c3794ba5b8ea9fb9a57825cb154fc1e9a9dddf809dd6bb11a207625b23b274344e7e0b7ca666e456735d5901f1341aca42e749183823b3debbd563aeebc68f9b15dce13d0fc1acef47d38d5967c2b6b3fe8ed69b180dbcbf17455ee6825641202ccd145c0a0a0f4091622338f48474e5838d8915f814eb87ad45e710b07f79f662c2120278ce05978d8a7aee20fc5661a08c072977ed878092e7183332b70c9c54db307c705e527f6fd2076e39c216b0490f552d52a109652958c62fc6bf7f913818dbdf5d92550779aae541d54d059d5844658422c17a24e374fa6f92e5a9fda87eee249747b9cd292043c9731d2c1d08d06eab030fb49e779cb58bf4f776d6aa0185db860007d8b2d0f7205dacb9201ac9538d2c37062f736b6b44e971e11500", ) .unwrap(); - let plain_text = decrypt(&key, &cipher_text).unwrap(); + + let mut text = BytesMut::from(&cipher_text[..]); + decrypt(&key, &mut text).unwrap(); let secret_msg = "Last enemy position 0830h AJ 9863".as_bytes().to_vec(); - assert_eq!(plain_text, secret_msg); + assert_eq!(text, secret_msg); } #[test] @@ -399,106 +439,86 @@ mod test { #[test] fn pad_message_correctness() { // test for small message - let message = &[0u8, 10, 22, 11, 38, 74, 59, 91, 73, 82, 75, 23, 59]; - let prepend_message = (message.len() as u32).to_le_bytes(); - let pad = std::iter::repeat(0u8) - .take(MESSAGE_BASE_LENGTH - message.len() - prepend_message.len()) + let message = [0u8, 10, 22, 11, 38, 74, 59, 91, 73, 82, 75, 23, 59].as_slice(); + let pad = iter::repeat(0u8) + .take(MESSAGE_BASE_LENGTH - message.len()) .collect::>(); - let pad_message = pad_message_to_base_length_multiple(message).unwrap(); + let mut pad_message = BytesMut::from(message); + pad_message_to_base_length_multiple(&mut pad_message, 0).unwrap(); // padded message is of correct length assert_eq!(pad_message.len(), MESSAGE_BASE_LENGTH); - // prepend message is well specified - assert_eq!(prepend_message, pad_message[..prepend_message.len()]); // message body is well specified - assert_eq!( - *message, - pad_message[prepend_message.len()..prepend_message.len() + message.len()] - ); + assert_eq!(*message, pad_message[..message.len()]); // pad is well specified - assert_eq!(pad, pad_message[prepend_message.len() + message.len()..]); + assert_eq!(pad, pad_message[message.len()..]); // test for large message - let message = &[100u8; MESSAGE_BASE_LENGTH * 8 - 100]; - let prepend_message = (message.len() as u32).to_le_bytes(); - let pad_message = pad_message_to_base_length_multiple(message).unwrap(); - let pad = std::iter::repeat(0u8) - .take((8 * MESSAGE_BASE_LENGTH) - message.len() - prepend_message.len()) + let message = encode_with_prepended_length(&vec![100u8; MESSAGE_BASE_LENGTH * 8 - 100], 0); + let mut pad_message = message.clone(); + pad_message_to_base_length_multiple(&mut pad_message, 0).unwrap(); + let pad = iter::repeat(0u8) + .take((8 * MESSAGE_BASE_LENGTH) - message.len()) .collect::>(); // padded message is of correct length assert_eq!(pad_message.len(), 8 * MESSAGE_BASE_LENGTH); - // prepend message is well specified - assert_eq!(prepend_message, pad_message[..prepend_message.len()]); // message body is well specified - assert_eq!( - *message, - pad_message[prepend_message.len()..prepend_message.len() + message.len()] - ); + assert_eq!(*message, pad_message[..message.len()]); // pad is well specified - assert_eq!(pad, pad_message[prepend_message.len() + message.len()..]); + assert_eq!(pad, pad_message[message.len()..]); // test for base message of multiple base length - let message = &[100u8; MESSAGE_BASE_LENGTH * 9 - 123]; - let prepend_message = (message.len() as u32).to_le_bytes(); + let message = encode_with_prepended_length(&vec![100u8; MESSAGE_BASE_LENGTH * 9 - 123], 0); let pad = std::iter::repeat(0u8) - .take((9 * MESSAGE_BASE_LENGTH) - message.len() - prepend_message.len()) + .take((9 * MESSAGE_BASE_LENGTH) - message.len()) .collect::>(); - let pad_message = pad_message_to_base_length_multiple(message).unwrap(); + let mut pad_message = message.clone(); + pad_message_to_base_length_multiple(&mut pad_message, 0).unwrap(); // padded message is of correct length assert_eq!(pad_message.len(), 9 * MESSAGE_BASE_LENGTH); - // prepend message is well specified - assert_eq!(prepend_message, pad_message[..prepend_message.len()]); // message body is well specified - assert_eq!( - *message, - pad_message[prepend_message.len()..prepend_message.len() + message.len()] - ); + assert_eq!(*message, pad_message[..message.len()]); // pad is well specified - assert_eq!(pad, pad_message[prepend_message.len() + message.len()..]); + assert_eq!(pad, pad_message[message.len()..]); // test for empty message - let message: [u8; 0] = []; - let prepend_message = (message.len() as u32).to_le_bytes(); - let pad_message = pad_message_to_base_length_multiple(&message).unwrap(); + let message = encode_with_prepended_length(&vec![], 0); + let mut pad_message = message.clone(); + pad_message_to_base_length_multiple(&mut pad_message, 0).unwrap(); let pad = [0u8; MESSAGE_BASE_LENGTH - 4]; // padded message is of correct length assert_eq!(pad_message.len(), MESSAGE_BASE_LENGTH); - // prepend message is well specified - assert_eq!(prepend_message, pad_message[..prepend_message.len()]); // message body is well specified - assert_eq!( - message, - pad_message[prepend_message.len()..prepend_message.len() + message.len()] - ); + assert_eq!(message, pad_message[..message.len()]); // pad is well specified - assert_eq!(pad, pad_message[prepend_message.len() + message.len()..]); + assert_eq!(pad, pad_message[message.len()..]); } #[test] fn unpadding_failure_modes() { // The padded message is empty - let message: [u8; 0] = []; - assert!(get_original_message_from_padded_text(&message) + let mut message = BytesMut::new(); + assert!(get_original_message_from_padded_text(&mut message) .unwrap_err() .to_string() .contains("Padded message is not long enough for length extraction")); // We cannot extract the message length - let message = [0u8; size_of::() - 1]; - assert!(get_original_message_from_padded_text(&message) + let mut message = BytesMut::from([0u8; size_of::() - 1].as_slice()); + assert!(get_original_message_from_padded_text(&mut message) .unwrap_err() .to_string() .contains("Padded message is not long enough for length extraction")); // The padded message is not a multiple of the base length - let message = [0u8; 2 * MESSAGE_BASE_LENGTH + 1]; - assert!(get_original_message_from_padded_text(&message) + let mut message = BytesMut::from([0u8; 2 * MESSAGE_BASE_LENGTH + 1].as_slice()); + assert!(get_original_message_from_padded_text(&mut message) .unwrap_err() .to_string() .contains("Padded message must be a multiple of the base length")); @@ -508,44 +528,56 @@ mod test { fn get_original_message_from_padded_text_successful() { // test for short message let message = vec![0u8, 10, 22, 11, 38, 74, 59, 91, 73, 82, 75, 23, 59]; - let pad_message = pad_message_to_base_length_multiple(message.as_slice()).unwrap(); + let mut pad_message = encode_with_prepended_length(&message, 0); + pad_message_to_base_length_multiple(&mut pad_message, 0).unwrap(); - let output_message = get_original_message_from_padded_text(pad_message.as_slice()).unwrap(); - assert_eq!(message, output_message); + // + let mut output_message = pad_message.clone(); + get_original_message_from_padded_text(&mut output_message).unwrap(); + assert_eq!(message.to_encoded_bytes(), output_message); // test for large message let message = vec![100u8; 1024]; - let pad_message = pad_message_to_base_length_multiple(message.as_slice()).unwrap(); + let mut pad_message = encode_with_prepended_length(&message, 0); + pad_message_to_base_length_multiple(&mut pad_message, 0).unwrap(); - let output_message = get_original_message_from_padded_text(pad_message.as_slice()).unwrap(); - assert_eq!(message, output_message); + let mut output_message = pad_message.clone(); + get_original_message_from_padded_text(&mut output_message).unwrap(); + assert_eq!(message.to_encoded_bytes(), output_message); // test for base message of base length let message = vec![100u8; 984]; - let pad_message = pad_message_to_base_length_multiple(message.as_slice()).unwrap(); + let mut pad_message = encode_with_prepended_length(&message, 0); + pad_message_to_base_length_multiple(&mut pad_message, 0).unwrap(); - let output_message = get_original_message_from_padded_text(pad_message.as_slice()).unwrap(); - assert_eq!(message, output_message); + let mut output_message = pad_message.clone(); + get_original_message_from_padded_text(&mut output_message).unwrap(); + assert_eq!(message.to_encoded_bytes(), output_message); // test for empty message let message: Vec = vec![]; - let pad_message = pad_message_to_base_length_multiple(message.as_slice()).unwrap(); + let mut pad_message = encode_with_prepended_length(&message, 0); + pad_message_to_base_length_multiple(&mut pad_message, 0).unwrap(); - let output_message = get_original_message_from_padded_text(pad_message.as_slice()).unwrap(); - assert_eq!(message, output_message); + let mut output_message = pad_message.clone(); + get_original_message_from_padded_text(&mut output_message).unwrap(); + assert_eq!(message.to_encoded_bytes(), output_message); } #[test] fn padding_fails_if_pad_message_prepend_length_is_bigger_than_plaintext_length() { - let message = "This is my secret message, keep it secret !".as_bytes(); - let mut pad_message = pad_message_to_base_length_multiple(message).unwrap(); + let message = "This is my secret message, keep it secret !".as_bytes().to_vec(); + let mut pad_message = encode_with_prepended_length(&message, 0); + pad_message_to_base_length_multiple(&mut pad_message, 0).unwrap(); + let mut pad_message = pad_message.to_vec(); // we modify the prepend length, in order to assert that the get original message // method will output a different length message pad_message[0] = 1; - let modified_message = get_original_message_from_padded_text(pad_message.as_slice()).unwrap(); - assert!(message.len() != modified_message.len()); + let mut modified_message = BytesMut::from(pad_message.as_slice()); + get_original_message_from_padded_text(&mut modified_message).unwrap(); + assert_ne!(message.len(), modified_message.len()); // add big number from le bytes of prepend bytes pad_message[0] = 255; @@ -553,7 +585,8 @@ mod test { pad_message[2] = 255; pad_message[3] = 255; - assert!(get_original_message_from_padded_text(pad_message.as_slice()) + let mut pad_message = BytesMut::from(pad_message.as_slice()); + assert!(get_original_message_from_padded_text(&mut pad_message) .unwrap_err() .to_string() .contains("Claimed unpadded message length is too large")); @@ -565,24 +598,30 @@ mod test { // in any way the value of the decrypted content, by applying a cipher stream let pk = CommsPublicKey::default(); let key = CipherKey(*chacha20::Key::from_slice(pk.as_bytes())); - let message = "My secret message, keep it secret !".as_bytes().to_vec(); - let mut encrypted = encrypt(&key, &message).unwrap(); + let message = "My secret message, keep it secret !".to_string(); + let mut msg = encode_with_prepended_length(&message, size_of::()); + encrypt(&key, &mut msg).unwrap(); - let n = encrypted.len(); - encrypted[n - 1] += 1; + let n = msg.len(); + msg[n - 1] += 1; - assert!(decrypt(&key, &encrypted).unwrap() == message); + decrypt(&key, &mut msg).unwrap(); + assert_eq!(String::decode(&msg[..]).unwrap(), message); } #[test] fn decryption_fails_if_message_body_is_modified() { let pk = CommsPublicKey::default(); let key = CipherKey(*chacha20::Key::from_slice(pk.as_bytes())); - let message = "My secret message, keep it secret !".as_bytes().to_vec(); - let mut encrypted = encrypt(&key, &message).unwrap(); + let message = "My secret message, keep it secret !".to_string(); + let mut msg = encode_with_prepended_length(&message, size_of::()); + encrypt(&key, &mut msg).unwrap(); - encrypted[size_of::() + size_of::() + 1] += 1; + msg[size_of::() + size_of::() + 1] += 1; - assert!(decrypt(&key, &encrypted).unwrap() != message); + // TODO: decryption does not "fail" is this intended? + decrypt(&key, &mut msg).unwrap(); + eprintln!("msg = {:?}", msg); + assert_ne!(msg, message); } } diff --git a/comms/dht/src/dedup/mod.rs b/comms/dht/src/dedup/mod.rs index fa7cf3f20e..f49e48a4a4 100644 --- a/comms/dht/src/dedup/mod.rs +++ b/comms/dht/src/dedup/mod.rs @@ -197,7 +197,7 @@ mod test { assert!(dedup.poll_ready(&mut cx).is_ready()); let node_identity = make_node_identity(); let inbound_message = - make_dht_inbound_message(&node_identity, vec![], DhtMessageFlags::empty(), false, false).unwrap(); + make_dht_inbound_message(&node_identity, &vec![], DhtMessageFlags::empty(), false, false).unwrap(); let decrypted_msg = DecryptedDhtMessage::succeeded(wrap_in_envelope_body!(vec![]), None, inbound_message); rt.block_on(dedup.call(decrypted_msg.clone())).unwrap(); @@ -213,12 +213,12 @@ mod test { #[test] fn deterministic_hash() { const TEST_MSG: &[u8] = b"test123"; - const EXPECTED_HASH: &str = "d6333668f259f677703fbe4e89152ee41c7c01f6dec502befc63120246523ffe"; + const EXPECTED_HASH: &str = "1c2bb1bcff443af4441b789bd1d6984bb8d7bed2c9f85e8cf4f45615fdd9e47d"; let node_identity = make_node_identity(); let dht_message = make_dht_inbound_message( &node_identity, - TEST_MSG.to_vec(), + &TEST_MSG.to_vec(), DhtMessageFlags::empty(), false, false, @@ -229,7 +229,7 @@ mod test { let node_identity = make_node_identity(); let dht_message = make_dht_inbound_message( &node_identity, - TEST_MSG.to_vec(), + &TEST_MSG.to_vec(), DhtMessageFlags::empty(), false, false, diff --git a/comms/dht/src/dht.rs b/comms/dht/src/dht.rs index 5361665f42..e3acdae98a 100644 --- a/comms/dht/src/dht.rs +++ b/comms/dht/src/dht.rs @@ -494,7 +494,7 @@ mod test { let msg = wrap_in_envelope_body!(b"secret".to_vec()); let dht_envelope = make_dht_envelope( &node_identity, - msg.to_encoded_bytes(), + &msg, DhtMessageFlags::empty(), false, MessageTag::new(), @@ -546,7 +546,7 @@ mod test { // Encrypt for self let dht_envelope = make_dht_envelope( &node_identity, - msg.to_encoded_bytes(), + &msg, DhtMessageFlags::ENCRYPTED, true, MessageTag::new(), @@ -602,10 +602,11 @@ mod test { let node_identity2 = make_node_identity(); let ecdh_key = crypt::generate_ecdh_secret(node_identity2.secret_key(), node_identity2.public_key()); let key_message = crypt::generate_key_message(&ecdh_key); - let encrypted_bytes = crypt::encrypt(&key_message, &msg.to_encoded_bytes()).unwrap(); + let mut encrypted_bytes = msg.encode_into_bytes_mut(); + crypt::encrypt(&key_message, &mut encrypted_bytes).unwrap(); let dht_envelope = make_dht_envelope( &node_identity2, - encrypted_bytes, + &encrypted_bytes.to_vec(), DhtMessageFlags::ENCRYPTED, true, MessageTag::new(), @@ -667,7 +668,7 @@ mod test { let msg = wrap_in_envelope_body!(b"secret".to_vec()); let mut dht_envelope = make_dht_envelope( &node_identity, - msg.to_encoded_bytes(), + &msg, DhtMessageFlags::empty(), false, MessageTag::new(), diff --git a/comms/dht/src/envelope.rs b/comms/dht/src/envelope.rs index 27038803af..3f4f2ef06e 100644 --- a/comms/dht/src/envelope.rs +++ b/comms/dht/src/envelope.rs @@ -28,7 +28,6 @@ use std::{ }; use bitflags::bitflags; -use bytes::Bytes; use chrono::{DateTime, NaiveDateTime, Utc}; use prost_types::Timestamp; use serde::{Deserialize, Serialize}; @@ -249,10 +248,10 @@ impl From for DhtHeader { } impl DhtEnvelope { - pub fn new(header: DhtHeader, body: &Bytes) -> Self { + pub fn new(header: DhtHeader, body: Vec) -> Self { Self { header: Some(header), - body: body.to_vec(), + body, } } } diff --git a/comms/dht/src/inbound/decryption.rs b/comms/dht/src/inbound/decryption.rs index 3c9c9e634c..419baf00c0 100644 --- a/comms/dht/src/inbound/decryption.rs +++ b/comms/dht/src/inbound/decryption.rs @@ -30,6 +30,7 @@ use tari_comms::{ message::EnvelopeBody, peer_manager::NodeIdentity, pipeline::PipelineError, + BytesMut, }; use thiserror::Error; use tower::{layer::Layer, Service, ServiceExt}; @@ -406,11 +407,11 @@ where S: Service message_body: &[u8], ) -> Result { let key_message = crypt::generate_key_message(shared_secret); - let decrypted = - crypt::decrypt(&key_message, message_body).map_err(DecryptionError::DecryptionFailedMalformedCipher)?; + let mut decrypted = BytesMut::from(message_body); + crypt::decrypt(&key_message, &mut decrypted).map_err(DecryptionError::DecryptionFailedMalformedCipher)?; // Deserialization into an EnvelopeBody is done here to determine if the // decryption produced valid bytes or not. - EnvelopeBody::decode(decrypted.as_slice()) + EnvelopeBody::decode(decrypted.freeze()) .and_then(|body| { // Check if we received a body length of zero // @@ -477,10 +478,11 @@ mod test { use futures::{executor::block_on, future}; use tari_comms::{ - message::{MessageExt, MessageTag}, + message::MessageTag, runtime, test_utils::mocks::create_connectivity_mock, wrap_in_envelope_body, + BytesMut, }; use tari_test_utils::{counter_context, unpack_enum}; use tokio::time::sleep; @@ -492,6 +494,7 @@ mod test { test_utils::{ make_dht_header, make_dht_inbound_message, + make_dht_inbound_message_raw, make_keypair, make_node_identity, make_valid_message_signature, @@ -527,14 +530,8 @@ mod test { let mut service = DecryptionService::new(Default::default(), node_identity.clone(), connectivity, service); let plain_text_msg = wrap_in_envelope_body!(b"Secret plans".to_vec()); - let inbound_msg = make_dht_inbound_message( - &node_identity, - plain_text_msg.to_encoded_bytes(), - DhtMessageFlags::ENCRYPTED, - true, - true, - ) - .unwrap(); + let inbound_msg = + make_dht_inbound_message(&node_identity, &plain_text_msg, DhtMessageFlags::ENCRYPTED, true, true).unwrap(); block_on(service.call(inbound_msg)).unwrap(); let decrypted = result.lock().unwrap().take().unwrap(); @@ -560,7 +557,7 @@ mod test { let some_other_node_identity = make_node_identity(); let inbound_msg = make_dht_inbound_message( &some_other_node_identity, - some_secret, + &some_secret, DhtMessageFlags::ENCRYPTED, true, true, @@ -591,7 +588,7 @@ mod test { let nonsense = b"Cannot Decrypt this".to_vec(); let inbound_msg = - make_dht_inbound_message(&node_identity, nonsense.clone(), DhtMessageFlags::ENCRYPTED, true, true).unwrap(); + make_dht_inbound_message_raw(&node_identity, nonsense, DhtMessageFlags::ENCRYPTED, true, true).unwrap(); let err = service.call(inbound_msg).await.unwrap_err(); let err = err.downcast::().unwrap(); @@ -615,14 +612,8 @@ mod test { let mut service = DecryptionService::new(Default::default(), node_identity.clone(), connectivity, service); let plain_text_msg = b"Secret message to nowhere".to_vec(); - let inbound_msg = make_dht_inbound_message( - &node_identity, - plain_text_msg.to_encoded_bytes(), - DhtMessageFlags::ENCRYPTED, - true, - false, - ) - .unwrap(); + let inbound_msg = + make_dht_inbound_message(&node_identity, &plain_text_msg, DhtMessageFlags::ENCRYPTED, true, false).unwrap(); let err = service.call(inbound_msg).await.unwrap_err(); let err = err.downcast::().unwrap(); @@ -645,13 +636,15 @@ mod test { let node_identity = make_node_identity(); let mut service = DecryptionService::new(Default::default(), node_identity.clone(), connectivity, service); - let plain_text_msg = b"Secret message".to_vec(); + let plain_text_msg = BytesMut::from(b"Secret message".as_slice()); let (e_secret_key, e_public_key) = make_keypair(); let shared_secret = crypt::generate_ecdh_secret(&e_secret_key, node_identity.public_key()); let key_message = crypt::generate_key_message(&shared_secret); let msg_tag = MessageTag::new(); - let message = crypt::encrypt(&key_message, &plain_text_msg).unwrap(); + let mut message = plain_text_msg.clone(); + crypt::encrypt(&key_message, &mut message).unwrap(); + let message = message.freeze(); let header = make_dht_header( &node_identity, &e_public_key, @@ -663,7 +656,7 @@ mod test { true, ) .unwrap(); - let envelope = DhtEnvelope::new(header.into(), &message.into()); + let envelope = DhtEnvelope::new(header.into(), message.into()); let msg_tag = MessageTag::new(); let mut inbound_msg = DhtInboundMessage::new( msg_tag, @@ -706,13 +699,15 @@ mod test { let node_identity = make_node_identity(); let mut service = DecryptionService::new(Default::default(), node_identity.clone(), connectivity, service); - let plain_text_msg = b"Public message".to_vec(); + let plain_text_msg = BytesMut::from(b"Public message".as_slice()); let (e_secret_key, e_public_key) = make_keypair(); let shared_secret = crypt::generate_ecdh_secret(&e_secret_key, node_identity.public_key()); let key_message = crypt::generate_key_message(&shared_secret); let msg_tag = MessageTag::new(); - let message = crypt::encrypt(&key_message, &plain_text_msg).unwrap(); + let mut message = plain_text_msg.clone(); + crypt::encrypt(&key_message, &mut message).unwrap(); + let message = message.freeze(); let header = make_dht_header( &node_identity, &e_public_key, @@ -724,7 +719,7 @@ mod test { true, ) .unwrap(); - let envelope = DhtEnvelope::new(header.into(), &message.into()); + let envelope = DhtEnvelope::new(header.into(), message.into()); let msg_tag = MessageTag::new(); let mut inbound_msg = DhtInboundMessage::new( msg_tag, diff --git a/comms/dht/src/inbound/deserialize.rs b/comms/dht/src/inbound/deserialize.rs index 7f50c7317a..23537899ff 100644 --- a/comms/dht/src/inbound/deserialize.rs +++ b/comms/dht/src/inbound/deserialize.rs @@ -161,7 +161,7 @@ mod test { let dht_envelope = make_dht_envelope( &node_identity, - b"A".to_vec(), + &b"A".to_vec(), DhtMessageFlags::empty(), false, MessageTag::new(), @@ -181,7 +181,7 @@ mod test { .unwrap(); let msg = spy.pop_request().unwrap(); - assert_eq!(msg.body, b"A".to_vec()); + assert_eq!(msg.body, b"A".to_vec().to_encoded_bytes()); assert_eq!(msg.dht_header, dht_envelope.header.unwrap().try_into().unwrap()); } } diff --git a/comms/dht/src/inbound/dht_handler/task.rs b/comms/dht/src/inbound/dht_handler/task.rs index 1760b47295..e6ee3c7a5d 100644 --- a/comms/dht/src/inbound/dht_handler/task.rs +++ b/comms/dht/src/inbound/dht_handler/task.rs @@ -234,7 +234,7 @@ where S: Service .with_debug_info("Propagating join message".to_string()) .with_dht_header(dht_header) .finish(), - body.to_encoded_bytes(), + body.encode_into_bytes_mut(), ) .await?; } diff --git a/comms/dht/src/inbound/forward.rs b/comms/dht/src/inbound/forward.rs index 7ddd9e4fa7..e687eff8a1 100644 --- a/comms/dht/src/inbound/forward.rs +++ b/comms/dht/src/inbound/forward.rs @@ -24,7 +24,8 @@ use std::task::Poll; use futures::{future::BoxFuture, task::Context}; use log::*; -use tari_comms::{peer_manager::Peer, pipeline::PipelineError}; +use prost::bytes::BufMut; +use tari_comms::{peer_manager::Peer, pipeline::PipelineError, BytesMut}; use tari_utilities::epoch_time::EpochTime; use tower::{layer::Layer, Service, ServiceExt}; @@ -204,12 +205,11 @@ where S: Service return Ok(()); } } - - let body = decryption_result + let err_body = decryption_result .as_ref() - .err() - .cloned() - .expect("previous check that decryption failed"); + .expect_err("previous check that decryption failed"); + let mut body = BytesMut::with_capacity(err_body.len()); + body.put(err_body.as_slice()); let excluded_peers = vec![source_peer.node_id.clone()]; let dest_node_id = dht_header.destination.to_derived_node_id(); @@ -259,7 +259,7 @@ where S: Service mod test { use std::time::Duration; - use tari_comms::{runtime, runtime::task, wrap_in_envelope_body}; + use tari_comms::{message::MessageExt, runtime, runtime::task, wrap_in_envelope_body}; use tokio::sync::mpsc; use super::*; @@ -278,7 +278,7 @@ mod test { let node_identity = make_node_identity(); let inbound_msg = - make_dht_inbound_message(&node_identity, b"".to_vec(), DhtMessageFlags::empty(), false, false).unwrap(); + make_dht_inbound_message(&node_identity, &b"".to_vec(), DhtMessageFlags::empty(), false, false).unwrap(); let msg = DecryptedDhtMessage::succeeded( wrap_in_envelope_body!(Vec::new()), Some(node_identity.public_key().clone()), @@ -300,7 +300,7 @@ mod test { let sample_body = b"Lorem ipsum"; let inbound_msg = make_dht_inbound_message( &make_node_identity(), - sample_body.to_vec(), + &sample_body.to_vec(), DhtMessageFlags::empty(), false, false, @@ -318,7 +318,7 @@ mod test { let (params, body) = oms_mock_state.pop_call().await.unwrap(); // Header and body are preserved when forwarding - assert_eq!(&body.to_vec(), &sample_body); + assert_eq!(&body.to_vec(), &sample_body.to_vec().to_encoded_bytes()); assert_eq!(params.dht_header.unwrap(), header); } } diff --git a/comms/dht/src/outbound/broadcast.rs b/comms/dht/src/outbound/broadcast.rs index 8999d2fd41..1dd2b49649 100644 --- a/comms/dht/src/outbound/broadcast.rs +++ b/comms/dht/src/outbound/broadcast.rs @@ -22,7 +22,6 @@ use std::{sync::Arc, task::Poll}; -use bytes::Bytes; use chrono::{DateTime, Utc}; use futures::{ future, @@ -37,6 +36,8 @@ use tari_comms::{ peer_manager::{NodeId, NodeIdentity, Peer}, pipeline::PipelineError, types::CommsPublicKey, + Bytes, + BytesMut, }; use tari_crypto::{keys::PublicKey, tari_utilities::epoch_time::EpochTime}; use tari_utilities::{hex::Hex, ByteArray}; @@ -238,7 +239,7 @@ where S: Service async fn handle_send_message( &mut self, params: FinalSendMessageParams, - body: Bytes, + body: BytesMut, reply_tx: oneshot::Sender, ) -> Result, DhtOutboundError> { trace!(target: LOG_TARGET, "Send params: {:?}", params); @@ -405,7 +406,7 @@ where S: Service extra_flags: DhtMessageFlags, force_origin: bool, is_broadcast: bool, - body: Bytes, + body: BytesMut, expires: Option>, tag: Option, ) -> Result<(Vec, Vec), DhtOutboundError> { @@ -485,7 +486,7 @@ where S: Service message_type: DhtMessageType, flags: DhtMessageFlags, expires: Option, - body: Bytes, + mut body: BytesMut, ) -> Result { match encryption { OutboundEncryption::EncryptFor(public_key) => { @@ -497,7 +498,8 @@ where S: Service // Generate key message for encryption of message let key_message = crypt::generate_key_message(&shared_ephemeral_secret); // Encrypt the message with the body with key message above - let encrypted_body = crypt::encrypt(&key_message, &body)?; + crypt::encrypt(&key_message, &mut body)?; + let encrypted_body = body.freeze(); // Produce domain separated signature signature let mac_signature = crypt::create_message_domain_separated_hash_parts( @@ -525,7 +527,7 @@ where S: Service Ok(( Some(Arc::new(e_public_key)), Some(encrypted_message_signature.into()), - encrypted_body.into(), + encrypted_body, )) }, OutboundEncryption::ClearText => { @@ -546,9 +548,9 @@ where S: Service &binding_message_representation, ) .to_proto(); - Ok((None, Some(signature.to_encoded_bytes().into()), body)) + Ok((None, Some(signature.to_encoded_bytes().into()), body.freeze())) } else { - Ok((None, None, body)) + Ok((None, None, body.freeze())) } }, } @@ -633,7 +635,7 @@ mod test { service .call(DhtOutboundRequest::SendMessage( Box::new(SendMessageParams::new().flood(vec![]).finish()), - b"custom_msg".to_vec().into(), + b"custom_msg".as_slice().into(), reply_tx, )) .await @@ -680,7 +682,7 @@ mod test { .with_discovery(false) .finish(), ), - Bytes::from_static(b"custom_msg"), + BytesMut::from(b"custom_msg".as_slice()), reply_tx, )) .await @@ -728,7 +730,7 @@ mod test { .with_discovery(true) .finish(), ), - b"custom_msg".to_vec().into(), + b"custom_msg".as_slice().into(), reply_tx, )) .await diff --git a/comms/dht/src/outbound/message.rs b/comms/dht/src/outbound/message.rs index 544287e090..588cbb6929 100644 --- a/comms/dht/src/outbound/message.rs +++ b/comms/dht/src/outbound/message.rs @@ -22,11 +22,12 @@ use std::{fmt, fmt::Display, sync::Arc}; -use bytes::Bytes; use tari_comms::{ message::{MessageTag, MessagingReplyTx}, peer_manager::NodeId, types::CommsPublicKey, + Bytes, + BytesMut, }; use tari_utilities::hex::Hex; use thiserror::Error; @@ -145,7 +146,11 @@ impl SendMessageResponse { #[derive(Debug)] pub enum DhtOutboundRequest { /// Send a message using the given broadcast strategy - SendMessage(Box, Bytes, oneshot::Sender), + SendMessage( + Box, + BytesMut, + oneshot::Sender, + ), } impl fmt::Display for DhtOutboundRequest { diff --git a/comms/dht/src/outbound/mock.rs b/comms/dht/src/outbound/mock.rs index 7d7b58d926..c36640f13c 100644 --- a/comms/dht/src/outbound/mock.rs +++ b/comms/dht/src/outbound/mock.rs @@ -21,15 +21,17 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use std::{ + mem, sync::Arc, time::{Duration, Instant}, }; -use bytes::Bytes; +use chacha20::Nonce; use log::*; use tari_comms::{ message::{MessageTag, MessagingReplyTx}, protocol::messaging::SendFailReason, + BytesMut, }; use tokio::{ sync::{mpsc, oneshot, watch, Mutex, RwLock}, @@ -61,7 +63,7 @@ pub fn create_outbound_service_mock(size: usize) -> (OutboundMessageRequester, O #[derive(Clone)] pub struct OutboundServiceMockState { #[allow(clippy::type_complexity)] - calls: Arc>>, + calls: Arc>>, next_response: Arc>>, notif_sender: Arc>, notif_reciever: watch::Receiver<()>, @@ -121,17 +123,36 @@ impl OutboundServiceMockState { self.next_response.write().await.take() } - pub async fn add_call(&self, req: (FinalSendMessageParams, Bytes)) { + async fn add_call(&self, req: (FinalSendMessageParams, BytesMut)) { self.calls.lock().await.push(req); let _r = self.notif_sender.send(()); } - pub async fn take_calls(&self) -> Vec<(FinalSendMessageParams, Bytes)> { - self.calls.lock().await.drain(..).collect() + pub async fn take_calls(&self) -> Vec<(FinalSendMessageParams, BytesMut)> { + self.calls + .lock() + .await + .drain(..) + .map(|(p, mut b)| { + if p.encryption.is_encrypt() { + // Remove prefix data + (p, b.split_off(mem::size_of::() + mem::size_of::())) + } else { + (p, b) + } + }) + .collect() } - pub async fn pop_call(&self) -> Option<(FinalSendMessageParams, Bytes)> { - self.calls.lock().await.pop() + pub async fn pop_call(&self) -> Option<(FinalSendMessageParams, BytesMut)> { + self.calls.lock().await.pop().map(|(p, mut b)| { + if p.encryption.is_encrypt() { + // Remove prefix data + (p, b.split_off(mem::size_of::() + mem::size_of::())) + } else { + (p, b) + } + }) } pub async fn set_behaviour(&self, behaviour: MockBehaviour) { @@ -232,7 +253,7 @@ impl OutboundServiceMock { async fn add_call( &mut self, params: FinalSendMessageParams, - body: Bytes, + body: BytesMut, ) -> (SendMessageResponse, MessagingReplyTx) { self.mock_state.add_call((params, body)).await; let (inner_reply_tx, inner_reply_rx) = oneshot::channel(); diff --git a/comms/dht/src/outbound/requester.rs b/comms/dht/src/outbound/requester.rs index 0b1e38e9ee..0ac3e2e619 100644 --- a/comms/dht/src/outbound/requester.rs +++ b/comms/dht/src/outbound/requester.rs @@ -21,11 +21,12 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use log::*; -use tari_comms::{message::MessageExt, peer_manager::NodeId, types::CommsPublicKey, wrap_in_envelope_body}; +use tari_comms::{peer_manager::NodeId, types::CommsPublicKey, wrap_in_envelope_body, BytesMut}; use tokio::sync::{mpsc, oneshot}; use super::message::DhtOutboundRequest; use crate::{ + crypt::prepare_message, domain_message::OutboundDomainMessage, envelope::NodeDestination, outbound::{ @@ -259,7 +260,8 @@ impl OutboundMessageRequester { } else { message.to_propagation_header() }; - let body = wrap_in_envelope_body!(header, message.into_inner()).to_encoded_bytes(); + let msg = wrap_in_envelope_body!(header, message.into_inner()); + let body = prepare_message(params.encryption.is_encrypt(), &msg); self.send_raw(params, body).await } @@ -275,7 +277,8 @@ impl OutboundMessageRequester { if cfg!(debug_assertions) { trace!(target: LOG_TARGET, "Send Message: {} {:?}", params, message); } - let body = wrap_in_envelope_body!(message).to_encoded_bytes(); + let msg = wrap_in_envelope_body!(message); + let body = prepare_message(params.encryption.is_encrypt(), &msg); self.send_raw(params, body).await } @@ -291,7 +294,8 @@ impl OutboundMessageRequester { if cfg!(debug_assertions) { trace!(target: LOG_TARGET, "Send Message: {} {:?}", params, message); } - let body = wrap_in_envelope_body!(message).to_encoded_bytes(); + let msg = wrap_in_envelope_body!(message); + let body = prepare_message(params.encryption.is_encrypt(), &msg); self.send_raw_no_wait(params, body).await } @@ -299,11 +303,11 @@ impl OutboundMessageRequester { pub async fn send_raw( &mut self, params: FinalSendMessageParams, - body: Vec, + body: BytesMut, ) -> Result { let (reply_tx, reply_rx) = oneshot::channel(); self.sender - .send(DhtOutboundRequest::SendMessage(Box::new(params), body.into(), reply_tx)) + .send(DhtOutboundRequest::SendMessage(Box::new(params), body, reply_tx)) .await?; reply_rx @@ -315,11 +319,11 @@ impl OutboundMessageRequester { pub async fn send_raw_no_wait( &mut self, params: FinalSendMessageParams, - body: Vec, + body: BytesMut, ) -> Result<(), DhtOutboundError> { let (reply_tx, _) = oneshot::channel(); self.sender - .send(DhtOutboundRequest::SendMessage(Box::new(params), body.into(), reply_tx)) + .send(DhtOutboundRequest::SendMessage(Box::new(params), body, reply_tx)) .await?; Ok(()) } diff --git a/comms/dht/src/outbound/serialize.rs b/comms/dht/src/outbound/serialize.rs index 0d47a64cc5..ff0e8fe745 100644 --- a/comms/dht/src/outbound/serialize.rs +++ b/comms/dht/src/outbound/serialize.rs @@ -97,7 +97,7 @@ where message_tag: tag.as_value(), expires, }); - let envelope = DhtEnvelope::new(dht_header, &body); + let envelope = DhtEnvelope::new(dht_header, body.into()); let body = Bytes::from(envelope.to_encoded_bytes()); diff --git a/comms/dht/src/store_forward/saf_handler/task.rs b/comms/dht/src/store_forward/saf_handler/task.rs index 0aada15e4e..7f5390d382 100644 --- a/comms/dht/src/store_forward/saf_handler/task.rs +++ b/comms/dht/src/store_forward/saf_handler/task.rs @@ -34,6 +34,7 @@ use tari_comms::{ peer_manager::{NodeId, NodeIdentity, Peer, PeerFeatures, PeerManagerError}, pipeline::PipelineError, types::CommsPublicKey, + BytesMut, }; use tari_utilities::{convert::try_convert_all, ByteArray}; use tokio::sync::mpsc; @@ -563,9 +564,10 @@ where S: Service ); let key_message = crypt::generate_key_message(&shared_secret); - let decrypted_bytes = crypt::decrypt(&key_message, body)?; + let mut decrypted_bytes = BytesMut::from(body); + crypt::decrypt(&key_message, &mut decrypted_bytes)?; let envelope_body = - EnvelopeBody::decode(decrypted_bytes.as_slice()).map_err(|_| StoreAndForwardError::DecryptionFailed)?; + EnvelopeBody::decode(decrypted_bytes.freeze()).map_err(|_| StoreAndForwardError::DecryptionFailed)?; if envelope_body.is_empty() { return Err(StoreAndForwardError::InvalidEnvelopeBody); } @@ -702,7 +704,7 @@ mod test { None, make_dht_inbound_message( &node_identity, - b"Keep this for others please".to_vec(), + &b"Keep this for others please".to_vec(), DhtMessageFlags::ENCRYPTED, true, false, @@ -793,10 +795,9 @@ mod test { sleep(Duration::from_secs(5)).await; } assert_eq!(oms_mock_state.call_count().await, 1); - let call = oms_mock_state.pop_call().await.unwrap(); + let (_, body) = oms_mock_state.pop_call().await.unwrap(); - let body = call.1.to_vec(); - let body = EnvelopeBody::decode(body.as_slice()).unwrap(); + let body = EnvelopeBody::decode(body).unwrap(); let msg = body.decode_part::(0).unwrap().unwrap(); assert_eq!(msg.messages().len(), 1); @@ -827,19 +828,19 @@ mod test { let node_identity = make_node_identity(); - let msg_a = wrap_in_envelope_body!(&b"A".to_vec()).to_encoded_bytes(); + let msg_a = wrap_in_envelope_body!(&b"A".to_vec()); let inbound_msg_a = - make_dht_inbound_message(&node_identity, msg_a.clone(), DhtMessageFlags::ENCRYPTED, true, false).unwrap(); + make_dht_inbound_message(&node_identity, &msg_a, DhtMessageFlags::ENCRYPTED, true, false).unwrap(); // Need to know the peer to process a stored message peer_manager .add_peer(Clone::clone(&*inbound_msg_a.source_peer)) .await .unwrap(); - let msg_b = &wrap_in_envelope_body!(b"B".to_vec()).to_encoded_bytes(); + let msg_b = wrap_in_envelope_body!(b"B".to_vec()); let inbound_msg_b = - make_dht_inbound_message(&node_identity, msg_b.clone(), DhtMessageFlags::ENCRYPTED, true, false).unwrap(); + make_dht_inbound_message(&node_identity, &msg_b, DhtMessageFlags::ENCRYPTED, true, false).unwrap(); // Need to know the peer to process a stored message peer_manager .add_peer(Clone::clone(&*inbound_msg_b.source_peer)) @@ -856,20 +857,14 @@ mod test { let msg2 = ProtoStoredMessage::new(0, inbound_msg_b.dht_header, inbound_msg_b.body, msg2_time); // Cleartext message - let clear_msg = wrap_in_envelope_body!(b"Clear".to_vec()).to_encoded_bytes(); - let clear_header = make_dht_inbound_message( - &node_identity, - clear_msg.clone(), - DhtMessageFlags::empty(), - false, - false, - ) - .unwrap() - .dht_header; + let clear_msg = wrap_in_envelope_body!(b"Clear".to_vec()); + let clear_header = make_dht_inbound_message(&node_identity, &clear_msg, DhtMessageFlags::empty(), false, false) + .unwrap() + .dht_header; let msg_clear_time = Utc::now() .checked_sub_signed(chrono::Duration::from_std(Duration::from_secs(120)).unwrap()) .unwrap(); - let msg_clear = ProtoStoredMessage::new(0, clear_header, clear_msg, msg_clear_time); + let msg_clear = ProtoStoredMessage::new(0, clear_header, clear_msg.to_encoded_bytes(), msg_clear_time); let mut message = DecryptedDhtMessage::succeeded( wrap_in_envelope_body!(StoredMessagesResponse { messages: vec![msg1.clone(), msg2, msg_clear], @@ -879,7 +874,7 @@ mod test { None, make_dht_inbound_message( &node_identity, - b"Stored message".to_vec(), + &b"Stored message".to_vec(), DhtMessageFlags::ENCRYPTED, true, false, @@ -950,9 +945,9 @@ mod test { let node_identity = make_node_identity(); - let msg_a = wrap_in_envelope_body!(&b"A".to_vec()).to_encoded_bytes(); + let msg_a = wrap_in_envelope_body!(&b"A".to_vec()); let inbound_msg_a = - make_dht_inbound_message(&node_identity, msg_a, DhtMessageFlags::ENCRYPTED, true, false).unwrap(); + make_dht_inbound_message(&node_identity, &msg_a, DhtMessageFlags::ENCRYPTED, true, false).unwrap(); peer_manager .add_peer(Clone::clone(&*inbound_msg_a.source_peer)) .await @@ -973,7 +968,7 @@ mod test { None, make_dht_inbound_message( &node_identity, - b"Stored message".to_vec(), + &b"Stored message".to_vec(), DhtMessageFlags::ENCRYPTED, true, false, @@ -1023,9 +1018,9 @@ mod test { let node_identity = make_node_identity(); - let msg_a = wrap_in_envelope_body!(&b"A".to_vec()).to_encoded_bytes(); + let msg_a = wrap_in_envelope_body!(&b"A".to_vec()); let inbound_msg_a = - make_dht_inbound_message(&node_identity, msg_a, DhtMessageFlags::ENCRYPTED, true, false).unwrap(); + make_dht_inbound_message(&node_identity, &msg_a, DhtMessageFlags::ENCRYPTED, true, false).unwrap(); peer_manager .add_peer(Clone::clone(&*inbound_msg_a.source_peer)) .await @@ -1046,7 +1041,7 @@ mod test { None, make_dht_inbound_message( &node_identity, - b"Stored message".to_vec(), + &b"Stored message".to_vec(), DhtMessageFlags::ENCRYPTED, true, false, diff --git a/comms/dht/src/store_forward/store.rs b/comms/dht/src/store_forward/store.rs index 61519cd8ca..c0d2b8d224 100644 --- a/comms/dht/src/store_forward/store.rs +++ b/comms/dht/src/store_forward/store.rs @@ -483,7 +483,7 @@ mod test { let inbound_msg = make_dht_inbound_message( &make_node_identity(), - b"".to_vec(), + &b"".to_vec(), DhtMessageFlags::empty(), false, false, @@ -509,7 +509,7 @@ mod test { let msg_node_identity = make_node_identity(); let inbound_msg = make_dht_inbound_message( &msg_node_identity, - b"This shouldnt be stored".to_vec(), + &b"This shouldnt be stored".to_vec(), DhtMessageFlags::ENCRYPTED, true, false, @@ -539,7 +539,7 @@ mod test { let mut inbound_msg = make_dht_inbound_message( &origin_node_identity, - b"Will you keep this for me?".to_vec(), + &b"Will you keep this for me?".to_vec(), DhtMessageFlags::ENCRYPTED, true, false, @@ -582,7 +582,7 @@ mod test { let mut inbound_msg = make_dht_inbound_message( &origin_node_identity, - b"Will you keep this for me?".to_vec(), + &b"Will you keep this for me?".to_vec(), DhtMessageFlags::ENCRYPTED, true, false, diff --git a/comms/dht/src/test_utils/makers.rs b/comms/dht/src/test_utils/makers.rs index 7646346b3a..c9ba154d98 100644 --- a/comms/dht/src/test_utils/makers.rs +++ b/comms/dht/src/test_utils/makers.rs @@ -36,6 +36,7 @@ use tari_test_utils::{paths::create_temporary_data_path, random}; use crate::{ crypt, + crypt::prepare_message, envelope::{DhtMessageFlags, DhtMessageHeader, NodeDestination}, inbound::DhtInboundMessage, message_signature::MessageSignature, @@ -123,9 +124,9 @@ pub fn make_valid_message_signature(node_identity: &NodeIdentity, message: &[u8] .to_encoded_bytes() } -pub fn make_dht_inbound_message( +pub fn make_dht_inbound_message( node_identity: &NodeIdentity, - body: Vec, + body: &T, flags: DhtMessageFlags, include_origin: bool, include_destination: bool, @@ -148,24 +149,65 @@ pub fn make_dht_inbound_message( )) } +pub fn make_dht_inbound_message_raw( + node_identity: &NodeIdentity, + body: Vec, + flags: DhtMessageFlags, + include_origin: bool, + include_destination: bool, +) -> Result { + let msg_tag = MessageTag::new(); + let (e_secret_key, e_public_key) = make_keypair(); + let header = make_dht_header( + node_identity, + &e_public_key, + &e_secret_key, + &body, + flags, + include_origin, + msg_tag, + include_destination, + )? + .into(); + let envelope = DhtEnvelope::new(header, body); + Ok(DhtInboundMessage::new( + msg_tag, + envelope.header.unwrap().try_into().unwrap(), + Arc::new(Peer::new( + node_identity.public_key().clone(), + node_identity.node_id().clone(), + Vec::::new().into(), + PeerFlags::empty(), + PeerFeatures::COMMUNICATION_NODE, + Default::default(), + Default::default(), + )), + envelope.body, + )) +} + pub fn make_keypair() -> (CommsSecretKey, CommsPublicKey) { CommsPublicKey::random_keypair(&mut OsRng) } -pub fn make_dht_envelope( +pub fn make_dht_envelope( node_identity: &NodeIdentity, - mut message: Vec, + message: &T, flags: DhtMessageFlags, include_origin: bool, trace: MessageTag, include_destination: bool, ) -> Result { let (e_secret_key, e_public_key) = make_keypair(); - if flags.is_encrypted() { + let message = if flags.is_encrypted() { let shared_secret = crypt::generate_ecdh_secret(&e_secret_key, node_identity.public_key()); let key_message = crypt::generate_key_message(&shared_secret); - message = crypt::encrypt(&key_message, &message).unwrap(); - } + let mut message = prepare_message(true, message); + crypt::encrypt(&key_message, &mut message).unwrap(); + message.freeze() + } else { + prepare_message(false, message).freeze() + }; let header = make_dht_header( node_identity, &e_public_key, @@ -177,7 +219,7 @@ pub fn make_dht_envelope( include_destination, )? .into(); - Ok(DhtEnvelope::new(header, &message.into())) + Ok(DhtEnvelope::new(header, message.into())) } pub fn build_peer_manager() -> Arc { diff --git a/comms/dht/src/test_utils/mod.rs b/comms/dht/src/test_utils/mod.rs index 03f531c075..39e8fff377 100644 --- a/comms/dht/src/test_utils/mod.rs +++ b/comms/dht/src/test_utils/mod.rs @@ -45,7 +45,9 @@ pub use dht_actor_mock::{create_dht_actor_mock, DhtMockState}; mod dht_discovery_mock; pub use dht_discovery_mock::{create_dht_discovery_mock, DhtDiscoveryMockState}; +#[cfg(test)] mod makers; +#[cfg(test)] pub use makers::*; mod service; diff --git a/comms/dht/tests/dht.rs b/comms/dht/tests/dht.rs index 9928c1df79..55e9da8e72 100644 --- a/comms/dht/tests/dht.rs +++ b/comms/dht/tests/dht.rs @@ -33,7 +33,6 @@ use tari_comms::{ protocol::messaging::{MessagingEvent, MessagingEventSender, MessagingProtocolExtension}, transports::MemoryTransport, types::CommsDatabase, - wrap_in_envelope_body, CommsBuilder, CommsNode, }; @@ -419,16 +418,13 @@ async fn dht_store_forward() { node_A .dht .outbound_requester() - .send_raw( - params.clone(), - wrap_in_envelope_body!(secret_msg1.to_vec()).to_encoded_bytes(), - ) + .send_message_no_header(params.clone(), secret_msg1.to_vec()) .await .unwrap(); node_A .dht .outbound_requester() - .send_raw(params, wrap_in_envelope_body!(secret_msg2.to_vec()).to_encoded_bytes()) + .send_message_no_header(params, secret_msg2.to_vec()) .await .unwrap(); @@ -722,7 +718,7 @@ async fn dht_do_not_store_invalid_message_in_dedup() { // Get the message that was received by Node B let mut msg = node_B.next_inbound_message(Duration::from_secs(10)).await.unwrap(); - let bytes = msg.decryption_result.unwrap().to_encoded_bytes(); + let bytes = msg.decryption_result.unwrap().encode_into_bytes_mut(); // Clone header without modification let header_unmodified = msg.dht_header.clone(); @@ -972,9 +968,9 @@ async fn dht_propagate_message_contents_not_malleable_ban() { let msg = node_B.next_inbound_message(Duration::from_secs(10)).await.unwrap(); - let mut bytes = msg.decryption_result.unwrap().to_encoded_bytes(); + let mut envelope = msg.decryption_result.unwrap(); // Change the message - bytes.push(0x42); + envelope.push_part([0x42].to_vec()); let mut connectivity_events = node_C.comms.connectivity().get_event_subscription(); @@ -982,7 +978,7 @@ async fn dht_propagate_message_contents_not_malleable_ban() { node_B .dht .outbound_requester() - .send_raw( + .send_message_no_header( SendMessageParams::new() .propagate(node_B.node_identity().public_key().clone().into(), vec![msg .source_peer @@ -990,7 +986,7 @@ async fn dht_propagate_message_contents_not_malleable_ban() { .clone()]) .with_dht_header(msg.dht_header) .finish(), - bytes, + envelope, ) .await .unwrap(); @@ -1016,7 +1012,6 @@ async fn dht_propagate_message_contents_not_malleable_ban() { #[tokio::test] #[allow(non_snake_case)] async fn dht_header_not_malleable() { - env_logger::init(); let node_C = make_node("node_C", PeerFeatures::COMMUNICATION_NODE, dht_config(), None).await; // Node B knows about Node C let mut node_B = make_node( @@ -1081,14 +1076,14 @@ async fn dht_header_not_malleable() { // Modify the header msg.dht_header.message_type = DhtMessageType::from_i32(21i32).unwrap(); - let bytes = msg.decryption_result.unwrap().to_encoded_bytes(); + let envelope = msg.decryption_result.unwrap(); let mut connectivity_events = node_C.comms.connectivity().get_event_subscription(); // Propagate the changed message (to node C) node_B .dht .outbound_requester() - .send_raw( + .send_message_no_header( SendMessageParams::new() .propagate(node_B.node_identity().public_key().clone().into(), vec![msg .source_peer @@ -1096,7 +1091,7 @@ async fn dht_header_not_malleable() { .clone()]) .with_dht_header(msg.dht_header) .finish(), - bytes, + envelope, ) .await .unwrap(); diff --git a/comms/rpc_macros/Cargo.toml b/comms/rpc_macros/Cargo.toml index e0cfa8968b..81e33db8ea 100644 --- a/comms/rpc_macros/Cargo.toml +++ b/comms/rpc_macros/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [lib] diff --git a/infrastructure/derive/Cargo.toml b/infrastructure/derive/Cargo.toml index 70786001ba..dbb5fe630c 100644 --- a/infrastructure/derive/Cargo.toml +++ b/infrastructure/derive/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [lib] diff --git a/infrastructure/libtor/Cargo.toml b/infrastructure/libtor/Cargo.toml index a46d9283f4..3ec4e98bc9 100644 --- a/infrastructure/libtor/Cargo.toml +++ b/infrastructure/libtor/Cargo.toml @@ -13,7 +13,7 @@ derivative = "2.2.0" log = "0.4.8" log4rs = { version = "1.0.0", default_features = false, features = ["config_parsing", "threshold_filter", "yaml_format"] } multiaddr = { version = "0.14.0" } -rand = "0.8" +rand = "0.7.3" tempfile = "3.1.0" tor-hash-passwd = "1.0.1" diff --git a/infrastructure/shutdown/Cargo.toml b/infrastructure/shutdown/Cargo.toml index f82bc04043..9070aab5e4 100644 --- a/infrastructure/shutdown/Cargo.toml +++ b/infrastructure/shutdown/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/infrastructure/storage/Cargo.toml b/infrastructure/storage/Cargo.toml index c2977ab94b..181f62b20e 100644 --- a/infrastructure/storage/Cargo.toml +++ b/infrastructure/storage/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.38.4" +version = "0.38.5" edition = "2018" [dependencies] @@ -18,5 +18,5 @@ serde = "1.0.80" serde_derive = "1.0.80" [dev-dependencies] -rand = "0.8" -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +rand = "0.7.3" +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } diff --git a/infrastructure/tari_script/Cargo.toml b/infrastructure/tari_script/Cargo.toml index 3f9a5694c3..c0f5e1af53 100644 --- a/infrastructure/tari_script/Cargo.toml +++ b/infrastructure/tari_script/Cargo.toml @@ -11,8 +11,8 @@ readme = "README.md" license = "BSD-3-Clause" [dependencies] -tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.5" } -tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.6" } +tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.7" } blake2 = "0.9" digest = "0.9.0" @@ -21,4 +21,6 @@ serde = "1.0.136" sha2 = "0.9" sha3 = "0.9" thiserror = "1.0.30" -rand = "0.8.5" + +[dev-dependencies] +rand = "0.7.3" diff --git a/infrastructure/tari_script/src/lib.rs b/infrastructure/tari_script/src/lib.rs index e796c55a4d..5a50a52b72 100644 --- a/infrastructure/tari_script/src/lib.rs +++ b/infrastructure/tari_script/src/lib.rs @@ -24,7 +24,7 @@ mod serde; mod stack; pub use error::ScriptError; -pub use op_codes::{slice_to_boxed_hash, slice_to_hash, HashValue, Opcode}; +pub use op_codes::{slice_to_boxed_hash, slice_to_boxed_message, slice_to_hash, HashValue, Opcode}; pub use script::TariScript; pub use script_commitment::{ScriptCommitment, ScriptCommitmentError, ScriptCommitmentFactory}; pub use script_context::ScriptContext; diff --git a/infrastructure/tari_script/src/op_codes.rs b/infrastructure/tari_script/src/op_codes.rs index 944fac641c..16faa5b913 100644 --- a/infrastructure/tari_script/src/op_codes.rs +++ b/infrastructure/tari_script/src/op_codes.rs @@ -24,6 +24,7 @@ use tari_utilities::{hex::Hex, ByteArray, ByteArrayError}; use super::ScriptError; pub type HashValue = [u8; 32]; +pub type ScalarValue = [u8; 32]; pub type Message = [u8; MESSAGE_LENGTH]; const PUBLIC_KEY_LENGTH: usize = 32; @@ -116,6 +117,8 @@ pub const OP_CHECK_MULTI_SIG_VERIFY: u8 = 0xaf; pub const OP_HASH_BLAKE256: u8 = 0xb0; pub const OP_HASH_SHA256: u8 = 0xb1; pub const OP_HASH_SHA3: u8 = 0xb2; +pub const OP_TO_RISTRETTO_POINT: u8 = 0xb3; +pub const OP_CHECK_MULTI_SIG_VERIFY_AGGREGATE_PUB_KEY: u8 = 0xb4; // Opcode constants: Miscellaneous pub const OP_RETURN: u8 = 0x60; @@ -232,6 +235,12 @@ pub enum Opcode { /// Identical to CheckMultiSig, except that nothing is pushed to the stack if the m signatures are valid, and the /// operation fails with VERIFY_FAILED if any of the signatures are invalid. CheckMultiSigVerify(u8, u8, Vec, Box), + /// Pops the top element which must be a valid 32-byte scalar or hash and calculates the corresponding Ristretto + /// point, and pushes the result to the stack. Fails with EMPTY_STACK if the stack is empty. + ToRistrettoPoint, + /// Pop m signatures from the stack. If m signatures out of the provided n public keys sign the 32-byte message, + /// push the aggregate of the public keys to the stack, otherwise fails with VERIFY_FAILED. + CheckMultiSigVerifyAggregatePubKey(u8, u8, Vec, Box), // Miscellaneous /// Always fails with VERIFY_FAILED. @@ -350,6 +359,11 @@ impl Opcode { let (m, n, keys, msg, end) = Opcode::read_multisig_args(bytes)?; Ok((CheckMultiSigVerify(m, n, keys, msg), &bytes[end..])) }, + OP_TO_RISTRETTO_POINT => Ok((ToRistrettoPoint, &bytes[1..])), + OP_CHECK_MULTI_SIG_VERIFY_AGGREGATE_PUB_KEY => { + let (m, n, keys, msg, end) = Opcode::read_multisig_args(bytes)?; + Ok((CheckMultiSigVerifyAggregatePubKey(m, n, keys, msg), &bytes[end..])) + }, OP_RETURN => Ok((Return, &bytes[1..])), OP_IF_THEN => Ok((IfThen, &bytes[1..])), OP_ELSE => Ok((Else, &bytes[1..])), @@ -447,12 +461,20 @@ impl Opcode { CheckMultiSig(m, n, public_keys, msg) => { array.extend_from_slice(&[OP_CHECK_MULTI_SIG, *m, *n]); for public_key in public_keys { - array.extend(public_key.to_vec()); + array.extend(public_key.as_bytes()); } array.extend_from_slice(msg.deref()); }, CheckMultiSigVerify(m, n, public_keys, msg) => { array.extend_from_slice(&[OP_CHECK_MULTI_SIG_VERIFY, *m, *n]); + for public_key in public_keys { + array.extend(public_key.as_bytes()); + } + array.extend_from_slice(msg.deref()); + }, + ToRistrettoPoint => array.push(OP_TO_RISTRETTO_POINT), + CheckMultiSigVerifyAggregatePubKey(m, n, public_keys, msg) => { + array.extend_from_slice(&[OP_CHECK_MULTI_SIG_VERIFY_AGGREGATE_PUB_KEY, *m, *n]); for public_key in public_keys { array.extend(public_key.to_vec()); } @@ -473,70 +495,78 @@ impl fmt::Display for Opcode { #[allow(clippy::enum_glob_use)] use Opcode::*; match self { - CheckHeightVerify(height) => fmt.write_str(&format!("CheckHeightVerify({})", *height)), - CheckHeight(height) => fmt.write_str(&format!("CheckHeight({})", *height)), - CompareHeightVerify => fmt.write_str("CompareHeightVerify"), - CompareHeight => fmt.write_str("CompareHeight"), - Nop => fmt.write_str("Nop"), - PushZero => fmt.write_str("PushZero"), - PushOne => fmt.write_str("PushOne"), - PushHash(h) => fmt.write_str(&format!("PushHash({})", (*h).to_hex())), - PushInt(n) => fmt.write_str(&format!("PushInt({})", *n)), - PushPubKey(h) => fmt.write_str(&format!("PushPubKey({})", (*h).to_hex())), - Drop => fmt.write_str("Drop"), - Dup => fmt.write_str("Dup"), - RevRot => fmt.write_str("RevRot"), - GeZero => fmt.write_str("GeZero"), - GtZero => fmt.write_str("GtZero"), - LeZero => fmt.write_str("LeZero"), - LtZero => fmt.write_str("LtZero"), - Add => fmt.write_str("Add"), - Sub => fmt.write_str("Sub"), - Equal => fmt.write_str("Equal"), - EqualVerify => fmt.write_str("EqualVerify"), - Or(n) => fmt.write_str(&format!("Or({})", *n)), - OrVerify(n) => fmt.write_str(&format!("OrVerify({})", *n)), - HashBlake256 => fmt.write_str("HashBlake256"), - HashSha256 => fmt.write_str("HashSha256"), - HashSha3 => fmt.write_str("HashSha3"), - CheckSig(msg) => fmt.write_str(&format!("CheckSig({})", (*msg).to_hex())), - CheckSigVerify(msg) => fmt.write_str(&format!("CheckSigVerify({})", (*msg).to_hex())), + CheckHeightVerify(height) => write!(fmt, "CheckHeightVerify({})", *height), + CheckHeight(height) => write!(fmt, "CheckHeight({})", *height), + CompareHeightVerify => write!(fmt, "CompareHeightVerify"), + CompareHeight => write!(fmt, "CompareHeight"), + Nop => write!(fmt, "Nop"), + PushZero => write!(fmt, "PushZero"), + PushOne => write!(fmt, "PushOne"), + PushHash(h) => write!(fmt, "PushHash({})", (*h).to_hex()), + PushInt(n) => write!(fmt, "PushInt({})", *n), + PushPubKey(h) => write!(fmt, "PushPubKey({})", (*h).to_hex()), + Drop => write!(fmt, "Drop"), + Dup => write!(fmt, "Dup"), + RevRot => write!(fmt, "RevRot"), + GeZero => write!(fmt, "GeZero"), + GtZero => write!(fmt, "GtZero"), + LeZero => write!(fmt, "LeZero"), + LtZero => write!(fmt, "LtZero"), + Add => write!(fmt, "Add"), + Sub => write!(fmt, "Sub"), + Equal => write!(fmt, "Equal"), + EqualVerify => write!(fmt, "EqualVerify"), + Or(n) => write!(fmt, "Or({})", *n), + OrVerify(n) => write!(fmt, "OrVerify({})", *n), + HashBlake256 => write!(fmt, "HashBlake256"), + HashSha256 => write!(fmt, "HashSha256"), + HashSha3 => write!(fmt, "HashSha3"), + CheckSig(msg) => write!(fmt, "CheckSig({})", (*msg).to_hex()), + CheckSigVerify(msg) => write!(fmt, "CheckSigVerify({})", (*msg).to_hex()), CheckMultiSig(m, n, public_keys, msg) => { let keys: Vec = public_keys.iter().map(|p| p.to_hex()).collect(); - fmt.write_str(&format!( + write!( + fmt, "CheckMultiSig({}, {}, [{}], {})", *m, *n, keys.join(", "), (*msg).to_hex() - )) + ) }, CheckMultiSigVerify(m, n, public_keys, msg) => { let keys: Vec = public_keys.iter().map(|p| p.to_hex()).collect(); - fmt.write_str(&format!( + write!( + fmt, "CheckMultiSigVerify({}, {}, [{}], {})", *m, *n, keys.join(", "), (*msg).to_hex() + ) + }, + ToRistrettoPoint => write!(fmt, "ToRistrettoPoint"), + CheckMultiSigVerifyAggregatePubKey(m, n, public_keys, msg) => { + let keys: Vec = public_keys.iter().map(|p| p.to_hex()).collect(); + fmt.write_str(&format!( + "CheckMultiSigVerifyAggregatePubKey({}, {}, [{}], {})", + *m, + *n, + keys.join(", "), + (*msg).to_hex() )) }, - Return => fmt.write_str("Return"), - IfThen => fmt.write_str("IfThen"), - Else => fmt.write_str("Else"), - EndIf => fmt.write_str("EndIf"), + Return => write!(fmt, "Return"), + IfThen => write!(fmt, "IfThen"), + Else => write!(fmt, "Else"), + EndIf => write!(fmt, "EndIf"), } } } #[cfg(test)] mod test { - use crate::{ - op_codes::*, - Opcode, - Opcode::{Dup, PushHash, Return}, - ScriptError, - }; + use crate::{op_codes::*, Opcode, ScriptError}; #[test] fn empty_script() { @@ -552,9 +582,9 @@ mod test { let script = [0x60u8, 0x71]; let opcodes = Opcode::parse(&script).unwrap(); let code = opcodes.first().unwrap(); - assert_eq!(code, &Return); + assert_eq!(code, &Opcode::Return); let code = opcodes.get(1).unwrap(); - assert_eq!(code, &Dup); + assert_eq!(code, &Opcode::Dup); let err = Opcode::parse(&[0x7a]).unwrap_err(); assert!(matches!(err, ScriptError::InvalidData)); @@ -563,7 +593,7 @@ mod test { #[test] fn push_hash() { let (code, b) = Opcode::read_next(b"\x7a/thirty-two~character~hash~val./").unwrap(); - assert!(matches!(code, PushHash(v) if &*v == b"/thirty-two~character~hash~val./")); + assert!(matches!(code, Opcode::PushHash(v) if &*v == b"/thirty-two~character~hash~val./")); assert!(b.is_empty()); } @@ -761,12 +791,20 @@ mod test { 6c9cb4d3e57351462122310fa22c90b1e6dfb528d64615363d1261a75da3e401)", ); test_checkmultisig( - &Opcode::CheckMultiSigVerify(1, 2, keys, Box::new(*msg)), + &Opcode::CheckMultiSigVerify(1, 2, keys.clone(), Box::new(*msg)), OP_CHECK_MULTI_SIG_VERIFY, "CheckMultiSigVerify(1, 2, [9c8bc5f90d221191748e8dd7686f09e1114b4bada4c367ed58ae199c51eb100b, \ 56e9f018b138ba843521b3243a29d81730c3a4c25108b108b1ca47c2132db569], \ 6c9cb4d3e57351462122310fa22c90b1e6dfb528d64615363d1261a75da3e401)", ); + test_checkmultisig( + &Opcode::CheckMultiSigVerifyAggregatePubKey(1, 2, keys, Box::new(*msg)), + OP_CHECK_MULTI_SIG_VERIFY_AGGREGATE_PUB_KEY, + "CheckMultiSigVerifyAggregatePubKey(1, 2, \ + [9c8bc5f90d221191748e8dd7686f09e1114b4bada4c367ed58ae199c51eb100b, \ + 56e9f018b138ba843521b3243a29d81730c3a4c25108b108b1ca47c2132db569], \ + 6c9cb4d3e57351462122310fa22c90b1e6dfb528d64615363d1261a75da3e401)", + ); } #[test] @@ -794,6 +832,7 @@ mod test { test_opcode(OP_HASH_SHA3, &Opcode::HashSha3); test_opcode(OP_HASH_BLAKE256, &Opcode::HashBlake256); test_opcode(OP_HASH_SHA256, &Opcode::HashSha256); + test_opcode(OP_TO_RISTRETTO_POINT, &Opcode::ToRistrettoPoint); test_opcode(OP_IF_THEN, &Opcode::IfThen); test_opcode(OP_ELSE, &Opcode::Else); test_opcode(OP_END_IF, &Opcode::EndIf); @@ -825,6 +864,7 @@ mod test { test_opcode(OP_HASH_SHA3, &Opcode::HashSha3); test_opcode(OP_HASH_BLAKE256, &Opcode::HashBlake256); test_opcode(OP_HASH_SHA256, &Opcode::HashSha256); + test_opcode(OP_TO_RISTRETTO_POINT, &Opcode::ToRistrettoPoint); test_opcode(OP_IF_THEN, &Opcode::IfThen); test_opcode(OP_ELSE, &Opcode::Else); test_opcode(OP_END_IF, &Opcode::EndIf); @@ -856,6 +896,7 @@ mod test { test_opcode(&Opcode::HashSha3, "HashSha3"); test_opcode(&Opcode::HashBlake256, "HashBlake256"); test_opcode(&Opcode::HashSha256, "HashSha256"); + test_opcode(&Opcode::ToRistrettoPoint, "ToRistrettoPoint"); test_opcode(&Opcode::IfThen, "IfThen"); test_opcode(&Opcode::Else, "Else"); test_opcode(&Opcode::EndIf, "EndIf"); diff --git a/infrastructure/tari_script/src/script.rs b/infrastructure/tari_script/src/script.rs index d3e4eeabba..fd2bc9f8ff 100644 --- a/infrastructure/tari_script/src/script.rs +++ b/infrastructure/tari_script/src/script.rs @@ -23,6 +23,7 @@ use sha2::Sha256; use sha3::Sha3_256; use tari_crypto::{ hash::blake2::Blake256, + keys::PublicKey, ristretto::{RistrettoPublicKey, RistrettoSchnorr, RistrettoSecretKey}, }; use tari_utilities::{ @@ -247,19 +248,27 @@ impl TariScript { } }, CheckMultiSig(m, n, public_keys, msg) => { - if self.check_multisig(stack, *m, *n, public_keys, *msg.deref())? { + if self.check_multisig(stack, *m, *n, public_keys, *msg.deref())?.is_some() { stack.push(Number(1)) } else { stack.push(Number(0)) } }, CheckMultiSigVerify(m, n, public_keys, msg) => { - if self.check_multisig(stack, *m, *n, public_keys, *msg.deref())? { + if self.check_multisig(stack, *m, *n, public_keys, *msg.deref())?.is_some() { Ok(()) } else { Err(ScriptError::VerifyFailed) } }, + ToRistrettoPoint => self.handle_to_ristretto_point(stack), + CheckMultiSigVerifyAggregatePubKey(m, n, public_keys, msg) => { + if let Some(agg_pub_key) = self.check_multisig(stack, *m, *n, public_keys, *msg.deref())? { + stack.push(PublicKey(agg_pub_key)) + } else { + Err(ScriptError::VerifyFailed) + } + }, Return => Err(ScriptError::Return), IfThen => TariScript::handle_if_then(stack, state), Else => TariScript::handle_else(state), @@ -503,9 +512,9 @@ impl TariScript { n: u8, public_keys: &[RistrettoPublicKey], message: Message, - ) -> Result { - if m == 0 || n == 0 || m > n || n > MAX_MULTISIG_LIMIT { - return Err(ScriptError::InvalidData); + ) -> Result, ScriptError> { + if m == 0 || n == 0 || m > n || n > MAX_MULTISIG_LIMIT || public_keys.len() != n as usize { + return Err(ScriptError::ValueExceedsBounds); } // pop m sigs let m = m as usize; @@ -522,20 +531,38 @@ impl TariScript { #[allow(clippy::mutable_key_type)] let mut sig_set = HashSet::new(); + let mut agg_pub_key = RistrettoPublicKey::default(); for s in &signatures { for (i, pk) in public_keys.iter().enumerate() { if !sig_set.contains(s) && !key_signed[i] && s.verify_challenge(pk, &message) { key_signed[i] = true; sig_set.insert(s); + agg_pub_key = agg_pub_key + pk; break; } } if !sig_set.contains(s) { - return Ok(false); + return Ok(None); } } + if sig_set.len() == m { + Ok(Some(agg_pub_key)) + } else { + Ok(None) + } + } - Ok(sig_set.len() == m) + fn handle_to_ristretto_point(&self, stack: &mut ExecutionStack) -> Result<(), ScriptError> { + let item = stack.pop().ok_or(ScriptError::StackUnderflow)?; + let scalar = match &item { + StackItem::Hash(hash) => hash.as_slice(), + StackItem::Scalar(scalar) => scalar.as_slice(), + _ => return Err(ScriptError::IncompatibleTypes), + }; + let ristretto_sk = RistrettoSecretKey::from_bytes(scalar).map_err(|_| ScriptError::InvalidData)?; + let ristretto_pk = RistrettoPublicKey::from_secret_key(&ristretto_sk); + stack.push(StackItem::PublicKey(ristretto_pk))?; + Ok(()) } } @@ -610,6 +637,7 @@ mod test { inputs, op_codes::{slice_to_boxed_hash, slice_to_boxed_message, HashValue, Message}, ExecutionStack, + Opcode::CheckMultiSigVerifyAggregatePubKey, ScriptContext, StackItem, StackItem::{Commitment, Hash, Number}, @@ -1130,21 +1158,21 @@ mod test { let script = TariScript::new(ops); let inputs = inputs!(s_alice.clone()); let err = script.execute(&inputs).unwrap_err(); - assert_eq!(err, ScriptError::InvalidData); + assert_eq!(err, ScriptError::ValueExceedsBounds); let keys = vec![p_alice.clone(), p_bob.clone()]; let ops = vec![CheckMultiSig(1, 0, keys, msg.clone())]; let script = TariScript::new(ops); let inputs = inputs!(s_alice.clone()); let err = script.execute(&inputs).unwrap_err(); - assert_eq!(err, ScriptError::InvalidData); + assert_eq!(err, ScriptError::ValueExceedsBounds); let keys = vec![p_alice, p_bob]; let ops = vec![CheckMultiSig(2, 1, keys, msg)]; let script = TariScript::new(ops); let inputs = inputs!(s_alice); let err = script.execute(&inputs).unwrap_err(); - assert_eq!(err, ScriptError::InvalidData); + assert_eq!(err, ScriptError::ValueExceedsBounds); // max n is 32 let (msg, data) = multisig_data(33); @@ -1154,7 +1182,7 @@ mod test { let items = sigs.map(StackItem::Signature).collect(); let inputs = ExecutionStack::new(items); let err = script.execute(&inputs).unwrap_err(); - assert_eq!(err, ScriptError::InvalidData); + assert_eq!(err, ScriptError::ValueExceedsBounds); // 3 of 4 let (msg, data) = multisig_data(4); @@ -1243,7 +1271,7 @@ mod test { // 1 of 3 let keys = vec![p_alice.clone(), p_bob.clone(), p_carol.clone()]; - let ops = vec![CheckMultiSigVerify(1, 2, keys, msg.clone())]; + let ops = vec![CheckMultiSigVerify(1, 3, keys, msg.clone())]; let script = TariScript::new(ops); let inputs = inputs!(Number(1), s_alice.clone()); @@ -1277,6 +1305,31 @@ mod test { let err = script.execute(&inputs).unwrap_err(); assert_eq!(err, ScriptError::VerifyFailed); + // 2 of 3 (returning the aggregate public key of the signatories) + let keys = vec![p_alice.clone(), p_bob.clone(), p_carol.clone()]; + let ops = vec![CheckMultiSigVerifyAggregatePubKey(2, 3, keys, msg.clone())]; + let script = TariScript::new(ops); + + let inputs = inputs!(s_alice.clone(), s_bob.clone()); + let agg_pub_key = script.execute(&inputs).unwrap(); + assert_eq!(agg_pub_key, StackItem::PublicKey(p_alice.clone() + p_bob.clone())); + + let inputs = inputs!(s_alice.clone(), s_carol.clone()); + let agg_pub_key = script.execute(&inputs).unwrap(); + assert_eq!(agg_pub_key, StackItem::PublicKey(p_alice.clone() + p_carol.clone())); + + let inputs = inputs!(s_bob.clone(), s_carol.clone()); + let agg_pub_key = script.execute(&inputs).unwrap(); + assert_eq!(agg_pub_key, StackItem::PublicKey(p_bob.clone() + p_carol.clone())); + + let inputs = inputs!(s_alice.clone(), s_carol.clone(), s_bob.clone()); + let err = script.execute(&inputs).unwrap_err(); + assert_eq!(err, ScriptError::NonUnitLengthStack); + + let inputs = inputs!(p_bob.clone()); + let err = script.execute(&inputs).unwrap_err(); + assert_eq!(err, ScriptError::StackUnderflow); + // 3 of 3 let keys = vec![p_alice.clone(), p_bob.clone(), p_carol]; let ops = vec![CheckMultiSigVerify(3, 3, keys, msg.clone())]; @@ -1298,21 +1351,21 @@ mod test { let script = TariScript::new(ops); let inputs = inputs!(s_alice.clone()); let err = script.execute(&inputs).unwrap_err(); - assert_eq!(err, ScriptError::InvalidData); + assert_eq!(err, ScriptError::ValueExceedsBounds); let keys = vec![p_alice.clone(), p_bob.clone()]; let ops = vec![CheckMultiSigVerify(1, 0, keys, msg.clone())]; let script = TariScript::new(ops); let inputs = inputs!(s_alice.clone()); let err = script.execute(&inputs).unwrap_err(); - assert_eq!(err, ScriptError::InvalidData); + assert_eq!(err, ScriptError::ValueExceedsBounds); let keys = vec![p_alice, p_bob]; let ops = vec![CheckMultiSigVerify(2, 1, keys, msg)]; let script = TariScript::new(ops); let inputs = inputs!(s_alice); let err = script.execute(&inputs).unwrap_err(); - assert_eq!(err, ScriptError::InvalidData); + assert_eq!(err, ScriptError::ValueExceedsBounds); // 3 of 4 let (msg, data) = multisig_data(4); @@ -1540,4 +1593,32 @@ mod test { let result = script.execute(&inputs).unwrap_err(); assert_eq!(result, ScriptError::Return); } + + #[test] + fn to_ristretto_point() { + use crate::StackItem::PublicKey; + let mut rng = rand::thread_rng(); + let (k_1, p_1) = RistrettoPublicKey::random_keypair(&mut rng); + + use crate::Opcode::ToRistrettoPoint; + let ops = vec![ToRistrettoPoint]; + let script = TariScript::new(ops); + + // Invalid stack type + let inputs = inputs!(RistrettoPublicKey::default()); + let err = script.execute(&inputs).unwrap_err(); + assert!(matches!(err, ScriptError::IncompatibleTypes)); + + // scalar + let mut scalar = [0u8; 32]; + scalar.copy_from_slice(k_1.as_bytes()); + let inputs = inputs!(scalar); + let result = script.execute(&inputs).unwrap(); + assert_eq!(result, PublicKey(p_1.clone())); + + // hash + let inputs = ExecutionStack::new(vec![Hash(scalar)]); + let result = script.execute(&inputs).unwrap(); + assert_eq!(result, PublicKey(p_1)); + } } diff --git a/infrastructure/tari_script/src/stack.rs b/infrastructure/tari_script/src/stack.rs index 84b6519b0f..757988f9c3 100644 --- a/infrastructure/tari_script/src/stack.rs +++ b/infrastructure/tari_script/src/stack.rs @@ -24,7 +24,11 @@ use tari_utilities::{ ByteArray, }; -use crate::{error::ScriptError, op_codes::HashValue}; +use crate::{ + error::ScriptError, + op_codes::{HashValue, ScalarValue}, +}; + pub const MAX_STACK_SIZE: usize = 255; #[macro_export] @@ -52,11 +56,13 @@ pub const TYPE_HASH: u8 = 2; pub const TYPE_COMMITMENT: u8 = 3; pub const TYPE_PUBKEY: u8 = 4; pub const TYPE_SIG: u8 = 5; +pub const TYPE_SCALAR: u8 = 6; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum StackItem { Number(i64), Hash(HashValue), + Scalar(ScalarValue), Commitment(PedersenCommitment), PublicKey(RistrettoPublicKey), Signature(RistrettoSchnorr), @@ -89,6 +95,10 @@ impl StackItem { array.extend_from_slice(s.get_public_nonce().as_bytes()); array.extend_from_slice(s.get_signature().as_bytes()); }, + StackItem::Scalar(scalar) => { + array.push(TYPE_SCALAR); + array.extend_from_slice(scalar); + }, }; &array[n..] } @@ -103,6 +113,7 @@ impl StackItem { TYPE_COMMITMENT => StackItem::b_to_commitment(&bytes[1..]), TYPE_PUBKEY => StackItem::b_to_pubkey(&bytes[1..]), TYPE_SIG => StackItem::b_to_sig(&bytes[1..]), + TYPE_SCALAR => StackItem::b_to_scalar(&bytes[1..]), _ => None, } } @@ -125,6 +136,15 @@ impl StackItem { Some((StackItem::Hash(arr), &b[32..])) } + fn b_to_scalar(b: &[u8]) -> Option<(Self, &[u8])> { + if b.len() < 32 { + return None; + } + let mut arr = [0u8; 32]; + arr.copy_from_slice(&b[..32]); + Some((StackItem::Scalar(arr), &b[32..])) + } + fn b_to_commitment(b: &[u8]) -> Option<(Self, &[u8])> { if b.len() < 32 { return None; @@ -156,6 +176,7 @@ stack_item_from!(i64 => Number); stack_item_from!(PedersenCommitment => Commitment); stack_item_from!(RistrettoPublicKey => PublicKey); stack_item_from!(RistrettoSchnorr => Signature); +stack_item_from!(ScalarValue => Scalar); #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ExecutionStack { @@ -211,7 +232,7 @@ impl ExecutionStack { // check that all popped items are of the same variant // first count each variant - let counts = items.iter().fold([0; 5], counter); + let counts = items.iter().fold([0; 6], counter); // also check the n + 1 item let counts = counter(counts, &item); @@ -302,29 +323,34 @@ impl Hex for ExecutionStack { /// Utility function that given a count of `StackItem` variants, adds 1 for the given item. #[allow(clippy::many_single_char_names)] -fn counter(values: [u8; 5], item: &StackItem) -> [u8; 5] { - let [n, h, c, p, s] = values; - use StackItem::{Commitment, Hash, Number, PublicKey, Signature}; +fn counter(values: [u8; 6], item: &StackItem) -> [u8; 6] { + let [n, h, c, p, s, z] = values; + #[allow(clippy::enum_glob_use)] + use StackItem::*; match item { Number(_) => { let n = n + 1; - [n, h, c, p, s] + [n, h, c, p, s, z] }, Hash(_) => { let h = h + 1; - [n, h, c, p, s] + [n, h, c, p, s, z] }, Commitment(_) => { let c = c + 1; - [n, h, c, p, s] + [n, h, c, p, s, z] }, PublicKey(_) => { let p = p + 1; - [n, h, c, p, s] + [n, h, c, p, s, z] }, Signature(_) => { let s = s + 1; - [n, h, c, p, s] + [n, h, c, p, s, z] + }, + Scalar(_) => { + let z = z + 1; + [n, h, c, p, s, z] }, } } @@ -337,9 +363,9 @@ mod test { keys::{PublicKey, SecretKey}, ristretto::{utils, utils::SignatureSet, RistrettoPublicKey, RistrettoSchnorr, RistrettoSecretKey}, }; - use tari_utilities::hex::Hex; + use tari_utilities::hex::{from_hex, Hex}; - use crate::{ExecutionStack, StackItem}; + use crate::{op_codes::ScalarValue, ExecutionStack, StackItem}; #[test] fn as_bytes_roundtrip() { @@ -366,19 +392,33 @@ mod test { let p = RistrettoPublicKey::from_secret_key(&k); let m = Blake256::digest(b"Hello Tari Script"); let sig = RistrettoSchnorr::sign(k, r, m.as_slice()).unwrap(); - let inputs = inputs!(sig, p); - assert_eq!(inputs.to_hex(), "0500f7c695528c858cde76dab3076908e01228b6dbdd5f671bed1b03b89e170c316db1023d5c46d78a97da8eb6c5a37e00d5f2fee182dcb38c1b6c65e90a43c1090456c0fa32558d6edc0916baa26b48e745de834571534ca253ea82435f08ebbc7c"); + let scalar: ScalarValue = m.into(); + let inputs = inputs!(sig, p, scalar); + assert_eq!(inputs.to_hex(), "0500f7c695528c858cde76dab3076908e01228b6dbdd5f671bed1b03b89e170c316db1023d5c46d78a97da8eb6c5a37e00d5f2fee182dcb38c1b6c65e90a43c1090456c0fa32558d6edc0916baa26b48e745de834571534ca253ea82435f08ebbc7c06fdf9fc345d2cdd8aff624a55f824c7c9ce3cc972e011b4e750e417a90ecc5da5"); } #[test] fn serialisation() { - let s = "0500f7c695528c858cde76dab3076908e01228b6dbdd5f671bed1b03b89e170c316db1023d5c46d78a97da8eb6c5\ - a37e00d5f2fee182dcb38c1b6c65e90a43c1090456c0fa32558d6edc0916baa26b48e745de834571534ca253ea82435f08ebbc7c"; + // let p = + // RistrettoPublicKey::from_hex("56c0fa32558d6edc0916baa26b48e745de834571534ca253ea82435f08ebbc7c"). + // unwrap(); let r = + // RistrettoPublicKey::from_hex("00f7c695528c858cde76dab3076908e01228b6dbdd5f671bed1b03b89e170c31"). + // unwrap(); let s = + // RistrettoSecretKey::from_hex("6db1023d5c46d78a97da8eb6c5a37e00d5f2fee182dcb38c1b6c65e90a43c109"). + // unwrap(); let sig = RistrettoSchnorr::new(r, s); + // let m: HashValue = Blake256::digest(b"Hello Tari Script").into(); + // let inputs = inputs!(m, sig, p); + // eprintln!("to_hex(&m) = {:?}", tari_utilities::hex::to_hex(&m)); + // eprintln!("inputs.to_hex() = {:?}", inputs.to_hex()); + + let s = "06fdf9fc345d2cdd8aff624a55f824c7c9ce3cc972e011b4e750e417a90ecc5da50500f7c695528c858cde76dab3076908e0122\ + 8b6dbdd5f671bed1b03b89e170c316db1023d5c46d78a97da8eb6c5a37e00d5f2fee182dcb38c1b6c65e90a43c1090456c0fa32558d6edc0916baa2\ + 6b48e745de834571534ca253ea82435f08ebbc7c"; let mut stack = ExecutionStack::from_hex(s).unwrap(); - assert_eq!(stack.size(), 2); + assert_eq!(stack.size(), 3); if let Some(StackItem::PublicKey(p)) = stack.pop() { assert_eq!( - &p.to_hex(), + p.to_hex(), "56c0fa32558d6edc0916baa26b48e745de834571534ca253ea82435f08ebbc7c" ); } else { @@ -386,15 +426,23 @@ mod test { } if let Some(StackItem::Signature(s)) = stack.pop() { assert_eq!( - &s.get_public_nonce().to_hex(), + s.get_public_nonce().to_hex(), "00f7c695528c858cde76dab3076908e01228b6dbdd5f671bed1b03b89e170c31" ); assert_eq!( - &s.get_signature().to_hex(), + s.get_signature().to_hex(), "6db1023d5c46d78a97da8eb6c5a37e00d5f2fee182dcb38c1b6c65e90a43c109" ); } else { panic!("Expected signature") } + if let Some(StackItem::Scalar(s)) = stack.pop() { + assert_eq!( + s.as_slice(), + from_hex("fdf9fc345d2cdd8aff624a55f824c7c9ce3cc972e011b4e750e417a90ecc5da5").unwrap() + ); + } else { + panic!("Expected scalar") + } } } diff --git a/infrastructure/test_utils/Cargo.toml b/infrastructure/test_utils/Cargo.toml index 531a0c412a..809e2b0f67 100644 --- a/infrastructure/test_utils/Cargo.toml +++ b/infrastructure/test_utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tari_test_utils" description = "Utility functions used in Tari test functions" -version = "0.38.4" +version = "0.38.5" authors = ["The Tari Development Community"] edition = "2018" license = "BSD-3-Clause" @@ -12,7 +12,7 @@ license = "BSD-3-Clause" tari_shutdown = { version = "*", path = "../shutdown" } futures = { version = "^0.3.1" } -rand = "0.8" +rand = "0.7.3" tokio = { version = "1.20", features = ["rt-multi-thread", "time", "sync"] } tempfile = "3.1.0" diff --git a/integration_tests/features/WalletCli.feature b/integration_tests/features/WalletCli.feature index 6766701946..5dc8fdcd19 100644 --- a/integration_tests/features/WalletCli.feature +++ b/integration_tests/features/WalletCli.feature @@ -66,8 +66,7 @@ Feature: Wallet CLI When I create a burn transaction of 201552500000 uT from WALLET via command line When I mine 5 blocks on BASE Then all nodes are at height 20 - # Then I wait for wallet WALLET to have at least 100 uT - Then I get balance of wallet WALLET is at most 18462621580 uT via command line + Then I get balance of wallet WALLET is at least 15000000000 uT via command line # TODO: verify the actual burned kernel @long-running diff --git a/integration_tests/features/WalletTransactions.feature b/integration_tests/features/WalletTransactions.feature index c5b7d55f4e..0b57c5d8a1 100644 --- a/integration_tests/features/WalletTransactions.feature +++ b/integration_tests/features/WalletTransactions.feature @@ -405,11 +405,15 @@ Feature: Wallet Transactions Given I have a seed node NODE And I have 2 base nodes connected to all seed nodes And I have wallet WALLET_A connected to all seed nodes - And I have mining node MINER connected to base node NODE and wallet WALLET_A - When mining node MINER mines 15 blocks + And I have wallet WALLET_B connected to all seed nodes + And I have mining node MINER_A connected to base node NODE and wallet WALLET_A + And I have mining node MINER_B connected to base node NODE and wallet WALLET_B + When mining node MINER_A mines 12 blocks + When mining node MINER_B mines 3 blocks Then all nodes are at height 15 - When I wait for wallet WALLET_A to have at least 55000000000 uT - When I create a burn transaction of 1000000 uT from WALLET_A at fee 100 - When mining node MINER mines 10 blocks - Then all nodes are at height 25 - Then wallet WALLET_A detects all transactions as Mined_Confirmed \ No newline at end of file + When I wait for wallet WALLET_A to have at least 221552530060 uT + When I create a burn transaction of 201552500000 uT from WALLET_A at fee 100 + When mining node MINER_B mines 5 blocks + Then all nodes are at height 20 + Then wallet WALLET_A detects all transactions as Mined_Confirmed + When I wait for wallet WALLET_A to have at least 20000000000 uT diff --git a/integration_tests/helpers/walletProcess.js b/integration_tests/helpers/walletProcess.js index 661ea1f22f..7868281d2f 100644 --- a/integration_tests/helpers/walletProcess.js +++ b/integration_tests/helpers/walletProcess.js @@ -285,6 +285,7 @@ class WalletProcess { "--non-interactive", "--network", "localnet", + "--enable-grpc", ]; if (this.logFilePath) { args.push("--log-config", this.logFilePath); diff --git a/package-lock.json b/package-lock.json index 7f5bfdaab6..e2497b00af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "tari", - "version": "0.38.4", + "version": "0.38.5", "lockfileVersion": 2, "requires": true, "packages": {}