diff --git a/.github/workflows/base_node_binaries.yml b/.github/workflows/base_node_binaries.yml index aec488f199..d7f7ae4127 100644 --- a/.github/workflows/base_node_binaries.yml +++ b/.github/workflows/base_node_binaries.yml @@ -20,7 +20,7 @@ env: jobs: builds: - name: Build and deploy tari_base_node + name: Build and upload Binaries strategy: fail-fast: false matrix: @@ -94,6 +94,7 @@ jobs: libappindicator3-dev \ patchelf \ librsvg2-dev + - name: Install macOS dependencies if: startsWith(runner.os,'macOS') run: brew install cmake zip coreutils automake autoconf @@ -141,6 +142,9 @@ jobs: ~/.cargo/git target key: ${{ runner.os }}-${{ matrix.os }}-${{ matrix.target_cpu }}-${{ matrix.features }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.os }}-${{ matrix.target_cpu }}-${{ matrix.features }}-cargo-build-target- + ${{ runner.os }}-${{ matrix.os }}-${{ matrix.target_cpu }}-${{ matrix.features }}- - name: Compile launchpad GUI run: | @@ -154,6 +158,12 @@ jobs: npm install npm run build + - name: Info - Pre-Compile Space Check for Nix + if: "!startsWith(runner.os,'Windows')" + shell: bash + run: | + df -h + - name: Build rust binaries env: RUSTFLAGS: "-C target_cpu=${{ matrix.target_cpu }}" @@ -162,6 +172,12 @@ jobs: echo "Cache Key: ${{ runner.os }}-${{ matrix.os }}-${{ matrix.target_cpu }}-${{ matrix.features }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}" cargo build --release + - name: Info - Post-Compile Space Check for Nix + if: "!startsWith(runner.os,'Windows')" + shell: bash + run: | + df -h + - name: Copy binaries to folder for zipping shell: bash run: | @@ -185,8 +201,9 @@ jobs: cp -v "$GITHUB_WORKSPACE/target/release/tari_launchpad${TBN_EXT}" . cp -v "$GITHUB_WORKSPACE/applications/tari_base_node/${PLATFORM_SPECIFIC_DIR}/runtime/start_tor${SHELL_EXT}" . - - name: Build the macos pkg + - name: Build the macOS pkg if: startsWith(runner.os,'macOS') + continue-on-error: true env: MACOS_KEYCHAIN_PASS: ${{ secrets.MACOS_KEYCHAIN_PASS }} MACOS_APPLICATION_ID: ${{ secrets.MACOS_APPLICATION_ID }} @@ -206,10 +223,19 @@ jobs: security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $MACOS_KEYCHAIN_PASS build.keychain cd buildtools ./create_osx_install_zip.sh unused nozip - FILES=("tari_base_node" "tari_console_wallet" "tari_mining_node" "tari_merge_mining_proxy") + FILES=( + "tari_base_node" + "tari_console_wallet" + "tari_mining_node" + "tari_merge_mining_proxy" + "tari_validator_node" + "tari_collectibles" + "tari_launchpad" + ) for FILE in "${FILES[@]}"; do codesign --force -s "Developer ID Application: $MACOS_APPLICATION_ID" "/tmp/tari_testnet/runtime/$FILE" -v codesign --verify --deep --display --verbose=4 "/tmp/tari_testnet/runtime/$FILE" + cp -vf "/tmp/tari_testnet/runtime/$FILE" "$GITHUB_WORKSPACE${{ env.TBN_DIST }}" done pkgbuild --root /tmp/tari_testnet \ --identifier "com.tarilabs.pkg" \ @@ -218,15 +244,17 @@ jobs: --scripts "/tmp/tari_testnet/scripts" \ --sign "Developer ID Installer: $MACOS_INSTALLER_ID" \ "${{ github.workspace }}${{ env.TBN_DIST }}/tari-${{ env.VERSION }}.pkg" - - name: Artifact macos pkg + + - name: Artifact upload for macOS pkg if: startsWith(runner.os,'macOS') + continue-on-error: true uses: actions/upload-artifact@v2 with: name: tari-${{ env.VERSION }}.pkg path: "${{ github.workspace }}${{ env.TBN_DIST }}/tari-${{ env.VERSION }}.pkg" # unlike inno script studio, iscc.exe doesn't run the [precompile] step generate_config.bat - - name: Build the windows installer + - name: Build the Windows installer shell: cmd if: startsWith(runner.os,'Windows') run: | @@ -234,7 +262,7 @@ jobs: call generate_config.bat "%programfiles(x86)%\Inno Setup 6\iscc.exe" "/DMyAppVersion=${{ env.VERSION }}-${{ env.VSHA_SHORT }}-release" "windows_inno_installer.iss" - - name: Upload artifact for Windows installer + - name: Artifact upload for Windows installer uses: actions/upload-artifact@v2 if: startsWith(runner.os,'Windows') with: @@ -255,14 +283,14 @@ jobs: ${SHARUN} --check "${{ env.BINFILE }}.zip.sha256" #rm -f "${BINFILE}" - - name: Artifact archive + - name: Artifact upload for Archive uses: actions/upload-artifact@v2 with: #name: ${{ env.TBN_FILENAME }}-${{ env.VERSION }}-${{ env.VSHA_SHORT }}-${{ matrix.os }}-${{ matrix.target_cpu }}-${{ matrix.features }} name: tari_binary_archive-${{ matrix.os }}-${{ matrix.target_cpu }} path: "${{ github.workspace }}${{ env.TBN_DIST }}/${{ env.BINFILE }}.zip*" - - name: Artifact miner + - name: Artifact upload for Miner uses: actions/upload-artifact@v2 with: name: tari_mining_node-${{ matrix.os }}-${{ matrix.target_cpu }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56d5a2bd43..ce9f7f6626 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,17 +24,13 @@ jobs: steps: - name: checkout uses: actions/checkout@v2 - - name: caching - uses: actions/cache@v2 + - name: toolchain + uses: actions-rs/toolchain@v1 with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-${{ runner.cpu-model }}-${{ env.toolchain }}-clippy-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-${{ runner.cpu-model }}-${{ env.toolchain }}-clippy- - ${{ runner.os }}-${{ runner.cpu-model }}-${{ env.toolchain }}- + toolchain: ${{ env.toolchain }} + components: clippy, rustfmt + override: true + - uses: Swatinem/rust-cache@v1 - name: ubuntu dependencies run: | sudo apt-get update && \ @@ -63,12 +59,6 @@ jobs: cd applications/launchpad/gui-vue npm ci npm run build - - name: toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ env.toolchain }} - components: clippy, rustfmt - override: true - name: cargo fmt uses: actions-rs/cargo@v1 with: @@ -85,17 +75,13 @@ jobs: steps: - name: checkout uses: actions/checkout@v2 - - name: caching - uses: actions/cache@v2 + - name: toolchain + uses: actions-rs/toolchain@v1 with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-${{ runner.cpu-model }}-${{ env.toolchain }}-build-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-${{ runner.cpu-model }}-${{ env.toolchain }}-build- - ${{ runner.os }}-${{ runner.cpu-model }}-${{ env.toolchain }}- + toolchain: ${{ env.toolchain }} + profile: minimal + override: true + - uses: Swatinem/rust-cache@v1 - name: ubuntu dependencies run: | sudo apt-get update && \ @@ -116,12 +102,6 @@ jobs: cd applications/launchpad/gui-vue npm ci npm run build - - name: toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ env.toolchain }} - components: clippy, rustfmt - override: true - name: cargo check uses: actions-rs/cargo@v1 with: @@ -133,17 +113,13 @@ jobs: steps: - name: checkout uses: actions/checkout@v2 - - name: caching - uses: actions/cache@v2 + - name: toolchain + uses: actions-rs/toolchain@v1 with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-${{ runner.cpu-model }}-stable-build-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-${{ runner.cpu-model }}-stable-build- - ${{ runner.os }}-${{ runner.cpu-model }}-stable- + toolchain: stable + profile: minimal + override: true + - uses: Swatinem/rust-cache@v1 - name: ubuntu dependencies run: | sudo apt-get update && \ @@ -164,12 +140,6 @@ jobs: cd applications/launchpad/gui-vue npm ci npm run build - - name: toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - profile: minimal - override: true - name: rustup show run: | rustup show @@ -180,22 +150,16 @@ jobs: args: --release --all-targets test: name: test - needs: build + # needs: build runs-on: ubuntu-18.04 steps: - name: checkout uses: actions/checkout@v2 - - name: caching - uses: actions/cache@v2 + - name: toolchain + uses: actions-rs/toolchain@v1 with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-${{ runner.cpu-model }}-${{ env.toolchain }}-test-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-${{ runner.cpu-model }}-${{ env.toolchain }}-test- - ${{ runner.os }}-${{ runner.cpu-model }}-${{ env.toolchain }}- + toolchain: ${{ env.toolchain }} + - uses: Swatinem/rust-cache@v1 - name: ubuntu dependencies run: | sudo apt-get update && \ @@ -216,12 +180,12 @@ jobs: cd applications/launchpad/gui-vue npm ci npm run build - - name: toolchain - uses: actions-rs/toolchain@v1 + - name: cargo test compile + uses: actions-rs/cargo@v1 with: - toolchain: ${{ env.toolchain }} + command: test + args: --no-run --locked - name: cargo test uses: actions-rs/cargo@v1 with: command: test - args: --release --all-targets diff --git a/Cargo.lock b/Cargo.lock index bb89122659..9453467596 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,6 +182,56 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +[[package]] +name = "ashpd" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7915e26e0786f91768d23de32afafa4ee5e2ea76be21c0ecd8e14441543c1655" +dependencies = [ + "enumflags2", + "futures 0.3.21", + "rand 0.8.4", + "serde 1.0.136", + "serde_repr", + "zbus", +] + +[[package]] +name = "async-broadcast" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90622698a1218e0b2fb846c97b5f19a0831f6baddee73d9454156365ccfa473b" +dependencies = [ + "easy-parallel", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + [[package]] name = "async-io" version = "1.6.0" @@ -201,6 +251,26 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "async-lock" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-recursion" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-stream" version = "0.3.2" @@ -222,6 +292,12 @@ dependencies = [ "syn", ] +[[package]] +name = "async-task" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d306121baf53310a3fd342d88dc0824f6bbeace68347593658525565abee8" + [[package]] name = "async-trait" version = "0.1.52" @@ -235,9 +311,9 @@ dependencies = [ [[package]] name = "atk" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a83b21d2aa75e464db56225e1bda2dd5993311ba1095acaa8fa03d1ae67026ba" +checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" dependencies = [ "atk-sys", "bitflags 1.3.2", @@ -247,30 +323,30 @@ dependencies = [ [[package]] name = "atk-sys" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badcf670157c84bb8b1cf6b5f70b650fed78da2033c9eed84c4e49b11cbe83ea" +checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" dependencies = [ - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys 0.15.5", + "gobject-sys 0.15.5", "libc", - "system-deps 3.2.0", + "system-deps 6.0.1", ] [[package]] name = "attohttpc" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8bda305457262b339322106c776e3fd21df860018e566eb6a5b1aa4b6ae02d" +checksum = "e69e13a99a7e6e070bb114f7ff381e58c7ccc188630121fc4c2fe4bcf24cd072" dependencies = [ "flate2", "http", "log", "native-tls", "openssl", - "serde 1.0.135", + "serde 1.0.136", "serde_json", - "serde_urlencoded 0.6.1", + "serde_urlencoded", "url 2.2.2", "wildmatch", ] @@ -288,15 +364,18 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.1.0", +] [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "autotools" @@ -369,7 +448,7 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -443,16 +522,16 @@ dependencies = [ [[package]] name = "blake3" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882e99e4a0cb2ae6cb6e442102e8e6b7131718d94110e64c3e6a34ea9b106f37" +checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" dependencies = [ "arrayref", "arrayvec 0.7.2", "cc", "cfg-if 1.0.0", "constant_time_eq", - "digest 0.10.1", + "digest 0.10.2", "rayon", ] @@ -486,9 +565,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ "generic-array 0.14.5", ] @@ -557,12 +636,12 @@ dependencies = [ "hyperlocal", "log", "pin-project 1.0.10", - "serde 1.0.135", + "serde 1.0.136", "serde_derive", "serde_json", - "serde_urlencoded 0.7.1", + "serde_urlencoded", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-util", "url 2.2.2", "winapi 0.3.9", @@ -575,7 +654,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2f2e73fffe9455141e170fb9c1feb0ac521ec7e7dcd47a7cab72a658490fb8" dependencies = [ "chrono", - "serde 1.0.135", + "serde 1.0.136", "serde_with", ] @@ -594,7 +673,7 @@ dependencies = [ "lazy_static 1.4.0", "memchr", "regex-automata", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -633,7 +712,7 @@ checksum = "adf4c9d0bbf32eea58d7c0f812058138ee8edaf0f2802b6d03561b504729a325" dependencies = [ "bincode", "byteorder", - "serde 1.0.135", + "serde 1.0.136", "trackable 0.2.24", ] @@ -661,7 +740,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" dependencies = [ - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -699,9 +778,9 @@ checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" [[package]] name = "cairo-rs" -version = "0.14.9" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b5725979db0c586d98abad2193cdb612dd40ef95cd26bd99851bf93b3cb482" +checksum = "b869e97a87170f96762f9f178eae8c461147e722ba21dd8814105bf5716bf14a" dependencies = [ "bitflags 1.3.2", "cairo-sys-rs", @@ -712,13 +791,24 @@ dependencies = [ [[package]] name = "cairo-sys-rs" -version = "0.14.9" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b448b876970834fda82ba3aeaccadbd760206b75388fc5c1b02f1e343b697570" +checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" dependencies = [ - "glib-sys 0.14.0", + "glib-sys 0.15.5", "libc", - "system-deps 3.2.0", + "system-deps 6.0.1", +] + +[[package]] +name = "cargo_toml" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e270ef0cd868745878982f7ce470aa898d0d4bb248af67f0cf66f54617913ef" +dependencies = [ + "serde 1.0.136", + "serde_derive", + "toml 0.5.8", ] [[package]] @@ -759,7 +849,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "syn", "tempfile", @@ -812,6 +902,15 @@ dependencies = [ "smallvec", ] +[[package]] +name = "cfg-expr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7" +dependencies = [ + "smallvec", +] + [[package]] name = "cfg-if" version = "0.1.10" @@ -870,8 +969,8 @@ dependencies = [ "libc", "num-integer", "num-traits 0.2.14", - "serde 1.0.135", - "time", + "serde 1.0.136", + "time 0.1.43", "winapi 0.3.9", ] @@ -882,7 +981,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6316c62053228eddd526a5e6deb6344c80bf2bc1e9786e7f90b3083e73197c1" dependencies = [ "bitstring", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -911,9 +1010,9 @@ checksum = "b0fc239e0f6cb375d2402d48afb92f76f5404fd1df208a41930ec81eda078bea" [[package]] name = "clang-sys" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90" +checksum = "4cc00842eed744b858222c4c9faf7243aafc6d33f92f96935263ef4d8a41ce21" dependencies = [ "glob", "libc", @@ -937,34 +1036,17 @@ dependencies = [ [[package]] name = "clap" -version = "3.0.0-beta.2" +version = "3.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142" +checksum = "b63edc3f163b3c71ec8aa23f9bd6070f77edbf3d1d198b164afa90ff00e4ec62" dependencies = [ "atty", "bitflags 1.3.2", - "clap_derive", "indexmap", - "lazy_static 1.4.0", "os_str_bytes", "strsim 0.10.0", "termcolor", - "textwrap 0.12.1", - "unicode-width", - "vec_map", -] - -[[package]] -name = "clap_derive" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153" -dependencies = [ - "heck 0.4.0", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", + "textwrap 0.14.2", ] [[package]] @@ -1005,8 +1087,8 @@ dependencies = [ "bitflags 1.3.2", "block", "cocoa-foundation", - "core-foundation 0.9.2", - "core-graphics 0.22.3", + "core-foundation", + "core-graphics", "foreign-types", "libc", "objc", @@ -1020,7 +1102,7 @@ checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" dependencies = [ "bitflags 1.3.2", "block", - "core-foundation 0.9.2", + "core-foundation", "core-graphics-types", "foreign-types", "libc", @@ -1033,37 +1115,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" -[[package]] -name = "com" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a30a2b2a013da986dc5cc3eda3d19c0d59d53f835be1b2356eb8d00f000c793" -dependencies = [ - "com_macros", -] - -[[package]] -name = "com_macros" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7606b05842fea68ddcc89e8053b8860ebcb2a0ba8d6abfe3a148e5d5a8d3f0c1" -dependencies = [ - "com_macros_support", - "proc-macro2", - "syn", -] - -[[package]] -name = "com_macros_support" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97e9a6d20f4ac8830e309a455d7e9416e65c6af5a97c88c55fbb4c2012e107da" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "concurrent-queue" version = "1.2.2" @@ -1082,7 +1133,7 @@ dependencies = [ "lazy_static 1.4.0", "nom 4.2.3", "rust-ini", - "serde 1.0.135", + "serde 1.0.136", "serde-hjson 0.8.2", "serde_json", "toml 0.4.10", @@ -1098,7 +1149,7 @@ dependencies = [ "lazy_static 1.4.0", "nom 5.1.2", "rust-ini", - "serde 1.0.135", + "serde 1.0.136", "serde-hjson 0.9.1", "serde_json", "toml 0.5.8", @@ -1129,48 +1180,20 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" -dependencies = [ - "core-foundation-sys 0.7.0", - "libc", -] - -[[package]] -name = "core-foundation" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ - "core-foundation-sys 0.8.3", + "core-foundation-sys", "libc", ] -[[package]] -name = "core-foundation-sys" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" - [[package]] name = "core-foundation-sys" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" -[[package]] -name = "core-graphics" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.7.0", - "foreign-types", - "libc", -] - [[package]] name = "core-graphics" version = "0.22.3" @@ -1178,7 +1201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.2", + "core-foundation", "core-graphics-types", "foreign-types", "libc", @@ -1191,24 +1214,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.2", + "core-foundation", "foreign-types", "libc", ] -[[package]] -name = "core-video-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" -dependencies = [ - "cfg-if 0.1.10", - "core-foundation-sys 0.7.0", - "core-graphics 0.19.2", - "libc", - "objc", -] - [[package]] name = "cpufeatures" version = "0.2.1" @@ -1232,9 +1242,9 @@ checksum = "fd121741cf3eb82c08dd3023eb55bf2665e5f60ec20f89760cf836ae4562e6a0" [[package]] name = "crc32fast" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ "cfg-if 1.0.0", ] @@ -1259,7 +1269,7 @@ dependencies = [ "rand_xoshiro", "rayon", "rayon-core", - "serde 1.0.135", + "serde 1.0.136", "serde_derive", "serde_json", "tinytemplate", @@ -1310,7 +1320,7 @@ dependencies = [ "crossbeam-deque", "crossbeam-epoch", "crossbeam-queue", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", ] [[package]] @@ -1329,7 +1339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", ] [[package]] @@ -1340,17 +1350,17 @@ checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", ] [[package]] name = "crossbeam-epoch" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762" +checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", "lazy_static 1.4.0", "memoffset", "scopeguard", @@ -1358,12 +1368,12 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b979d76c9fcb84dffc80a73f7290da0f83e4c95773494674cb44b76d13a7a110" +checksum = "4dd435b205a4842da59efd07628f921c096bc1cc0a156835b4fa0bcb9a19bcce" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", ] [[package]] @@ -1378,9 +1388,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" +checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" dependencies = [ "cfg-if 1.0.0", "lazy_static 1.4.0", @@ -1418,6 +1428,22 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "crossterm" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85525306c4291d1b73ce93c8acf9c339f9b213aef6c1d85c3830cbf1c16325c" +dependencies = [ + "bitflags 1.3.2", + "crossterm_winapi 0.9.0", + "libc", + "mio 0.7.14", + "parking_lot 0.11.2", + "signal-hook 0.3.13", + "signal-hook-mio", + "winapi 0.3.9", +] + [[package]] name = "crossterm_winapi" version = "0.6.2" @@ -1436,6 +1462,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "crossterm_winapi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "crunchy" version = "0.2.2" @@ -1444,9 +1479,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" +checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06" dependencies = [ "generic-array 0.14.5", ] @@ -1498,7 +1533,7 @@ dependencies = [ "csv-core", "itoa 0.4.8", "ryu", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -1510,6 +1545,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "ctor" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "ctr" version = "0.6.0" @@ -1558,7 +1603,7 @@ dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", - "serde 1.0.135", + "serde 1.0.136", "subtle", "zeroize", ] @@ -1573,7 +1618,7 @@ dependencies = [ "digest 0.9.0", "packed_simd_2", "rand_core 0.6.3", - "serde 1.0.135", + "serde 1.0.136", "subtle-ng", "zeroize", ] @@ -1812,13 +1857,12 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" +checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837" dependencies = [ - "block-buffer 0.10.0", + "block-buffer 0.10.2", "crypto-common", - "generic-array 0.14.5", "subtle", ] @@ -1885,6 +1929,12 @@ dependencies = [ "dtoa", ] +[[package]] +name = "easy-parallel" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946" + [[package]] name = "ed25519" version = "1.3.0" @@ -1903,8 +1953,8 @@ dependencies = [ "curve25519-dalek", "ed25519", "rand 0.7.3", - "serde 1.0.135", - "sha2", + "serde 1.0.136", + "sha2 0.9.9", "zeroize", ] @@ -1949,19 +1999,19 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.6.4" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0" +checksum = "a25c90b056b3f84111cf183cbeddef0d3a0bbe9a674f057e1a1533c315f24def" dependencies = [ "enumflags2_derive", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] name = "enumflags2_derive" -version = "0.6.4" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" +checksum = "144ec79496cbab6f84fa125dc67be9264aef22eb8a28da8454d9c33f15108da4" dependencies = [ "proc-macro2", "quote", @@ -2044,6 +2094,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f58da196a1fc8f14cb51f373f504efc66c434c577b777c2cd30d6fad16e4822" +[[package]] +name = "event-listener" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" + [[package]] name = "fake-simd" version = "0.1.2" @@ -2216,9 +2272,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" dependencies = [ "mac", "new_debug_unreachable", @@ -2232,9 +2288,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", @@ -2247,9 +2303,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -2257,15 +2313,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-executor" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -2274,9 +2330,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-lite" @@ -2295,9 +2351,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ "proc-macro2", "quote", @@ -2306,21 +2362,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-test" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e741bc851e1e90ad08901b329389ae77e02d5e9a0ec61955b80834630fbdc2f" +checksum = "8c3e9379dbbfb35dd6df79e895d73c0f75558827fe68eb853b858ff417a8ee98" dependencies = [ "futures-core", "futures-executor", @@ -2335,9 +2391,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ "futures 0.1.31", "futures-channel", @@ -2369,9 +2425,9 @@ checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" [[package]] name = "gdk" -version = "0.14.3" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d749dcfc00d8de0d7c3a289e04a04293eb5ba3d8a4e64d64911d481fa9933b" +checksum = "614258e81ec35ed8770e64a0838f3a47f95b398bc51e724d3b3fa09c1ee0f8d5" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -2385,10 +2441,11 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.14.0" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534192cb8f01daeb8fab2c8d4baa8f9aae5b7a39130525779f5c2608e235b10f" +checksum = "73aa2f5de1b45710da90a55863276667dc3a3264aaf6a2aeace62bb015244d49" dependencies = [ + "bitflags 1.3.2", "gdk-pixbuf-sys", "gio", "glib", @@ -2397,32 +2454,45 @@ dependencies = [ [[package]] name = "gdk-pixbuf-sys" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f097c0704201fbc8f69c1762dc58c6947c8bb188b8ed0bc7e65259f1894fe590" +checksum = "413424d9818621fa3cfc8a3a915cdb89a7c3c507d56761b4ec83a9a98e587171" dependencies = [ - "gio-sys 0.14.0", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "gio-sys 0.15.5", + "glib-sys 0.15.5", + "gobject-sys 0.15.5", "libc", - "system-deps 3.2.0", + "system-deps 6.0.1", ] [[package]] name = "gdk-sys" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e091b3d3d6696949ac3b3fb3c62090e5bfd7bd6850bef5c3c5ea701de1b1f1e" +checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", - "gio-sys 0.14.0", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "gio-sys 0.15.5", + "glib-sys 0.15.5", + "gobject-sys 0.15.5", "libc", "pango-sys", "pkg-config", - "system-deps 3.2.0", + "system-deps 6.0.1", +] + +[[package]] +name = "gdkx11-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178" +dependencies = [ + "gdk-sys", + "glib-sys 0.15.5", + "libc", + "system-deps 6.0.1", + "x11", ] [[package]] @@ -2525,15 +2595,15 @@ dependencies = [ [[package]] name = "gio" -version = "0.14.8" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711c3632b3ebd095578a9c091418d10fed492da9443f58ebc8f45efbeb215cb0" +checksum = "59105fa464928adf56b159c8d980cc11fbfbe414befb904caac5163d383049bf" dependencies = [ "bitflags 1.3.2", "futures-channel", "futures-core", "futures-io", - "gio-sys 0.14.0", + "gio-sys 0.15.5", "glib", "libc", "once_cell", @@ -2542,27 +2612,27 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.10.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e24fb752f8f5d2cf6bbc2c606fd2bc989c81c5e2fe321ab974d54f8b6344eac" +checksum = "c0a41df66e57fcc287c4bcf74fc26b884f31901ea9792ec75607289b456f48fa" dependencies = [ - "glib-sys 0.10.1", - "gobject-sys 0.10.0", + "glib-sys 0.14.0", + "gobject-sys 0.14.0", "libc", - "system-deps 1.3.2", + "system-deps 3.2.0", "winapi 0.3.9", ] [[package]] name = "gio-sys" -version = "0.14.0" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a41df66e57fcc287c4bcf74fc26b884f31901ea9792ec75607289b456f48fa" +checksum = "4f0bc4cfc9ebcdd05cc5057bc51b99c32f8f9bf246274f6a556ffd27279f8fe3" dependencies = [ - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys 0.15.5", + "gobject-sys 0.15.5", "libc", - "system-deps 3.2.0", + "system-deps 6.0.1", "winapi 0.3.9", ] @@ -2583,9 +2653,9 @@ dependencies = [ [[package]] name = "glib" -version = "0.14.8" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c515f1e62bf151ef6635f528d05b02c11506de986e43b34a5c920ef0b3796a4" +checksum = "41dcfbdb6cc6c02aee163339465d8a40d6f3f64c3a43f729a4195f0e153338b7" dependencies = [ "bitflags 1.3.2", "futures-channel", @@ -2593,21 +2663,22 @@ dependencies = [ "futures-executor", "futures-task", "glib-macros", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys 0.15.5", + "gobject-sys 0.15.5", "libc", "once_cell", "smallvec", + "thiserror", ] [[package]] name = "glib-macros" -version = "0.14.1" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aad66361f66796bfc73f530c51ef123970eb895ffba991a234fcf7bea89e518" +checksum = "e58b262ff65ef771003873cea8c10e0fe854f1c508d48d62a4111a1ff163f7d1" dependencies = [ "anyhow", - "heck 0.3.3", + "heck 0.4.0", "proc-macro-crate 1.1.0", "proc-macro-error", "proc-macro2", @@ -2617,22 +2688,22 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.10.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" +checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae" dependencies = [ "libc", - "system-deps 1.3.2", + "system-deps 3.2.0", ] [[package]] name = "glib-sys" -version = "0.14.0" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae" +checksum = "fa1d4e1a63d8574541e5b92931e4e669ddc87ffa85d58e84e631dba13ad2e10c" dependencies = [ "libc", - "system-deps 3.2.0", + "system-deps 6.0.1", ] [[package]] @@ -2656,31 +2727,31 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.10.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c" +checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5" dependencies = [ - "glib-sys 0.10.1", + "glib-sys 0.14.0", "libc", - "system-deps 1.3.2", + "system-deps 3.2.0", ] [[package]] name = "gobject-sys" -version = "0.14.0" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5" +checksum = "df6859463843c20cf3837e3a9069b6ab2051aeeadf4c899d33344f4aea83189a" dependencies = [ - "glib-sys 0.14.0", + "glib-sys 0.15.5", "libc", - "system-deps 3.2.0", + "system-deps 6.0.1", ] [[package]] name = "gtk" -version = "0.14.3" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb51122dd3317e9327ec1e4faa151d1fa0d95664cd8fb8dcfacf4d4d29ac70c" +checksum = "c7978eaec05bea63947c801d29a21372f2ed39aec0bf56bf7725d3599094675e" dependencies = [ "atk", "bitflags 1.3.2", @@ -2701,30 +2772,29 @@ dependencies = [ [[package]] name = "gtk-sys" -version = "0.14.0" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c14c8d3da0545785a7c5a120345b3abb534010fb8ae0f2ef3f47c027fba303e" +checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" dependencies = [ "atk-sys", "cairo-sys-rs", "gdk-pixbuf-sys", "gdk-sys", - "gio-sys 0.14.0", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "gio-sys 0.15.5", + "glib-sys 0.15.5", + "gobject-sys 0.15.5", "libc", "pango-sys", - "system-deps 3.2.0", + "system-deps 6.0.1", ] [[package]] name = "gtk3-macros" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21de1da96dc117443fb03c2e270b2d34b7de98d0a79a19bbb689476173745b79" +checksum = "8c891188af69e77a1e8a0b1746fbd03b9b396e7d34d518c5331b15950259f541" dependencies = [ "anyhow", - "heck 0.3.3", "proc-macro-crate 1.1.0", "proc-macro-error", "proc-macro2", @@ -2734,9 +2804,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9de88456263e249e241fcd211d3954e2c9b0ef7ccfc235a444eb367cae3689" +checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" dependencies = [ "bytes 1.1.0", "fnv", @@ -2746,7 +2816,7 @@ dependencies = [ "http", "indexmap", "slab", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-util", "tracing", ] @@ -2773,9 +2843,9 @@ dependencies = [ [[package]] name = "headers" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c4eb0471fcb85846d8b0690695ef354f9afb11cb03cac2e1d7c9253351afb0" +checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" dependencies = [ "base64 0.13.0", "bitflags 1.3.2", @@ -2784,7 +2854,7 @@ dependencies = [ "http", "httpdate", "mime", - "sha-1 0.9.8", + "sha-1 0.10.0", ] [[package]] @@ -2876,9 +2946,9 @@ checksum = "eee9694f83d9b7c09682fdb32213682939507884e5bcf227be9aff5d644b90dc" [[package]] name = "httparse" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" [[package]] name = "httpdate" @@ -2903,9 +2973,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.16" +version = "0.14.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" +checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd" dependencies = [ "bytes 1.1.0", "futures-channel", @@ -2916,10 +2986,10 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 0.4.8", + "itoa 1.0.1", "pin-project-lite 0.2.8", "socket2", - "tokio 1.15.0", + "tokio 1.16.1", "tower-service", "tracing", "want", @@ -2933,7 +3003,7 @@ checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ "hyper", "pin-project-lite 0.2.8", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-io-timeout", ] @@ -2946,7 +3016,7 @@ dependencies = [ "bytes 1.1.0", "hyper", "native-tls", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-native-tls", ] @@ -2960,7 +3030,7 @@ dependencies = [ "hex", "hyper", "pin-project 1.0.10", - "tokio 1.15.0", + "tokio 1.16.1", ] [[package]] @@ -3007,7 +3077,7 @@ version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" dependencies = [ - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", "globset", "lazy_static 1.4.0", "log", @@ -3039,7 +3109,7 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "hashbrown", ] @@ -3138,21 +3208,25 @@ checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "javascriptcore-rs" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca9c7d1445bba2889672fbadc16c3d5007bfdcf0a15a18a3a50fe9fab2c7427" +checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c" dependencies = [ + "bitflags 1.3.2", "glib", "javascriptcore-rs-sys", ] [[package]] name = "javascriptcore-rs-sys" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f46ada8a08dcd75a10afae872fbfb51275df4a8ae0d46b8cc7c708f08dd2998" +checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c" dependencies = [ + "glib-sys 0.15.5", + "gobject-sys 0.15.5", "libc", + "system-deps 5.0.0", ] [[package]] @@ -3179,6 +3253,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-patch" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f995a3c8f2bc3dd52a18a583e90f9ec109c047fa1603a853e46bcda14d2e279d" +dependencies = [ + "serde 1.0.136", + "serde_json", + "treediff", +] + [[package]] name = "json5" version = "0.2.8" @@ -3187,7 +3272,7 @@ checksum = "8eb2522ff59fbfefb955e9bd44d04d5e5c2d0e8865bfc2c3d1ab3916183ef5ee" dependencies = [ "pest", "pest_derive", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -3197,7 +3282,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f8423b78fc94d12ef1a4a9d13c348c9a78766dda0cc18817adf0faf77e670c8" dependencies = [ "base64-compat", - "serde 1.0.135", + "serde 1.0.136", "serde_derive", "serde_json", ] @@ -3266,9 +3351,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.113" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9" +checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" [[package]] name = "libgit2-sys" @@ -3313,9 +3398,9 @@ checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" [[package]] name = "libm" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" +checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db" [[package]] name = "libsqlite3-sys" @@ -3436,9 +3521,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ "scopeguard", ] @@ -3450,7 +3535,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if 1.0.0", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -3473,7 +3558,7 @@ dependencies = [ "libc", "log", "log-mdc", - "serde 1.0.135", + "serde 1.0.136", "serde-value 0.5.3", "serde_derive", "serde_yaml", @@ -3499,7 +3584,7 @@ dependencies = [ "log-mdc", "parking_lot 0.11.2", "regex", - "serde 1.0.135", + "serde 1.0.136", "serde-value 0.7.0", "serde_json", "serde_yaml", @@ -3518,10 +3603,10 @@ dependencies = [ "cfg-if 1.0.0", "generator", "scoped-tls", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "tracing", - "tracing-subscriber 0.3.6", + "tracing-subscriber 0.3.8", ] [[package]] @@ -3618,7 +3703,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", ] [[package]] @@ -3670,12 +3755,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "minisign-verify" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0507fe8e3c68cd62961cf9f87f6c2b21d884d3515a7150a4a3fa9d014e5c12" - [[package]] name = "miniz_oxide" version = "0.3.7" @@ -3692,7 +3771,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", - "autocfg 1.0.1", + "autocfg 1.1.0", ] [[package]] @@ -3759,7 +3838,7 @@ dependencies = [ "fixed-hash", "hex", "hex-literal", - "serde 1.0.135", + "serde 1.0.136", "serde-big-array", "thiserror", "tiny-keccak", @@ -3777,7 +3856,7 @@ dependencies = [ "data-encoding", "multihash", "percent-encoding 2.1.0", - "serde 1.0.135", + "serde 1.0.136", "static_assertions", "unsigned-varint", "url 2.2.2", @@ -3832,16 +3911,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "nb-connect" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1bb540dc6ef51cfe1916ec038ce7a620daf3a111e2502d745197cd53d6bca15" -dependencies = [ - "libc", - "socket2", -] - [[package]] name = "ndk" version = "0.4.0" @@ -3920,19 +3989,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "nix" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" -dependencies = [ - "bitflags 1.3.2", - "cc", - "cfg-if 0.1.10", - "libc", - "void", -] - [[package]] name = "nix" version = "0.23.1" @@ -3981,12 +4037,12 @@ dependencies = [ [[package]] name = "notify-rust" -version = "4.5.5" +version = "4.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ebab865e67efdd7182a88d76cadbdd2a8d02d1c7a4e16bb7c234016a12cac" +checksum = "367e1355a950d3e758e414f3ca1b3981a57a2aa1fa3338eb0059f5b230b6ffa4" dependencies = [ "mac-notification-sys", - "serde 1.0.135", + "serde 1.0.136", "winrt-notification", "zbus", "zvariant", @@ -3995,9 +4051,9 @@ dependencies = [ [[package]] name = "ntapi" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" dependencies = [ "winapi 0.3.9", ] @@ -4008,7 +4064,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "num-integer", "num-traits 0.2.14", ] @@ -4019,15 +4075,15 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d51546d704f52ef14b3c962b5776e53d5b862e5790e40a350d366c209bd7f7a" dependencies = [ - "autocfg 0.1.7", + "autocfg 0.1.8", "byteorder", "lazy_static 1.4.0", - "libm 0.2.1", + "libm 0.2.2", "num-integer", "num-iter", "num-traits 0.2.14", "rand 0.7.3", - "serde 1.0.135", + "serde 1.0.136", "smallvec", "zeroize", ] @@ -4059,7 +4115,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "num-traits 0.2.14", ] @@ -4069,7 +4125,7 @@ version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "num-integer", "num-traits 0.2.14", ] @@ -4080,7 +4136,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "num-integer", "num-traits 0.2.14", ] @@ -4100,7 +4156,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", ] [[package]] @@ -4134,6 +4190,15 @@ dependencies = [ "syn", ] +[[package]] +name = "num_threads" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15" +dependencies = [ + "libc", +] + [[package]] name = "objc" version = "0.2.7" @@ -4141,6 +4206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", + "objc_exception", ] [[package]] @@ -4154,6 +4220,15 @@ dependencies = [ "objc_id", ] +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + [[package]] name = "objc_id" version = "0.1.1" @@ -4226,7 +4301,7 @@ version = "0.9.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "cc", "libc", "openssl-src", @@ -4242,14 +4317,14 @@ checksum = "e1cf9b1c4e9a6c4de793c632496fa490bdc0e1eea73f0c91394f7b6990935d22" dependencies = [ "async-trait", "crossbeam-channel 0.5.2", - "futures 0.3.19", + "futures 0.3.21", "js-sys", "lazy_static 1.4.0", "percent-encoding 2.1.0", "pin-project 1.0.10", "rand 0.8.4", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-stream", ] @@ -4283,7 +4358,7 @@ dependencies = [ "reqwest", "thiserror", "thrift", - "tokio 1.15.0", + "tokio 1.16.1", ] [[package]] @@ -4313,22 +4388,32 @@ dependencies = [ "num-traits 0.2.14", ] +[[package]] +name = "ordered-stream" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1" +dependencies = [ + "futures-core", + "pin-project-lite 0.2.8", +] + [[package]] name = "os_info" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198e392be7e882f0c2836f425e430f81d9a0e99651e4646311347417cddbfd43" +checksum = "023df84d545ef479cf67fd2f4459a613585c9db4852c2fad12ab70587859d340" dependencies = [ "log", - "serde 1.0.135", + "serde 1.0.136", "winapi 0.3.9", ] [[package]] name = "os_pipe" -version = "0.9.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb233f06c2307e1f5ce2ecad9f8121cffbbee2c95428f44ea85222e460d0d213" +checksum = "0e3492ebca331b895fe23ed427dce2013d9b2e00c45964f12040b0db38b8ab27" dependencies = [ "libc", "winapi 0.3.9", @@ -4336,25 +4421,28 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "2.4.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] [[package]] name = "packed_simd_2" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c0c06716cfc81616fa8e22b721ce92fecd594508bc0eb3d04ae3ef35ac10c5" +checksum = "defdcfef86dcc44ad208f71d9ff4ce28df6537a4e0d6b0e8e845cb8ca10059a6" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libm 0.1.4", ] [[package]] name = "pango" -version = "0.14.8" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546fd59801e5ca735af82839007edd226fe7d3bb06433ec48072be4439c28581" +checksum = "79211eff430c29cc38c69e0ab54bc78fa1568121ca9737707eee7f92a8417a94" dependencies = [ "bitflags 1.3.2", "glib", @@ -4365,14 +4453,14 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2367099ca5e761546ba1d501955079f097caa186bb53ce0f718dca99ac1942fe" +checksum = "7022c2fb88cd2d9d55e1a708a8c53a3ae8678234c4a54bf623400aeb7f31fac2" dependencies = [ - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys 0.15.5", + "gobject-sys 0.15.5", "libc", - "system-deps 3.2.0", + "system-deps 6.0.1", ] [[package]] @@ -4398,7 +4486,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", - "lock_api 0.4.5", + "lock_api 0.4.6", "parking_lot_core 0.8.5", ] @@ -4595,7 +4683,7 @@ dependencies = [ "ripemd160", "rsa", "sha-1 0.9.8", - "sha2", + "sha2 0.9.9", "sha3", "signature", "smallvec", @@ -4805,6 +4893,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "pollster" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7" + [[package]] name = "poly1305" version = "0.7.2" @@ -4979,9 +5073,9 @@ dependencies = [ [[package]] name = "protobuf" -version = "2.25.2" +version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c327e191621a2158159df97cdbc2e7074bb4e940275e35abf38eb3d2595754" +checksum = "cf7e6d18738ecd0902d30d1ad232c9125985a3422929b16c65517b38adc14f96" [[package]] name = "qrcode" @@ -5170,16 +5264,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "raw-window-handle" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76" -dependencies = [ - "libc", - "raw-window-handle 0.4.2", -] - [[package]] name = "raw-window-handle" version = "0.4.2" @@ -5195,7 +5279,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "crossbeam-deque", "either", "rayon-core", @@ -5209,7 +5293,7 @@ checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" dependencies = [ "crossbeam-channel 0.5.2", "crossbeam-deque", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", "lazy_static 1.4.0", "num_cpus", ] @@ -5318,10 +5402,10 @@ dependencies = [ "native-tls", "percent-encoding 2.1.0", "pin-project-lite 0.2.8", - "serde 1.0.135", + "serde 1.0.136", "serde_json", - "serde_urlencoded 0.7.1", - "tokio 1.15.0", + "serde_urlencoded", + "tokio 1.16.1", "tokio-native-tls", "url 2.2.2", "wasm-bindgen", @@ -5332,25 +5416,28 @@ dependencies = [ [[package]] name = "rfd" -version = "0.4.4" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609ed912e110af7d7084b6b17d2a68b25e766208e015a37beba1be3c2d7cbb3b" +checksum = "2aaf1d71ccd44689f7c2c72da1117fd8db71f72a76fe9b5c5dbb17ab903007e0" dependencies = [ + "ashpd", "block", "dispatch", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys 0.15.5", + "gobject-sys 0.15.5", "gtk-sys", "js-sys", "lazy_static 1.4.0", + "log", "objc", "objc-foundation", "objc_id", - "raw-window-handle 0.3.4", + "pollster", + "raw-window-handle", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winapi 0.3.9", + "windows 0.30.0", ] [[package]] @@ -5397,7 +5484,7 @@ checksum = "011e1d58446e9fa3af7cdc1fb91295b10621d3ac4cb3a85cc86385ee9ca50cd3" dependencies = [ "byteorder", "rmp", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -5425,7 +5512,7 @@ dependencies = [ "num-traits 0.2.14", "pem", "rand 0.7.3", - "sha2", + "sha2 0.9.9", "simple_asn1", "subtle", "thiserror", @@ -5441,7 +5528,7 @@ dependencies = [ "base64 0.13.0", "blake2b_simd", "constant_time_eq", - "crossbeam-utils 0.8.6", + "crossbeam-utils 0.8.7", ] [[package]] @@ -5477,7 +5564,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.4", + "semver 1.0.5", ] [[package]] @@ -5496,15 +5583,23 @@ dependencies = [ [[package]] name = "rustls" -version = "0.19.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" dependencies = [ - "base64 0.13.0", "log", "ring", "sct", - "webpki", + "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]] @@ -5527,7 +5622,7 @@ dependencies = [ "libc", "log", "memchr", - "nix 0.23.1", + "nix", "radix_trie", "scopeguard", "smallvec", @@ -5601,9 +5696,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sct" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ "ring", "untrusted", @@ -5611,24 +5706,24 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d09d3c15d814eda1d6a836f2f2b56a6abc1446c8a34351cb3180d3db92ffe4ce" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.2", - "core-foundation-sys 0.8.3", + "core-foundation", + "core-foundation-sys", "libc", "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90dd10c41c6bfc633da6e0c659bd25d31e0791e5974ac42970267d59eba87f7" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" dependencies = [ - "core-foundation-sys 0.8.3", + "core-foundation-sys", "libc", ] @@ -5663,9 +5758,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" +checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7" [[package]] name = "semver-parser" @@ -5684,9 +5779,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" [[package]] name = "serde" -version = "1.0.135" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cf9235533494ea2ddcdb794665461814781c53f19d87b76e571a1c35acbad2b" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] @@ -5697,7 +5792,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18b20e7752957bbe9661cff4e0bb04d183d0948cdab2ea58cdb9df36a61dfe62" dependencies = [ - "serde 1.0.135", + "serde 1.0.136", "serde_derive", ] @@ -5733,7 +5828,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a663f873dedc4eac1a559d4c6bc0d0b2c34dc5ac4702e105014b8281489e44f" dependencies = [ "ordered-float 1.1.1", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -5743,14 +5838,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ "ordered-float 2.10.0", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] name = "serde_derive" -version = "1.0.135" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dcde03d87d4c973c04be249e7d8f0b35db1c848c487bd43032808e59dd8328d" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -5765,7 +5860,7 @@ checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" dependencies = [ "itoa 1.0.1", "ryu", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -5788,18 +5883,6 @@ dependencies = [ "serde 0.8.23", ] -[[package]] -name = "serde_urlencoded" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" -dependencies = [ - "dtoa", - "itoa 0.4.8", - "serde 1.0.135", - "url 2.2.2", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -5809,17 +5892,17 @@ dependencies = [ "form_urlencoded", "itoa 1.0.1", "ryu", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] name = "serde_with" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad6056b4cb69b6e43e3a0f055def223380baecc99da683884f205bf347f7c4b3" +checksum = "ec1e6ec4d8950e5b1e894eac0d360742f3b1407a6078a604a731c4b3f49cefbc" dependencies = [ "rustversion", - "serde 1.0.135", + "serde 1.0.136", "serde_with_macros", ] @@ -5843,10 +5926,32 @@ checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" dependencies = [ "indexmap", "ryu", - "serde 1.0.135", + "serde 1.0.136", "yaml-rust", ] +[[package]] +name = "serialize-to-javascript" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +dependencies = [ + "serde 1.0.136", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "servo_arc" version = "0.1.1" @@ -5882,6 +5987,17 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.2", +] + [[package]] name = "sha1" version = "0.6.0" @@ -5901,6 +6017,17 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha2" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.2", +] + [[package]] name = "sha3" version = "0.9.1" @@ -5924,9 +6051,9 @@ dependencies = [ [[package]] name = "shared_child" -version = "0.3.5" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6be9f7d5565b1483af3e72975e2dee33879b3b86bd48c0929fccf6585d79e65a" +checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" dependencies = [ "libc", "winapi 0.3.9", @@ -6026,34 +6153,33 @@ dependencies = [ "rand 0.8.4", "rand_core 0.6.3", "rustc_version 0.3.3", - "sha2", + "sha2 0.9.9", "subtle", "x25519-dalek", ] [[package]] name = "socket2" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f82496b90c36d70af5fcd482edaa2e0bd16fade569de1330405fecbbdac736b" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" dependencies = [ "libc", "winapi 0.3.9", ] [[package]] -name = "soup-sys" -version = "0.10.0" +name = "soup2-sys" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7adf08565630bbb71f955f11f8a68464817ded2703a3549747c235b58a13e" +checksum = "9f056675eda9a7417163e5f742bb119e8e1d385edd2ada8f7031a7230a3ec10a" dependencies = [ "bitflags 1.3.2", - "gio-sys 0.10.1", - "glib-sys 0.10.1", - "gobject-sys 0.10.0", + "gio-sys 0.14.0", + "glib-sys 0.14.0", + "gobject-sys 0.14.0", "libc", - "pkg-config", - "system-deps 1.3.2", + "system-deps 5.0.0", ] [[package]] @@ -6097,16 +6223,16 @@ checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" [[package]] name = "string_cache" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923f0f39b6267d37d23ce71ae7235602134b250ace715dd2c90421998ddac0c6" +checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26" dependencies = [ "lazy_static 1.4.0", "new_debug_unreachable", "parking_lot 0.11.2", - "phf_shared 0.8.0", + "phf_shared 0.10.0", "precomputed-hash", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -6163,12 +6289,6 @@ dependencies = [ "syn", ] -[[package]] -name = "strum" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" - [[package]] name = "strum" version = "0.21.0" @@ -6190,18 +6310,6 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" -[[package]] -name = "strum_macros" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "strum_macros" version = "0.21.1" @@ -6281,18 +6389,13 @@ dependencies = [ ] [[package]] -name = "system-deps" -version = "1.3.2" +name = "sys-info" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" +checksum = "0b3a0d0aba8bf96a0e1ddfdc352fc53b3df7f39318c71854910c3c4b024ae52c" dependencies = [ - "heck 0.3.3", - "pkg-config", - "strum 0.18.0", - "strum_macros 0.18.0", - "thiserror", - "toml 0.5.8", - "version-compare 0.0.10", + "cc", + "libc", ] [[package]] @@ -6302,7 +6405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6" dependencies = [ "anyhow", - "cfg-expr", + "cfg-expr 0.8.1", "heck 0.3.3", "itertools 0.10.3", "pkg-config", @@ -6313,27 +6416,53 @@ dependencies = [ "version-compare 0.0.11", ] +[[package]] +name = "system-deps" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e" +dependencies = [ + "cfg-expr 0.9.1", + "heck 0.3.3", + "pkg-config", + "toml 0.5.8", + "version-compare 0.0.11", +] + +[[package]] +name = "system-deps" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad3a97fdef3daf935d929b3e97e5a6a680cd4622e40c2941ca0875d6566416f8" +dependencies = [ + "cfg-expr 0.9.1", + "heck 0.4.0", + "pkg-config", + "toml 0.5.8", + "version-compare 0.1.0", +] + [[package]] name = "tao" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aa57de7c282b68f8906278543a724ed8f5a2568f069dd0cc05fc10d1f07036b" +checksum = "402f170c4da28cc3108d854c7567d6904c82fc0e30e5b69f2a6b3e48f8a4f705" dependencies = [ "bitflags 1.3.2", "cairo-rs", "cc", "cocoa", - "core-foundation 0.9.2", - "core-graphics 0.22.3", - "core-video-sys", + "core-foundation", + "core-graphics", "crossbeam-channel 0.5.2", "dispatch", "gdk", "gdk-pixbuf", "gdk-sys", + "gdkx11-sys", "gio", "glib", - "glib-sys 0.14.0", + "glib-sys 0.15.5", "gtk", "instant", "lazy_static 1.4.0", @@ -6344,14 +6473,28 @@ dependencies = [ "ndk-sys", "objc", "parking_lot 0.11.2", - "raw-window-handle 0.3.4", + "raw-window-handle", "scopeguard", - "serde 1.0.135", + "serde 1.0.136", + "tao-core-video-sys", "unicode-segmentation", - "winapi 0.3.9", + "windows 0.30.0", + "windows_macros", "x11-dl", ] +[[package]] +name = "tao-core-video-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271450eb289cb4d8d0720c6ce70c72c8c858c93dd61fc625881616752e6b98f6" +dependencies = [ + "cfg-if 1.0.0", + "core-foundation-sys", + "libc", + "objc", +] + [[package]] name = "tar" version = "0.4.38" @@ -6365,7 +6508,7 @@ dependencies = [ [[package]] name = "tari_app_grpc" -version = "0.27.3" +version = "0.28.0" dependencies = [ "chrono", "prost", @@ -6381,15 +6524,15 @@ dependencies = [ [[package]] name = "tari_app_utilities" -version = "0.27.3" +version = "0.28.0" dependencies = [ "config 0.9.3", "dirs-next 1.0.2", - "futures 0.3.19", + "futures 0.3.21", "json5", "log", "rand 0.8.4", - "serde 1.0.135", + "serde 1.0.136", "structopt", "tari_common", "tari_common_types", @@ -6398,19 +6541,20 @@ dependencies = [ "tari_p2p", "tari_utilities", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", ] [[package]] name = "tari_base_node" -version = "0.27.3" +version = "0.28.0" dependencies = [ "anyhow", "bincode", "chrono", "config 0.9.3", + "crossterm 0.22.1", "either", - "futures 0.3.19", + "futures 0.3.21", "log", "log-mdc", "num_cpus", @@ -6437,7 +6581,7 @@ dependencies = [ "tari_shutdown", "tari_utilities", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tonic", "tracing", "tracing-opentelemetry", @@ -6457,7 +6601,7 @@ dependencies = [ "merlin", "rand 0.8.4", "rand_core 0.6.3", - "serde 1.0.135", + "serde 1.0.136", "serde_derive", "sha3", "subtle-ng", @@ -6471,12 +6615,12 @@ dependencies = [ "blake2", "diesel", "diesel_migrations", - "futures 0.3.19", + "futures 0.3.21", "log", "prost", "prost-types", "rand 0.8.4", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "structopt", "tari_app_grpc", @@ -6491,14 +6635,14 @@ dependencies = [ "tauri", "tauri-build", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tonic", "uuid", ] [[package]] name = "tari_common" -version = "0.27.3" +version = "0.28.0" dependencies = [ "anyhow", "config 0.9.3", @@ -6511,12 +6655,12 @@ dependencies = [ "multiaddr", "path-clean", "prost-build", - "serde 1.0.135", + "serde 1.0.136", "serde_json", - "sha2", + "sha2 0.9.9", "structopt", "tari_storage", - "tari_test_utils 0.27.3", + "tari_test_utils 0.28.0", "tempfile", "thiserror", "toml 0.5.8", @@ -6524,7 +6668,7 @@ dependencies = [ [[package]] name = "tari_common_sqlite" -version = "0.27.3" +version = "0.28.0" dependencies = [ "diesel", "log", @@ -6533,21 +6677,21 @@ dependencies = [ [[package]] name = "tari_common_types" -version = "0.27.3" +version = "0.28.0" dependencies = [ "digest 0.9.0", "lazy_static 1.4.0", "rand 0.8.4", - "serde 1.0.135", + "serde 1.0.136", "tari_crypto", "tari_utilities", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", ] [[package]] name = "tari_comms" -version = "0.27.3" +version = "0.28.0" dependencies = [ "anyhow", "async-trait", @@ -6560,7 +6704,7 @@ dependencies = [ "data-encoding", "digest 0.9.0", "env_logger 0.7.1", - "futures 0.3.19", + "futures 0.3.21", "lazy_static 1.4.0", "lmdb-zero", "log", @@ -6573,7 +6717,7 @@ dependencies = [ "prost", "prost-types", "rand 0.8.4", - "serde 1.0.135", + "serde 1.0.136", "serde_derive", "serde_json", "snow", @@ -6583,10 +6727,10 @@ dependencies = [ "tari_metrics", "tari_shutdown", "tari_storage", - "tari_test_utils 0.27.3", + "tari_test_utils 0.28.0", "tempfile", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-stream", "tokio-util", "tower", @@ -6596,7 +6740,7 @@ dependencies = [ [[package]] name = "tari_comms_dht" -version = "0.27.3" +version = "0.28.0" dependencies = [ "anyhow", "bitflags 1.3.2", @@ -6608,7 +6752,7 @@ dependencies = [ "diesel_migrations", "digest 0.9.0", "env_logger 0.7.1", - "futures 0.3.19", + "futures 0.3.21", "futures-test", "futures-util", "lazy_static 1.4.0", @@ -6621,7 +6765,7 @@ dependencies = [ "prost", "prost-types", "rand 0.8.4", - "serde 1.0.135", + "serde 1.0.136", "serde_derive", "tari_common", "tari_common_sqlite", @@ -6630,39 +6774,39 @@ dependencies = [ "tari_crypto", "tari_shutdown", "tari_storage", - "tari_test_utils 0.27.3", + "tari_test_utils 0.28.0", "tari_utilities", "tempfile", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-stream", "tower", ] [[package]] name = "tari_comms_rpc_macros" -version = "0.27.3" +version = "0.28.0" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "proc-macro2", "prost", "quote", "syn", "tari_comms", - "tari_test_utils 0.27.3", - "tokio 1.15.0", + "tari_test_utils 0.28.0", + "tokio 1.16.1", "tower-service", ] [[package]] name = "tari_console_wallet" -version = "0.27.3" +version = "0.28.0" dependencies = [ "bitflags 1.3.2", "chrono", "crossterm 0.17.7", "digest 0.9.0", - "futures 0.3.19", + "futures 0.3.21", "log", "opentelemetry", "opentelemetry-jaeger", @@ -6671,7 +6815,7 @@ dependencies = [ "regex", "rpassword", "rustyline", - "sha2", + "sha2 0.9.9", "strum 0.22.0", "strum_macros 0.22.0", "tari_app_grpc", @@ -6689,7 +6833,7 @@ dependencies = [ "tari_utilities", "tari_wallet", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tonic", "tracing", "tracing-opentelemetry", @@ -6701,7 +6845,7 @@ dependencies = [ [[package]] name = "tari_core" -version = "0.27.3" +version = "0.28.0" dependencies = [ "async-trait", "bincode", @@ -6716,7 +6860,7 @@ dependencies = [ "digest 0.9.0", "env_logger 0.7.1", "fs2 0.3.0", - "futures 0.3.19", + "futures 0.3.21", "hex", "integer-encoding 3.0.2", "lmdb-zero", @@ -6730,7 +6874,7 @@ dependencies = [ "prost-types", "rand 0.8.4", "randomx-rs", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "sha3", "strum_macros 0.22.0", @@ -6746,11 +6890,11 @@ dependencies = [ "tari_service_framework", "tari_shutdown", "tari_storage", - "tari_test_utils 0.27.3", + "tari_test_utils 0.28.0", "tari_utilities", "tempfile", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tracing", "tracing-attributes", "uint", @@ -6771,9 +6915,9 @@ dependencies = [ "merlin", "rand 0.8.4", "rmp-serde", - "serde 1.0.135", + "serde 1.0.136", "serde_json", - "sha2", + "sha2 0.9.9", "sha3", "tari_bulletproofs", "tari_utilities", @@ -6799,13 +6943,14 @@ dependencies = [ "bytecodec", "clap 2.34.0", "digest 0.9.0", - "futures 0.3.19", + "futures 0.3.21", "lmdb-zero", "log", "patricia_tree", "prost", "prost-types", - "serde 1.0.135", + "rand 0.8.4", + "serde 1.0.136", "serde_json", "tari_common", "tari_common_types", @@ -6823,7 +6968,7 @@ dependencies = [ "tari_test_utils 0.8.1", "tari_utilities", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-stream", ] @@ -6842,13 +6987,13 @@ dependencies = [ "tari_dan_core", "tari_utilities", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-stream", ] [[package]] name = "tari_key_manager" -version = "0.27.3" +version = "0.28.0" dependencies = [ "argon2", "arrayvec 0.7.2", @@ -6862,10 +7007,10 @@ dependencies = [ "getrandom 0.2.4", "js-sys", "rand 0.8.4", - "serde 1.0.135", + "serde 1.0.136", "serde_derive", "serde_json", - "sha2", + "sha2 0.9.9", "strum 0.22.0", "strum_macros 0.22.0", "tari_common_types", @@ -6877,15 +7022,15 @@ dependencies = [ [[package]] name = "tari_launchpad" -version = "0.27.3" +version = "0.28.0" dependencies = [ "bollard", "config 0.11.0", "env_logger 0.9.0", - "futures 0.3.19", + "futures 0.3.21", "log", "rand 0.8.4", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "strum 0.23.0", "strum_macros 0.23.1", @@ -6894,7 +7039,7 @@ dependencies = [ "tauri", "tauri-build", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tor-hash-passwd", ] @@ -6915,7 +7060,7 @@ dependencies = [ [[package]] name = "tari_merge_mining_proxy" -version = "0.27.3" +version = "0.28.0" dependencies = [ "anyhow", "bincode", @@ -6923,14 +7068,14 @@ dependencies = [ "chrono", "config 0.9.3", "env_logger 0.7.1", - "futures 0.3.19", + "futures 0.3.21", "hex", "hyper", "jsonrpc", "log", "rand 0.8.4", "reqwest", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "structopt", "tari_app_grpc", @@ -6941,7 +7086,7 @@ dependencies = [ "tari_crypto", "tari_utilities", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tonic", "tracing", "url 2.2.2", @@ -6952,24 +7097,24 @@ name = "tari_metrics" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.19", + "futures 0.3.21", "log", "once_cell", "prometheus", "reqwest", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "warp", ] [[package]] name = "tari_mining_node" -version = "0.27.3" +version = "0.28.0" dependencies = [ "bufstream", "chrono", "crossbeam", - "futures 0.3.19", + "futures 0.3.21", "hex", "log", "native-tls", @@ -6977,7 +7122,7 @@ dependencies = [ "prost-types", "rand 0.8.4", "reqwest", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "sha3", "tari_app_grpc", @@ -6988,13 +7133,13 @@ dependencies = [ "tari_crypto", "tari_utilities", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tonic", ] [[package]] name = "tari_mmr" -version = "0.27.3" +version = "0.28.0" dependencies = [ "bincode", "blake2", @@ -7003,7 +7148,7 @@ dependencies = [ "digest 0.9.0", "log", "rand 0.8.4", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "tari_crypto", "tari_utilities", @@ -7012,14 +7157,14 @@ dependencies = [ [[package]] name = "tari_p2p" -version = "0.27.3" +version = "0.28.0" dependencies = [ "anyhow", "bytes 0.5.6", "chrono", "clap 2.34.0", "fs2 0.3.0", - "futures 0.3.19", + "futures 0.3.21", "lazy_static 1.4.0", "lmdb-zero", "log", @@ -7029,8 +7174,8 @@ dependencies = [ "rand 0.8.4", "reqwest", "rustls", - "semver 1.0.4", - "serde 1.0.135", + "semver 1.0.5", + "serde 1.0.136", "serde_derive", "tari_common", "tari_comms", @@ -7039,52 +7184,52 @@ dependencies = [ "tari_service_framework", "tari_shutdown", "tari_storage", - "tari_test_utils 0.27.3", + "tari_test_utils 0.28.0", "tari_utilities", "tempfile", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-stream", "tower", "tower-service", "trust-dns-client", - "webpki", + "webpki 0.21.4", ] [[package]] name = "tari_service_framework" -version = "0.27.3" +version = "0.28.0" dependencies = [ "anyhow", "async-trait", - "futures 0.3.19", + "futures 0.3.21", "futures-test", "log", "tari_shutdown", - "tari_test_utils 0.27.3", + "tari_test_utils 0.28.0", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tower", "tower-service", ] [[package]] name = "tari_shutdown" -version = "0.27.3" +version = "0.28.0" dependencies = [ - "futures 0.3.19", - "tokio 1.15.0", + "futures 0.3.21", + "tokio 1.16.1", ] [[package]] name = "tari_storage" -version = "0.27.3" +version = "0.28.0" dependencies = [ "bincode", "lmdb-zero", "log", "rand 0.8.4", - "serde 1.0.135", + "serde 1.0.136", "serde_derive", "tari_utilities", "thiserror", @@ -7092,11 +7237,11 @@ dependencies = [ [[package]] name = "tari_stratum_ffi" -version = "0.27.3" +version = "0.28.0" dependencies = [ "hex", "libc", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "tari_common", "tari_comms", @@ -7108,21 +7253,21 @@ dependencies = [ [[package]] name = "tari_stratum_transcoder" -version = "0.27.3" +version = "0.28.0" dependencies = [ "bincode", "bytes 0.5.6", "chrono", "config 0.9.3", "env_logger 0.7.1", - "futures 0.3.19", + "futures 0.3.21", "hex", "hyper", "jsonrpc", "log", "rand 0.7.3", "reqwest", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "structopt", "tari_app_grpc", @@ -7132,7 +7277,7 @@ dependencies = [ "tari_crypto", "tari_utilities", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tonic", "tonic-build", "tracing", @@ -7145,7 +7290,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f11c0804a3f136ad0f821981411215886f0039bf1519c4ec0ec0af8098a8def" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "futures-test", "lazy_static 1.4.0", "rand 0.7.3", @@ -7155,14 +7300,14 @@ dependencies = [ [[package]] name = "tari_test_utils" -version = "0.27.3" +version = "0.28.0" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "futures-test", "rand 0.8.4", "tari_shutdown", "tempfile", - "tokio 1.15.0", + "tokio 1.16.1", ] [[package]] @@ -7178,14 +7323,14 @@ dependencies = [ "clear_on_drop", "newtype-ops", "rand 0.7.3", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "thiserror", ] [[package]] name = "tari_validator_node" -version = "0.27.3" +version = "0.28.0" dependencies = [ "anyhow", "async-trait", @@ -7193,13 +7338,13 @@ dependencies = [ "bytecodec", "clap 2.34.0", "digest 0.9.0", - "futures 0.3.19", + "futures 0.3.21", "lmdb-zero", "log", "patricia_tree", "prost", "prost-types", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "tari_app_grpc", "tari_app_utilities", @@ -7218,16 +7363,16 @@ dependencies = [ "tari_service_framework", "tari_shutdown", "tari_storage", - "tari_test_utils 0.27.3", + "tari_test_utils 0.28.0", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-stream", "tonic", ] [[package]] name = "tari_wallet" -version = "0.27.3" +version = "0.28.0" dependencies = [ "aes-gcm 0.8.0", "argon2", @@ -7242,16 +7387,16 @@ dependencies = [ "digest 0.9.0", "env_logger 0.7.1", "fs2 0.3.0", - "futures 0.3.19", + "futures 0.3.21", "libsqlite3-sys", "lmdb-zero", "log", "log4rs 1.0.0", "prost", "rand 0.8.4", - "serde 1.0.135", + "serde 1.0.136", "serde_json", - "sha2", + "sha2 0.9.9", "strum 0.22.0", "strum_macros 0.22.0", "tari_common", @@ -7266,20 +7411,20 @@ dependencies = [ "tari_service_framework", "tari_shutdown", "tari_storage", - "tari_test_utils 0.27.3", + "tari_test_utils 0.28.0", "tari_utilities", "tempfile", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "tower", ] [[package]] name = "tari_wallet_ffi" -version = "0.27.3" +version = "0.28.0" dependencies = [ "chrono", - "futures 0.3.19", + "futures 0.3.21", "lazy_static 1.4.0", "libc", "log", @@ -7296,36 +7441,35 @@ dependencies = [ "tari_p2p", "tari_service_framework", "tari_shutdown", - "tari_test_utils 0.27.3", + "tari_test_utils 0.28.0", "tari_utilities", "tari_wallet", "tempfile", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", ] [[package]] name = "tauri" -version = "1.0.0-beta.8" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79a0579dcc6fb883fe90dd3c66d76b8b8f4a1786e1e915e314b2017a500ede09" +checksum = "05cd4bbdc3d855aa78bad4c7c39bf425d51f09d614d75fff2493c70aa89e16f4" dependencies = [ "attohttpc", - "base64 0.13.0", "bincode", "cfg_aliases", - "clap 3.0.0-beta.2", + "clap 3.0.14", "dirs-next 2.0.0", "either", "embed_plist", "flate2", - "futures 0.3.19", + "futures 0.3.21", "futures-lite", "glib", + "glob", "gtk", "http", "ignore", - "minisign-verify", "notify-rust", "once_cell", "open", @@ -7333,12 +7477,14 @@ dependencies = [ "os_pipe", "percent-encoding 2.1.0", "rand 0.8.4", - "raw-window-handle 0.3.4", + "raw-window-handle", + "regex", "rfd", - "semver 1.0.4", - "serde 1.0.135", + "semver 1.0.5", + "serde 1.0.136", "serde_json", "serde_repr", + "serialize-to-javascript", "shared_child", "state", "tar", @@ -7348,7 +7494,7 @@ dependencies = [ "tauri-utils", "tempfile", "thiserror", - "tokio 1.15.0", + "tokio 1.16.1", "url 2.2.2", "uuid", "zip", @@ -7356,13 +7502,12 @@ dependencies = [ [[package]] name = "tauri-build" -version = "1.0.0-beta.4" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9c9a9bea25b9d6f5845b8662e18447e17218f99860cab37e39e2b57a9fcd49" +checksum = "53075d8ce33827474e1c97ef5c75e4a007e9cae81dba4ce8c61f29a459b5aae8" dependencies = [ "anyhow", - "proc-macro2", - "quote", + "cargo_toml", "serde_json", "tauri-utils", "winres", @@ -7370,58 +7515,63 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "1.0.0-beta.4" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1663739ab53e281919676f216fb56a031104d0d2cd1a2dd5b012d279bcdb0ea4" +checksum = "a52763b36186053eeede537589a7373d8a253de5ac4c6235ad104c2c971343ce" dependencies = [ + "base64 0.13.0", "blake3", - "kuchiki", "proc-macro2", "quote", "regex", - "serde 1.0.135", + "serde 1.0.136", "serde_json", + "sha2 0.10.1", "tauri-utils", "thiserror", + "uuid", "walkdir", "zstd", ] [[package]] name = "tauri-macros" -version = "1.0.0-beta.5" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddf9f5868402323f35ef94fa6ab1d5d10b29aea9de598d829723aa1db5693b4" +checksum = "5493f2bcfc0634e77ace91d83820d4f7f597b94ff2314cd4b3431caf020a5558" dependencies = [ + "heck 0.4.0", "proc-macro2", "quote", "syn", "tauri-codegen", + "tauri-utils", ] [[package]] name = "tauri-runtime" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c52eccfb7f2ce5a09262bdc3671f0f07f637e27f8aa25e5f38145cddcd4e01" +checksum = "be5d4967753541a0d1ac324c50c2c381811fbdc3e743ad0a8b6132f55143ace5" dependencies = [ "gtk", "http", "http-range", "infer", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "tauri-utils", "thiserror", "uuid", - "winapi 0.3.9", + "webview2-com", + "windows 0.30.0", ] [[package]] name = "tauri-runtime-wry" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fed8dd0a448c303fa764859d6dfa1c746c4f2c6c30a83c162f8bebb12e4af4e" +checksum = "61854d1fb4ebf92044a9885cf64e04e515fa1d50daa9390a8ab373b7b2a2b21c" dependencies = [ "gtk", "ico", @@ -7430,25 +7580,33 @@ dependencies = [ "tauri-runtime", "tauri-utils", "uuid", - "winapi 0.3.9", + "webview2-com", + "windows 0.30.0", "wry", ] [[package]] name = "tauri-utils" -version = "1.0.0-beta.3" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb9b79594f22b6ed0cc8362e0dfde5b7969962de3cd8ca683de702e59e8221b" +checksum = "355ec32fbbc19eadc28adc24a90882e5dac111d779fda60cb05c02b56080df5f" dependencies = [ + "ctor", + "glob", + "heck 0.4.0", "html5ever", + "json-patch", "kuchiki", "phf 0.10.1", "proc-macro2", "quote", - "serde 1.0.135", + "serde 1.0.136", "serde_json", + "serde_with", + "serialize-to-javascript", "thiserror", "url 2.2.2", + "walkdir", "zstd", ] @@ -7488,16 +7646,16 @@ dependencies = [ [[package]] name = "test_faucet" -version = "0.27.3" +version = "0.28.0" dependencies = [ "rand 0.8.4", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "tari_common_types", "tari_core", "tari_crypto", "tari_utilities", - "tokio 1.15.0", + "tokio 1.16.1", ] [[package]] @@ -7511,12 +7669,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.12.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789" -dependencies = [ - "unicode-width", -] +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" [[package]] name = "thin-slice" @@ -7596,6 +7751,16 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "time" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" +dependencies = [ + "libc", + "num_threads", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -7611,7 +7776,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ - "serde 1.0.135", + "serde 1.0.136", "serde_json", ] @@ -7646,9 +7811,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.15.0" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" +checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a" dependencies = [ "bytes 1.1.0", "libc", @@ -7669,7 +7834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" dependencies = [ "pin-project-lite 0.2.8", - "tokio 1.15.0", + "tokio 1.16.1", ] [[package]] @@ -7690,18 +7855,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" dependencies = [ "native-tls", - "tokio 1.15.0", + "tokio 1.16.1", ] [[package]] name = "tokio-rustls" -version = "0.22.0" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" dependencies = [ "rustls", - "tokio 1.15.0", - "webpki", + "tokio 1.16.1", + "webpki 0.22.0", ] [[package]] @@ -7712,7 +7877,7 @@ checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" dependencies = [ "futures-core", "pin-project-lite 0.2.8", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-util", ] @@ -7728,7 +7893,7 @@ dependencies = [ "futures-sink", "log", "pin-project-lite 0.2.8", - "tokio 1.15.0", + "tokio 1.16.1", ] [[package]] @@ -7737,7 +7902,7 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" dependencies = [ - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -7746,7 +7911,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -7770,7 +7935,7 @@ dependencies = [ "pin-project 1.0.10", "prost", "prost-derive", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-stream", "tokio-util", "tower", @@ -7819,7 +7984,7 @@ dependencies = [ "pin-project-lite 0.2.8", "rand 0.8.4", "slab", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-stream", "tokio-util", "tower-layer", @@ -7841,9 +8006,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9" dependencies = [ "cfg-if 1.0.0", "log", @@ -7854,9 +8019,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" dependencies = [ "proc-macro2", "quote", @@ -7865,11 +8030,12 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" dependencies = [ "lazy_static 1.4.0", + "valuable", ] [[package]] @@ -7908,11 +8074,11 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" dependencies = [ - "serde 1.0.135", + "serde 1.0.136", "tracing-core", ] @@ -7927,7 +8093,7 @@ dependencies = [ "lazy_static 1.4.0", "matchers 0.0.1", "regex", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "sharded-slab", "smallvec", @@ -7940,9 +8106,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77be66445c4eeebb934a7340f227bfe7b338173d3f8c00a60a5a58005c9faecf" +checksum = "74786ce43333fcf51efe947aed9718fbe46d5c7328ec3f1029e818083966d9aa" dependencies = [ "ansi_term", "lazy_static 1.4.0", @@ -7991,14 +8157,22 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +[[package]] +name = "treediff" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "761e8d5ad7ce14bb82b7e61ccc0ca961005a275a060b9644a2431aa11553c2ff" +dependencies = [ + "serde_json", +] + [[package]] name = "trust-dns-client" -version = "0.21.0-alpha.4" +version = "0.21.0-alpha.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bd50900d7796338807398681ed6d8de0c840d0d9aac65cff093b5635b22e57" +checksum = "b62dfcea87b25f0810e2a527458dd621e252fd8a5827153329308d6e1f252d68" dependencies = [ "cfg-if 1.0.0", - "chrono", "data-encoding", "futures-channel", "futures-util", @@ -8009,16 +8183,17 @@ dependencies = [ "ring", "rustls", "thiserror", - "tokio 1.15.0", + "time 0.3.7", + "tokio 1.16.1", "trust-dns-proto", - "webpki", + "webpki 0.22.0", ] [[package]] name = "trust-dns-proto" -version = "0.21.0-alpha.4" +version = "0.21.0-alpha.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e43c627e8301d45629cdfaf63e2e0c57305a07e9f1ea48208fd262ba2d87eb" +checksum = "df4689a56fb36e79b76d13f52056c116f1f014afb1bd330162f2d9dc08ef5405" dependencies = [ "async-trait", "cfg-if 1.0.0", @@ -8034,13 +8209,14 @@ dependencies = [ "rand 0.8.4", "ring", "rustls", + "rustls-pemfile", "smallvec", "thiserror", "tinyvec", - "tokio 1.15.0", + "tokio 1.16.1", "tokio-rustls", "url 2.2.2", - "webpki", + "webpki 0.22.0", ] [[package]] @@ -8105,9 +8281,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] name = "uint" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f" +checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" dependencies = [ "byteorder", "crunchy", @@ -8141,9 +8317,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" [[package]] name = "unicode-width" @@ -8209,7 +8385,7 @@ dependencies = [ "idna 0.2.3", "matches", "percent-encoding 2.1.0", - "serde 1.0.135", + "serde 1.0.136", ] [[package]] @@ -8231,9 +8407,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ "getrandom 0.2.4", - "serde 1.0.135", + "serde 1.0.136", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -8248,15 +8430,15 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version-compare" -version = "0.0.10" +version = "0.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" +checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" [[package]] name = "version-compare" -version = "0.0.11" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" +checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" [[package]] name = "version_check" @@ -8270,12 +8452,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - [[package]] name = "waker-fn" version = "1.1.0" @@ -8321,10 +8497,10 @@ dependencies = [ "percent-encoding 2.1.0", "pin-project 1.0.10", "scoped-tls", - "serde 1.0.135", + "serde 1.0.136", "serde_json", - "serde_urlencoded 0.7.1", - "tokio 1.15.0", + "serde_urlencoded", + "tokio 1.16.1", "tokio-stream", "tokio-util", "tower-service", @@ -8350,7 +8526,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" dependencies = [ "cfg-if 1.0.0", - "serde 1.0.135", + "serde 1.0.136", "serde_json", "wasm-bindgen-macro", ] @@ -8447,19 +8623,19 @@ dependencies = [ [[package]] name = "webkit2gtk" -version = "0.14.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3e47b7f870883fc21612d2a51b74262f7f2cc5371f1621370817292a35300a9" +checksum = "2cbd39499e917de9dad36eb11c09f665eb984d432638ae7971feed98eb96df88" dependencies = [ "bitflags 1.3.2", "cairo-rs", "gdk", "gdk-sys", "gio", - "gio-sys 0.14.0", + "gio-sys 0.15.5", "glib", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys 0.15.5", + "gobject-sys 0.15.5", "gtk", "gtk-sys", "javascriptcore-rs", @@ -8470,25 +8646,25 @@ dependencies = [ [[package]] name = "webkit2gtk-sys" -version = "0.14.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66ccc9f0cb4de7c3b92376a5bf64e7ddffb33852f092721731a039ec38dda98" +checksum = "ddcce6f1e0fc7715d651dba29875741509f5fc12f4e2976907272a74405f2b01" dependencies = [ "atk-sys", "bitflags 1.3.2", "cairo-sys-rs", "gdk-pixbuf-sys", "gdk-sys", - "gio-sys 0.14.0", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "gio-sys 0.15.5", + "glib-sys 0.15.5", + "gobject-sys 0.15.5", "gtk-sys", "javascriptcore-rs-sys", "libc", "pango-sys", "pkg-config", - "soup-sys", - "system-deps 3.2.0", + "soup2-sys", + "system-deps 5.0.0", ] [[package]] @@ -8502,26 +8678,50 @@ dependencies = [ ] [[package]] -name = "webview2" -version = "0.1.4" +name = "webpki" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "283bf6b0ed9c83faea8c7bfe40bb261592147a109effaa4077eed294863d5031" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ - "com", - "once_cell", - "webview2-sys", - "widestring", - "winapi 0.3.9", + "ring", + "untrusted", ] [[package]] -name = "webview2-sys" -version = "0.1.1" +name = "webview2-com" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b7889e893ac4c50d7346356be3ce13a85e56512c38b8fde0526559b8012a4c" +checksum = "1975ce3573344c099935fe3903f1708dac69efe8539f1efee3ae54d8f9315fbb" dependencies = [ - "com", - "winapi 0.3.9", + "webview2-com-macros", + "webview2-com-sys", + "windows 0.30.0", + "windows_macros", +] + +[[package]] +name = "webview2-com-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515c6c82fcee93f6edaacc72c8e233dbe4ff3ca569dce1901dfc36c404a3e99" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "webview2-com-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a746838a94b7391f707209a246e3436d81d1e71832126a65a897d3ee5511040" +dependencies = [ + "regex", + "serde 1.0.136", + "serde_json", + "thiserror", + "windows 0.30.0", + "windows-bindgen", ] [[package]] @@ -8553,17 +8753,11 @@ dependencies = [ "libc", ] -[[package]] -name = "widestring" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" - [[package]] name = "wildmatch" -version = "1.1.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f44b95f62d34113cf558c93511ac93027e03e9c29a60dd0fd70e6e025c7270a" +checksum = "d6c48bd20df7e4ced539c12f570f937c6b4884928a87fee70a479d72f031d4e0" [[package]] name = "winapi" @@ -8620,6 +8814,29 @@ dependencies = [ "windows_x86_64_msvc 0.24.0", ] +[[package]] +name = "windows" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b749ebd2304aa012c5992d11a25d07b406bdbe5f79d371cb7a918ce501a19eb0" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu 0.30.0", + "windows_i686_msvc 0.30.0", + "windows_x86_64_gnu 0.30.0", + "windows_x86_64_msvc 0.30.0", +] + +[[package]] +name = "windows-bindgen" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "944c545fcae9dd66488308f8b69aa3ba34f53714416ecfcdcbbfa4b6821e27c6" +dependencies = [ + "windows_quote", + "windows_reader", +] + [[package]] name = "windows-sys" version = "0.30.0" @@ -8639,6 +8856,16 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" +[[package]] +name = "windows_gen" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30dff4d91d22520628bb94b66f2bb313cb16a09a515a32320a84a1b449bc94c0" +dependencies = [ + "windows_quote", + "windows_reader", +] + [[package]] name = "windows_i686_gnu" version = "0.24.0" @@ -8663,6 +8890,30 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" +[[package]] +name = "windows_macros" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ae44ab917e9005fe710d99d52d227ca0164b10a09be90649142cc3fab825d3" +dependencies = [ + "syn", + "windows_gen", + "windows_quote", + "windows_reader", +] + +[[package]] +name = "windows_quote" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71f02c51a77e6248c1206aaa920802c32d50a05205e229b118d7f3afd3036667" + +[[package]] +name = "windows_reader" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e44e6df0da993cda589c5ac852272fbb2a0ead67a031a017dd3eac11528a2d72" + [[package]] name = "windows_x86_64_gnu" version = "0.24.0" @@ -8712,18 +8963,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "007a0353840b23e0c6dc73e5b962ff58ed7f6bc9ceff3ce7fe6fbad8d496edf4" dependencies = [ "strum 0.22.0", - "windows", + "windows 0.24.0", "xml-rs", ] [[package]] name = "wry" -version = "0.12.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9549393a3917b5303277abb0267f8eecf9fd629b25f1c04e5284aa58b61915" +checksum = "194b2750d8fe10fef189af5e2ca09e56cb8c5458a365d2b32842b024351f58c9" dependencies = [ "cocoa", - "core-graphics 0.22.3", + "core-graphics", "gdk", "gio", "glib", @@ -8734,16 +8985,17 @@ dependencies = [ "objc", "objc_id", "once_cell", - "serde 1.0.135", + "serde 1.0.136", "serde_json", + "sys-info", "tao", "thiserror", "url 2.2.2", "webkit2gtk", "webkit2gtk-sys", - "webview2", - "webview2-sys", - "winapi 0.3.9", + "webview2-com", + "windows 0.30.0", + "windows_macros", ] [[package]] @@ -8756,6 +9008,16 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "x11" +version = "2.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd0565fa8bfba8c5efe02725b14dff114c866724eff2cfd44d76cea74bcd87a" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "x11-dl" version = "2.19.1" @@ -8808,7 +9070,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7d9028f208dd5e63c614be69f115c1b53cacc1111437d4c765185856666c107" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "log", "nohash-hasher", "parking_lot 0.11.2", @@ -8818,39 +9080,65 @@ dependencies = [ [[package]] name = "zbus" -version = "1.9.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2326acc379a3ac4e34b794089f5bdb17086bf29a5fdf619b7b4cc772dc2e9dad" +checksum = "7bb86f3d4592e26a48b2719742aec94f8ae6238ebde20d98183ee185d1275e9a" dependencies = [ + "async-broadcast", + "async-channel", + "async-executor", "async-io", + "async-lock", + "async-recursion", + "async-task", + "async-trait", "byteorder", "derivative", "enumflags2", - "fastrand", - "futures 0.3.19", - "nb-connect", - "nix 0.17.0", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "lazy_static 1.4.0", + "nix", "once_cell", - "polling", - "scoped-tls", - "serde 1.0.135", + "ordered-stream", + "rand 0.8.4", + "serde 1.0.136", "serde_repr", + "sha1", + "static_assertions", + "winapi 0.3.9", "zbus_macros", + "zbus_names", "zvariant", ] [[package]] name = "zbus_macros" -version = "1.9.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a482c56029e48681b89b92b5db3c446db0915e8dd1052c0328a574eda38d5f93" +checksum = "36823cc10fddc3c6b19f048903262dacaf8274170e9a255784bdd8b4570a8040" dependencies = [ - "proc-macro-crate 0.1.5", + "proc-macro-crate 1.1.0", "proc-macro2", "quote", + "regex", "syn", ] +[[package]] +name = "zbus_names" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45dfcdcf87b71dad505d30cc27b1b7b88a64b6d1c435648f48f9dbc1fdc4b7e1" +dependencies = [ + "serde 1.0.136", + "static_assertions", + "zvariant", +] + [[package]] name = "zeroize" version = "1.3.0" @@ -8883,23 +9171,23 @@ dependencies = [ "crc32fast", "flate2", "thiserror", - "time", + "time 0.1.43", ] [[package]] name = "zstd" -version = "0.9.2+zstd.1.5.1" +version = "0.10.0+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2390ea1bf6c038c39674f22d95f0564725fc06034a47129179810b2fc58caa54" +checksum = "3b1365becbe415f3f0fcd024e2f7b45bacfb5bdd055f0dc113571394114e7bdd" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.3+zstd.1.5.1" +version = "4.1.4+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e99d81b99fb3c2c2c794e3fe56c305c63d5173a16a46b5850b07c935ffc7db79" +checksum = "2f7cd17c9af1a4d6c24beb1cc54b17e2ef7b593dc92f19e9d9acad8b182bbaee" dependencies = [ "libc", "zstd-sys", @@ -8907,9 +9195,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.2+zstd.1.5.1" +version = "1.6.3+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2daf2f248d9ea44454bfcb2516534e8b8ad2fc91bf818a1885495fc42bc8ac9f" +checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" dependencies = [ "cc", "libc", @@ -8917,23 +9205,23 @@ dependencies = [ [[package]] name = "zvariant" -version = "2.10.0" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68c7b55f2074489b7e8e07d2d0a6ee6b4f233867a653c664d8020ba53692525" +checksum = "49ea5dc38b2058fae6a5b79009388143dadce1e91c26a67f984a0fc0381c8033" dependencies = [ "byteorder", "enumflags2", "libc", - "serde 1.0.135", + "serde 1.0.136", "static_assertions", "zvariant_derive", ] [[package]] name = "zvariant_derive" -version = "2.10.0" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ca5e22593eb4212382d60d26350065bf2a02c34b85bc850474a74b589a3de9" +checksum = "8c2cecc5a61c2a053f7f653a24cd15b3b0195d7f7ddb5042c837fb32e161fb7a" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", diff --git a/RFC/README.md b/RFC/README.md index fc8aa7a21a..9c537651f8 100644 --- a/RFC/README.md +++ b/RFC/README.md @@ -2,4 +2,12 @@ RFC documents for the Tari protocol -The rendered version of these docs can be found at https://rfc.tari.com \ No newline at end of file +These documents are in the form of an mdbook. The rendered version of these docs can be found at https://rfc.tari.com + +## View local rendered version + +- run `cargo install mdbook` + +- in the `/RFC` folder run `mdbook serve` + +- in a browser navigate to [`localhost:3000`](http://localhost:3000) diff --git a/RFC/src/SUMMARY.md b/RFC/src/SUMMARY.md index 683f6adc34..9d384e4e7e 100644 --- a/RFC/src/SUMMARY.md +++ b/RFC/src/SUMMARY.md @@ -48,4 +48,5 @@ - [RFC-0130: Mining](RFC-0130_Mining.md) +- [RFC template](RFC_template.md) - [Glossary](Glossary.md) diff --git a/RFC/src/about.md b/RFC/src/about.md index cc7abe1529..61448748b8 100644 --- a/RFC/src/about.md +++ b/RFC/src/about.md @@ -9,10 +9,10 @@ iterations before reaching this point: not cast in stone. RFCs can, and should, undergo further evaluation and discussion by the community. RFC comments are best made using Github [issue]s. -New RFC's should follow the format given in the [RFC template](./RFC_template.md). +New RFC's should follow the format given in the [RFC template](RFC_template.md). ## Lifecycle -RFCs go through the following lifecycle, which roughly corresponds to the [COSS](https://rfc.unprotocols.org/spec:2/COSS/): +RFCs go through the following lifecycle, which roughly corresponds to the [COSS](https://github.com/unprotocols/rfc/blob/master/2/README.md): | Status | | Description | |:------------|:--------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| diff --git a/applications/daily_tests/cron_jobs.js b/applications/daily_tests/cron_jobs.js index d3041c6250..17fd67aa9b 100644 --- a/applications/daily_tests/cron_jobs.js +++ b/applications/daily_tests/cron_jobs.js @@ -123,6 +123,10 @@ ${logLines.join("\n")} async function main() { console.log("👩‍💻 Updating repo..."); + await git.reset(__dirname).catch((err) => { + console.error("🚨 Failed to do git reset --hard"); + console.error(err); + }); await git.pull(__dirname).catch((err) => { console.error("🚨 Failed to update git repo"); console.error(err); @@ -136,11 +140,20 @@ async function main() { ).start(); new CronJob("30 1 * * *", () => runBaseNodeSyncTest(SyncType.Pruned)).start(); new CronJob("0 0 * * *", () => - git.pull(__dirname).catch((err) => { - failed("Failed to update git repo"); - console.error(err); - return Promise.resolve(null); - }) + git + .reset(__dirname) + .catch((err) => { + console.error("🚨 Failed to do git reset --hard"); + console.error(err); + return Promise.resolve(null); + }) + .then( + git.pull(__dirname).catch((err) => { + failed("Failed to update git repo"); + console.error(err); + return Promise.resolve(null); + }) + ) ).start(); console.log("⏱ Cron jobs started."); diff --git a/applications/daily_tests/helpers.js b/applications/daily_tests/helpers.js index 1dd97a016f..e01c6608fd 100644 --- a/applications/daily_tests/helpers.js +++ b/applications/daily_tests/helpers.js @@ -154,10 +154,10 @@ async function monitorProcessOutput({ } const git = { - pull(cwd = null) { + command(params, cwd = null) { cwd = cwd || process.cwd(); return new Promise((resolve, reject) => { - let ps = spawn("git", ["pull", "--rebase"], { cwd }); + let ps = spawn("git", params, { cwd }); ps.stdout.on("data", (buf) => { console.log(buf.toString()); }); @@ -173,6 +173,8 @@ const git = { }); }); }, + reset: (cwd = null) => git.command(["reset", "--hard"], cwd), + pull: (cwd = null) => git.command(["pull", "--rebase"], cwd), }; module.exports = { diff --git a/applications/ffi_client/index.js b/applications/ffi_client/index.js index 20aeaf6c39..c7a7c81f39 100644 --- a/applications/ffi_client/index.js +++ b/applications/ffi_client/index.js @@ -69,6 +69,18 @@ try { console.log("txMinedUnconfirmed: ", ptr, confirmations); } ); + // callback_faux_transaction_confirmed: unsafe extern "C" fn(*mut TariCompletedTransaction), + const txFauxConfirmed = ffi.Callback("void", ["pointer"], function (ptr) { + console.log("txFauxConfirmed: ", ptr); + }); + // callback_faux_transaction_unconfirmed: unsafe extern "C" fn(*mut TariCompletedTransaction, u64), + const txFauxUnconfirmed = ffi.Callback( + "void", + ["pointer"], + function (ptr, confirmations) { + console.log("txFauxUnconfirmed: ", ptr, confirmations); + } + ); // callback_direct_send_result: unsafe extern "C" fn(c_ulonglong, bool), const directSendResult = ffi.Callback("void", [u64, bool], function (i, j) { console.log("directSendResult: ", i, j); @@ -112,6 +124,8 @@ try { txBroadcast, txMined, txMinedUnconfirmed, + txFauxConfirmed, + txFauxUnconfirmed, directSendResult, safResult, txCancelled, diff --git a/applications/ffi_client/lib/index.js b/applications/ffi_client/lib/index.js index db922de1f0..b9e8b34da7 100644 --- a/applications/ffi_client/lib/index.js +++ b/applications/ffi_client/lib/index.js @@ -66,6 +66,9 @@ const libWallet = ffi.Library("./libtari_wallet_ffi.dylib", { fn, fn, fn, + fn, + fn, + bool, errPtr, ], ], diff --git a/applications/ffi_client/recovery.js b/applications/ffi_client/recovery.js index 0c51d3daa3..bf82225ca2 100644 --- a/applications/ffi_client/recovery.js +++ b/applications/ffi_client/recovery.js @@ -80,6 +80,18 @@ try { console.log("txMinedUnconfirmed: ", ptr, confirmations); } ); + // callback_faux_transaction_confirmed: unsafe extern "C" fn(*mut TariCompletedTransaction), + const txFauxConfirmed = ffi.Callback("void", ["pointer"], function (ptr) { + console.log("txFauxConfirmed: ", ptr); + }); + // callback_faux_transaction_unconfirmed: unsafe extern "C" fn(*mut TariCompletedTransaction, u64), + const txFauxUnconfirmed = ffi.Callback( + "void", + ["pointer"], + function (ptr, confirmations) { + console.log("txFauxUnconfirmed: ", ptr, confirmations); + } + ); // callback_direct_send_result: unsafe extern "C" fn(c_ulonglong, bool), const directSendResult = ffi.Callback("void", [u64, bool], function (i, j) { console.log("directSendResult: ", i, j); diff --git a/applications/launchpad/backend/Cargo.toml b/applications/launchpad/backend/Cargo.toml index 162bc04036..8480e0530f 100644 --- a/applications/launchpad/backend/Cargo.toml +++ b/applications/launchpad/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_launchpad" -version = "0.27.3" +version = "0.28.0" description = "The Tari Launcher" authors = ["The Tari Development Community"] license = "" @@ -14,8 +14,8 @@ build = "src/build.rs" tauri-build = { version = "1.0.0-beta.4" } [dependencies] -tari_app_utilities = { version = "^0.27", path = "../../tari_app_utilities" } -tari_comms = { version = "^0.27", path = "../../../comms" } +tari_app_utilities = { version = "^0.28", path = "../../tari_app_utilities" } +tari_comms = { version = "^0.28", path = "../../../comms" } bollard = "0.11.0" config = "0.11.0" env_logger = "0.9.0" diff --git a/applications/launchpad/backend/src/commands/create_workspace.rs b/applications/launchpad/backend/src/commands/create_workspace.rs index 95b6a6cac3..5930642876 100644 --- a/applications/launchpad/backend/src/commands/create_workspace.rs +++ b/applications/launchpad/backend/src/commands/create_workspace.rs @@ -56,7 +56,13 @@ pub fn copy_config_file>( file: &str, ) -> Result<(), LauncherError> { let path = Path::new("assets").join(file); - let config_path = resolve_path(config, package_info, &path, Some(BaseDirectory::Resource))?; + let config_path = resolve_path( + config, + package_info, + &Default::default(), + &path, + Some(BaseDirectory::Resource), + )?; let cfg = std::fs::read_to_string(&config_path).expect("The config assets were not bundled with the App"); info!("Log Configuration file ({}) loaded", file); debug!("{}", cfg); diff --git a/applications/launchpad/backend/src/docker/error.rs b/applications/launchpad/backend/src/docker/error.rs index 07f4b8a864..7dd20bae56 100644 --- a/applications/launchpad/backend/src/docker/error.rs +++ b/applications/launchpad/backend/src/docker/error.rs @@ -23,7 +23,7 @@ use std::error::Error; -use tari_app_utilities::common::exit_codes::ExitCodes; +use tari_app_utilities::common::exit_codes::ExitError; use thiserror::Error; #[derive(Debug, Error)] @@ -43,7 +43,7 @@ pub enum DockerWrapperError { #[error("It should not be possible to be in this error state")] UnexpectedError, #[error("Could not create an identity file")] - IdentityError(#[from] ExitCodes), + IdentityError(#[from] ExitError), #[error("The specified image type is not supported")] InvalidImageType, } diff --git a/applications/launchpad/backend/src/main.rs b/applications/launchpad/backend/src/main.rs index 1622ab7ccc..a7e501f5a4 100644 --- a/applications/launchpad/backend/src/main.rs +++ b/applications/launchpad/backend/src/main.rs @@ -14,15 +14,17 @@ use tari_launchpad::{ commands::*, docker::{DockerWrapper, Workspaces}, }; -use tauri::{api::cli::get_matches, async_runtime::block_on, utils::config::CliConfig, Event, Manager}; +use tauri::{api::cli::get_matches, async_runtime::block_on, utils::config::CliConfig, Manager, PackageInfo, RunEvent}; fn main() { env_logger::init(); let context = tauri::generate_context!(); let cli_config = context.config().tauri.cli.clone().unwrap(); + // We're going to attach this to the AppState because Tauri does not expose it for some reason + let package_info = context.package_info().clone(); // Handle --help and --version. Exits after printing - handle_cli_options(&cli_config); + handle_cli_options(&cli_config, &package_info); let docker = match DockerWrapper::new() { Ok(docker) => docker, @@ -34,8 +36,6 @@ fn main() { // TODO - Load workspace definitions from persistent storage here let workspaces = Workspaces::default(); - // We're going to attach this to the AppState because Tauri does not expose it for some reason - let package_info = context.package_info().clone(); info!("Using Docker version: {}", docker.version()); let app = tauri::Builder::default() @@ -55,7 +55,7 @@ fn main() { .expect("error while running Launchpad"); app.run(|app, event| { - if let Event::Exit = event { + if let RunEvent::Exit = event { info!("Received Exit event"); block_on(async move { let state = app.state(); @@ -65,8 +65,8 @@ fn main() { }); } -fn handle_cli_options(cli_config: &CliConfig) { - match get_matches(cli_config) { +fn handle_cli_options(cli_config: &CliConfig, pkg_info: &PackageInfo) { + match get_matches(cli_config, pkg_info) { Ok(matches) => { if let Some(arg_data) = matches.args.get("help") { debug!("{}", arg_data.value.as_str().unwrap_or("No help available")); diff --git a/applications/launchpad/gui-vue/package-lock.json b/applications/launchpad/gui-vue/package-lock.json index db72d6e596..96c92b69a7 100644 --- a/applications/launchpad/gui-vue/package-lock.json +++ b/applications/launchpad/gui-vue/package-lock.json @@ -9170,9 +9170,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "dev": true, "funding": [ { @@ -27170,9 +27170,9 @@ } }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "dev": true }, "for-in": { diff --git a/applications/tari_app_grpc/Cargo.toml b/applications/tari_app_grpc/Cargo.toml index b58d68feb3..3b1181b0dd 100644 --- a/applications/tari_app_grpc/Cargo.toml +++ b/applications/tari_app_grpc/Cargo.toml @@ -4,11 +4,11 @@ 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.27.3" +version = "0.28.0" edition = "2018" [dependencies] -tari_common_types = { version = "^0.27", path = "../../base_layer/common_types"} +tari_common_types = { version = "^0.28", path = "../../base_layer/common_types"} tari_core = { path = "../../base_layer/core"} tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } tari_comms = { path = "../../comms"} diff --git a/applications/tari_app_grpc/proto/wallet.proto b/applications/tari_app_grpc/proto/wallet.proto index 3ba81bbf0f..acdd7086b6 100644 --- a/applications/tari_app_grpc/proto/wallet.proto +++ b/applications/tari_app_grpc/proto/wallet.proto @@ -77,6 +77,8 @@ service Wallet { rpc MintTokens(MintTokensRequest) returns (MintTokensResponse); rpc GetOwnedTokens(GetOwnedTokensRequest) returns (GetOwnedTokensResponse); + + rpc SetBaseNode(SetBaseNodeRequest) returns (SetBaseNodeResponse); } message GetVersionRequest { } @@ -164,7 +166,6 @@ message TransactionInfo { bytes excess_sig = 9; google.protobuf.Timestamp timestamp = 10; string message = 11; - bool valid = 12; } enum TransactionDirection { @@ -192,6 +193,10 @@ enum TransactionStatus { TRANSACTION_STATUS_NOT_FOUND = 7; // The transaction was rejected by the mempool TRANSACTION_STATUS_REJECTED = 8; + // This is faux transaction mainly for one-sided transaction outputs or wallet recovery outputs have been found + TRANSACTION_STATUS_FAUX_UNCONFIRMED = 9; + // All Imported and FauxUnconfirmed transactions will end up with this status when the outputs have been confirmed + TRANSACTION_STATUS_FAUX_CONFIRMED = 10; } message GetCompletedTransactionsRequest { } @@ -331,3 +336,10 @@ message CancelTransactionResponse { message RevalidateRequest{} message RevalidateResponse{} + +message SetBaseNodeRequest { + string public_key_hex = 1; + string net_address = 2; +} + +message SetBaseNodeResponse{} diff --git a/applications/tari_app_grpc/src/conversions/output_features.rs b/applications/tari_app_grpc/src/conversions/output_features.rs index 969f62374d..7c0a009248 100644 --- a/applications/tari_app_grpc/src/conversions/output_features.rs +++ b/applications/tari_app_grpc/src/conversions/output_features.rs @@ -26,7 +26,7 @@ use tari_common_types::{ array::copy_into_fixed_array, types::{Commitment, PublicKey}, }; -use tari_core::transactions::transaction::{ +use tari_core::transactions::transaction_components::{ AssetOutputFeatures, MintNonFungibleFeatures, OutputFeatures, diff --git a/applications/tari_app_grpc/src/conversions/transaction.rs b/applications/tari_app_grpc/src/conversions/transaction.rs index fffb851ef7..2757e22188 100644 --- a/applications/tari_app_grpc/src/conversions/transaction.rs +++ b/applications/tari_app_grpc/src/conversions/transaction.rs @@ -26,7 +26,7 @@ use std::{ }; use tari_common_types::transaction::{TransactionDirection, TransactionStatus, TxId}; -use tari_core::transactions::transaction::Transaction; +use tari_core::transactions::transaction_components::Transaction; use tari_crypto::ristretto::RistrettoSecretKey; use tari_utilities::ByteArray; @@ -98,6 +98,8 @@ impl From for grpc::TransactionStatus { Pending => grpc::TransactionStatus::Pending, Coinbase => grpc::TransactionStatus::Coinbase, Rejected => grpc::TransactionStatus::Rejected, + FauxUnconfirmed => grpc::TransactionStatus::FauxUnconfirmed, + FauxConfirmed => grpc::TransactionStatus::FauxConfirmed, } } } diff --git a/applications/tari_app_grpc/src/conversions/transaction_input.rs b/applications/tari_app_grpc/src/conversions/transaction_input.rs index b35fcb1391..7856784ab2 100644 --- a/applications/tari_app_grpc/src/conversions/transaction_input.rs +++ b/applications/tari_app_grpc/src/conversions/transaction_input.rs @@ -25,7 +25,7 @@ use std::convert::{TryFrom, TryInto}; use tari_common_types::types::{Commitment, PublicKey}; use tari_core::{ covenants::Covenant, - transactions::transaction::{TransactionInput, TransactionInputVersion}, + transactions::transaction_components::{TransactionInput, TransactionInputVersion}, }; use tari_crypto::{ script::{ExecutionStack, TariScript}, diff --git a/applications/tari_app_grpc/src/conversions/transaction_kernel.rs b/applications/tari_app_grpc/src/conversions/transaction_kernel.rs index 3d92769e4f..b7e835e22c 100644 --- a/applications/tari_app_grpc/src/conversions/transaction_kernel.rs +++ b/applications/tari_app_grpc/src/conversions/transaction_kernel.rs @@ -25,7 +25,7 @@ use std::convert::{TryFrom, TryInto}; use tari_common_types::types::Commitment; use tari_core::transactions::{ tari_amount::MicroTari, - transaction::{KernelFeatures, TransactionKernel, TransactionKernelVersion}, + transaction_components::{KernelFeatures, TransactionKernel, TransactionKernelVersion}, }; use tari_crypto::tari_utilities::{ByteArray, Hashable}; diff --git a/applications/tari_app_grpc/src/conversions/transaction_output.rs b/applications/tari_app_grpc/src/conversions/transaction_output.rs index 1e3b91257d..a22dcd3cf3 100644 --- a/applications/tari_app_grpc/src/conversions/transaction_output.rs +++ b/applications/tari_app_grpc/src/conversions/transaction_output.rs @@ -25,7 +25,7 @@ use std::convert::{TryFrom, TryInto}; use tari_common_types::types::{BulletRangeProof, Commitment, PublicKey}; use tari_core::{ covenants::Covenant, - transactions::transaction::{TransactionOutput, TransactionOutputVersion}, + transactions::transaction_components::{TransactionOutput, TransactionOutputVersion}, }; use tari_crypto::script::TariScript; use tari_utilities::{ByteArray, Hashable}; diff --git a/applications/tari_app_grpc/src/conversions/unblinded_output.rs b/applications/tari_app_grpc/src/conversions/unblinded_output.rs index 3979087040..395887c768 100644 --- a/applications/tari_app_grpc/src/conversions/unblinded_output.rs +++ b/applications/tari_app_grpc/src/conversions/unblinded_output.rs @@ -27,7 +27,7 @@ use tari_core::{ covenants::Covenant, transactions::{ tari_amount::MicroTari, - transaction::{TransactionOutputVersion, UnblindedOutput}, + transaction_components::{TransactionOutputVersion, UnblindedOutput}, }, }; use tari_crypto::script::{ExecutionStack, TariScript}; diff --git a/applications/tari_app_utilities/Cargo.toml b/applications/tari_app_utilities/Cargo.toml index 01ab2fec14..97883782be 100644 --- a/applications/tari_app_utilities/Cargo.toml +++ b/applications/tari_app_utilities/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_app_utilities" -version = "0.27.3" +version = "0.28.0" authors = ["The Tari Development Community"] edition = "2018" diff --git a/applications/tari_app_utilities/src/identity_management.rs b/applications/tari_app_utilities/src/identity_management.rs index 41fb3d24aa..d16afeca65 100644 --- a/applications/tari_app_utilities/src/identity_management.rs +++ b/applications/tari_app_utilities/src/identity_management.rs @@ -27,7 +27,7 @@ use rand::rngs::OsRng; use serde::{de::DeserializeOwned, Serialize}; use tari_common::{ configuration::{bootstrap::prompt, utils::get_local_ip}, - exit_codes::ExitCodes, + exit_codes::{ExitCode, ExitError}, }; use tari_comms::{multiaddr::Multiaddr, peer_manager::PeerFeatures, NodeIdentity}; use tari_crypto::tari_utilities::hex::Hex; @@ -48,7 +48,7 @@ pub fn setup_node_identity>( public_address: &Option, create_id: bool, peer_features: PeerFeatures, -) -> Result, ExitCodes> { +) -> Result, ExitError> { match load_identity(&identity_file) { Ok(id) => match public_address { Some(public_address) => { @@ -69,12 +69,15 @@ pub fn setup_node_identity>( identity.", e ); - return Err(ExitCodes::ConfigError(format!( - "Node identity information not found. {}. You can update the configuration file to point to a \ - valid node identity file, or re-run the node with the --create-id flag to create a new \ - identity.", - e - ))); + return Err(ExitError::new( + ExitCode::ConfigError, + format!( + "Node identity information not found. {}. You can update the configuration file to point \ + to a valid node identity file, or re-run the node with the --create-id flag to create a \ + new identity.", + e + ), + )); }; } @@ -93,10 +96,10 @@ pub fn setup_node_identity>( }, Err(e) => { error!(target: LOG_TARGET, "Could not create new node id. {:?}.", e); - Err(ExitCodes::ConfigError(format!( - "Could not create new node id. {:?}.", - e - ))) + Err(ExitError::new( + ExitCode::ConfigError, + format!("Could not create new node id. {:?}.", e), + )) }, } }, diff --git a/applications/tari_app_utilities/src/initialization.rs b/applications/tari_app_utilities/src/initialization.rs index c82c0520ab..0f37b67c87 100644 --- a/applications/tari_app_utilities/src/initialization.rs +++ b/applications/tari_app_utilities/src/initialization.rs @@ -4,7 +4,7 @@ use config::Config; use structopt::StructOpt; use tari_common::{ configuration::{bootstrap::ApplicationType, Network}, - exit_codes::ExitCodes, + exit_codes::ExitError, ConfigBootstrap, DatabaseType, GlobalConfig, @@ -16,7 +16,7 @@ pub const LOG_TARGET: &str = "tari::application"; pub fn init_configuration( application_type: ApplicationType, -) -> Result<(ConfigBootstrap, GlobalConfig, Config), ExitCodes> { +) -> Result<(ConfigBootstrap, GlobalConfig, Config), ExitError> { // Parse and validate command-line arguments let mut bootstrap = ConfigBootstrap::from_args(); diff --git a/applications/tari_app_utilities/src/utilities.rs b/applications/tari_app_utilities/src/utilities.rs index 2c38e65550..7d60904721 100644 --- a/applications/tari_app_utilities/src/utilities.rs +++ b/applications/tari_app_utilities/src/utilities.rs @@ -24,7 +24,13 @@ use std::sync::Arc; use futures::future::Either; use log::*; -use tari_common::{exit_codes::ExitCodes, CommsTransport, GlobalConfig, SocksAuthentication, TorControlAuthentication}; +use tari_common::{ + exit_codes::{ExitCode, ExitError}, + CommsTransport, + GlobalConfig, + SocksAuthentication, + TorControlAuthentication, +}; use tari_common_types::{emoji::EmojiId, types::BlockHash}; use tari_comms::{ peer_manager::NodeId, @@ -145,7 +151,7 @@ pub fn convert_socks_authentication(auth: SocksAuthentication) -> socks::Authent /// /// ## Returns /// A result containing the runtime on success, string indicating the error on failure -pub fn setup_runtime(config: &GlobalConfig) -> Result { +pub fn setup_runtime(config: &GlobalConfig) -> Result { let mut builder = runtime::Builder::new_multi_thread(); if let Some(core_threads) = config.core_threads { @@ -163,7 +169,7 @@ pub fn setup_runtime(config: &GlobalConfig) -> Result { builder.enable_all().build().map_err(|e| { let msg = format!("There was an error while building the node runtime. {}", e); - ExitCodes::UnknownError(msg) + ExitError::new(ExitCode::UnknownError, msg) }) } diff --git a/applications/tari_base_node/Cargo.toml b/applications/tari_base_node/Cargo.toml index 1f6582cef5..e66205b475 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.27.3" +version = "0.28.0" edition = "2018" [dependencies] @@ -27,6 +27,7 @@ anyhow = "1.0.53" bincode = "1.3.1" chrono = { version = "0.4.19", default-features = false } config = { version = "0.9.3" } +crossterm = "0.22" either = "1.6.1" futures = { version = "^0.3.16", default-features = false, features = ["alloc"] } log = { version = "0.4.8", features = ["std"] } diff --git a/applications/tari_base_node/build.rs b/applications/tari_base_node/build.rs new file mode 100644 index 0000000000..1c502c938a --- /dev/null +++ b/applications/tari_base_node/build.rs @@ -0,0 +1,11 @@ +#[cfg(windows)] +fn main() { + use std::env; + println!("cargo:rerun-if-changed=icon.res"); + let mut path = env::current_dir().unwrap(); + path.push("icon.res"); + println!("cargo:rustc-link-arg={}", path.into_os_string().into_string().unwrap()); +} + +#[cfg(not(windows))] +fn main() {} diff --git a/applications/tari_base_node/icon.ico b/applications/tari_base_node/icon.ico new file mode 100644 index 0000000000..974b0eaf7b Binary files /dev/null and b/applications/tari_base_node/icon.ico differ diff --git a/applications/tari_base_node/icon.rc b/applications/tari_base_node/icon.rc new file mode 100644 index 0000000000..26527deb57 --- /dev/null +++ b/applications/tari_base_node/icon.rc @@ -0,0 +1 @@ +mining_node ICON "icon.ico" \ No newline at end of file diff --git a/applications/tari_base_node/icon.res b/applications/tari_base_node/icon.res new file mode 100644 index 0000000000..50f5aa7f9a Binary files /dev/null and b/applications/tari_base_node/icon.res differ diff --git a/applications/tari_base_node/src/bootstrap.rs b/applications/tari_base_node/src/bootstrap.rs index 48bd6afa7d..cb0540eb1a 100644 --- a/applications/tari_base_node/src/bootstrap.rs +++ b/applications/tari_base_node/src/bootstrap.rs @@ -145,7 +145,6 @@ where B: BlockchainBackend + 'static .add_initializer(LivenessInitializer::new( LivenessConfig { auto_ping_interval: Some(Duration::from_secs(config.auto_ping_interval)), - refresh_neighbours_interval: Duration::from_secs(3 * 60), monitored_peers: sync_peers.clone(), ..Default::default() }, diff --git a/applications/tari_base_node/src/cli.rs b/applications/tari_base_node/src/cli.rs index 5731619602..cab727d892 100644 --- a/applications/tari_base_node/src/cli.rs +++ b/applications/tari_base_node/src/cli.rs @@ -20,7 +20,10 @@ // 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::io::stdout; + use chrono::{Datelike, Utc}; +use crossterm::{execute, terminal::SetSize}; use tari_app_utilities::consts; /// returns the top or bottom box line of the specified length @@ -100,6 +103,14 @@ fn multiline_find_display_length(lines: &str) -> usize { result } +/// Try to resize terminal to make sure the width is enough. +/// In case of error, just simply print out the error. +fn resize_terminal_to_fit_the_box(width: usize, height: usize) { + if let Err(e) = execute!(stdout(), SetSize(width as u16, height as u16)) { + println!("Can't resize terminal to fit the box. Error: {}", e) + } +} + /// Prints a pretty banner on the console as well as the list of available commands pub fn print_banner(commands: Vec, chunk_size: i32) { let chunks: Vec> = commands.chunks(chunk_size as usize).map(|x| x.to_vec()).collect(); @@ -141,6 +152,7 @@ pub fn print_banner(commands: Vec, chunk_size: i32) { let banner = include!("../assets/tari_banner.rs"); let target_line_length = multiline_find_display_length(banner); + for line in banner.lines() { println!("{}", line); } @@ -168,8 +180,13 @@ pub fn print_banner(commands: Vec, chunk_size: i32) { println!("{}", box_data("~~~~~~~~".to_string(), target_line_length)); println!("{}", box_separator(target_line_length)); let rows = box_tabular_data_rows(command_data, row_cell_size, target_line_length, 10); + // There are 24 fixed rows besides the possible changed "Commands" rows + // and plus 2 more blank rows for better layout. + let height_to_resize = &rows.len() + 24 + 2; for row in rows { println!("{}", row); } println!("{}", box_line(target_line_length, false)); + + resize_terminal_to_fit_the_box(target_line_length, height_to_resize); } diff --git a/applications/tari_base_node/src/grpc/base_node_grpc_server.rs b/applications/tari_base_node/src/grpc/base_node_grpc_server.rs index ff5ab12b7d..2ef8258366 100644 --- a/applications/tari_base_node/src/grpc/base_node_grpc_server.rs +++ b/applications/tari_base_node/src/grpc/base_node_grpc_server.rs @@ -48,7 +48,7 @@ use tari_core::{ iterators::NonOverlappingIntegerPairIter, mempool::{service::LocalMempoolService, TxStorageResponse}, proof_of_work::PowAlgorithm, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, }; use tari_p2p::{auto_update::SoftwareUpdaterHandle, services::liveness::LivenessHandle}; use tari_utilities::{hex::Hex, message_format::MessageFormat, ByteArray, Hashable}; @@ -602,8 +602,8 @@ impl tari_rpc::base_node_server::BaseNode for BaseNodeGrpcServer { let response = tari_rpc::ListAssetRegistrationsResponse { asset_public_key: output .features - .mint_non_fungible - .map(|mint| mint.asset_public_key.to_vec()) + .asset + .map(|asset| asset.public_key.to_vec()) .unwrap_or_default(), unique_id: output.features.unique_id.unwrap_or_default(), owner_commitment: output.commitment.to_vec(), diff --git a/applications/tari_base_node/src/main.rs b/applications/tari_base_node/src/main.rs index 1d1b2c360c..f877df47d7 100644 --- a/applications/tari_base_node/src/main.rs +++ b/applications/tari_base_node/src/main.rs @@ -120,7 +120,12 @@ use tari_app_utilities::{ }; #[cfg(all(unix, feature = "libtor"))] use tari_common::CommsTransport; -use tari_common::{configuration::bootstrap::ApplicationType, exit_codes::ExitCodes, ConfigBootstrap, GlobalConfig}; +use tari_common::{ + configuration::bootstrap::ApplicationType, + exit_codes::{ExitCode, ExitError}, + ConfigBootstrap, + GlobalConfig, +}; use tari_comms::{ peer_manager::PeerFeatures, tor::HiddenServiceControllerError, @@ -146,19 +151,19 @@ const LOG_TARGET: &str = "base_node::app"; /// Application entry point fn main() { - if let Err(exit_code) = main_inner() { - exit_code.eprint_details(); + if let Err(err) = main_inner() { + eprintln!("{:?}", err); + let exit_code = err.exit_code; + eprintln!("{}", exit_code.hint()); error!( target: LOG_TARGET, - "Exiting with code ({}): {:?}", - exit_code.as_i32(), - exit_code + "Exiting with code ({}): {:?}", exit_code as i32, err ); - process::exit(exit_code.as_i32()); + process::exit(exit_code as i32); } } -fn main_inner() -> Result<(), ExitCodes> { +fn main_inner() -> Result<(), ExitError> { #[allow(unused_mut)] // config isn't mutated on windows let (bootstrap, mut config, _) = init_configuration(ApplicationType::BaseNode)?; debug!(target: LOG_TARGET, "Using configuration: {:?}", config); @@ -220,7 +225,7 @@ async fn run_node( config: Arc, bootstrap: ConfigBootstrap, shutdown: Shutdown, -) -> Result<(), ExitCodes> { +) -> Result<(), ExitError> { if bootstrap.tracing_enabled { enable_tracing(); } @@ -244,7 +249,7 @@ async fn run_node( recovery::initiate_recover_db(&config)?; recovery::run_recovery(&config) .await - .map_err(|e| ExitCodes::RecoveryError(e.to_string()))?; + .map_err(|e| ExitError::new(ExitCode::RecoveryError, e))?; return Ok(()); }; @@ -259,29 +264,29 @@ async fn run_node( .map_err(|err| { for boxed_error in err.chain() { if let Some(HiddenServiceControllerError::TorControlPortOffline) = boxed_error.downcast_ref() { - return ExitCodes::TorOffline; + return ExitCode::TorOffline.into(); } if let Some(ChainStorageError::DatabaseResyncRequired(reason)) = boxed_error.downcast_ref() { - return ExitCodes::DbInconsistentState(format!( - "You may need to resync your database because {}", - reason - )); + return ExitError::new( + ExitCode::DbInconsistentState, + format!("You may need to resync your database because {}", reason), + ); } // todo: find a better way to do this if boxed_error.to_string().contains("Invalid force sync peer") { println!("Please check your force sync peers configuration"); - return ExitCodes::ConfigError(boxed_error.to_string()); + return ExitError::new(ExitCode::ConfigError, boxed_error); } } - ExitCodes::UnknownError(err.to_string()) + ExitError::new(ExitCode::UnknownError, err) })?; if let Some(ref base_node_config) = config.base_node_config { if let Some(ref address) = base_node_config.grpc_address { // Go, GRPC, go go let grpc = crate::grpc::base_node_grpc_server::BaseNodeGrpcServer::from_base_node_context(&ctx); - let socket_addr = multiaddr_to_socketaddr(address).map_err(|e| ExitCodes::ConfigError(e.to_string()))?; + let socket_addr = multiaddr_to_socketaddr(address).map_err(|e| ExitError::new(ExitCode::ConfigError, e))?; task::spawn(run_grpc(grpc, socket_addr, shutdown.to_signal())); } } @@ -352,7 +357,7 @@ async fn run_grpc( .serve_with_shutdown(grpc_address, interrupt_signal.map(|_| ())) .await .map_err(|err| { - error!(target: LOG_TARGET, "GRPC encountered an error:{}", err); + error!(target: LOG_TARGET, "GRPC encountered an error: {}", err); err })?; diff --git a/applications/tari_base_node/src/recovery.rs b/applications/tari_base_node/src/recovery.rs index 280d376a03..648dd94b10 100644 --- a/applications/tari_base_node/src/recovery.rs +++ b/applications/tari_base_node/src/recovery.rs @@ -30,7 +30,12 @@ use std::{ use anyhow::anyhow; use log::*; -use tari_common::{configuration::Network, exit_codes::ExitCodes, DatabaseType, GlobalConfig}; +use tari_common::{ + configuration::Network, + exit_codes::{ExitCode, ExitError}, + DatabaseType, + GlobalConfig, +}; use tari_core::{ chain_storage::{ async_db::AsyncBlockchainDb, @@ -54,19 +59,19 @@ use tari_core::{ pub const LOG_TARGET: &str = "base_node::app"; -pub fn initiate_recover_db(node_config: &GlobalConfig) -> Result<(), ExitCodes> { +pub fn initiate_recover_db(node_config: &GlobalConfig) -> Result<(), ExitError> { // create recovery db match &node_config.db_type { DatabaseType::LMDB(p) => { let _backend = create_recovery_lmdb_database(&p).map_err(|err| { error!(target: LOG_TARGET, "{}", err); - ExitCodes::UnknownError(err.to_string()) + ExitError::new(ExitCode::UnknownError, err) })?; }, _ => { const MSG: &str = "Recovery mode is only available for LMDB"; error!(target: LOG_TARGET, "{}", MSG); - return Err(ExitCodes::UnknownError(MSG.to_string())); + return Err(ExitError::new(ExitCode::UnknownError, MSG)); }, }; Ok(()) diff --git a/applications/tari_collectibles/src-tauri/Cargo.toml b/applications/tari_collectibles/src-tauri/Cargo.toml index 383ddf166f..55f8bae803 100644 --- a/applications/tari_collectibles/src-tauri/Cargo.toml +++ b/applications/tari_collectibles/src-tauri/Cargo.toml @@ -7,13 +7,12 @@ license = "MIT" repository = "https://github.com/tari-project/tari" default-run = "tari_collectibles" edition = "2018" -build = "src/build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [build-dependencies] -tauri-build = { version = "1.0.0-beta.4" } +tauri-build = { version = "1.0.0-beta.4", features = [] } [dependencies] tari_app_grpc = { path = "../../tari_app_grpc" } diff --git a/applications/tari_collectibles/src-tauri/src/build.rs b/applications/tari_collectibles/src-tauri/build.rs similarity index 100% rename from applications/tari_collectibles/src-tauri/src/build.rs rename to applications/tari_collectibles/src-tauri/build.rs diff --git a/applications/tari_collectibles/web-app/package-lock.json b/applications/tari_collectibles/web-app/package-lock.json index c5ff9373ed..f67cdad75c 100644 --- a/applications/tari_collectibles/web-app/package-lock.json +++ b/applications/tari_collectibles/web-app/package-lock.json @@ -9434,9 +9434,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "funding": [ { "type": "individual", @@ -28974,9 +28974,9 @@ } }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==" + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" }, "for-in": { "version": "1.0.2", diff --git a/applications/tari_collectibles/web-app/src/AccountDashboard.js b/applications/tari_collectibles/web-app/src/AccountDashboard.js index 0b79e1d1b1..aa25391e8f 100644 --- a/applications/tari_collectibles/web-app/src/AccountDashboard.js +++ b/applications/tari_collectibles/web-app/src/AccountDashboard.js @@ -176,14 +176,23 @@ class AccountDashboard extends React.Component { }; onSendToAmountChanged = async (e) => { - this.setState({ sendToAmount: parseInt(e.target.value) }); + if ( + RegExp(`^\\d*(\\.\\d{0,${this.state.tip002Data.decimals}})?$`).test( + e.target.value + ) + ) + this.setState({ sendToAmount: e.target.value }); }; onSend = async () => { try { this.setState({ error: "" }); + let sendToAmount = Math.round( + Number(this.state.sendToAmount) * + Math.pow(10, this.state.tip002Data.decimals) + ); let result = await binding.command_asset_wallets_send_to( this.state.assetPublicKey, - this.state.sendToAmount, + sendToAmount, this.state.sendToAddress ); console.log(result); @@ -242,7 +251,7 @@ class AccountDashboard extends React.Component { )} - {this.state.assetInfo.name}{" "} + {this.state.assetInfo.name} {this.state.hasAssetWallet ? ( ) : ( @@ -271,9 +280,9 @@ class AccountDashboard extends React.Component { TIP002 - Balance:{" "} + Balance: {this.state.balance / - Math.pow(10, this.state.tip002Data.decimals)}{" "} + Math.pow(10, this.state.tip002Data.decimals)} {this.state.tip002Data.symbol} @@ -286,7 +295,7 @@ class AccountDashboard extends React.Component { @@ -365,6 +374,6 @@ AccountDashboard.propTypes = { assetPubKey: PropTypes.string, }), }).isRequired, -} +}; export default withRouter(AccountDashboard); diff --git a/applications/tari_collectibles/web-app/src/Create.js b/applications/tari_collectibles/web-app/src/Create.js index 93c5a496d3..31ce44c95f 100644 --- a/applications/tari_collectibles/web-app/src/Create.js +++ b/applications/tari_collectibles/web-app/src/Create.js @@ -56,7 +56,7 @@ class Create extends React.Component { image: "", cid: "", error: "", - ipfsUploadError: null, + imageError: null, isSaving: false, tip001: true, tip002: false, @@ -92,9 +92,9 @@ class Create extends React.Component { try { // only use the first file if multiple are dropped let cid = await this.addFileToIPFS(payload[0]); - this.setState({ cid, ipfsUploadError: null }); + this.setState({ cid, imageError: null }); } catch (e) { - this.setState({ ipfsUploadError: e.toString() }); + this.setState({ imageError: e.toString() }); } } } @@ -294,15 +294,16 @@ class Create extends React.Component { try { let cid = await this.addFileToIPFS(filePath); console.info("IPFS cid: ", cid); - this.setState({ cid, ipfsUploadError: null }); + this.setState({ cid, imageError: null }); } catch (e) { - this.setState({ ipfsUploadError: e.toString() }); + this.setState({ imageError: e.toString() }); } }; addFileToIPFS = async (filePath) => { const parts = filePath.split("/"); const name = parts[parts.length - 1]; + const timestamp = new Date().valueOf(); // unfortunately the ipfs http /add api doesn't play nicely with the tauri http client // resulting in "file argument 'path' is required" // so we'll shell out to the ipfs command @@ -329,7 +330,14 @@ class Create extends React.Component { }); }); - const cp = new Command("ipfs", ["files", "cp", `/ipfs/${cid}`, `/${name}`]); + if (!cid) return; + + const cp = new Command("ipfs", [ + "files", + "cp", + `/ipfs/${cid}`, + `/${timestamp}${name}`, + ]); await cp.spawn(); await new Promise((resolve, reject) => { @@ -347,22 +355,6 @@ class Create extends React.Component { }); return cid; - // console.log("command", command); - // const { success, output, error } = commandOutput(command); - // if (success) { - // const cid = output; - // console.log("cid", cid); - // const command = await runCommand("ipfs", [ - // "files", - // "cp", - // `/ipfs/${cid}`, - // `/${name}`, - // ]); - // const { error } = commandOutput(command); - // if (error) console.error("error: ", error); - // } else { - // console.error("error: ", error); - // } }; render() { @@ -424,7 +416,8 @@ class Create extends React.Component { cid={this.state.cid} setCid={(cid) => this.setState({ cid })} image={this.state.image} - error={this.state.ipfsUploadError} + error={this.state.imageError} + setError={(e) => this.setState({ imageError: e })} /> @@ -550,7 +543,7 @@ ImageSwitch.propTypes = { setMode: PropTypes.func, }; -const ImageUrl = ({ setImage }) => { +const ImageUrl = ({ setImage, setMode }) => { const [url, setUrl] = useState(""); return ( @@ -565,54 +558,78 @@ const ImageUrl = ({ setImage }) => { onChange={(e) => setUrl(e.target.value)} /> + ); }; ImageUrl.propTypes = { setImage: PropTypes.func, + setMode: PropTypes.func, }; -const ImageUpload = ({ selectFile, error }) => { +const ImageUpload = ({ selectFile, setMode }) => { return (

Select an image, or drag and drop an image onto this window

- - {error ? {error} : } +
); }; ImageUpload.propTypes = { selectFile: PropTypes.func, + setMode: PropTypes.func, error: PropTypes.string, }; -const ImageSelector = ({ cid, image, selectFile, setImage, setCid, error }) => { +const ImageSelector = ({ + cid, + image, + selectFile, + setImage, + setCid, + error, + setError, +}) => { const [mode, setMode] = useState(""); + const reset = () => { + setError(""); + setMode(""); + setImage(""); + }; + + if (error) { + return ( +
+ {error} + +
+ ); + } if (image) { return (

-

setImage("")}>Change

+
); } if (cid) { - return ; + return ; } let display; switch (mode) { case "url": - display = ; + display = ; break; case "upload": - display = ; + display = ; break; default: display = ; @@ -628,9 +645,10 @@ ImageSelector.propTypes = { setImage: PropTypes.func, setCid: PropTypes.func, error: PropTypes.string, + setError: PropTypes.func, }; -const IpfsImage = ({ cid, setCid, error }) => { +const IpfsImage = ({ cid, setCid, reset, error }) => { const [src, setSrc] = useState(""); const [httpError, setHttpError] = useState(null); @@ -659,7 +677,15 @@ const IpfsImage = ({ cid, setCid, error }) => {

-

setCid("")}>Change

+
); } @@ -667,7 +693,17 @@ const IpfsImage = ({ cid, setCid, error }) => { if (error || httpError) { return (
- {error || httpError} + + {error || httpError} - is the IPFS daemon running? + +
); } @@ -678,6 +714,7 @@ const IpfsImage = ({ cid, setCid, error }) => { IpfsImage.propTypes = { cid: PropTypes.string, setCid: PropTypes.func, + reset: PropTypes.func, error: PropTypes.string, }; diff --git a/applications/tari_console_wallet/Cargo.toml b/applications/tari_console_wallet/Cargo.toml index 257f2a9f26..351f044d85 100644 --- a/applications/tari_console_wallet/Cargo.toml +++ b/applications/tari_console_wallet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_console_wallet" -version = "0.27.3" +version = "0.28.0" authors = ["The Tari Development Community"] edition = "2018" diff --git a/applications/tari_console_wallet/build.rs b/applications/tari_console_wallet/build.rs new file mode 100644 index 0000000000..1c502c938a --- /dev/null +++ b/applications/tari_console_wallet/build.rs @@ -0,0 +1,11 @@ +#[cfg(windows)] +fn main() { + use std::env; + println!("cargo:rerun-if-changed=icon.res"); + let mut path = env::current_dir().unwrap(); + path.push("icon.res"); + println!("cargo:rustc-link-arg={}", path.into_os_string().into_string().unwrap()); +} + +#[cfg(not(windows))] +fn main() {} diff --git a/applications/tari_console_wallet/icon.ico b/applications/tari_console_wallet/icon.ico new file mode 100644 index 0000000000..be8613e7ea Binary files /dev/null and b/applications/tari_console_wallet/icon.ico differ diff --git a/applications/tari_console_wallet/icon.rc b/applications/tari_console_wallet/icon.rc new file mode 100644 index 0000000000..26527deb57 --- /dev/null +++ b/applications/tari_console_wallet/icon.rc @@ -0,0 +1 @@ +mining_node ICON "icon.ico" \ No newline at end of file diff --git a/applications/tari_console_wallet/icon.res b/applications/tari_console_wallet/icon.res new file mode 100644 index 0000000000..64f8e2ad90 Binary files /dev/null and b/applications/tari_console_wallet/icon.res differ diff --git a/applications/tari_console_wallet/src/automation/command_parser.rs b/applications/tari_console_wallet/src/automation/command_parser.rs index 3d58ae3371..d5e53ff7f6 100644 --- a/applications/tari_console_wallet/src/automation/command_parser.rs +++ b/applications/tari_console_wallet/src/automation/command_parser.rs @@ -128,8 +128,8 @@ pub fn parse_command(command: &str) -> Result { CoinSplit => parse_coin_split(args)?, DiscoverPeer => parse_public_key(args)?, Whois => parse_whois(args)?, - ExportUtxos => parse_export_utxos(args)?, // todo: only show X number of utxos - ExportSpentUtxos => parse_export_spent_utxos(args)?, // todo: only show X number of utxos + ExportUtxos => parse_export_utxos(args)?, + ExportSpentUtxos => parse_export_spent_utxos(args)?, CountUtxos => Vec::new(), SetBaseNode => parse_public_key_and_address(args)?, SetCustomBaseNode => parse_public_key_and_address(args)?, diff --git a/applications/tari_console_wallet/src/automation/commands.rs b/applications/tari_console_wallet/src/automation/commands.rs index 7404be6eaa..f9065b5aa9 100644 --- a/applications/tari_console_wallet/src/automation/commands.rs +++ b/applications/tari_console_wallet/src/automation/commands.rs @@ -44,7 +44,7 @@ use tari_comms::{ use tari_comms_dht::{envelope::NodeDestination, DhtDiscoveryRequester}; use tari_core::transactions::{ tari_amount::{uT, MicroTari, Tari}, - transaction::{TransactionOutput, UnblindedOutput}, + transaction_components::{TransactionOutput, UnblindedOutput}, }; use tari_crypto::{ keys::PublicKey as PublicKeyTrait, @@ -113,7 +113,7 @@ pub struct SentTransaction {} fn get_transaction_parameters( args: Vec, ) -> Result<(MicroTari, MicroTari, PublicKey, String), CommandError> { - // TODO: Consolidate "fee per gram" in codebase + // TODO: Consolidate "fee per gram" in codebase #LOGGED let fee_per_gram = 25 * uT; use ParsedArgument::*; @@ -138,7 +138,7 @@ fn get_transaction_parameters( fn get_init_sha_atomic_swap_parameters( args: Vec, ) -> Result<(MicroTari, MicroTari, PublicKey, String), CommandError> { - // TODO: Consolidate "fee per gram" in codebase + // TODO: Consolidate "fee per gram" in codebase #LOGGED let fee_per_gram = 25 * uT; use ParsedArgument::*; @@ -801,7 +801,7 @@ pub async fn command_runner( let name = parsed.args[0].to_string(); let message = format!("Register asset: {}", name); let mut manager = wallet.asset_manager.clone(); - // todo: key manager + // todo: key manager #LOGGED let mut rng = rand::thread_rng(); let (_, public_key) = PublicKey::random_keypair(&mut rng); let (tx_id, transaction) = manager diff --git a/applications/tari_console_wallet/src/automation/error.rs b/applications/tari_console_wallet/src/automation/error.rs index 617887a6df..ea521dd8e6 100644 --- a/applications/tari_console_wallet/src/automation/error.rs +++ b/applications/tari_console_wallet/src/automation/error.rs @@ -23,10 +23,10 @@ use std::num::{ParseFloatError, ParseIntError}; use log::*; -use tari_common::exit_codes::ExitCodes; +use tari_common::exit_codes::{ExitCode, ExitError}; use tari_core::transactions::{ tari_amount::{MicroTariError, TariConversionError}, - transaction::TransactionError, + transaction_components::TransactionError, }; use tari_utilities::hex::HexError; use tari_wallet::{ @@ -70,10 +70,10 @@ pub enum CommandError { ShaError(String), } -impl From for ExitCodes { +impl From for ExitError { fn from(err: CommandError) -> Self { error!(target: LOG_TARGET, "{}", err); - Self::CommandError(err.to_string()) + Self::new(ExitCode::CommandError, err) } } @@ -103,10 +103,10 @@ pub enum ParseError { Unimplemented(String), } -impl From for ExitCodes { +impl From for ExitError { fn from(err: ParseError) -> Self { error!(target: LOG_TARGET, "{}", err); let msg = format!("Failed to parse input file commands! {}", err); - Self::InputError(msg) + Self::new(ExitCode::InputError, msg) } } diff --git a/applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs b/applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs index d394bcb338..3d4366fb7f 100644 --- a/applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs +++ b/applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs @@ -64,6 +64,8 @@ use tari_app_grpc::{ RevalidateResponse, SendShaAtomicSwapRequest, SendShaAtomicSwapResponse, + SetBaseNodeRequest, + SetBaseNodeResponse, TransactionDirection, TransactionInfo, TransactionStatus, @@ -76,10 +78,10 @@ use tari_common_types::{ array::copy_into_fixed_array, types::{BlockHash, PublicKey, Signature}, }; -use tari_comms::{types::CommsPublicKey, CommsNode}; +use tari_comms::{multiaddr::Multiaddr, types::CommsPublicKey, CommsNode}; use tari_core::transactions::{ tari_amount::MicroTari, - transaction::{OutputFeatures, UnblindedOutput}, + transaction_components::{OutputFeatures, UnblindedOutput}, }; use tari_crypto::{ristretto::RistrettoPublicKey, tari_utilities::Hashable}; use tari_utilities::{hex::Hex, ByteArray}; @@ -150,6 +152,29 @@ impl wallet_server::Wallet for WalletGrpcServer { })) } + async fn set_base_node( + &self, + request: Request, + ) -> Result, Status> { + let message = request.into_inner(); + let public_key = PublicKey::from_hex(&message.public_key_hex) + .map_err(|e| Status::invalid_argument(format!("Base node public key was not a valid pub key: {}", e)))?; + let net_address = message + .net_address + .parse::() + .map_err(|e| Status::invalid_argument(format!("Base node net address was not valid: {}", e)))?; + + println!("Setting base node peer..."); + println!("{}::{}", public_key, net_address); + let mut wallet = self.wallet.clone(); + wallet + .set_base_node_peer(public_key.clone(), net_address.clone()) + .await + .map_err(|e| Status::internal(format!("{:?}", e)))?; + + Ok(Response::new(SetBaseNodeResponse {})) + } + async fn get_balance(&self, _request: Request) -> Result, Status> { let mut output_service = self.get_output_manager_service(); let balance; @@ -514,7 +539,7 @@ impl wallet_server::Wallet for WalletGrpcServer { dest_pk: txn.destination_public_key.to_vec(), status: TransactionStatus::from(txn.status) as i32, amount: txn.amount.into(), - is_cancelled: txn.cancelled, + is_cancelled: txn.cancelled.is_some(), direction: TransactionDirection::from(txn.direction) as i32, fee: txn.fee.into(), timestamp: Some(naive_datetime_to_timestamp(txn.timestamp)), @@ -525,7 +550,6 @@ impl wallet_server::Wallet for WalletGrpcServer { .get_signature() .to_vec(), message: txn.message, - valid: txn.valid, }), }; match sender.send(Ok(response)).await { @@ -739,8 +763,8 @@ impl wallet_server::Wallet for WalletGrpcServer { let mut transaction_service = self.wallet.transaction_service.clone(); let message = request.into_inner(); - // TODO: Clean up unwrap - let asset_public_key = PublicKey::from_bytes(message.asset_public_key.as_slice()).unwrap(); + let asset_public_key = + PublicKey::from_bytes(message.asset_public_key.as_slice()).map_err(|e| Status::internal(e.to_string()))?; let asset = asset_manager .get_owned_asset_by_pub_key(&asset_public_key) .await @@ -906,7 +930,6 @@ fn convert_wallet_transaction_into_transaction_info( excess_sig: Default::default(), timestamp: Some(naive_datetime_to_timestamp(tx.timestamp)), message: tx.message, - valid: true, }, PendingOutbound(tx) => TransactionInfo { tx_id: tx.tx_id.into(), @@ -920,7 +943,6 @@ fn convert_wallet_transaction_into_transaction_info( excess_sig: Default::default(), timestamp: Some(naive_datetime_to_timestamp(tx.timestamp)), message: tx.message, - valid: true, }, Completed(tx) => TransactionInfo { tx_id: tx.tx_id.into(), @@ -928,7 +950,7 @@ fn convert_wallet_transaction_into_transaction_info( dest_pk: tx.destination_public_key.to_vec(), status: TransactionStatus::from(tx.status) as i32, amount: tx.amount.into(), - is_cancelled: tx.cancelled, + is_cancelled: tx.cancelled.is_some(), direction: TransactionDirection::from(tx.direction) as i32, fee: tx.fee.into(), timestamp: Some(naive_datetime_to_timestamp(tx.timestamp)), @@ -938,7 +960,6 @@ fn convert_wallet_transaction_into_transaction_info( .map(|s| s.get_signature().to_vec()) .unwrap_or_default(), message: tx.message, - valid: tx.valid, }, } } diff --git a/applications/tari_console_wallet/src/init/mod.rs b/applications/tari_console_wallet/src/init/mod.rs index 96644b0f04..7ad81f0542 100644 --- a/applications/tari_console_wallet/src/init/mod.rs +++ b/applications/tari_console_wallet/src/init/mod.rs @@ -26,7 +26,11 @@ use log::*; use rpassword::prompt_password_stdout; use rustyline::Editor; use tari_app_utilities::utilities::create_transport_type; -use tari_common::{exit_codes::ExitCodes, ConfigBootstrap, GlobalConfig}; +use tari_common::{ + exit_codes::{ExitCode, ExitError}, + ConfigBootstrap, + GlobalConfig, +}; use tari_comms::{ multiaddr::Multiaddr, peer_manager::{Peer, PeerFeatures}, @@ -79,7 +83,7 @@ pub enum WalletBoot { pub fn get_or_prompt_password( arg_password: Option, config_password: Option, -) -> Result, ExitCodes> { +) -> Result, ExitError> { if arg_password.is_some() { return Ok(arg_password); } @@ -88,7 +92,7 @@ pub fn get_or_prompt_password( if let Some(p) = env { let env_password = Some( p.into_string() - .map_err(|_| ExitCodes::IOError("Failed to convert OsString into String".to_string()))?, + .map_err(|_| ExitError::new(ExitCode::IOError, "Failed to convert OsString into String"))?, ); return Ok(env_password); } @@ -102,9 +106,9 @@ pub fn get_or_prompt_password( Ok(Some(password)) } -fn prompt_password(prompt: &str) -> Result { +fn prompt_password(prompt: &str) -> Result { let password = loop { - let pass = prompt_password_stdout(prompt).map_err(|e| ExitCodes::IOError(e.to_string()))?; + let pass = prompt_password_stdout(prompt).map_err(|e| ExitError::new(ExitCode::IOError, e))?; if pass.is_empty() { println!("Password cannot be empty!"); continue; @@ -121,25 +125,25 @@ pub async fn change_password( config: &GlobalConfig, arg_password: Option, shutdown_signal: ShutdownSignal, -) -> Result<(), ExitCodes> { +) -> Result<(), ExitError> { let mut wallet = init_wallet(config, arg_password, None, None, shutdown_signal).await?; let passphrase = prompt_password("New wallet password: ")?; let confirmed = prompt_password("Confirm new password: ")?; if passphrase != confirmed { - return Err(ExitCodes::InputError("Passwords don't match!".to_string())); + return Err(ExitError::new(ExitCode::InputError, "Passwords don't match!")); } wallet .remove_encryption() .await - .map_err(|e| ExitCodes::WalletError(e.to_string()))?; + .map_err(|e| ExitError::new(ExitCode::WalletError, e))?; wallet .apply_encryption(passphrase) .await - .map_err(|e| ExitCodes::WalletError(e.to_string()))?; + .map_err(|e| ExitError::new(ExitCode::WalletError, e))?; println!("Wallet password changed successfully."); @@ -153,7 +157,7 @@ pub async fn change_password( pub async fn get_base_node_peer_config( config: &GlobalConfig, wallet: &mut WalletSqlite, -) -> Result { +) -> Result { // custom let mut base_node_custom = get_custom_base_node_peer_from_db(wallet).await; @@ -163,7 +167,10 @@ pub async fn get_base_node_peer_config( base_node_custom = Some(Peer::from(node)); }, Err(err) => { - return Err(ExitCodes::ConfigError(format!("Malformed custom base node: {}", err))); + return Err(ExitError::new( + ExitCode::ConfigError, + format!("Malformed custom base node: {}", err), + )); }, } } @@ -175,7 +182,7 @@ pub async fn get_base_node_peer_config( .map(|s| SeedPeer::from_str(s)) .map(|r| r.map(Peer::from)) .collect::, _>>() - .map_err(|err| ExitCodes::ConfigError(format!("Malformed base node peer: {}", err)))?; + .map_err(|err| ExitError::new(ExitCode::ConfigError, format!("Malformed base node peer: {}", err)))?; // peer seeds let peer_seeds = config @@ -184,7 +191,7 @@ pub async fn get_base_node_peer_config( .map(|s| SeedPeer::from_str(s)) .map(|r| r.map(Peer::from)) .collect::, _>>() - .map_err(|err| ExitCodes::ConfigError(format!("Malformed seed peer: {}", err)))?; + .map_err(|err| ExitError::new(ExitCode::ConfigError, format!("Malformed seed peer: {}", err)))?; let peer_config = PeerConfig::new(base_node_custom, base_node_peers, peer_seeds); debug!(target: LOG_TARGET, "base node peer config: {:?}", peer_config); @@ -222,7 +229,7 @@ pub fn wallet_mode(bootstrap: &ConfigBootstrap, boot_mode: WalletBoot) -> Wallet } /// Get the notify program script path from config bootstrap or global config if provided -pub fn get_notify_script(bootstrap: &ConfigBootstrap, config: &GlobalConfig) -> Result, ExitCodes> { +pub fn get_notify_script(bootstrap: &ConfigBootstrap, config: &GlobalConfig) -> Result, ExitError> { debug!(target: LOG_TARGET, "Checking args and config for notify script."); let notify_script = match (&bootstrap.wallet_notify, &config.console_wallet_notify_file) { @@ -255,7 +262,7 @@ pub fn get_notify_script(bootstrap: &ConfigBootstrap, config: &GlobalConfig) -> if let Some(path) = ¬ify_script { if !path.exists() { let error = format!("Wallet notify script does not exist at path: {:#?}", path); - return Err(ExitCodes::ConfigError(error)); + return Err(ExitError::new(ExitCode::ConfigError, error)); } } @@ -269,16 +276,16 @@ pub async fn init_wallet( seed_words_file_name: Option, recovery_seed: Option, shutdown_signal: ShutdownSignal, -) -> Result { +) -> Result { fs::create_dir_all( &config .console_wallet_db_file .parent() .expect("console_wallet_db_file cannot be set to a root directory"), ) - .map_err(|e| ExitCodes::WalletError(format!("Error creating Wallet folder. {}", e)))?; + .map_err(|e| ExitError::new(ExitCode::WalletError, format!("Error creating Wallet folder. {}", e)))?; fs::create_dir_all(&config.console_wallet_peer_db_path) - .map_err(|e| ExitCodes::WalletError(format!("Error creating peer db folder. {}", e)))?; + .map_err(|e| ExitError::new(ExitCode::WalletError, format!("Error creating peer db folder. {}", e)))?; debug!(target: LOG_TARGET, "Running Wallet database migrations"); @@ -460,9 +467,9 @@ pub async fn init_wallet( .await .map_err(|e| { if let WalletError::CommsInitializationError(e) = e { - ExitCodes::WalletError(e.to_friendly_string()) + ExitError::new(ExitCode::WalletError, e.to_friendly_string()) } else { - ExitCodes::WalletError(format!("Error creating Wallet Container: {}", e)) + ExitError::new(ExitCode::WalletError, format!("Error creating Wallet Container: {}", e)) } })?; if let Some(hs) = wallet.comms.hidden_service() { @@ -470,7 +477,7 @@ pub async fn init_wallet( .db .set_tor_identity(hs.tor_identity().clone()) .await - .map_err(|e| ExitCodes::WalletError(format!("Problem writing tor identity. {}", e)))?; + .map_err(|e| ExitError::new(ExitCode::WalletError, format!("Problem writing tor identity. {}", e)))?; } if !wallet_encrypted { @@ -487,7 +494,7 @@ pub async fn init_wallet( let confirmed = prompt_password("Confirm wallet password: ")?; if password != confirmed { - return Err(ExitCodes::InputError("Passwords don't match!".to_string())); + return Err(ExitError::new(ExitCode::InputError, "Passwords don't match!")); } (password, true) @@ -510,8 +517,12 @@ pub async fn init_wallet( } if let Some(file_name) = seed_words_file_name { let seed_words = wallet.output_manager_service.get_seed_words().await?.join(" "); - let _ = fs::write(file_name, seed_words) - .map_err(|e| ExitCodes::WalletError(format!("Problem writing seed words to file: {}", e))); + let _ = fs::write(file_name, seed_words).map_err(|e| { + ExitError::new( + ExitCode::WalletError, + format!("Problem writing seed words to file: {}", e), + ) + }); }; Ok(wallet) @@ -522,19 +533,24 @@ pub async fn start_wallet( wallet: &mut WalletSqlite, base_node: &Peer, wallet_mode: &WalletMode, -) -> Result<(), ExitCodes> { - // TODO gRPC interfaces for setting base node +) -> Result<(), ExitError> { + // TODO gRPC interfaces for setting base node #LOGGED debug!(target: LOG_TARGET, "Setting base node peer"); let net_address = base_node .addresses .first() - .ok_or_else(|| ExitCodes::ConfigError("Configured base node has no address!".to_string()))?; + .ok_or_else(|| ExitError::new(ExitCode::ConfigError, "Configured base node has no address!"))?; wallet .set_base_node_peer(base_node.public_key.clone(), net_address.address.clone()) .await - .map_err(|e| ExitCodes::WalletError(format!("Error setting wallet base node peer. {}", e)))?; + .map_err(|e| { + ExitError::new( + ExitCode::WalletError, + format!("Error setting wallet base node peer. {}", e), + ) + })?; // Restart transaction protocols if not running in script or command modes @@ -555,12 +571,12 @@ pub async fn start_wallet( Ok(()) } -async fn validate_txos(wallet: &mut WalletSqlite) -> Result<(), ExitCodes> { +async fn validate_txos(wallet: &mut WalletSqlite) -> Result<(), ExitError> { debug!(target: LOG_TARGET, "Starting TXO validations."); wallet.output_manager_service.validate_txos().await.map_err(|e| { error!(target: LOG_TARGET, "Error validating Unspent TXOs: {}", e); - ExitCodes::WalletError(e.to_string()) + ExitError::new(ExitCode::WalletError, e) })?; debug!(target: LOG_TARGET, "TXO validations started."); @@ -568,7 +584,7 @@ async fn validate_txos(wallet: &mut WalletSqlite) -> Result<(), ExitCodes> { Ok(()) } -async fn confirm_seed_words(wallet: &mut WalletSqlite) -> Result<(), ExitCodes> { +async fn confirm_seed_words(wallet: &mut WalletSqlite) -> Result<(), ExitError> { let seed_words = wallet.output_manager_service.get_seed_words().await?; println!(); @@ -595,7 +611,7 @@ async fn confirm_seed_words(wallet: &mut WalletSqlite) -> Result<(), ExitCodes> _ => continue, }, Err(e) => { - return Err(ExitCodes::IOError(e.to_string())); + return Err(ExitError::new(ExitCode::IOError, e)); }, } } @@ -621,16 +637,19 @@ pub fn tari_splash_screen(heading: &str) { /// Prompts the user for a new wallet or to recover an existing wallet. /// Returns the wallet bootmode indicating if it's a new or existing wallet, or if recovery is required. -pub(crate) fn boot(bootstrap: &ConfigBootstrap, config: &GlobalConfig) -> Result { +pub(crate) fn boot(bootstrap: &ConfigBootstrap, config: &GlobalConfig) -> Result { let wallet_exists = config.console_wallet_db_file.exists(); // forced recovery if bootstrap.recovery { if wallet_exists { - return Err(ExitCodes::RecoveryError(format!( - "Wallet already exists at {:#?}. Remove it if you really want to run recovery in this directory!", - config.console_wallet_db_file - ))); + return Err(ExitError::new( + ExitCode::RecoveryError, + format!( + "Wallet already exists at {:#?}. Remove it if you really want to run recovery in this directory!", + config.console_wallet_db_file + ), + )); } return Ok(WalletBoot::Recovery); } @@ -666,7 +685,7 @@ pub(crate) fn boot(bootstrap: &ConfigBootstrap, config: &GlobalConfig) -> Result } }, Err(e) => { - return Err(ExitCodes::IOError(e.to_string())); + return Err(ExitError::new(ExitCode::IOError, e)); }, } } diff --git a/applications/tari_console_wallet/src/main.rs b/applications/tari_console_wallet/src/main.rs index 1ac1cd42a8..50e166faa8 100644 --- a/applications/tari_console_wallet/src/main.rs +++ b/applications/tari_console_wallet/src/main.rs @@ -48,7 +48,11 @@ use recovery::prompt_private_key_from_seed_words; use tari_app_utilities::{consts, initialization::init_configuration}; #[cfg(all(unix, feature = "libtor"))] use tari_common::CommsTransport; -use tari_common::{configuration::bootstrap::ApplicationType, exit_codes::ExitCodes, ConfigBootstrap}; +use tari_common::{ + configuration::bootstrap::ApplicationType, + exit_codes::{ExitCode, ExitError}, + ConfigBootstrap, +}; use tari_key_manager::cipher_seed::CipherSeed; #[cfg(all(unix, feature = "libtor"))] use tari_libtor::tor::Tor; @@ -73,20 +77,19 @@ pub mod wallet_modes; fn main() { match main_inner() { Ok(_) => process::exit(0), - Err(exit_code) => { - eprintln!("{:?}", exit_code); + Err(err) => { + eprintln!("{:?}", err); + let exit_code = err.exit_code; error!( target: LOG_TARGET, - "Exiting with code ({:?}): {:?}", - exit_code.as_i32(), - exit_code + "Exiting with code ({}): {:?}", exit_code as i32, exit_code ); - process::exit(exit_code.as_i32()) + process::exit(exit_code as i32) }, } } -fn main_inner() -> Result<(), ExitCodes> { +fn main_inner() -> Result<(), ExitError> { let runtime = tokio::runtime::Builder::new_multi_thread() .enable_all() .build() @@ -197,8 +200,9 @@ fn main_inner() -> Result<(), ExitCodes> { WalletMode::Script(path) => script_mode(config, wallet.clone(), path), WalletMode::Command(command) => command_mode(config, wallet.clone(), command), WalletMode::RecoveryDaemon | WalletMode::RecoveryTui => recovery_mode(config, wallet.clone()), - WalletMode::Invalid => Err(ExitCodes::InputError( - "Invalid wallet mode - are you trying too many command options at once?".to_string(), + WalletMode::Invalid => Err(ExitError::new( + ExitCode::InputError, + "Invalid wallet mode - are you trying too many command options at once?", )), }; @@ -210,7 +214,7 @@ fn main_inner() -> Result<(), ExitCodes> { result } -fn get_recovery_seed(boot_mode: WalletBoot, bootstrap: &ConfigBootstrap) -> Result, ExitCodes> { +fn get_recovery_seed(boot_mode: WalletBoot, bootstrap: &ConfigBootstrap) -> Result, ExitError> { if matches!(boot_mode, WalletBoot::Recovery) { let seed = if bootstrap.seed_words.is_some() { let seed_words: Vec = bootstrap @@ -238,10 +242,14 @@ fn enable_tracing() { global::set_text_map_propagator(opentelemetry_jaeger::Propagator::new()); let tracer = opentelemetry_jaeger::new_pipeline() .with_service_name("tari::console_wallet") - .with_tags(vec![KeyValue::new("pid", process::id().to_string()), KeyValue::new("current_exe", env::current_exe().unwrap().to_str().unwrap_or_default().to_owned())]) - // TODO: uncomment when using tokio 1 - // .install_batch(opentelemetry::runtime::Tokio) - .install_simple() + .with_tags(vec![ + KeyValue::new("pid", process::id().to_string()), + KeyValue::new( + "current_exe", + env::current_exe().unwrap().to_str().unwrap_or_default().to_owned(), + ), + ]) + .install_batch(opentelemetry::runtime::Tokio) .unwrap(); let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); let subscriber = Registry::default().with(telemetry); diff --git a/applications/tari_console_wallet/src/recovery.rs b/applications/tari_console_wallet/src/recovery.rs index 54b01a8571..0b81b25b73 100644 --- a/applications/tari_console_wallet/src/recovery.rs +++ b/applications/tari_console_wallet/src/recovery.rs @@ -24,7 +24,7 @@ use chrono::offset::Local; use futures::FutureExt; use log::*; use rustyline::Editor; -use tari_common::exit_codes::ExitCodes; +use tari_common::exit_codes::{ExitCode, ExitError}; use tari_crypto::tari_utilities::hex::Hex; use tari_key_manager::{cipher_seed::CipherSeed, mnemonic::Mnemonic}; use tari_shutdown::Shutdown; @@ -40,7 +40,7 @@ use crate::wallet_modes::PeerConfig; pub const LOG_TARGET: &str = "wallet::recovery"; /// Prompt the user to input their seed words in a single line. -pub fn prompt_private_key_from_seed_words() -> Result { +pub fn prompt_private_key_from_seed_words() -> Result { debug!(target: LOG_TARGET, "Prompting for seed words."); let mut rl = Editor::<()>::new(); @@ -48,7 +48,7 @@ pub fn prompt_private_key_from_seed_words() -> Result { println!("Recovery Mode"); println!(); println!("Type or paste all of your seed words on one line, only separated by spaces."); - let input = rl.readline(">> ").map_err(|e| ExitCodes::IOError(e.to_string()))?; + let input = rl.readline(">> ").map_err(|e| ExitError::new(ExitCode::IOError, e))?; let seed_words: Vec = input.split_whitespace().map(str::to_string).collect(); match CipherSeed::from_mnemonic(&seed_words, None) { @@ -63,14 +63,14 @@ pub fn prompt_private_key_from_seed_words() -> Result { } /// Return seed matching the seed words. -pub fn get_seed_from_seed_words(seed_words: Vec) -> Result { +pub fn get_seed_from_seed_words(seed_words: Vec) -> Result { debug!(target: LOG_TARGET, "Return seed derived from the provided seed words"); match CipherSeed::from_mnemonic(&seed_words, None) { Ok(seed) => Ok(seed), Err(e) => { let err_msg = format!("MnemonicError parsing seed words: {}", e); warn!(target: LOG_TARGET, "{}", err_msg); - Err(ExitCodes::RecoveryError(err_msg)) + Err(ExitError::new(ExitCode::RecoveryError, err_msg)) }, } } @@ -82,7 +82,7 @@ pub async fn wallet_recovery( wallet: &WalletSqlite, base_node_config: &PeerConfig, retry_limit: usize, -) -> Result<(), ExitCodes> { +) -> Result<(), ExitError> { println!("\nPress Ctrl-C to stop the recovery process\n"); // We dont care about the shutdown signal here, so we just create one let shutdown = Shutdown::new(); @@ -103,7 +103,7 @@ pub async fn wallet_recovery( peer_manager .add_peer(peer) .await - .map_err(|err| ExitCodes::NetworkError(err.to_string()))?; + .map_err(|err| ExitError::new(ExitCode::NetworkError, err))?; } let mut recovery_task = UtxoScannerService::::builder() @@ -200,6 +200,6 @@ pub async fn wallet_recovery( recovery_join_handle .await - .map_err(|e| ExitCodes::RecoveryError(format!("{}", e)))? - .map_err(|e| ExitCodes::RecoveryError(format!("{}", e))) + .map_err(|e| ExitError::new(ExitCode::RecoveryError, e))? + .map_err(|e| ExitError::new(ExitCode::RecoveryError, e)) } diff --git a/applications/tari_console_wallet/src/ui/app.rs b/applications/tari_console_wallet/src/ui/app.rs index 145ce992e4..a67078909b 100644 --- a/applications/tari_console_wallet/src/ui/app.rs +++ b/applications/tari_console_wallet/src/ui/app.rs @@ -36,6 +36,7 @@ use crate::{ components::{ assets_tab::AssetsTab, base_node::BaseNode, + contacts_tab::ContactsTab, events_component::EventsComponent, log_tab::LogTab, menu::Menu, @@ -91,6 +92,7 @@ impl App { .add("Transactions".into(), Box::new(TransactionsTab::new())) .add("Send".into(), Box::new(SendTab::new(&app_state))) .add("Receive".into(), Box::new(ReceiveTab::new())) + .add("Contacts".into(), Box::new(ContactsTab::new())) .add("Network".into(), Box::new(NetworkTab::new(base_node_selected))) .add("Assets".into(), Box::new(AssetsTab::new())) .add("Tokens".into(), Box::new(TokensComponent::new())) @@ -173,17 +175,20 @@ impl App { .constraints([Constraint::Length(MAX_WIDTH), Constraint::Min(0)].as_ref()) .split(f.size()); let title_chunks = Layout::default() - .constraints([Constraint::Length(3), Constraint::Min(0), Constraint::Length(2)].as_ref()) + .constraints( + [ + Constraint::Length(3), + Constraint::Min(0), + Constraint::Length(2), + Constraint::Length(1), + ] + .as_ref(), + ) .split(max_width_layout[0]); - let title_halves = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(65), Constraint::Percentage(35)].as_ref()) - .split(title_chunks[0]); - - self.tabs.draw_titles(f, title_halves[0], &self.app_state); - self.base_node_status.draw(f, title_halves[1], &self.app_state); + self.tabs.draw_titles(f, title_chunks[0], &self.app_state); self.tabs.draw_content(f, title_chunks[1], &mut self.app_state); - self.menu.draw(f, title_chunks[2], &self.app_state); + self.base_node_status.draw(f, title_chunks[2], &self.app_state); + self.menu.draw(f, title_chunks[3], &self.app_state); } } diff --git a/applications/tari_console_wallet/src/ui/components/base_node.rs b/applications/tari_console_wallet/src/ui/components/base_node.rs index bfe2bd1c79..118f706455 100644 --- a/applications/tari_console_wallet/src/ui/components/base_node.rs +++ b/applications/tari_console_wallet/src/ui/components/base_node.rs @@ -23,14 +23,14 @@ use tari_wallet::connectivity_service::{OnlineStatus, WalletConnectivityInterface}; use tui::{ backend::Backend, - layout::Rect, - style::{Color, Modifier, Style}, + layout::{Constraint, Direction, Layout, Rect}, + style::{Color, Style}, text::{Span, Spans}, widgets::{Block, Borders, Paragraph}, Frame, }; -use crate::ui::{components::Component, state::AppState}; +use crate::ui::{components::Component, state::AppState, MAX_WIDTH}; pub struct BaseNode {} @@ -43,9 +43,13 @@ impl BaseNode { impl Component for BaseNode { fn draw(&mut self, f: &mut Frame, area: Rect, app_state: &AppState) where B: Backend { - let base_node_state = app_state.get_base_node_state(); - let current_online_status = app_state.get_wallet_connectivity().get_connectivity_status(); + let title = Spans::from(vec![Span::styled( + " Base Node Status - ", + Style::default().fg(Color::White), + )]); + let current_online_status = app_state.get_wallet_connectivity().get_connectivity_status(); + let mut base_node_id_color = Color::White; let chain_info = match current_online_status { OnlineStatus::Connecting => Spans::from(vec![ Span::styled("Chain Tip:", Style::default().fg(Color::Magenta)), @@ -58,14 +62,27 @@ impl Component for BaseNode { Span::styled("Offline", Style::default().fg(Color::Red)), ]), OnlineStatus::Online => { + let base_node_state = app_state.get_base_node_state(); if let Some(ref metadata) = base_node_state.chain_metadata { let tip = metadata.height_of_longest_chain(); let synced = base_node_state.is_synced.unwrap_or_default(); let (tip_color, sync_text) = if synced { - (Color::Green, "Synced.") + ( + { + base_node_id_color = Color::Green; + base_node_id_color + }, + "Synced.", + ) } else { - (Color::Yellow, "Syncing...") + ( + { + base_node_id_color = Color::Yellow; + base_node_id_color + }, + "Syncing...", + ) }; let latency = base_node_state.latency.unwrap_or_default().as_millis(); @@ -100,11 +117,42 @@ impl Component for BaseNode { }, }; - let chain_metadata_paragraph = - Paragraph::new(chain_info).block(Block::default().borders(Borders::ALL).title(Span::styled( - "Base Node Status:", - Style::default().fg(Color::White).add_modifier(Modifier::BOLD), - ))); - f.render_widget(chain_metadata_paragraph, area); + let base_node_id = Spans::from(vec![ + Span::styled(" Connected Base Node ID: ", Style::default().fg(Color::Magenta)), + Span::styled( + format!("{}", app_state.get_selected_base_node().node_id.clone()), + Style::default().fg(base_node_id_color), + ), + Span::styled(" ", Style::default().fg(Color::White)), + ]); + + let chunks = Layout::default() + .constraints([Constraint::Length(1), Constraint::Length(1)].as_ref()) + .split(area); + + let columns = Layout::default() + .direction(Direction::Horizontal) + .constraints( + [ + Constraint::Ratio(title.width() as u32, MAX_WIDTH as u32), + Constraint::Ratio( + MAX_WIDTH.saturating_sub((title.width() + base_node_id.width()) as u16) as u32, + MAX_WIDTH as u32, + ), + Constraint::Ratio(base_node_id.width() as u32, MAX_WIDTH as u32), + ] + .as_ref(), + ) + .split(chunks[0]); + + let paragraph = Paragraph::new(title).block(Block::default()); + f.render_widget(paragraph, columns[0]); + let paragraph = Paragraph::new(chain_info).block(Block::default()); + f.render_widget(paragraph, columns[1]); + let paragraph = Paragraph::new(base_node_id).block(Block::default()); + f.render_widget(paragraph, columns[2]); + + let divider = Block::default().borders(Borders::BOTTOM); + f.render_widget(divider, chunks[1]); } } diff --git a/applications/tari_console_wallet/src/ui/components/contacts_tab.rs b/applications/tari_console_wallet/src/ui/components/contacts_tab.rs new file mode 100644 index 0000000000..169388104c --- /dev/null +++ b/applications/tari_console_wallet/src/ui/components/contacts_tab.rs @@ -0,0 +1,371 @@ +use tokio::runtime::Handle; +use tui::{ + backend::Backend, + layout::{Constraint, Layout, Rect}, + style::{Color, Modifier, Style}, + text::{Span, Spans}, + widgets::{Block, Borders, Clear, ListItem, Paragraph, Wrap}, + Frame, +}; +use unicode_width::UnicodeWidthStr; + +use crate::{ + ui::{ + components::{Component, KeyHandled}, + state::AppState, + widgets::{centered_rect_absolute, draw_dialog, MultiColumnList, WindowedListState}, + MAX_WIDTH, + }, + utils::formatting::display_compressed_string, +}; + +pub struct ContactsTab { + edit_contact_mode: ContactInputMode, + show_edit_contact: bool, + alias_field: String, + public_key_field: String, + error_message: Option, + contacts_list_state: WindowedListState, + confirmation_dialog: Option, +} + +impl ContactsTab { + pub fn new() -> Self { + Self { + edit_contact_mode: ContactInputMode::None, + show_edit_contact: false, + alias_field: String::new(), + public_key_field: String::new(), + error_message: None, + contacts_list_state: WindowedListState::new(), + confirmation_dialog: None, + } + } + + fn draw_contacts(&mut self, f: &mut Frame, area: Rect, app_state: &AppState) + where B: Backend { + let block = Block::default().borders(Borders::ALL).title(Span::styled( + "Contacts", + Style::default().fg(Color::White).add_modifier(Modifier::BOLD), + )); + f.render_widget(block, area); + let list_areas = Layout::default() + .constraints([Constraint::Length(1), Constraint::Min(42)].as_ref()) + .margin(1) + .split(area); + + let instructions = Paragraph::new(Spans::from(vec![ + Span::raw("Use "), + Span::styled("Up↑/Down↓ Keys", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to select a contact, "), + Span::styled("E", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" or "), + Span::styled("Enter", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to (e)dit a contact, "), + Span::styled("D", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to (d)elete a contact and "), + Span::styled("N", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to create a (n)ew contact."), + ])) + .wrap(Wrap { trim: true }); + f.render_widget(instructions, list_areas[0]); + self.contacts_list_state.set_num_items(app_state.get_contacts().len()); + let mut list_state = self + .contacts_list_state + .get_list_state((list_areas[1].height as usize).saturating_sub(3)); + let window = self.contacts_list_state.get_start_end(); + let windowed_view = app_state.get_contacts_slice(window.0, window.1); + + let mut column0_items = Vec::new(); + let mut column1_items = Vec::new(); + let mut column2_items = Vec::new(); + for c in windowed_view.iter() { + column0_items.push(ListItem::new(Span::raw(c.alias.clone()))); + column1_items.push(ListItem::new(Span::raw(c.public_key.to_string()))); + column2_items.push(ListItem::new(Span::raw(display_compressed_string( + c.emoji_id.clone(), + 3, + 3, + )))); + } + let column_list = MultiColumnList::new() + .highlight_style(Style::default().add_modifier(Modifier::BOLD).fg(Color::Magenta)) + .heading_style(Style::default().fg(Color::Magenta)) + .max_width(MAX_WIDTH) + .add_column(Some("Alias"), Some(25), column0_items) + .add_column(None, Some(2), Vec::new()) + .add_column(Some("Public Key"), Some(64), column1_items) + .add_column(None, Some(2), Vec::new()) + .add_column(Some("Emoji ID"), None, column2_items); + column_list.render(f, list_areas[1], &mut list_state); + } + + fn draw_edit_contact(&mut self, f: &mut Frame, area: Rect, _app_state: &AppState) + where B: Backend { + let popup_area = centered_rect_absolute(120, 10, area); + + f.render_widget(Clear, popup_area); + + let block = Block::default().borders(Borders::ALL).title(Span::styled( + "Add/Edit Contact", + Style::default().fg(Color::White).add_modifier(Modifier::BOLD), + )); + f.render_widget(block, popup_area); + let vert_chunks = Layout::default() + .constraints([Constraint::Length(2), Constraint::Length(3), Constraint::Length(3)].as_ref()) + .margin(1) + .split(popup_area); + + let instructions = Paragraph::new(Spans::from(vec![ + Span::raw("Press "), + Span::styled("L", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to edit "), + Span::styled("Alias", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" field, "), + Span::styled("K", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to edit "), + Span::styled("Public Key/Emoji ID", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" field, "), + Span::styled("Enter", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to save Contact."), + ])) + .block(Block::default()); + f.render_widget(instructions, vert_chunks[0]); + + let alias_input = Paragraph::new(self.alias_field.as_ref()) + .style(match self.edit_contact_mode { + ContactInputMode::Alias => Style::default().fg(Color::Magenta), + _ => Style::default(), + }) + .block(Block::default().borders(Borders::ALL).title("A(l)ias:")); + f.render_widget(alias_input, vert_chunks[1]); + + let pubkey_input = Paragraph::new(self.public_key_field.as_ref()) + .style(match self.edit_contact_mode { + ContactInputMode::PubkeyEmojiId => Style::default().fg(Color::Magenta), + _ => Style::default(), + }) + .block(Block::default().borders(Borders::ALL).title("Public (K)ey / Emoji Id:")); + f.render_widget(pubkey_input, vert_chunks[2]); + + match self.edit_contact_mode { + ContactInputMode::None => (), + ContactInputMode::Alias => f.set_cursor( + // Put cursor past the end of the input text + vert_chunks[1].x + self.alias_field.width() as u16 + 1, + // Move one line down, from the border to the input line + vert_chunks[1].y + 1, + ), + ContactInputMode::PubkeyEmojiId => f.set_cursor( + // Put cursor past the end of the input text + vert_chunks[2].x + self.public_key_field.width() as u16 + 1, + // Move one line down, from the border to the input line + vert_chunks[2].y + 1, + ), + } + } + + fn on_key_confirmation_dialog(&mut self, c: char, app_state: &mut AppState) -> KeyHandled { + if self.confirmation_dialog.is_some() { + if 'n' == c { + self.confirmation_dialog = None; + return KeyHandled::Handled; + } else if 'y' == c { + match self.confirmation_dialog { + None => (), + Some(ConfirmationDialogType::DeleteContact) => { + if 'y' == c { + if let Some(c) = self + .contacts_list_state + .selected() + .and_then(|i| app_state.get_contact(i)) + .cloned() + { + if let Err(_e) = Handle::current().block_on(app_state.delete_contact(c.public_key)) { + self.error_message = + Some("Could not delete selected contact\nPress Enter to continue.".to_string()); + } + } + self.confirmation_dialog = None; + return KeyHandled::Handled; + } + }, + } + } + } + + KeyHandled::NotHandled + } + + fn on_key_edit_contact(&mut self, c: char, app_state: &mut AppState) -> KeyHandled { + if self.show_edit_contact && self.edit_contact_mode != ContactInputMode::None { + match self.edit_contact_mode { + ContactInputMode::None => return KeyHandled::Handled, + ContactInputMode::Alias => match c { + '\n' | '\t' => { + self.edit_contact_mode = ContactInputMode::PubkeyEmojiId; + return KeyHandled::Handled; + }, + c => { + self.alias_field.push(c); + return KeyHandled::Handled; + }, + }, + ContactInputMode::PubkeyEmojiId => match c { + '\n' => { + self.edit_contact_mode = ContactInputMode::None; + self.show_edit_contact = false; + + if let Err(_e) = Handle::current() + .block_on(app_state.upsert_contact(self.alias_field.clone(), self.public_key_field.clone())) + { + self.error_message = + Some("Invalid Public key or Emoji ID provided\n Press Enter to continue.".to_string()); + } + + self.alias_field = "".to_string(); + self.public_key_field = "".to_string(); + return KeyHandled::Handled; + }, + c => { + self.public_key_field.push(c); + return KeyHandled::Handled; + }, + }, + } + } + + KeyHandled::NotHandled + } + + fn on_key_show_contacts(&mut self, c: char, _app_state: &mut AppState) -> KeyHandled { + match c { + 'd' => { + if self.contacts_list_state.selected().is_none() { + return KeyHandled::NotHandled; + } + self.confirmation_dialog = Some(ConfirmationDialogType::DeleteContact); + return KeyHandled::Handled; + }, + 'n' => { + self.show_edit_contact = true; + self.edit_contact_mode = ContactInputMode::Alias; + return KeyHandled::Handled; + }, + _ => (), + } + + KeyHandled::NotHandled + } +} + +impl Component for ContactsTab { + fn draw(&mut self, f: &mut Frame, area: Rect, app_state: &AppState) { + self.draw_contacts(f, area, app_state); + if self.show_edit_contact { + self.draw_edit_contact(f, area, app_state); + } + + match self.confirmation_dialog { + None => (), + Some(ConfirmationDialogType::DeleteContact) => { + draw_dialog( + f, + area, + "Confirm Delete".to_string(), + "Are you sure you want to delete this contact?\n(Y)es / (N)o".to_string(), + Color::Red, + 120, + 9, + ); + }, + } + } + + fn on_key(&mut self, app_state: &mut AppState, c: char) { + if self.error_message.is_some() { + if '\n' == c { + self.error_message = None; + } + return; + } + + if self.on_key_confirmation_dialog(c, app_state) == KeyHandled::Handled { + return; + } + + if self.on_key_edit_contact(c, app_state) == KeyHandled::Handled { + return; + } + + if self.on_key_show_contacts(c, app_state) == KeyHandled::Handled { + return; + } + + match c { + 'e' | '\n' => { + if let Some(c) = self + .contacts_list_state + .selected() + .and_then(|i| app_state.get_contact(i)) + { + self.public_key_field = c.public_key.clone(); + self.alias_field = c.alias.clone(); + self.show_edit_contact = true; + self.edit_contact_mode = ContactInputMode::Alias; + } + }, + _ => { + self.show_edit_contact = false; + self.edit_contact_mode = ContactInputMode::Alias; + self.public_key_field = "".to_string(); + }, + } + } + + fn on_up(&mut self, app_state: &mut AppState) { + self.contacts_list_state.set_num_items(app_state.get_contacts().len()); + self.contacts_list_state.previous(); + } + + fn on_down(&mut self, app_state: &mut AppState) { + self.contacts_list_state.set_num_items(app_state.get_contacts().len()); + self.contacts_list_state.next(); + } + + fn on_esc(&mut self, _: &mut AppState) { + if self.confirmation_dialog.is_some() { + return; + } + self.edit_contact_mode = ContactInputMode::None; + if self.show_edit_contact { + self.show_edit_contact = false; + } else { + self.contacts_list_state.select(None); + } + } + + fn on_backspace(&mut self, _app_state: &mut AppState) { + match self.edit_contact_mode { + ContactInputMode::Alias => { + let _ = self.alias_field.pop(); + }, + ContactInputMode::PubkeyEmojiId => { + let _ = self.public_key_field.pop(); + }, + ContactInputMode::None => {}, + } + } +} + +#[derive(PartialEq, Debug)] +pub enum ContactInputMode { + None, + Alias, + PubkeyEmojiId, +} + +#[derive(PartialEq, Debug)] +pub enum ConfirmationDialogType { + DeleteContact, +} diff --git a/applications/tari_console_wallet/src/ui/components/mod.rs b/applications/tari_console_wallet/src/ui/components/mod.rs index 80b299bdc5..43d129edcd 100644 --- a/applications/tari_console_wallet/src/ui/components/mod.rs +++ b/applications/tari_console_wallet/src/ui/components/mod.rs @@ -35,6 +35,7 @@ pub mod tabs_container; pub mod tokens_component; pub mod transactions_tab; pub use self::component::*; +pub mod contacts_tab; pub mod events_component; #[derive(PartialEq, Eq)] diff --git a/applications/tari_console_wallet/src/ui/components/network_tab.rs b/applications/tari_console_wallet/src/ui/components/network_tab.rs index 146262c117..0ac5233d27 100644 --- a/applications/tari_console_wallet/src/ui/components/network_tab.rs +++ b/applications/tari_console_wallet/src/ui/components/network_tab.rs @@ -74,7 +74,7 @@ impl NetworkTab { Span::raw("Press "), Span::styled("B", Style::default().add_modifier(Modifier::BOLD)), Span::raw(" and use "), - Span::styled("Up/Down Arrow Keys", Style::default().add_modifier(Modifier::BOLD)), + Span::styled("Up↑/Down↓ Keys", Style::default().add_modifier(Modifier::BOLD)), Span::raw(" to select a new Base Node, "), Span::styled("Enter", Style::default().add_modifier(Modifier::BOLD)), Span::raw(" to set."), diff --git a/applications/tari_console_wallet/src/ui/components/notification_tab.rs b/applications/tari_console_wallet/src/ui/components/notification_tab.rs index 4e15ca6c14..e0866d2c8f 100644 --- a/applications/tari_console_wallet/src/ui/components/notification_tab.rs +++ b/applications/tari_console_wallet/src/ui/components/notification_tab.rs @@ -4,9 +4,9 @@ // are cleared. // Currently notifications are only added from the wallet_event_monitor which has // add_notification method. -// TODO: auto delete old notifications. +// TODO: auto delete old notifications. #LOGGED // TODO: add interaction with the notifications, e.g. if I have a pending transaction -// notification, the UI should go there if I click on it. +// notification, the UI should go there if I click on it. #LOGGED use tari_comms::runtime::Handle; use tui::{ diff --git a/applications/tari_console_wallet/src/ui/components/receive_tab.rs b/applications/tari_console_wallet/src/ui/components/receive_tab.rs index aefe4dfc0b..0e46ac1844 100644 --- a/applications/tari_console_wallet/src/ui/components/receive_tab.rs +++ b/applications/tari_console_wallet/src/ui/components/receive_tab.rs @@ -2,7 +2,7 @@ use tui::{ backend::Backend, layout::{Constraint, Direction, Layout, Rect}, style::{Color, Modifier, Style}, - text::Span, + text::{Span, Spans}, widgets::{Block, Borders, Paragraph}, Frame, }; @@ -24,84 +24,84 @@ impl ReceiveTab { )); f.render_widget(block, area); - let help_body_area = Layout::default() - .constraints([Constraint::Min(42)].as_ref()) - .margin(1) - .split(area); - let chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Length(48), Constraint::Min(1)].as_ref()) + .direction(Direction::Vertical) + .constraints([Constraint::Length(6), Constraint::Length(23)].as_ref()) .margin(1) - .split(help_body_area[0]); + .split(area); + // QR Code let qr_code = Paragraph::new(app_state.get_identity().qr_code.as_str()).block(Block::default()); + f.render_widget(qr_code, chunks[1]); - f.render_widget(qr_code, chunks[0]); - - let info_chunks = Layout::default() + // Connection details + let details_chunks = Layout::default() + .direction(Direction::Vertical) .constraints( [ - Constraint::Length(1), // Lining up fields with Qr Code - Constraint::Length(3), - Constraint::Length(3), - Constraint::Length(3), - Constraint::Length(3), - Constraint::Min(1), + Constraint::Length(1), + Constraint::Length(1), + Constraint::Length(1), + Constraint::Length(1), ] .as_ref(), ) - .horizontal_margin(1) - .split(chunks[1]); + .margin(1) + .split(chunks[0]); - // Public Key let block = Block::default() .borders(Borders::ALL) - .title(Span::styled("Public Key", Style::default().fg(Color::White))); - f.render_widget(block, info_chunks[1]); - let label_layout = Layout::default() - .constraints([Constraint::Length(1)].as_ref()) - .margin(1) - .split(info_chunks[1]); - // Put a space in front of pub key so it's easy to select - let public_key = Paragraph::new(format!(" {}", app_state.get_identity().public_key)); - f.render_widget(public_key, label_layout[0]); + .title(Span::styled("Connection Details", Style::default().fg(Color::White))); + f.render_widget(block, chunks[0]); + + const ITEM_01: &str = "Public Key: "; + const ITEM_02: &str = "Node ID: "; + const ITEM_03: &str = "Public Address: "; + const ITEM_04: &str = "Emoji ID: "; + + // Public Key + let public_key_text = Spans::from(vec![ + Span::styled(ITEM_01, Style::default().fg(Color::Magenta)), + Span::styled( + app_state.get_identity().public_key.clone(), + Style::default().fg(Color::White), + ), + ]); + let paragraph = Paragraph::new(public_key_text).block(Block::default()); + f.render_widget(paragraph, details_chunks[0]); // NodeId - let block = Block::default() - .borders(Borders::ALL) - .title(Span::styled("Node ID", Style::default().fg(Color::White))); - f.render_widget(block, info_chunks[2]); - let label_layout = Layout::default() - .constraints([Constraint::Length(1)].as_ref()) - .margin(1) - .split(info_chunks[2]); - let node_id = Paragraph::new(app_state.get_identity().node_id.as_str()); - f.render_widget(node_id, label_layout[0]); + let node_id_text = Spans::from(vec![ + Span::styled(ITEM_02, Style::default().fg(Color::Magenta)), + Span::styled( + app_state.get_identity().node_id.clone(), + Style::default().fg(Color::White), + ), + ]); + let paragraph = Paragraph::new(node_id_text).block(Block::default()); + f.render_widget(paragraph, details_chunks[1]); // Public Address - let block = Block::default() - .borders(Borders::ALL) - .title(Span::styled("Public Address", Style::default().fg(Color::White))); - f.render_widget(block, info_chunks[3]); - let label_layout = Layout::default() - .constraints([Constraint::Length(1)].as_ref()) - .margin(1) - .split(info_chunks[3]); - let public_address = Paragraph::new(format!(" {}", app_state.get_identity().public_address)); - f.render_widget(public_address, label_layout[0]); + let public_ddress_text = Spans::from(vec![ + Span::styled(ITEM_03, Style::default().fg(Color::Magenta)), + Span::styled( + app_state.get_identity().public_address.clone(), + Style::default().fg(Color::White), + ), + ]); + let paragraph = Paragraph::new(public_ddress_text).block(Block::default()); + f.render_widget(paragraph, details_chunks[2]); // Emoji ID - let block = Block::default() - .borders(Borders::ALL) - .title(Span::styled("Emoji ID", Style::default().fg(Color::White))); - f.render_widget(block, info_chunks[4]); - let label_layout = Layout::default() - .constraints([Constraint::Length(1)].as_ref()) - .margin(1) - .split(info_chunks[4]); - let emoji_id = Paragraph::new(app_state.get_identity().emoji_id.as_str()); - f.render_widget(emoji_id, label_layout[0]); + let emoji_id_text = Spans::from(vec![ + Span::styled(ITEM_04, Style::default().fg(Color::Magenta)), + Span::styled( + app_state.get_identity().emoji_id.clone(), + Style::default().fg(Color::White), + ), + ]); + let paragraph = Paragraph::new(emoji_id_text).block(Block::default()); + f.render_widget(paragraph, details_chunks[3]); } } diff --git a/applications/tari_console_wallet/src/ui/components/send_tab.rs b/applications/tari_console_wallet/src/ui/components/send_tab.rs index 43af6be008..614c0fb619 100644 --- a/applications/tari_console_wallet/src/ui/components/send_tab.rs +++ b/applications/tari_console_wallet/src/ui/components/send_tab.rs @@ -7,7 +7,7 @@ use tui::{ layout::{Constraint, Direction, Layout, Rect}, style::{Color, Modifier, Style}, text::{Span, Spans}, - widgets::{Block, Borders, Clear, ListItem, Paragraph, Row, Table, TableState, Wrap}, + widgets::{Block, Borders, ListItem, Paragraph, Row, Table, TableState, Wrap}, Frame, }; use unicode_width::UnicodeWidthStr; @@ -16,7 +16,7 @@ use crate::{ ui::{ components::{balance::Balance, styles, Component, KeyHandled}, state::{AppState, UiTransactionSendStatus}, - widgets::{centered_rect_absolute, draw_dialog, MultiColumnList, WindowedListState}, + widgets::{draw_dialog, MultiColumnList, WindowedListState}, MAX_WIDTH, }, utils::formatting::display_compressed_string, @@ -25,15 +25,11 @@ use crate::{ pub struct SendTab { balance: Balance, send_input_mode: SendInputMode, - edit_contact_mode: ContactInputMode, show_contacts: bool, - show_edit_contact: bool, to_field: String, amount_field: String, fee_field: String, message_field: String, - alias_field: String, - public_key_field: String, error_message: Option, success_message: Option, contacts_list_state: WindowedListState, @@ -48,15 +44,11 @@ impl SendTab { Self { balance: Balance::new(), send_input_mode: SendInputMode::None, - edit_contact_mode: ContactInputMode::None, show_contacts: false, - show_edit_contact: false, to_field: String::new(), amount_field: String::new(), fee_field: app_state.get_default_fee_per_gram().as_u64().to_string(), message_field: String::new(), - alias_field: String::new(), - public_key_field: String::new(), error_message: None, success_message: None, contacts_list_state: WindowedListState::new(), @@ -211,14 +203,8 @@ impl SendTab { let instructions = Paragraph::new(Spans::from(vec![ Span::raw(" Use "), - Span::styled("Up/Down Arrow Keys", Style::default().add_modifier(Modifier::BOLD)), + Span::styled("Up↑/Down↓ Keys", Style::default().add_modifier(Modifier::BOLD)), Span::raw(" to choose a contact, "), - Span::styled("E", Style::default().add_modifier(Modifier::BOLD)), - Span::raw(" to (e)dit and "), - Span::styled("D", Style::default().add_modifier(Modifier::BOLD)), - Span::raw(" to (d)elete a contact, "), - Span::styled("N", Style::default().add_modifier(Modifier::BOLD)), - Span::raw(" to create a (n)ew contact, "), Span::styled("Enter", Style::default().add_modifier(Modifier::BOLD)), Span::raw(" to select."), ])) @@ -247,77 +233,14 @@ impl SendTab { .highlight_style(Style::default().add_modifier(Modifier::BOLD).fg(Color::Magenta)) .heading_style(Style::default().fg(Color::Magenta)) .max_width(MAX_WIDTH) - .add_column(Some("Alias"), Some(12), column0_items) - .add_column(Some("Public Key"), Some(67), column1_items) + .add_column(Some("Alias"), Some(25), column0_items) + .add_column(None, Some(2), Vec::new()) + .add_column(Some("Public Key"), Some(64), column1_items) + .add_column(None, Some(2), Vec::new()) .add_column(Some("Emoji ID"), None, column2_items); column_list.render(f, list_areas[1], &mut list_state); } - fn draw_edit_contact(&mut self, f: &mut Frame, area: Rect, _app_state: &AppState) - where B: Backend { - let popup_area = centered_rect_absolute(120, 10, area); - - f.render_widget(Clear, popup_area); - - let block = Block::default().borders(Borders::ALL).title(Span::styled( - "Add/Edit Contact", - Style::default().fg(Color::White).add_modifier(Modifier::BOLD), - )); - f.render_widget(block, popup_area); - let vert_chunks = Layout::default() - .constraints([Constraint::Length(2), Constraint::Length(3), Constraint::Length(3)].as_ref()) - .margin(1) - .split(popup_area); - - let instructions = Paragraph::new(Spans::from(vec![ - Span::raw("Press "), - Span::styled("L", Style::default().add_modifier(Modifier::BOLD)), - Span::raw(" to edit "), - Span::styled("Alias", Style::default().add_modifier(Modifier::BOLD)), - Span::raw(" field, "), - Span::styled("K", Style::default().add_modifier(Modifier::BOLD)), - Span::raw(" to edit "), - Span::styled("Public Key/Emoji ID", Style::default().add_modifier(Modifier::BOLD)), - Span::raw(" field, "), - Span::styled("Enter", Style::default().add_modifier(Modifier::BOLD)), - Span::raw(" to save Contact."), - ])) - .block(Block::default()); - f.render_widget(instructions, vert_chunks[0]); - - let alias_input = Paragraph::new(self.alias_field.as_ref()) - .style(match self.edit_contact_mode { - ContactInputMode::Alias => Style::default().fg(Color::Magenta), - _ => Style::default(), - }) - .block(Block::default().borders(Borders::ALL).title("A(l)ias:")); - f.render_widget(alias_input, vert_chunks[1]); - - let pubkey_input = Paragraph::new(self.public_key_field.as_ref()) - .style(match self.edit_contact_mode { - ContactInputMode::PubkeyEmojiId => Style::default().fg(Color::Magenta), - _ => Style::default(), - }) - .block(Block::default().borders(Borders::ALL).title("Public (K)ey / Emoji Id:")); - f.render_widget(pubkey_input, vert_chunks[2]); - - match self.edit_contact_mode { - ContactInputMode::None => (), - ContactInputMode::Alias => f.set_cursor( - // Put cursor past the end of the input text - vert_chunks[1].x + self.alias_field.width() as u16 + 1, - // Move one line down, from the border to the input line - vert_chunks[1].y + 1, - ), - ContactInputMode::PubkeyEmojiId => f.set_cursor( - // Put cursor past the end of the input text - vert_chunks[2].x + self.public_key_field.width() as u16 + 1, - // Move one line down, from the border to the input line - vert_chunks[2].y + 1, - ), - } - } - fn draw_tokens(&mut self, f: &mut Frame, area: Rect, app_state: &AppState) where B: Backend { let tokens = app_state.get_owned_tokens(); @@ -401,7 +324,7 @@ impl SendTab { self.to_field.clone(), amount.into(), self.selected_unique_id.clone(), - None, // TODO: Select the actual value + None, fee_per_gram, self.message_field.clone(), tx, @@ -419,7 +342,7 @@ impl SendTab { self.to_field.clone(), amount.into(), self.selected_unique_id.clone(), - None, // TODO: select actual value + None, fee_per_gram, self.message_field.clone(), tx, @@ -446,23 +369,6 @@ impl SendTab { return KeyHandled::Handled; } }, - Some(ConfirmationDialogType::DeleteContact) => { - if 'y' == c { - if let Some(c) = self - .contacts_list_state - .selected() - .and_then(|i| app_state.get_contact(i)) - .cloned() - { - if let Err(_e) = Handle::current().block_on(app_state.delete_contact(c.public_key)) { - self.error_message = - Some("Could not delete selected contact\nPress Enter to continue.".to_string()); - } - } - self.confirmation_dialog = None; - return KeyHandled::Handled; - } - }, } } } @@ -520,74 +426,19 @@ impl SendTab { KeyHandled::NotHandled } - fn on_key_edit_contact(&mut self, c: char, app_state: &mut AppState) -> KeyHandled { - if self.show_edit_contact && self.edit_contact_mode != ContactInputMode::None { - match self.edit_contact_mode { - ContactInputMode::None => return KeyHandled::Handled, - ContactInputMode::Alias => match c { - '\n' | '\t' => { - self.edit_contact_mode = ContactInputMode::PubkeyEmojiId; - return KeyHandled::Handled; - }, - c => { - self.alias_field.push(c); - return KeyHandled::Handled; - }, - }, - ContactInputMode::PubkeyEmojiId => match c { - '\n' => { - self.edit_contact_mode = ContactInputMode::None; - self.show_edit_contact = false; - - if let Err(_e) = Handle::current() - .block_on(app_state.upsert_contact(self.alias_field.clone(), self.public_key_field.clone())) - { - self.error_message = - Some("Invalid Public key or Emoji ID provided\n Press Enter to continue.".to_string()); - } - - self.alias_field = "".to_string(); - self.public_key_field = "".to_string(); - return KeyHandled::Handled; - }, - c => { - self.public_key_field.push(c); - return KeyHandled::Handled; - }, - }, - } - } - - KeyHandled::NotHandled - } - fn on_key_show_contacts(&mut self, c: char, app_state: &mut AppState) -> KeyHandled { - if self.show_contacts { - match c { - 'd' => { - self.confirmation_dialog = Some(ConfirmationDialogType::DeleteContact); - return KeyHandled::Handled; - }, - '\n' => { - if let Some(c) = self - .contacts_list_state - .selected() - .and_then(|i| app_state.get_contact(i)) - .cloned() - { - self.to_field = c.public_key; - self.send_input_mode = SendInputMode::Amount; - self.show_contacts = false; - } - return KeyHandled::Handled; - }, - 'n' => { - self.show_edit_contact = true; - self.edit_contact_mode = ContactInputMode::Alias; - return KeyHandled::Handled; - }, - _ => (), + if self.show_contacts && c == '\n' { + if let Some(c) = self + .contacts_list_state + .selected() + .and_then(|i| app_state.get_contact(i)) + .cloned() + { + self.to_field = c.public_key; + self.send_input_mode = SendInputMode::Amount; + self.show_contacts = false; } + return KeyHandled::Handled; } KeyHandled::NotHandled @@ -613,9 +464,6 @@ impl Component for SendTab { if self.show_contacts { self.draw_contacts(f, areas[2], app_state); - if self.show_edit_contact { - self.draw_edit_contact(f, area, app_state); - } }; if self.send_input_mode == SendInputMode::Amount { @@ -686,17 +534,6 @@ impl Component for SendTab { 9, ); }, - Some(ConfirmationDialogType::DeleteContact) => { - draw_dialog( - f, - area, - "Confirm Delete".to_string(), - "Are you sure you want to delete this contact?\n(Y)es / (N)o".to_string(), - Color::Red, - 120, - 9, - ); - }, } } @@ -727,10 +564,6 @@ impl Component for SendTab { return; } - if self.on_key_edit_contact(c, app_state) == KeyHandled::Handled { - return; - } - if self.on_key_show_contacts(c, app_state) == KeyHandled::Handled { return; } @@ -738,28 +571,6 @@ impl Component for SendTab { match c { 'c' => { self.show_contacts = !self.show_contacts; - if self.show_contacts { - self.show_edit_contact = false; - self.edit_contact_mode = ContactInputMode::Alias; - self.public_key_field = "".to_string(); - self.amount_field = "".to_string(); - self.message_field = "".to_string(); - self.send_input_mode = SendInputMode::None; - } - }, - 'e' => { - if let Some(c) = self - .contacts_list_state - .selected() - .and_then(|i| app_state.get_contact(i)) - { - self.public_key_field = c.public_key.clone(); - self.alias_field = c.alias.clone(); - if self.show_contacts { - self.show_edit_contact = true; - self.edit_contact_mode = ContactInputMode::Alias; - } - } }, 't' => self.send_input_mode = SendInputMode::To, 'a' => { @@ -835,10 +646,8 @@ impl Component for SendTab { } fn on_esc(&mut self, _: &mut AppState) { - self.edit_contact_mode = ContactInputMode::None; self.send_input_mode = SendInputMode::None; self.show_contacts = false; - self.show_edit_contact = false; } fn on_backspace(&mut self, _app_state: &mut AppState) { @@ -859,16 +668,6 @@ impl Component for SendTab { }, SendInputMode::None => {}, } - - match self.edit_contact_mode { - ContactInputMode::Alias => { - let _ = self.alias_field.pop(); - }, - ContactInputMode::PubkeyEmojiId => { - let _ = self.public_key_field.pop(); - }, - ContactInputMode::None => {}, - } } } @@ -881,16 +680,8 @@ pub enum SendInputMode { Fee, } -#[derive(PartialEq, Debug)] -pub enum ContactInputMode { - None, - Alias, - PubkeyEmojiId, -} - #[derive(PartialEq, Debug)] pub enum ConfirmationDialogType { NormalSend, OneSidedSend, - DeleteContact, } diff --git a/applications/tari_console_wallet/src/ui/components/tabs_container.rs b/applications/tari_console_wallet/src/ui/components/tabs_container.rs index 7fb9380c6b..512e810df2 100644 --- a/applications/tari_console_wallet/src/ui/components/tabs_container.rs +++ b/applications/tari_console_wallet/src/ui/components/tabs_container.rs @@ -91,7 +91,6 @@ impl TabsContainer { impl Component for TabsContainer { fn draw(&mut self, _: &mut Frame, _: Rect, _: &AppState) { // Use draw_titles and draw_content instead, - // TODO: Create a layout and draw both unimplemented!() } diff --git a/applications/tari_console_wallet/src/ui/components/transactions_tab.rs b/applications/tari_console_wallet/src/ui/components/transactions_tab.rs index 315dad68cc..8f59431f48 100644 --- a/applications/tari_console_wallet/src/ui/components/transactions_tab.rs +++ b/applications/tari_console_wallet/src/ui/components/transactions_tab.rs @@ -1,7 +1,9 @@ use std::collections::HashMap; use chrono::{DateTime, Local}; +use log::*; use tari_common_types::transaction::{TransactionDirection, TransactionStatus}; +use tari_wallet::transaction_service::storage::models::TxCancellationReason; use tokio::runtime::Handle; use tui::{ backend::Backend, @@ -19,6 +21,8 @@ use crate::ui::{ MAX_WIDTH, }; +const LOG_TARGET: &str = "wallet::console_wallet::transaction_tab"; + pub struct TransactionsTab { balance: Balance, selected_tx_list: SelectedTransactionList, @@ -93,13 +97,16 @@ impl TransactionsTab { let mut column2_items = Vec::new(); let mut column3_items = Vec::new(); for t in windowed_view.iter() { - let text_color = text_colors.get(&t.cancelled).unwrap_or(&Color::Reset).to_owned(); + let text_color = text_colors + .get(&t.cancelled.is_some()) + .unwrap_or(&Color::Reset) + .to_owned(); if t.direction == TransactionDirection::Outbound { column0_items.push(ListItem::new(Span::styled( app_state.get_alias(&t.destination_public_key), Style::default().fg(text_color), ))); - let amount_style = if t.cancelled { + let amount_style = if t.cancelled.is_some() { Style::default().fg(Color::Red).add_modifier(Modifier::DIM) } else { Style::default().fg(Color::Red) @@ -115,7 +122,7 @@ impl TransactionsTab { app_state.get_alias(&t.source_public_key), Style::default().fg(text_color), ))); - let amount_style = if t.cancelled { + let amount_style = if t.cancelled.is_some() { Style::default().fg(Color::Green).add_modifier(Modifier::DIM) } else { Style::default().fg(Color::Green) @@ -188,14 +195,14 @@ impl TransactionsTab { let mut column3_items = Vec::new(); for t in windowed_view.iter() { - let cancelled = t.cancelled || !t.valid; + let cancelled = t.cancelled.is_some(); let text_color = text_colors.get(&cancelled).unwrap_or(&Color::Reset).to_owned(); if t.direction == TransactionDirection::Outbound { column0_items.push(ListItem::new(Span::styled( app_state.get_alias(&t.destination_public_key), Style::default().fg(text_color), ))); - let amount_style = if t.cancelled { + let amount_style = if t.cancelled.is_some() { Style::default().fg(Color::Red).add_modifier(Modifier::DIM) } else { Style::default().fg(Color::Red) @@ -211,7 +218,7 @@ impl TransactionsTab { app_state.get_alias(&t.source_public_key), Style::default().fg(text_color), ))); - let color = match (t.cancelled, chain_height) { + let color = match (t.cancelled.is_some(), chain_height) { // cancelled (true, _) => Color::DarkGray, // not mature yet @@ -232,14 +239,12 @@ impl TransactionsTab { format!("{}", local_time.format("%Y-%m-%d %H:%M:%S")), Style::default().fg(text_color), ))); - let status = if (t.cancelled || !t.valid) && t.status == TransactionStatus::Coinbase { + let status = if matches!(t.cancelled, Some(TxCancellationReason::AbandonedCoinbase)) { "Abandoned".to_string() - } else if t.cancelled && t.status == TransactionStatus::Rejected { - "Rejected".to_string() - } else if t.cancelled { + } else if matches!(t.cancelled, Some(TxCancellationReason::UserCancelled)) { "Cancelled".to_string() - } else if !t.valid { - "Invalid".to_string() + } else if t.cancelled.is_some() { + "Rejected".to_string() } else { t.status.to_string() }; @@ -375,15 +380,12 @@ impl TransactionsTab { Span::styled(format!("{}", tx.fee), Style::default().fg(Color::White)), fee_details, ]); - let status_msg = if tx.cancelled && tx.status == TransactionStatus::Rejected { - "Rejected".to_string() - } else if tx.cancelled { - "Cancelled".to_string() - } else if !tx.valid { - "Invalid".to_string() + let status_msg = if let Some(reason) = tx.cancelled { + format!("Cancelled: {}", reason) } else { tx.status.to_string() }; + let status = Span::styled(status_msg, Style::default().fg(Color::White)); let message = Span::styled(tx.message.as_str(), Style::default().fg(Color::White)); let local_time = DateTime::::from_utc(tx.timestamp, Local::now().offset().to_owned()); @@ -393,9 +395,9 @@ impl TransactionsTab { ); let excess = Span::styled(tx.excess_signature.as_str(), Style::default().fg(Color::White)); let confirmation_count = app_state.get_confirmations(&tx.tx_id); - let confirmations_msg = if tx.status == TransactionStatus::MinedConfirmed && !tx.cancelled { + let confirmations_msg = if tx.status == TransactionStatus::MinedConfirmed && tx.cancelled.is_none() { format!("{} required confirmations met", required_confirmations) - } else if tx.status == TransactionStatus::MinedUnconfirmed && !tx.cancelled { + } else if tx.status == TransactionStatus::MinedUnconfirmed && tx.cancelled.is_none() { if let Some(count) = confirmation_count { format!("{} of {} required confirmations met", count, required_confirmations) } else { @@ -474,18 +476,20 @@ impl Component for TransactionsTab { }; span_vec.push(Span::styled( - "Up/Down Arrow", + " Up↑/Down↓", Style::default().add_modifier(Modifier::BOLD), )); - span_vec.push(Span::raw(" selects a transaction, ")); + span_vec.push(Span::raw(" selects Tx, ")); span_vec.push(Span::styled("C", Style::default().add_modifier(Modifier::BOLD))); - span_vec.push(Span::raw(" cancels a selected Pending Tx, ")); + span_vec.push(Span::raw(" cancels selected Pending Tx, ")); span_vec.push(Span::styled("A", Style::default().add_modifier(Modifier::BOLD))); span_vec.push(Span::raw(" shows abandoned coinbase Txs, ")); + span_vec.push(Span::styled("R", Style::default().add_modifier(Modifier::BOLD))); + span_vec.push(Span::raw(" rebroadcast all Broadcast, ")); span_vec.push(Span::styled("Esc", Style::default().add_modifier(Modifier::BOLD))); - span_vec.push(Span::raw(" exits the list. R: Rebroadcast all in Broadcast")); + span_vec.push(Span::raw(" exits list.")); - let instructions = Paragraph::new(Spans::from(span_vec)).wrap(Wrap { trim: true }); + let instructions = Paragraph::new(Spans::from(span_vec)).wrap(Wrap { trim: false }); f.render_widget(instructions, areas[1]); self.draw_transaction_lists(f, areas[2], app_state); @@ -571,8 +575,9 @@ impl Component for TransactionsTab { }, // Rebroadcast 'r' => { - // TODO: use this result - let _res = Handle::current().block_on(app_state.rebroadcast_all()); + if let Err(e) = Handle::current().block_on(app_state.rebroadcast_all()) { + error!(target: LOG_TARGET, "Error rebroadcasting transactions: {}", e); + } }, 'a' => app_state.toggle_abandoned_coinbase_filter(), '\n' => match self.selected_tx_list { diff --git a/applications/tari_console_wallet/src/ui/mod.rs b/applications/tari_console_wallet/src/ui/mod.rs index bdb00f239d..24f0f6ed33 100644 --- a/applications/tari_console_wallet/src/ui/mod.rs +++ b/applications/tari_console_wallet/src/ui/mod.rs @@ -21,7 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use log::error; -use tari_common::exit_codes::ExitCodes; +use tari_common::exit_codes::{ExitCode, ExitError}; use crate::utils::crossterm_events::CrosstermEvents; @@ -52,7 +52,7 @@ use crate::utils::events::{Event, EventStream}; pub const MAX_WIDTH: u16 = 133; -pub fn run(app: App>) -> Result<(), ExitCodes> { +pub fn run(app: App>) -> Result<(), ExitError> { let mut app = app; Handle::current() .block_on(async { @@ -74,42 +74,42 @@ pub fn run(app: App>) -> Result<(), ExitCodes> { app.app_state.start_event_monitor(app.notifier.clone()).await; Result::<_, UiError>::Ok(()) }) - .map_err(|e| ExitCodes::WalletError(e.to_string()))?; + .map_err(|e| ExitError::new(ExitCode::WalletError, e))?; crossterm_loop(app) } /// This is the main loop of the application UI using Crossterm based events -fn crossterm_loop(mut app: App>) -> Result<(), ExitCodes> { +fn crossterm_loop(mut app: App>) -> Result<(), ExitError> { let events = CrosstermEvents::new(); enable_raw_mode().map_err(|e| { error!(target: LOG_TARGET, "Error enabling Raw Mode {}", e); - ExitCodes::InterfaceError + ExitCode::InterfaceError })?; let mut stdout = stdout(); execute!(stdout, EnterAlternateScreen).map_err(|e| { error!(target: LOG_TARGET, "Error creating stdout context. {}", e); - ExitCodes::InterfaceError + ExitCode::InterfaceError })?; let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend).map_err(|e| { error!(target: LOG_TARGET, "Error creating Terminal context. {}", e); - ExitCodes::InterfaceError + ExitCode::InterfaceError })?; terminal.clear().map_err(|e| { error!(target: LOG_TARGET, "Error clearing interface. {}", e); - ExitCodes::InterfaceError + ExitCode::InterfaceError })?; loop { terminal.draw(|f| app.draw(f)).map_err(|e| { error!(target: LOG_TARGET, "Error drawing interface. {}", e); - ExitCodes::InterfaceError + ExitCode::InterfaceError })?; match events.next().map_err(|e| { error!(target: LOG_TARGET, "Error reading input event: {}", e); - ExitCodes::InterfaceError + ExitCode::InterfaceError })? { Event::Input(event) => match (event.code, event.modifiers) { (KeyCode::Char(c), KeyModifiers::CONTROL) => app.on_control_key(c), @@ -137,20 +137,20 @@ fn crossterm_loop(mut app: App>) -> Result<(), ExitCode terminal.clear().map_err(|e| { error!(target: LOG_TARGET, "Error clearing interface. {}", e); - ExitCodes::InterfaceError + ExitCode::InterfaceError })?; disable_raw_mode().map_err(|e| { error!(target: LOG_TARGET, "Error disabling Raw Mode {}", e); - ExitCodes::InterfaceError + ExitCode::InterfaceError })?; execute!(terminal.backend_mut(), LeaveAlternateScreen).map_err(|e| { error!(target: LOG_TARGET, "Error releasing stdout {}", e); - ExitCodes::InterfaceError + ExitCode::InterfaceError })?; terminal.show_cursor().map_err(|e| { error!(target: LOG_TARGET, "Error showing cursor: {}", e); - ExitCodes::InterfaceError + ExitCode::InterfaceError })?; Ok(()) diff --git a/applications/tari_console_wallet/src/ui/state/app_state.rs b/applications/tari_console_wallet/src/ui/state/app_state.rs index 8a77875a53..06d0bd01d2 100644 --- a/applications/tari_console_wallet/src/ui/state/app_state.rs +++ b/applications/tari_console_wallet/src/ui/state/app_state.rs @@ -57,7 +57,10 @@ use tari_wallet::{ contacts_service::storage::database::Contact, output_manager_service::{handle::OutputManagerEventReceiver, service::Balance}, tokens::Token, - transaction_service::{handle::TransactionEventReceiver, storage::models::CompletedTransaction}, + transaction_service::{ + handle::TransactionEventReceiver, + storage::models::{CompletedTransaction, TxCancellationReason}, + }, WalletSqlite, }; use tokio::{ @@ -248,10 +251,7 @@ impl AppState { // Return alias or pub key if the contact is not in the list. pub fn get_alias(&self, pub_key: &RistrettoPublicKey) -> String { let pub_key_hex = format!("{}", pub_key); - // TODO: We can uncomment this to indicated unknown origin, otherwise there is our pub key. - // if self.get_identity().public_key == pub_key_hex { - // return "Unknown".to_string(); - // } + match self .cached_data .contacts @@ -418,7 +418,7 @@ impl AppState { self.cached_data .completed_txs .iter() - .filter(|tx| !((tx.cancelled || !tx.valid) && tx.status == TransactionStatus::Coinbase)) + .filter(|tx| !matches!(tx.cancelled, Some(TxCancellationReason::AbandonedCoinbase))) .collect() } else { self.cached_data.completed_txs.iter().collect() @@ -533,7 +533,7 @@ impl AppState { pub fn get_default_fee_per_gram(&self) -> MicroTari { use Network::*; - // TODO: TBD + // TODO: TBD #LOGGED match self.node_config.network { MainNet | LocalNet | Igor | Dibbler => MicroTari(5), Ridcully | Stibbons | Weatherwax => MicroTari(25), @@ -700,14 +700,14 @@ impl AppStateInner { let tx = CompletedTransactionInfo::from_completed_transaction(tx.into(), &self.get_transaction_weight()); if let Some(index) = self.data.pending_txs.iter().position(|i| i.tx_id == tx_id) { - if tx.status == TransactionStatus::Pending && !tx.cancelled { + if tx.status == TransactionStatus::Pending && tx.cancelled.is_none() { self.data.pending_txs[index] = tx; self.updated = true; return Ok(()); } else { let _ = self.data.pending_txs.remove(index); } - } else if tx.status == TransactionStatus::Pending && !tx.cancelled { + } else if tx.status == TransactionStatus::Pending && tx.cancelled.is_none() { self.data.pending_txs.push(tx); self.data.pending_txs.sort_by(|a, b| { b.timestamp @@ -974,9 +974,8 @@ pub struct CompletedTransactionInfo { pub status: TransactionStatus, pub message: String, pub timestamp: NaiveDateTime, - pub cancelled: bool, + pub cancelled: Option, pub direction: TransactionDirection, - pub valid: bool, pub mined_height: Option, pub is_coinbase: bool, pub weight: u64, @@ -1035,7 +1034,6 @@ impl CompletedTransactionInfo { timestamp: tx.timestamp, cancelled: tx.cancelled, direction: tx.direction, - valid: tx.valid, mined_height: tx.mined_height, is_coinbase, weight, diff --git a/applications/tari_console_wallet/src/ui/state/wallet_event_monitor.rs b/applications/tari_console_wallet/src/ui/state/wallet_event_monitor.rs index 8e341008c6..d01aadd520 100644 --- a/applications/tari_console_wallet/src/ui/state/wallet_event_monitor.rs +++ b/applications/tari_console_wallet/src/ui/state/wallet_event_monitor.rs @@ -94,13 +94,15 @@ impl WalletEventMonitor { self.trigger_balance_refresh(); notifier.transaction_received(tx_id); }, - TransactionEvent::TransactionMinedUnconfirmed{tx_id, num_confirmations, is_valid: _} => { + TransactionEvent::TransactionMinedUnconfirmed{tx_id, num_confirmations, is_valid: _} | + TransactionEvent::FauxTransactionUnconfirmed{tx_id, num_confirmations, is_valid: _}=> { self.trigger_confirmations_refresh(tx_id, num_confirmations).await; self.trigger_tx_state_refresh(tx_id).await; self.trigger_balance_refresh(); notifier.transaction_mined_unconfirmed(tx_id, num_confirmations); }, - TransactionEvent::TransactionMined{tx_id, is_valid: _} => { + TransactionEvent::TransactionMined{tx_id, is_valid: _} | + TransactionEvent::FauxTransactionConfirmed{tx_id, is_valid: _}=> { self.trigger_confirmations_cleanup(tx_id).await; self.trigger_tx_state_refresh(tx_id).await; self.trigger_balance_refresh(); @@ -114,7 +116,8 @@ impl WalletEventMonitor { TransactionEvent::ReceivedTransaction(tx_id) | TransactionEvent::ReceivedTransactionReply(tx_id) | TransactionEvent::TransactionBroadcast(tx_id) | - TransactionEvent::TransactionMinedRequestTimedOut(tx_id) | TransactionEvent::TransactionImported(tx_id) => { + TransactionEvent::TransactionMinedRequestTimedOut(tx_id) | + TransactionEvent::TransactionImported(tx_id) => { self.trigger_tx_state_refresh(tx_id).await; self.trigger_balance_refresh(); }, diff --git a/applications/tari_console_wallet/src/wallet_modes.rs b/applications/tari_console_wallet/src/wallet_modes.rs index 60b40f7247..8cd92c1b3b 100644 --- a/applications/tari_console_wallet/src/wallet_modes.rs +++ b/applications/tari_console_wallet/src/wallet_modes.rs @@ -23,7 +23,11 @@ use std::{fs, io::Stdout, path::PathBuf}; use log::*; use rand::{rngs::OsRng, seq::SliceRandom}; -use tari_common::{exit_codes::ExitCodes, ConfigBootstrap, GlobalConfig}; +use tari_common::{ + exit_codes::{ExitCode, ExitError}, + ConfigBootstrap, + GlobalConfig, +}; use tari_comms::{multiaddr::Multiaddr, peer_manager::Peer, utils::multiaddr::multiaddr_to_socketaddr}; use tari_wallet::WalletSqlite; use tokio::runtime::Handle; @@ -85,25 +89,26 @@ impl PeerConfig { /// 1. Custom Base Node /// 2. First configured Base Node Peer /// 3. Random configured Peer Seed - pub fn get_base_node_peer(&self) -> Result { + pub fn get_base_node_peer(&self) -> Result { if let Some(base_node) = self.base_node_custom.clone() { Ok(base_node) } else if !self.base_node_peers.is_empty() { Ok(self .base_node_peers .first() - .ok_or_else(|| ExitCodes::ConfigError("Configured base node peer has no address!".to_string()))? + .ok_or_else(|| ExitError::new(ExitCode::ConfigError, "Configured base node peer has no address!"))? .clone()) } else if !self.peer_seeds.is_empty() { // pick a random peer seed Ok(self .peer_seeds .choose(&mut OsRng) - .ok_or_else(|| ExitCodes::ConfigError("Peer seeds was empty.".to_string()))? + .ok_or_else(|| ExitError::new(ExitCode::ConfigError, "Peer seeds was empty."))? .clone()) } else { - Err(ExitCodes::ConfigError( - "No peer seeds or base node peer defined in config!".to_string(), + Err(ExitError::new( + ExitCode::ConfigError, + "No peer seeds or base node peer defined in config!", )) } } @@ -129,7 +134,7 @@ impl PeerConfig { } } -pub fn command_mode(config: WalletModeConfig, wallet: WalletSqlite, command: String) -> Result<(), ExitCodes> { +pub fn command_mode(config: WalletModeConfig, wallet: WalletSqlite, command: String) -> Result<(), ExitError> { let WalletModeConfig { global_config, handle, .. } = config.clone(); @@ -151,16 +156,16 @@ pub fn command_mode(config: WalletModeConfig, wallet: WalletSqlite, command: Str wallet_or_exit(config, wallet) } -pub fn script_mode(config: WalletModeConfig, wallet: WalletSqlite, path: PathBuf) -> Result<(), ExitCodes> { +pub fn script_mode(config: WalletModeConfig, wallet: WalletSqlite, path: PathBuf) -> Result<(), ExitError> { let WalletModeConfig { global_config, handle, .. } = config.clone(); info!(target: LOG_TARGET, "Starting wallet script mode"); println!("Starting wallet script mode"); - let script = fs::read_to_string(path).map_err(|e| ExitCodes::InputError(e.to_string()))?; + let script = fs::read_to_string(path).map_err(|e| ExitError::new(ExitCode::InputError, e))?; if script.is_empty() { - return Err(ExitCodes::InputError("Input file is empty!".to_string())); + return Err(ExitError::new(ExitCode::InputError, "Input file is empty!")); }; let mut commands = Vec::new(); @@ -192,7 +197,7 @@ pub fn script_mode(config: WalletModeConfig, wallet: WalletSqlite, path: PathBuf } /// Prompts the user to continue to the wallet, or exit. -fn wallet_or_exit(config: WalletModeConfig, wallet: WalletSqlite) -> Result<(), ExitCodes> { +fn wallet_or_exit(config: WalletModeConfig, wallet: WalletSqlite) -> Result<(), ExitError> { if config.bootstrap.command_mode_auto_exit { info!(target: LOG_TARGET, "Auto exit argument supplied - exiting."); return Ok(()); @@ -207,7 +212,7 @@ fn wallet_or_exit(config: WalletModeConfig, wallet: WalletSqlite) -> Result<(), let mut buf = String::new(); std::io::stdin() .read_line(&mut buf) - .map_err(|e| ExitCodes::IOError(e.to_string()))?; + .map_err(|e| ExitError::new(ExitCode::IOError, e))?; match buf.as_str().trim() { "quit" | "q" | "exit" => { @@ -222,7 +227,7 @@ fn wallet_or_exit(config: WalletModeConfig, wallet: WalletSqlite) -> Result<(), } } -pub fn tui_mode(config: WalletModeConfig, mut wallet: WalletSqlite) -> Result<(), ExitCodes> { +pub fn tui_mode(config: WalletModeConfig, mut wallet: WalletSqlite) -> Result<(), ExitError> { let WalletModeConfig { base_node_config, mut base_node_selected, @@ -279,7 +284,7 @@ pub fn tui_mode(config: WalletModeConfig, mut wallet: WalletSqlite) -> Result<() Ok(()) } -pub fn recovery_mode(config: WalletModeConfig, wallet: WalletSqlite) -> Result<(), ExitCodes> { +pub fn recovery_mode(config: WalletModeConfig, wallet: WalletSqlite) -> Result<(), ExitError> { let WalletModeConfig { base_node_config, handle, @@ -318,11 +323,14 @@ pub fn recovery_mode(config: WalletModeConfig, wallet: WalletSqlite) -> Result<( match wallet_mode { WalletMode::RecoveryDaemon => grpc_mode(config, wallet), WalletMode::RecoveryTui => tui_mode(config, wallet), - _ => Err(ExitCodes::RecoveryError("Unsupported post recovery mode".to_string())), + _ => Err(ExitError::new( + ExitCode::RecoveryError, + "Unsupported post recovery mode", + )), } } -pub fn grpc_mode(config: WalletModeConfig, wallet: WalletSqlite) -> Result<(), ExitCodes> { +pub fn grpc_mode(config: WalletModeConfig, wallet: WalletSqlite) -> Result<(), ExitError> { let WalletModeConfig { global_config, handle, .. } = config; @@ -331,7 +339,7 @@ pub fn grpc_mode(config: WalletModeConfig, wallet: WalletSqlite) -> Result<(), E let grpc = WalletGrpcServer::new(wallet); handle .block_on(run_grpc(grpc, grpc_address)) - .map_err(ExitCodes::GrpcError)?; + .map_err(|e| ExitError::new(ExitCode::GrpcError, e))?; } else { println!("No grpc address specified"); } diff --git a/applications/tari_merge_mining_proxy/Cargo.toml b/applications/tari_merge_mining_proxy/Cargo.toml index 7cdd0751dc..29e99352ea 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 miner proxy for xmrig" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.27.3" +version = "0.28.0" edition = "2018" [features] diff --git a/applications/tari_merge_mining_proxy/build.rs b/applications/tari_merge_mining_proxy/build.rs new file mode 100644 index 0000000000..1c502c938a --- /dev/null +++ b/applications/tari_merge_mining_proxy/build.rs @@ -0,0 +1,11 @@ +#[cfg(windows)] +fn main() { + use std::env; + println!("cargo:rerun-if-changed=icon.res"); + let mut path = env::current_dir().unwrap(); + path.push("icon.res"); + println!("cargo:rustc-link-arg={}", path.into_os_string().into_string().unwrap()); +} + +#[cfg(not(windows))] +fn main() {} diff --git a/applications/tari_merge_mining_proxy/icon.ico b/applications/tari_merge_mining_proxy/icon.ico new file mode 100644 index 0000000000..e952cc0f24 Binary files /dev/null and b/applications/tari_merge_mining_proxy/icon.ico differ diff --git a/applications/tari_merge_mining_proxy/icon.rc b/applications/tari_merge_mining_proxy/icon.rc new file mode 100644 index 0000000000..26527deb57 --- /dev/null +++ b/applications/tari_merge_mining_proxy/icon.rc @@ -0,0 +1 @@ +mining_node ICON "icon.ico" \ No newline at end of file diff --git a/applications/tari_merge_mining_proxy/icon.res b/applications/tari_merge_mining_proxy/icon.res new file mode 100644 index 0000000000..722ccfba07 Binary files /dev/null and b/applications/tari_merge_mining_proxy/icon.res differ diff --git a/applications/tari_merge_mining_proxy/src/common/merge_mining.rs b/applications/tari_merge_mining_proxy/src/common/merge_mining.rs index 0b13b1a1f1..7b85ec919d 100644 --- a/applications/tari_merge_mining_proxy/src/common/merge_mining.rs +++ b/applications/tari_merge_mining_proxy/src/common/merge_mining.rs @@ -25,7 +25,7 @@ use std::convert::{TryFrom, TryInto}; use tari_app_grpc::tari_rpc as grpc; use tari_core::{ blocks::NewBlockTemplate, - transactions::transaction::{TransactionKernel, TransactionOutput}, + transactions::transaction_components::{TransactionKernel, TransactionOutput}, }; use crate::error::MmProxyError; diff --git a/applications/tari_merge_mining_proxy/src/common/proxy.rs b/applications/tari_merge_mining_proxy/src/common/proxy.rs index 693714561b..61d9d1fd9c 100644 --- a/applications/tari_merge_mining_proxy/src/common/proxy.rs +++ b/applications/tari_merge_mining_proxy/src/common/proxy.rs @@ -76,7 +76,6 @@ pub fn into_body_from_response(resp: Response) -> Response { /// Reads the `Body` until there is no more to read pub async fn read_body_until_end(body: &mut Body) -> Result { - // TODO: Perhaps there is a more efficient way to do this let mut bytes = BytesMut::new(); while let Some(data) = body.next().await { let data = data?; diff --git a/applications/tari_mining_node/Cargo.toml b/applications/tari_mining_node/Cargo.toml index a5d18a2995..3d3657c9bd 100644 --- a/applications/tari_mining_node/Cargo.toml +++ b/applications/tari_mining_node/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "The tari mining node implementation" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.27.3" +version = "0.28.0" edition = "2018" [dependencies] diff --git a/applications/tari_mining_node/src/main.rs b/applications/tari_mining_node/src/main.rs index 0b1475abfe..266deca6a1 100644 --- a/applications/tari_mining_node/src/main.rs +++ b/applications/tari_mining_node/src/main.rs @@ -40,7 +40,7 @@ use tari_app_grpc::tari_rpc::{base_node_client::BaseNodeClient, wallet_client::W use tari_app_utilities::initialization::init_configuration; use tari_common::{ configuration::bootstrap::ApplicationType, - exit_codes::{ExitCodes, ExitCodes::ConfigError}, + exit_codes::{ExitCode, ExitError}, ConfigBootstrap, DefaultConfigLoader, }; @@ -75,15 +75,16 @@ fn main() { let rt = Runtime::new().expect("Failed to start tokio runtime"); match rt.block_on(main_inner()) { Ok(_) => std::process::exit(0), - Err(exit_code) => { - eprintln!("Fatal error: {:?}", exit_code); + Err(err) => { + eprintln!("Fatal error: {:?}", err); + let exit_code = err.exit_code; error!(target: LOG_TARGET, "Exiting with code: {:?}", exit_code); - std::process::exit(exit_code.as_i32()) + std::process::exit(exit_code as i32) }, } } -async fn main_inner() -> Result<(), ExitCodes> { +async fn main_inner() -> Result<(), ExitError> { let (bootstrap, global, cfg) = init_configuration(ApplicationType::MiningNode)?; let mut config = ::load_from(&cfg).expect("Failed to load config"); config.mine_on_tip_only = global.mine_on_tip_only; @@ -108,8 +109,12 @@ async fn main_inner() -> Result<(), ExitCodes> { if !config.mining_wallet_address.is_empty() && !config.mining_pool_address.is_empty() { let url = config.mining_pool_address.clone(); let mut miner_address = config.mining_wallet_address.clone(); - let _ = RistrettoPublicKey::from_hex(&miner_address) - .map_err(|_| ConfigError("Miner is not configured with a valid wallet address.".to_string()))?; + let _ = RistrettoPublicKey::from_hex(&miner_address).map_err(|_| { + ExitError::new( + ExitCode::ConfigError, + "Miner is not configured with a valid wallet address.", + ) + })?; if !config.mining_worker_name.is_empty() { miner_address += &format!("{}{}", ".", &config.mining_worker_name); } @@ -172,7 +177,9 @@ async fn main_inner() -> Result<(), ExitCodes> { target: LOG_TARGET_FILE, "mine_on_tip_only is {}", config.mine_on_tip_only ); - let (mut node_conn, mut wallet_conn) = connect(&config).await.map_err(ExitCodes::grpc)?; + let (mut node_conn, mut wallet_conn) = connect(&config) + .await + .map_err(|err| ExitError::new(ExitCode::GrpcError, format!("GRPC connection error: {}", err)))?; let mut blocks_found: u64 = 0; loop { diff --git a/applications/tari_stratum_transcoder/Cargo.toml b/applications/tari_stratum_transcoder/Cargo.toml index 5d2fc2b6ac..2d9b6be387 100644 --- a/applications/tari_stratum_transcoder/Cargo.toml +++ b/applications/tari_stratum_transcoder/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "The tari stratum transcoder for miningcore" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.27.3" +version = "0.28.0" edition = "2018" [features] diff --git a/applications/tari_stratum_transcoder/src/common/mining.rs b/applications/tari_stratum_transcoder/src/common/mining.rs index f3d7842628..97b88d6336 100644 --- a/applications/tari_stratum_transcoder/src/common/mining.rs +++ b/applications/tari_stratum_transcoder/src/common/mining.rs @@ -25,7 +25,7 @@ use std::convert::TryFrom; use tari_app_grpc::tari_rpc as grpc; use tari_core::{ blocks::NewBlockTemplate, - transactions::transaction::{TransactionKernel, TransactionOutput}, + transactions::transaction_components::{TransactionKernel, TransactionOutput}, }; use crate::error::StratumTranscoderProxyError; diff --git a/applications/tari_stratum_transcoder/src/common/proxy.rs b/applications/tari_stratum_transcoder/src/common/proxy.rs index b9553c6278..fae8d300b3 100644 --- a/applications/tari_stratum_transcoder/src/common/proxy.rs +++ b/applications/tari_stratum_transcoder/src/common/proxy.rs @@ -56,7 +56,6 @@ pub fn into_body_from_response(resp: Response) -> Response { /// Reads the `Body` until there is no more to read pub async fn read_body_until_end(body: &mut Body) -> Result { - // TODO: Perhaps there is a more efficient way to do this let mut bytes = BytesMut::new(); while let Some(data) = body.next().await { let data = data?; diff --git a/applications/tari_validator_node/Cargo.toml b/applications/tari_validator_node/Cargo.toml index d64d87a09d..27159e25b9 100644 --- a/applications/tari_validator_node/Cargo.toml +++ b/applications/tari_validator_node/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "The Tari validator node implementation" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.27.3" +version = "0.28.0" edition = "2018" [dependencies] diff --git a/applications/tari_validator_node/proto/dan/validator_node.proto b/applications/tari_validator_node/proto/dan/validator_node.proto index f43a5982cc..2793847476 100644 --- a/applications/tari_validator_node/proto/dan/validator_node.proto +++ b/applications/tari_validator_node/proto/dan/validator_node.proto @@ -74,7 +74,48 @@ message GetSidechainBlocksRequest { bytes end_hash = 3; } - message GetSidechainBlocksResponse { tari.dan.common.SideChainBlock block = 1; } + +message GetSidechainStateRequest { + bytes asset_public_key = 1; +} + +message GetSidechainStateResponse { + oneof state { + string schema = 1; + KeyValue key_value = 2; + } +} + +message KeyValue { + bytes key = 1; + bytes value = 2; +} + +message GetStateOpLogsRequest { + bytes asset_public_key = 1; + uint64 height = 2; +} + +message GetStateOpLogsResponse { + repeated StateOpLog op_logs = 1; +} + +message StateOpLog { + uint64 height = 1; + string operation = 2; + string schema = 3; + bytes key = 4; + bytes value = 5; + bytes merkle_root = 6; +} + +message GetTipNodeRequest{ + bytes asset_public_key = 1; +} + +message GetTipNodeResponse { + tari.dan.common.Node tip_node = 1; +} diff --git a/applications/tari_validator_node/src/comms.rs b/applications/tari_validator_node/src/comms.rs index 4211d5a05a..00601dbe45 100644 --- a/applications/tari_validator_node/src/comms.rs +++ b/applications/tari_validator_node/src/comms.rs @@ -28,7 +28,12 @@ use tari_app_utilities::{ identity_management::load_from_json, utilities::convert_socks_authentication, }; -use tari_common::{exit_codes::ExitCodes, CommsTransport, GlobalConfig, TorControlAuthentication}; +use tari_common::{ + exit_codes::{ExitCode, ExitError}, + CommsTransport, + GlobalConfig, + TorControlAuthentication, +}; use tari_comms::{ protocol::rpc::RpcServer, socks, @@ -61,7 +66,7 @@ pub async fn build_service_and_comms_stack( mempool: MempoolServiceHandle, db_factory: SqliteDbFactory, asset_processor: ConcreteAssetProcessor, -) -> Result<(ServiceHandles, SubscriptionFactory), ExitCodes> { +) -> Result<(ServiceHandles, SubscriptionFactory), ExitError> { // this code is duplicated from the base node let comms_config = create_comms_config(config, node_identity.clone()); @@ -71,7 +76,7 @@ pub async fn build_service_and_comms_stack( .add_initializer(P2pInitializer::new(comms_config, publisher)) .build() .await - .map_err(|err| ExitCodes::ConfigError(err.to_string()))?; + .map_err(|err| ExitError::new(ExitCode::ConfigError, err))?; let comms = handles .take_handle::() @@ -81,15 +86,15 @@ pub async fn build_service_and_comms_stack( let comms = spawn_comms_using_transport(comms, create_transport_type(config)) .await - .map_err(|e| ExitCodes::ConfigError(format!("Could not spawn using transport:{}", e)))?; + .map_err(|e| ExitError::new(ExitCode::ConfigError, format!("Could not spawn using transport:{}", e)))?; // Save final node identity after comms has initialized. This is required because the public_address can be // changed by comms during initialization when using tor. identity_management::save_as_json(&config.base_node_identity_file, &*comms.node_identity()) - .map_err(|e| ExitCodes::ConfigError(format!("Failed to save node identity: {}", e)))?; + .map_err(|e| ExitError::new(ExitCode::ConfigError, format!("Failed to save node identity: {}", e)))?; if let Some(hs) = comms.hidden_service() { identity_management::save_as_json(&config.base_node_tor_identity_file, hs.tor_identity()) - .map_err(|e| ExitCodes::ConfigError(format!("Failed to save tor identity: {}", e)))?; + .map_err(|e| ExitError::new(ExitCode::ConfigError, format!("Failed to save tor identity: {}", e)))?; } handles.register(comms); diff --git a/applications/tari_validator_node/src/dan_node.rs b/applications/tari_validator_node/src/dan_node.rs index 563e02465f..a7d94ef39d 100644 --- a/applications/tari_validator_node/src/dan_node.rs +++ b/applications/tari_validator_node/src/dan_node.rs @@ -22,8 +22,12 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; -use log::info; -use tari_common::{configuration::ValidatorNodeConfig, GlobalConfig}; +use log::*; +use tari_common::{ + configuration::ValidatorNodeConfig, + exit_codes::{ExitCode, ExitError}, + GlobalConfig, +}; use tari_comms::{types::CommsPublicKey, NodeIdentity}; use tari_comms_dht::Dht; use tari_crypto::tari_utilities::hex::Hex; @@ -55,7 +59,7 @@ use crate::{ inbound_connection_service::TariCommsInboundConnectionService, outbound_connection_service::TariCommsOutboundService, }, - ExitCodes, + TariCommsValidatorNodeClientFactory, }; const LOG_TARGET: &str = "tari::validator_node::app"; @@ -77,12 +81,12 @@ impl DanNode { db_factory: SqliteDbFactory, handles: ServiceHandles, subscription_factory: SubscriptionFactory, - ) -> Result<(), ExitCodes> { + ) -> Result<(), ExitError> { let dan_config = self .config .validator_node .as_ref() - .ok_or_else(|| ExitCodes::ConfigError("Missing dan section".to_string()))?; + .ok_or_else(|| ExitError::new(ExitCode::ConfigError, "Missing dan section"))?; let mut base_node_client = GrpcBaseNodeClient::new(dan_config.base_node_grpc_address); let mut tasks = HashMap::new(); @@ -105,16 +109,29 @@ impl DanNode { .get_assets_for_dan_node(node_identity.public_key().clone()) .await .unwrap(); + info!( + target: LOG_TARGET, + "Base node returned {} asset(s) to process", + assets.len() + ); for asset in assets { if tasks.contains_key(&asset.public_key) { + debug!( + target: LOG_TARGET, + "Asset task already running for asset '{}'", asset.public_key + ); continue; } if let Some(allow_list) = &dan_config.assets_allow_list { if !allow_list.contains(&asset.public_key.to_hex()) { + debug!( + target: LOG_TARGET, + "Asset '{}' is not whitelisted for processing ", asset.public_key + ); continue; } } - info!(target: LOG_TARGET, "Adding asset {:?}", asset.public_key); + info!(target: LOG_TARGET, "Adding asset '{}'", asset.public_key); let node_identity = node_identity.as_ref().clone(); let mempool = mempool_service.clone(); let handles = handles.clone(); @@ -125,7 +142,7 @@ impl DanNode { tasks.insert( asset.public_key.clone(), task::spawn(DanNode::start_asset_worker( - asset.clone(), + asset, node_identity, mempool, handles, @@ -154,14 +171,14 @@ impl DanNode { shutdown: ShutdownSignal, config: ValidatorNodeConfig, db_factory: SqliteDbFactory, - ) -> Result<(), ExitCodes> { + ) -> Result<(), ExitError> { let timeout = Duration::from_secs(asset_definition.phase_timeout); let committee = asset_definition .initial_committee .iter() .map(|s| { CommsPublicKey::from_hex(s) - .map_err(|e| ExitCodes::ConfigError(format!("could not convert to hex:{}", e))) + .map_err(|e| ExitError::new(ExitCode::ConfigError, format!("could not convert to hex:{}", e))) }) .collect::, _>>()?; @@ -196,6 +213,9 @@ impl DanNode { let chain_storage = SqliteStorageService {}; let wallet_client = GrpcWalletClient::new(config.wallet_grpc_address); let checkpoint_manager = ConcreteCheckpointManager::new(asset_definition.clone(), wallet_client); + let connectivity = handles.expect_handle(); + let validator_node_client_factory = + TariCommsValidatorNodeClientFactory::new(connectivity, dht.discovery_service_requester()); let mut consensus_worker = ConsensusWorker::::new( receiver, outbound, @@ -211,12 +231,13 @@ impl DanNode { db_factory, chain_storage, checkpoint_manager, + validator_node_client_factory, ); consensus_worker .run(shutdown.clone(), None) .await - .map_err(|err| ExitCodes::ConfigError(err.to_string()))?; + .map_err(|err| ExitError::new(ExitCode::ConfigError, err))?; Ok(()) } diff --git a/applications/tari_validator_node/src/grpc/services/base_node_client.rs b/applications/tari_validator_node/src/grpc/services/base_node_client.rs index 236627f353..6fb857dccb 100644 --- a/applications/tari_validator_node/src/grpc/services/base_node_client.rs +++ b/applications/tari_validator_node/src/grpc/services/base_node_client.rs @@ -23,6 +23,7 @@ use std::{convert::TryInto, net::SocketAddr}; use async_trait::async_trait; +use log::*; use tari_app_grpc::tari_rpc as grpc; use tari_common_types::types::PublicKey; use tari_crypto::tari_utilities::ByteArray; @@ -32,6 +33,8 @@ use tari_dan_core::{ DigitalAssetError, }; +const LOG_TARGET: &str = "tari::validator_node::app"; + #[derive(Clone)] pub struct GrpcBaseNodeClient { endpoint: SocketAddr, @@ -112,18 +115,23 @@ impl BaseNodeClient for GrpcBaseNodeClient { self.inner.as_mut().unwrap() }, }; - let request = grpc::ListAssetRegistrationsRequest { offset: 0, count: 0 }; + // TODO: probably should use output mmr indexes here + let request = grpc::ListAssetRegistrationsRequest { offset: 0, count: 100 }; let mut result = inner.list_asset_registrations(request).await.unwrap().into_inner(); let mut assets: Vec = vec![]; let tip = self.get_tip_info().await?; while let Some(r) = result.message().await.unwrap() { - if let Ok(asset_public_key) = PublicKey::from_bytes(r.unique_id.as_bytes()) { + if let Ok(asset_public_key) = PublicKey::from_bytes(r.asset_public_key.as_bytes()) { if let Some(checkpoint) = self .get_current_checkpoint(tip.height_of_longest_chain, asset_public_key.clone(), vec![3u8; 32]) .await? { if let Some(committee) = checkpoint.get_side_chain_committee() { if committee.contains(&dan_node_public_key) { + debug!( + target: LOG_TARGET, + "Node is on committee for asset : {}", asset_public_key + ); assets.push(AssetDefinition { public_key: asset_public_key, template_parameters: r @@ -144,4 +152,32 @@ impl BaseNodeClient for GrpcBaseNodeClient { } Ok(assets) } + + async fn get_asset_registration( + &mut self, + asset_public_key: PublicKey, + ) -> Result, DigitalAssetError> { + let conn = match self.inner.as_mut() { + Some(i) => i, + None => { + self.connect().await?; + self.inner.as_mut().unwrap() + }, + }; + + let req = grpc::GetAssetMetadataRequest { + asset_public_key: asset_public_key.to_vec(), + }; + let output = conn.get_asset_metadata(req).await.unwrap().into_inner(); + + let output = output + .features + .map(|features| match features.try_into() { + Ok(f) => Ok(BaseLayerOutput { features: f }), + Err(e) => Err(DigitalAssetError::ConversionError(e)), + }) + .transpose()?; + + Ok(output) + } } diff --git a/applications/tari_validator_node/src/grpc/validator_node_grpc_server.rs b/applications/tari_validator_node/src/grpc/validator_node_grpc_server.rs index 0bd54a1a24..f6e126b382 100644 --- a/applications/tari_validator_node/src/grpc/validator_node_grpc_server.rs +++ b/applications/tari_validator_node/src/grpc/validator_node_grpc_server.rs @@ -143,10 +143,10 @@ impl rpc::validator_node_ .get_state_db(&asset_public_key) .map_err(|e| Status::internal(format!("Could not create state db: {}", e)))? { - let mut unit_of_work = state.new_unit_of_work(); + let mut state_db_reader = state.reader(); let response_bytes = self .asset_processor - .invoke_read_method(template_id, request.method, &request.args, &mut unit_of_work) + .invoke_read_method(template_id, request.method, &request.args, &mut state_db_reader) .map_err(|e| Status::internal(format!("Could not invoke read method: {}", e)))?; Ok(Response::new(rpc::InvokeReadMethodResponse { result: response_bytes.unwrap_or_default(), diff --git a/applications/tari_validator_node/src/main.rs b/applications/tari_validator_node/src/main.rs index 99e95ad21c..a6790869ba 100644 --- a/applications/tari_validator_node/src/main.rs +++ b/applications/tari_validator_node/src/main.rs @@ -39,7 +39,11 @@ use futures::FutureExt; use log::*; use tari_app_grpc::tari_rpc::validator_node_server::ValidatorNodeServer; use tari_app_utilities::{identity_management::setup_node_identity, initialization::init_configuration}; -use tari_common::{configuration::bootstrap::ApplicationType, exit_codes::ExitCodes, GlobalConfig}; +use tari_common::{ + configuration::bootstrap::ApplicationType, + exit_codes::{ExitCode, ExitError}, + GlobalConfig, +}; use tari_comms::{connectivity::ConnectivityRequester, peer_manager::PeerFeatures, NodeIdentity}; use tari_comms_dht::Dht; use tari_dan_core::services::{ConcreteAssetProcessor, ConcreteAssetProxy, MempoolServiceHandle, ServiceSpecification}; @@ -61,19 +65,18 @@ const LOG_TARGET: &str = "tari::validator_node::app"; fn main() { // console_subscriber::init(); - if let Err(exit_code) = main_inner() { - eprintln!("{:?}", exit_code); + if let Err(err) = main_inner() { + let exit_code = err.exit_code; + eprintln!("{:?}", err); error!( target: LOG_TARGET, - "Exiting with code ({}): {:?}", - exit_code.as_i32(), - exit_code + "Exiting with code ({}): {:?}", exit_code as i32, exit_code ); - process::exit(exit_code.as_i32()); + process::exit(exit_code as i32); } } -fn main_inner() -> Result<(), ExitCodes> { +fn main_inner() -> Result<(), ExitError> { let (bootstrap, config, _) = init_configuration(ApplicationType::ValidatorNode)?; // let _operation_mode = cmd_args::get_operation_mode(); @@ -87,10 +90,14 @@ fn main_inner() -> Result<(), ExitCodes> { Ok(()) } -async fn run_node(config: GlobalConfig, create_id: bool) -> Result<(), ExitCodes> { +async fn run_node(config: GlobalConfig, create_id: bool) -> Result<(), ExitError> { let shutdown = Shutdown::new(); + let validator_node_config = config + .validator_node + .as_ref() + .ok_or_else(|| ExitError::new(ExitCode::ConfigError, "validator_node configuration not found"))?; - fs::create_dir_all(&config.peer_db_path).map_err(|err| ExitCodes::ConfigError(err.to_string()))?; + fs::create_dir_all(&config.peer_db_path).map_err(|err| ExitError::new(ExitCode::ConfigError, err))?; let node_identity = setup_node_identity( &config.base_node_identity_file, &config.public_address, @@ -122,7 +129,7 @@ async fn run_node(config: GlobalConfig, create_id: bool) -> Result<(), ExitCodes handles.expect_handle::().discovery_service_requester(), ); let asset_proxy: ConcreteAssetProxy = ConcreteAssetProxy::new( - GrpcBaseNodeClient::new(config.validator_node.clone().unwrap().base_node_grpc_address), + GrpcBaseNodeClient::new(validator_node_config.base_node_grpc_address), validator_node_client_factory, 5, mempool_service.clone(), @@ -153,12 +160,12 @@ async fn run_node(config: GlobalConfig, create_id: bool) -> Result<(), ExitCodes Ok(()) } -fn build_runtime() -> Result { +fn build_runtime() -> Result { let mut builder = runtime::Builder::new_multi_thread(); builder .enable_all() .build() - .map_err(|e| ExitCodes::UnknownError(e.to_string())) + .map_err(|e| ExitError::new(ExitCode::UnknownError, e)) } async fn run_dan_node( @@ -169,7 +176,7 @@ async fn run_dan_node( handles: ServiceHandles, subscription_factory: SubscriptionFactory, node_identity: Arc, -) -> Result<(), ExitCodes> { +) -> Result<(), ExitError> { let node = DanNode::new(config); node.start( shutdown_signal, @@ -194,7 +201,7 @@ async fn run_grpc( .serve_with_shutdown(grpc_address, shutdown_signal.map(|_| ())) .await .map_err(|err| { - error!(target: LOG_TARGET, "GRPC encountered an error:{}", err); + error!(target: LOG_TARGET, "GRPC encountered an error: {}", err); err })?; diff --git a/applications/tari_validator_node/src/p2p/proto/conversions.rs b/applications/tari_validator_node/src/p2p/proto/conversions.rs index 1bb4bd7012..115db3db03 100644 --- a/applications/tari_validator_node/src/p2p/proto/conversions.rs +++ b/applications/tari_validator_node/src/p2p/proto/conversions.rs @@ -24,22 +24,27 @@ use std::convert::{TryFrom, TryInto}; use tari_common_types::types::PublicKey; use tari_crypto::tari_utilities::ByteArray; -use tari_dan_core::models::{ - CheckpointData, - HotStuffMessage, - HotStuffMessageType, - HotStuffTreeNode, - Instruction, - InstructionSet, - Node, - QuorumCertificate, - SideChainBlock, - Signature, - StateRoot, - TariDanPayload, - TemplateId, - TreeNodeHash, - ViewId, +use tari_dan_core::{ + models::{ + CheckpointData, + HotStuffMessage, + HotStuffMessageType, + HotStuffTreeNode, + Instruction, + InstructionSet, + KeyValue, + Node, + QuorumCertificate, + SideChainBlock, + Signature, + StateOpLogEntry, + StateRoot, + TariDanPayload, + TemplateId, + TreeNodeHash, + ViewId, + }, + storage::state::DbStateOpLogEntry, }; use crate::p2p::proto; @@ -159,14 +164,19 @@ impl TryFrom for HotStuffTreeNode for Node { Ok(Self::new(hash, parent, height, is_committed)) } } + +impl From for proto::validator_node::KeyValue { + fn from(kv: KeyValue) -> Self { + Self { + key: kv.key, + value: kv.value, + } + } +} + +impl TryFrom for KeyValue { + type Error = String; + + fn try_from(kv: proto::validator_node::KeyValue) -> Result { + if kv.key.is_empty() { + return Err("KeyValue: key cannot be empty".to_string()); + } + + Ok(Self { + key: kv.key, + value: kv.value, + }) + } +} + +impl From for proto::validator_node::StateOpLog { + fn from(entry: StateOpLogEntry) -> Self { + let DbStateOpLogEntry { + height, + merkle_root, + operation, + schema, + key, + value, + } = entry.into_inner(); + Self { + height, + merkle_root: merkle_root.map(|r| r.as_bytes().to_vec()).unwrap_or_default(), + operation: operation.as_op_str().to_string(), + schema, + key, + value: value.unwrap_or_default(), + } + } +} +impl TryFrom for StateOpLogEntry { + type Error = String; + + fn try_from(value: proto::validator_node::StateOpLog) -> Result { + Ok(DbStateOpLogEntry { + height: value.height, + merkle_root: Some(value.merkle_root) + .filter(|r| !r.is_empty()) + .map(TryInto::try_into) + .transpose() + .map_err(|_| "Invalid merkle root value".to_string())?, + operation: value + .operation + .parse() + .map_err(|_| "Invalid oplog operation string".to_string())?, + schema: value.schema, + key: value.key, + value: Some(value.value).filter(|v| !v.is_empty()), + } + .into()) + } +} diff --git a/applications/tari_validator_node/src/p2p/rpc/mod.rs b/applications/tari_validator_node/src/p2p/rpc/mod.rs index e888b36430..771b777e80 100644 --- a/applications/tari_validator_node/src/p2p/rpc/mod.rs +++ b/applications/tari_validator_node/src/p2p/rpc/mod.rs @@ -60,6 +60,24 @@ pub trait ValidatorNodeRpcService: Send + Sync + 'static { &self, request: Request, ) -> Result, RpcStatus>; + + #[rpc(method = 5)] + async fn get_sidechain_state( + &self, + request: Request, + ) -> Result, RpcStatus>; + + #[rpc(method = 6)] + async fn get_op_logs( + &self, + request: Request, + ) -> Result, RpcStatus>; + + #[rpc(method = 7)] + async fn get_tip_node( + &self, + request: Request, + ) -> Result, RpcStatus>; } pub fn create_validator_node_rpc_service< diff --git a/applications/tari_validator_node/src/p2p/rpc/service_impl.rs b/applications/tari_validator_node/src/p2p/rpc/service_impl.rs index 8e6e7fab98..9a7d4947bf 100644 --- a/applications/tari_validator_node/src/p2p/rpc/service_impl.rs +++ b/applications/tari_validator_node/src/p2p/rpc/service_impl.rs @@ -24,12 +24,15 @@ use std::convert::TryFrom; use log::*; use tari_common_types::types::PublicKey; -use tari_comms::protocol::rpc::{Request, Response, RpcStatus, Streaming}; +use tari_comms::{ + protocol::rpc::{Request, Response, RpcStatus, Streaming}, + utils, +}; use tari_crypto::tari_utilities::ByteArray; use tari_dan_core::{ models::{Instruction, TemplateId, TreeNodeHash}, services::{AssetProcessor, MempoolService}, - storage::DbFactory, + storage::{state::StateDbUnitOfWorkReader, DbFactory}, }; use tokio::{sync::mpsc, task}; @@ -82,12 +85,14 @@ where let request = request.into_message(); let asset_public_key = PublicKey::from_bytes(&request.asset_public_key) .map_err(|err| RpcStatus::bad_request(format!("Asset public key was not a valid public key:{}", err)))?; + let state = self .db_factory .get_state_db(&asset_public_key) .map_err(|e| RpcStatus::general(format!("Could not create state db: {}", e)))? .ok_or_else(|| RpcStatus::not_found("This node does not process this asset".to_string()))?; - let mut unit_of_work = state.new_unit_of_work(); + + let mut unit_of_work = state.reader(); let response_bytes = self .asset_processor .invoke_read_method( @@ -97,6 +102,7 @@ where &mut unit_of_work, ) .map_err(|e| RpcStatus::general(format!("Could not invoke read method: {}", e)))?; + Ok(Response::new(proto::InvokeReadMethodResponse { result: response_bytes.unwrap_or_default(), })) @@ -221,4 +227,99 @@ where Ok(Streaming::new(rx)) } + + async fn get_sidechain_state( + &self, + request: Request, + ) -> Result, RpcStatus> { + let msg = request.into_message(); + + let asset_public_key = PublicKey::from_bytes(&msg.asset_public_key) + .map_err(|_| RpcStatus::bad_request("Invalid asset_public_key"))?; + + let db = self + .db_factory + .get_state_db(&asset_public_key) + .map_err(RpcStatus::log_internal_error(LOG_TARGET))? + .ok_or_else(|| RpcStatus::not_found("Asset not found"))?; + + let uow = db.reader(); + let data = uow.get_all_state().map_err(RpcStatus::log_internal_error(LOG_TARGET))?; + let (tx, rx) = mpsc::channel(10); + + task::spawn(async move { + for state in data { + let schema = proto::GetSidechainStateResponse { + state: Some(proto::get_sidechain_state_response::State::Schema(state.name)), + }; + + if tx.send(Ok(schema)).await.is_err() { + return; + } + + let key_values = state + .items + .into_iter() + .map(|kv| proto::get_sidechain_state_response::State::KeyValue(kv.into())) + .map(|state| Ok(proto::GetSidechainStateResponse { state: Some(state) })); + + if utils::mpsc::send_all(&tx, key_values).await.is_err() { + return; + } + } + }); + + Ok(Streaming::new(rx)) + } + + async fn get_op_logs( + &self, + request: Request, + ) -> Result, RpcStatus> { + let msg = request.into_message(); + + let asset_public_key = PublicKey::from_bytes(&msg.asset_public_key) + .map_err(|_| RpcStatus::bad_request("Invalid asset_public_key"))?; + + let db = self + .db_factory + .get_state_db(&asset_public_key) + .map_err(RpcStatus::log_internal_error(LOG_TARGET))? + .ok_or_else(|| RpcStatus::not_found("Asset not found"))?; + + let reader = db.reader(); + let op_logs = reader + .get_op_logs_for_height(msg.height) + .map_err(RpcStatus::log_internal_error(LOG_TARGET))?; + + let resp = proto::GetStateOpLogsResponse { + op_logs: op_logs.into_iter().map(Into::into).collect(), + }; + + Ok(Response::new(resp)) + } + + async fn get_tip_node( + &self, + request: Request, + ) -> Result, RpcStatus> { + let msg = request.into_message(); + + let asset_public_key = PublicKey::from_bytes(&msg.asset_public_key) + .map_err(|_| RpcStatus::bad_request("Invalid asset_public_key"))?; + + let db = self + .db_factory + .get_chain_db(&asset_public_key) + .map_err(RpcStatus::log_internal_error(LOG_TARGET))? + .ok_or_else(|| RpcStatus::not_found("Asset not found"))?; + + let tip_node = db.get_tip_node().map_err(RpcStatus::log_internal_error(LOG_TARGET))?; + + let resp = proto::GetTipNodeResponse { + tip_node: tip_node.map(Into::into), + }; + + Ok(Response::new(resp)) + } } diff --git a/applications/tari_validator_node/src/p2p/services/inbound_connection_service.rs b/applications/tari_validator_node/src/p2p/services/inbound_connection_service.rs index 2b48deba66..ba610ac9ce 100644 --- a/applications/tari_validator_node/src/p2p/services/inbound_connection_service.rs +++ b/applications/tari_validator_node/src/p2p/services/inbound_connection_service.rs @@ -116,18 +116,16 @@ impl TariCommsInboundConnectionService { tokio::select! { request = self.request_channel.recv() => { if let Some(request) = request { - self.handle_request(request).await?; - } - else { + self.handle_request(request).await?; + } else { debug!(target: LOG_TARGET, "All requesters have dropped, stopping."); return Ok(()) } }, message = self.loopback_receiver.recv() => { if let Some((from, message)) = message { - self.process_message(from, message).await?; - } - else { + self.process_message(from, message).await?; + } else { debug!(target: LOG_TARGET, "Loopback senders have all dropped, stopping"); return Ok(()) } diff --git a/applications/tari_validator_node/src/p2p/services/rpc_client.rs b/applications/tari_validator_node/src/p2p/services/rpc_client.rs index e009a33c90..3add896ecc 100644 --- a/applications/tari_validator_node/src/p2p/services/rpc_client.rs +++ b/applications/tari_validator_node/src/p2p/services/rpc_client.rs @@ -28,15 +28,14 @@ use tari_common_types::types::PublicKey; use tari_comms::{ connection_manager::ConnectionManagerError, connectivity::{ConnectivityError, ConnectivityRequester}, - peer_manager::NodeId, + peer_manager::{NodeId, PeerManagerError}, PeerConnection, }; use tari_comms_dht::{envelope::NodeDestination, DhtDiscoveryRequester}; use tari_crypto::tari_utilities::ByteArray; use tari_dan_core::{ - models::{SideChainBlock, TemplateId, TreeNodeHash}, - services::{ValidatorNodeClientFactory, ValidatorNodeRpcClient}, - DigitalAssetError, + models::{Node, SchemaState, SideChainBlock, StateOpLogEntry, TemplateId, TreeNodeHash}, + services::{ValidatorNodeClientError, ValidatorNodeClientFactory, ValidatorNodeRpcClient}, }; use tokio_stream::StreamExt; @@ -51,7 +50,7 @@ pub struct TariCommsValidatorNodeRpcClient { } impl TariCommsValidatorNodeRpcClient { - async fn create_connection(&mut self) -> Result { + async fn create_connection(&mut self) -> Result { match self.connectivity.dial_peer(NodeId::from(self.address.clone())).await { Ok(connection) => Ok(connection), Err(connectivity_error) => { @@ -61,7 +60,8 @@ impl TariCommsValidatorNodeRpcClient { match err { ConnectionManagerError::PeerConnectionError(_) | ConnectionManagerError::DialConnectFailedAllAddresses | - ConnectionManagerError::PeerIdentityNoValidAddresses => { + ConnectionManagerError::PeerIdentityNoValidAddresses | + ConnectionManagerError::PeerManagerError(PeerManagerError::PeerNotFoundError) => { // Try discover, then dial again // TODO: Should make discovery and connect the responsibility of the DHT layer self.dht_discovery @@ -97,7 +97,7 @@ impl ValidatorNodeRpcClient for TariCommsValidatorNodeRpcClient { template_id: TemplateId, method: String, args: Vec, - ) -> Result>, DigitalAssetError> { + ) -> Result>, ValidatorNodeClientError> { debug!( target: LOG_TARGET, r#"Invoking read method "{}" for asset '{}'"#, method, asset_public_key @@ -125,7 +125,7 @@ impl ValidatorNodeRpcClient for TariCommsValidatorNodeRpcClient { template_id: TemplateId, method: String, args: Vec, - ) -> Result>, DigitalAssetError> { + ) -> Result>, ValidatorNodeClientError> { debug!( target: LOG_TARGET, r#"Invoking method "{}" for asset '{}'"#, method, asset_public_key @@ -156,7 +156,7 @@ impl ValidatorNodeRpcClient for TariCommsValidatorNodeRpcClient { asset_public_key: &PublicKey, start_hash: TreeNodeHash, end_hash: Option, - ) -> Result, DigitalAssetError> { + ) -> Result, ValidatorNodeClientError> { let mut connection = self.create_connection().await?; let mut client = connection.connect_rpc::().await?; let request = proto::GetSidechainBlocksRequest { @@ -168,22 +168,114 @@ impl ValidatorNodeRpcClient for TariCommsValidatorNodeRpcClient { let stream = client.get_sidechain_blocks(request).await?; // TODO: By first collecting all the blocks, we lose the advantage of streaming. Since you cannot return // `Result, _>`, and the Map type is private in tokio-stream, its a little tricky to - // return the stream and not leak the RPC response type out of the client + // return the stream and not leak the RPC response type out of the client. + // Copying the tokio_stream::Map stream into our code / creating a custom conversion stream wrapper would + // solve this. let blocks = stream .map(|result| { - let resp = result.map_err(DigitalAssetError::from)?; + let resp = result?; let block: SideChainBlock = resp .block - .ok_or_else(|| DigitalAssetError::ConversionError("Node returned empty block".to_string()))? + .ok_or_else(|| { + ValidatorNodeClientError::InvalidPeerMessage("Node returned empty block".to_string()) + })? .try_into() - .map_err(DigitalAssetError::ConversionError)?; + .map_err(ValidatorNodeClientError::InvalidPeerMessage)?; Ok(block) }) - .collect::>() + .collect::>() .await?; Ok(blocks) } + + async fn get_sidechain_state( + &mut self, + asset_public_key: &PublicKey, + ) -> Result, ValidatorNodeClientError> { + let mut connection = self.create_connection().await?; + let mut client = connection.connect_rpc::().await?; + let request = proto::GetSidechainStateRequest { + asset_public_key: asset_public_key.to_vec(), + }; + + let mut stream = client.get_sidechain_state(request).await?; + // TODO: Same issue as get_sidechain_blocks + let mut schemas = Vec::new(); + let mut current_schema = None; + while let Some(resp) = stream.next().await { + let resp = resp?; + + match resp.state { + Some(proto::get_sidechain_state_response::State::Schema(name)) => { + if let Some(schema) = current_schema.take() { + schemas.push(schema); + } + current_schema = Some(SchemaState::new(name, vec![])); + }, + Some(proto::get_sidechain_state_response::State::KeyValue(kv)) => match current_schema.as_mut() { + Some(schema) => { + let kv = kv.try_into().map_err(ValidatorNodeClientError::InvalidPeerMessage)?; + schema.push_key_value(kv); + }, + None => { + return Err(ValidatorNodeClientError::InvalidPeerMessage(format!( + "Peer {} sent a key value response without first defining the schema", + self.address + ))) + }, + }, + None => { + return Err(ValidatorNodeClientError::ProtocolViolation { + peer: self.address.clone(), + details: "get_sidechain_state: Peer sent response without state".to_string(), + }) + }, + } + } + + if let Some(schema) = current_schema { + schemas.push(schema); + } + + Ok(schemas) + } + + async fn get_op_logs( + &mut self, + asset_public_key: &PublicKey, + height: u64, + ) -> Result, ValidatorNodeClientError> { + let mut connection = self.create_connection().await?; + let mut client = connection.connect_rpc::().await?; + let request = proto::GetStateOpLogsRequest { + asset_public_key: asset_public_key.as_bytes().to_vec(), + height, + }; + + let resp = client.get_op_logs(request).await?; + let op_logs = resp + .op_logs + .into_iter() + .map(TryInto::try_into) + .collect::, _>>() + .map_err(ValidatorNodeClientError::InvalidPeerMessage)?; + + Ok(op_logs) + } + + async fn get_tip_node(&mut self, asset_public_key: &PublicKey) -> Result, ValidatorNodeClientError> { + let mut connection = self.create_connection().await?; + let mut client = connection.connect_rpc::().await?; + let request = proto::GetTipNodeRequest { + asset_public_key: asset_public_key.as_bytes().to_vec(), + }; + let resp = client.get_tip_node(request).await?; + resp.tip_node + .map(TryInto::try_into) + .transpose() + .map_err(ValidatorNodeClientError::InvalidPeerMessage) + } } #[derive(Clone)] diff --git a/applications/tari_web_extension/package-lock.json b/applications/tari_web_extension/package-lock.json index 6c2b8b03c5..50ad77409c 100644 --- a/applications/tari_web_extension/package-lock.json +++ b/applications/tari_web_extension/package-lock.json @@ -9162,9 +9162,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", - "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "funding": [ { "type": "individual", @@ -28314,9 +28314,9 @@ } }, "follow-redirects": { - "version": "1.14.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", - "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" }, "for-in": { "version": "1.0.2", diff --git a/applications/tari_web_extension_example/package-lock.json b/applications/tari_web_extension_example/package-lock.json index 998a2a3633..8d5c15d1c4 100644 --- a/applications/tari_web_extension_example/package-lock.json +++ b/applications/tari_web_extension_example/package-lock.json @@ -9305,9 +9305,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", - "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "funding": [ { "type": "individual", @@ -28838,9 +28838,9 @@ } }, "follow-redirects": { - "version": "1.14.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", - "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" }, "for-in": { "version": "1.0.2", diff --git a/applications/test_faucet/Cargo.toml b/applications/test_faucet/Cargo.toml index e33f65e746..99f802dac6 100644 --- a/applications/test_faucet/Cargo.toml +++ b/applications/test_faucet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test_faucet" -version = "0.27.3" +version = "0.28.0" authors = ["The Tari Development Community"] edition = "2018" diff --git a/applications/test_faucet/src/main.rs b/applications/test_faucet/src/main.rs index 5667055f3f..a8d0d1ae8f 100644 --- a/applications/test_faucet/src/main.rs +++ b/applications/test_faucet/src/main.rs @@ -19,7 +19,7 @@ use tari_core::{ tari_amount::{MicroTari, T}, test_helpers, test_helpers::generate_keys, - transaction::{KernelFeatures, OutputFeatures, TransactionKernel, TransactionOutput}, + transaction_components::{KernelFeatures, OutputFeatures, TransactionKernel, TransactionOutput}, CryptoFactories, }, }; diff --git a/base_layer/common_types/Cargo.toml b/base_layer/common_types/Cargo.toml index 1720efae0d..f02d26abf9 100644 --- a/base_layer/common_types/Cargo.toml +++ b/base_layer/common_types/Cargo.toml @@ -3,7 +3,7 @@ name = "tari_common_types" authors = ["The Tari Development Community"] description = "Tari cryptocurrency common types" license = "BSD-3-Clause" -version = "0.27.3" +version = "0.28.0" edition = "2018" [dependencies] diff --git a/base_layer/common_types/src/transaction.rs b/base_layer/common_types/src/transaction.rs index 0e33ca237e..94ef6d12b7 100644 --- a/base_layer/common_types/src/transaction.rs +++ b/base_layer/common_types/src/transaction.rs @@ -17,7 +17,7 @@ pub enum TransactionStatus { Broadcast, /// This transaction has been mined and included in a block. MinedUnconfirmed, - /// This transaction was generated as part of importing a spendable UTXO + /// This transaction was generated as part of importing a spendable unblinded UTXO Imported, /// This transaction is still being negotiated by the parties Pending, @@ -27,6 +27,19 @@ pub enum TransactionStatus { MinedConfirmed, /// This transaction was Rejected by the mempool Rejected, + /// This is faux transaction mainly for one-sided transaction outputs or wallet recovery outputs have been found + FauxUnconfirmed, + /// All Imported and FauxUnconfirmed transactions will end up with this status when the outputs have been confirmed + FauxConfirmed, +} + +impl TransactionStatus { + pub fn is_faux(&self) -> bool { + matches!( + self, + TransactionStatus::Imported | TransactionStatus::FauxUnconfirmed | TransactionStatus::FauxConfirmed + ) + } } #[derive(Debug, Error)] @@ -48,6 +61,8 @@ impl TryFrom for TransactionStatus { 5 => Ok(TransactionStatus::Coinbase), 6 => Ok(TransactionStatus::MinedConfirmed), 7 => Ok(TransactionStatus::Rejected), + 8 => Ok(TransactionStatus::FauxUnconfirmed), + 9 => Ok(TransactionStatus::FauxConfirmed), code => Err(TransactionConversionError { code }), } } @@ -71,6 +86,43 @@ impl Display for TransactionStatus { TransactionStatus::Pending => write!(f, "Pending"), TransactionStatus::Coinbase => write!(f, "Coinbase"), TransactionStatus::Rejected => write!(f, "Rejected"), + TransactionStatus::FauxUnconfirmed => write!(f, "FauxUnconfirmed"), + TransactionStatus::FauxConfirmed => write!(f, "FauxConfirmed"), + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum ImportStatus { + /// This transaction import status is used when importing a spendable UTXO + Imported, + /// This transaction import status is used when a one-sided transaction has been scanned but is unconfirmed + FauxUnconfirmed, + /// This transaction import status is used when a one-sided transaction has been scanned and confirmed + FauxConfirmed, +} + +impl TryFrom for TransactionStatus { + type Error = TransactionConversionError; + + fn try_from(value: ImportStatus) -> Result { + match value { + ImportStatus::Imported => Ok(TransactionStatus::Imported), + ImportStatus::FauxUnconfirmed => Ok(TransactionStatus::FauxUnconfirmed), + ImportStatus::FauxConfirmed => Ok(TransactionStatus::FauxConfirmed), + } + } +} + +impl TryFrom for ImportStatus { + type Error = TransactionConversionError; + + fn try_from(value: TransactionStatus) -> Result { + match value { + TransactionStatus::Imported => Ok(ImportStatus::Imported), + TransactionStatus::FauxUnconfirmed => Ok(ImportStatus::FauxUnconfirmed), + TransactionStatus::FauxConfirmed => Ok(ImportStatus::FauxConfirmed), + _ => Err(TransactionConversionError { code: i32::MAX }), } } } diff --git a/base_layer/core/Cargo.toml b/base_layer/core/Cargo.toml index 5a7bc7c61c..998d9ca35a 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.27.3" +version = "0.28.0" edition = "2018" [features] @@ -18,19 +18,19 @@ base_node_proto = [] avx2 = ["tari_crypto/avx2"] [dependencies] -tari_common = { version = "^0.27", path = "../../common" } -tari_common_types = { version = "^0.27", path = "../../base_layer/common_types" } -tari_comms = { version = "^0.27", path = "../../comms" } -tari_comms_dht = { version = "^0.27", path = "../../comms/dht" } -tari_comms_rpc_macros = { version = "^0.27", path = "../../comms/rpc_macros" } +tari_common = { version = "^0.28", path = "../../common" } +tari_common_types = { version = "^0.28", path = "../../base_layer/common_types" } +tari_comms = { version = "^0.28", path = "../../comms" } +tari_comms_dht = { version = "^0.28", path = "../../comms/dht" } +tari_comms_rpc_macros = { version = "^0.28", path = "../../comms/rpc_macros" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } tari_metrics = { path = "../../infrastructure/metrics" } -tari_mmr = { version = "^0.27", path = "../../base_layer/mmr", optional = true, features = ["native_bitmap"] } -tari_p2p = { version = "^0.27", path = "../../base_layer/p2p" } -tari_service_framework = { version = "^0.27", path = "../service_framework" } -tari_shutdown = { version = "^0.27", path = "../../infrastructure/shutdown" } -tari_storage = { version = "^0.27", path = "../../infrastructure/storage" } -tari_test_utils = { version = "^0.27", path = "../../infrastructure/test_utils" } +tari_mmr = { version = "^0.28", path = "../../base_layer/mmr", optional = true, features = ["native_bitmap"] } +tari_p2p = { version = "^0.28", path = "../../base_layer/p2p" } +tari_service_framework = { version = "^0.28", path = "../service_framework" } +tari_shutdown = { version = "^0.28", path = "../../infrastructure/shutdown" } +tari_storage = { version = "^0.28", path = "../../infrastructure/storage" } +tari_test_utils = { version = "^0.28", path = "../../infrastructure/test_utils" } tari_utilities = "0.3.0" async-trait = "0.1.50" @@ -69,12 +69,12 @@ tracing-attributes = "*" uint = { version = "0.9", default-features = false } [dev-dependencies] -tari_p2p = { version = "^0.27", path = "../../base_layer/p2p", features = ["test-mocks"] } -tari_test_utils = { version = "^0.27", path = "../../infrastructure/test_utils" } +tari_p2p = { version = "^0.28", path = "../../base_layer/p2p", features = ["test-mocks"] } +tari_test_utils = { version = "^0.28", path = "../../infrastructure/test_utils" } config = { version = "0.9.3" } env_logger = "0.7.0" tempfile = "3.1.0" [build-dependencies] -tari_common = { version = "^0.27", path = "../../common", features = ["build"] } +tari_common = { version = "^0.28", path = "../../common", features = ["build"] } diff --git a/base_layer/core/src/base_node/comms_interface/comms_response.rs b/base_layer/core/src/base_node/comms_interface/comms_response.rs index a5a0e3c90f..2089ac2155 100644 --- a/base_layer/core/src/base_node/comms_interface/comms_response.rs +++ b/base_layer/core/src/base_node/comms_interface/comms_response.rs @@ -34,7 +34,7 @@ use crate::{ blocks::{Block, BlockHeader, ChainHeader, HistoricalBlock, NewBlockTemplate}, chain_storage::UtxoMinedInfo, proof_of_work::Difficulty, - transactions::transaction::{Transaction, TransactionKernel, TransactionOutput}, + transactions::transaction_components::{Transaction, TransactionKernel, TransactionOutput}, }; /// API Response enum diff --git a/base_layer/core/src/base_node/comms_interface/local_interface.rs b/base_layer/core/src/base_node/comms_interface/local_interface.rs index 4bd623cc46..620159bc36 100644 --- a/base_layer/core/src/base_node/comms_interface/local_interface.rs +++ b/base_layer/core/src/base_node/comms_interface/local_interface.rs @@ -40,7 +40,7 @@ use crate::{ blocks::{Block, ChainHeader, HistoricalBlock, NewBlockTemplate}, chain_storage::UtxoMinedInfo, proof_of_work::PowAlgorithm, - transactions::transaction::{TransactionKernel, TransactionOutput}, + transactions::transaction_components::{TransactionKernel, TransactionOutput}, }; pub type BlockEventSender = broadcast::Sender>; diff --git a/base_layer/core/src/base_node/rpc/service.rs b/base_layer/core/src/base_node/rpc/service.rs index 3a0de04db1..9eee31bb23 100644 --- a/base_layer/core/src/base_node/rpc/service.rs +++ b/base_layer/core/src/base_node/rpc/service.rs @@ -60,7 +60,7 @@ use crate::{ }, types::{Signature as SignatureProto, Transaction as TransactionProto}, }, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, }; const LOG_TARGET: &str = "c::base_node::rpc"; @@ -432,7 +432,6 @@ impl BaseNodeWalletService for BaseNodeWalletRpc for position in message.mmr_positions { if position > u32::MAX as u64 { - // TODO: in future, bitmap may support higher than u32 return Err(RpcStatus::bad_request("position must fit into a u32")); } let position = position as u32; diff --git a/base_layer/core/src/base_node/sync/horizon_state_sync/error.rs b/base_layer/core/src/base_node/sync/horizon_state_sync/error.rs index c30801729d..72fed92da6 100644 --- a/base_layer/core/src/base_node/sync/horizon_state_sync/error.rs +++ b/base_layer/core/src/base_node/sync/horizon_state_sync/error.rs @@ -34,7 +34,7 @@ use tokio::task; use crate::{ base_node::comms_interface::CommsInterfaceError, chain_storage::{ChainStorageError, MmrTree}, - transactions::transaction::TransactionError, + transactions::transaction_components::TransactionError, validation::ValidationError, }; diff --git a/base_layer/core/src/base_node/sync/horizon_state_sync/synchronizer.rs b/base_layer/core/src/base_node/sync/horizon_state_sync/synchronizer.rs index e971e5a601..dacc8d8512 100644 --- a/base_layer/core/src/base_node/sync/horizon_state_sync/synchronizer.rs +++ b/base_layer/core/src/base_node/sync/horizon_state_sync/synchronizer.rs @@ -67,7 +67,7 @@ use crate::{ SyncUtxosRequest, SyncUtxosResponse, }, - transactions::transaction::{TransactionKernel, TransactionOutput}, + transactions::transaction_components::{TransactionKernel, TransactionOutput}, validation::{helpers, FinalHorizonStateValidation}, }; diff --git a/base_layer/core/src/blocks/block.rs b/base_layer/core/src/blocks/block.rs index 998935ac91..25b3daee62 100644 --- a/base_layer/core/src/blocks/block.rs +++ b/base_layer/core/src/blocks/block.rs @@ -42,7 +42,7 @@ use crate::{ transactions::{ aggregated_body::AggregateBody, tari_amount::MicroTari, - transaction::{ + transaction_components::{ KernelFeatures, OutputFlags, Transaction, diff --git a/base_layer/core/src/blocks/genesis_block.rs b/base_layer/core/src/blocks/genesis_block.rs index 779a8ffeb6..f2e4f18501 100644 --- a/base_layer/core/src/blocks/genesis_block.rs +++ b/base_layer/core/src/blocks/genesis_block.rs @@ -37,7 +37,7 @@ use crate::{ transactions::{ aggregated_body::AggregateBody, tari_amount::MicroTari, - transaction::{KernelFeatures, OutputFeatures, OutputFlags, TransactionKernel, TransactionOutput}, + transaction_components::{KernelFeatures, OutputFeatures, OutputFlags, TransactionKernel, TransactionOutput}, }, }; diff --git a/base_layer/core/src/chain_storage/async_db.rs b/base_layer/core/src/chain_storage/async_db.rs index 621ef100b6..5e7b65bf14 100644 --- a/base_layer/core/src/chain_storage/async_db.rs +++ b/base_layer/core/src/chain_storage/async_db.rs @@ -66,7 +66,7 @@ use crate::{ }, common::rolling_vec::RollingVec, proof_of_work::{PowAlgorithm, TargetDifficultyWindow}, - transactions::transaction::{TransactionKernel, TransactionOutput}, + transactions::transaction_components::{TransactionKernel, TransactionOutput}, }; const LOG_TARGET: &str = "c::bn::async_db"; diff --git a/base_layer/core/src/chain_storage/blockchain_backend.rs b/base_layer/core/src/chain_storage/blockchain_backend.rs index d0dc0a7d4d..30dcec4b27 100644 --- a/base_layer/core/src/chain_storage/blockchain_backend.rs +++ b/base_layer/core/src/chain_storage/blockchain_backend.rs @@ -30,7 +30,7 @@ use crate::{ Reorg, UtxoMinedInfo, }, - transactions::transaction::{TransactionInput, TransactionKernel}, + transactions::transaction_components::{TransactionInput, TransactionKernel}, }; /// Identify behaviour for Blockchain database backends. Implementations must support `Send` and `Sync` so that diff --git a/base_layer/core/src/chain_storage/blockchain_database.rs b/base_layer/core/src/chain_storage/blockchain_database.rs index 75bad84454..d0dd16070b 100644 --- a/base_layer/core/src/chain_storage/blockchain_database.rs +++ b/base_layer/core/src/chain_storage/blockchain_database.rs @@ -79,7 +79,7 @@ use crate::{ common::rolling_vec::RollingVec, consensus::{chain_strength_comparer::ChainStrengthComparer, ConsensusConstants, ConsensusManager}, proof_of_work::{monero_rx::MoneroPowData, PowAlgorithm, TargetDifficultyWindow}, - transactions::transaction::{TransactionInput, TransactionKernel}, + transactions::transaction_components::{TransactionInput, TransactionKernel}, validation::{ helpers::calc_median_timestamp, DifficultyCalculator, diff --git a/base_layer/core/src/chain_storage/db_transaction.rs b/base_layer/core/src/chain_storage/db_transaction.rs index 88dd11cf47..a2ce4c5d92 100644 --- a/base_layer/core/src/chain_storage/db_transaction.rs +++ b/base_layer/core/src/chain_storage/db_transaction.rs @@ -36,7 +36,7 @@ use tari_crypto::tari_utilities::{ use crate::{ blocks::{Block, BlockHeader, BlockHeaderAccumulatedData, ChainBlock, ChainHeader, UpdateBlockAccumulatedData}, chain_storage::{error::ChainStorageError, HorizonData, Reorg}, - transactions::transaction::{TransactionKernel, TransactionOutput}, + transactions::transaction_components::{TransactionKernel, TransactionOutput}, }; #[derive(Debug)] diff --git a/base_layer/core/src/chain_storage/error.rs b/base_layer/core/src/chain_storage/error.rs index 4a0cee3645..65be9628c2 100644 --- a/base_layer/core/src/chain_storage/error.rs +++ b/base_layer/core/src/chain_storage/error.rs @@ -30,7 +30,7 @@ use crate::{ blocks::BlockError, chain_storage::MmrTree, proof_of_work::PowError, - transactions::transaction::TransactionError, + transactions::transaction_components::TransactionError, validation::ValidationError, }; diff --git a/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs b/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs index 7bbb2f67e9..8dde5cdb43 100644 --- a/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs +++ b/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs @@ -104,7 +104,7 @@ use crate::{ }, transactions::{ aggregated_body::AggregateBody, - transaction::{TransactionError, TransactionInput, TransactionKernel, TransactionOutput}, + transaction_components::{TransactionError, TransactionInput, TransactionKernel, TransactionOutput}, }, }; diff --git a/base_layer/core/src/chain_storage/lmdb_db/mod.rs b/base_layer/core/src/chain_storage/lmdb_db/mod.rs index e01ed62c58..ad8b12c831 100644 --- a/base_layer/core/src/chain_storage/lmdb_db/mod.rs +++ b/base_layer/core/src/chain_storage/lmdb_db/mod.rs @@ -24,7 +24,7 @@ pub use lmdb_db::{create_lmdb_database, create_recovery_lmdb_database, LMDBDatab use serde::{Deserialize, Serialize}; use tari_common_types::types::HashOutput; -use crate::transactions::transaction::{TransactionInput, TransactionKernel, TransactionOutput}; +use crate::transactions::transaction_components::{TransactionInput, TransactionKernel, TransactionOutput}; pub(crate) mod helpers; pub(crate) mod key_prefix_cursor; diff --git a/base_layer/core/src/chain_storage/pruned_output.rs b/base_layer/core/src/chain_storage/pruned_output.rs index 6686285214..e505963e77 100644 --- a/base_layer/core/src/chain_storage/pruned_output.rs +++ b/base_layer/core/src/chain_storage/pruned_output.rs @@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize}; use tari_common_types::types::HashOutput; use tari_crypto::tari_utilities::Hashable; -use crate::transactions::transaction::TransactionOutput; +use crate::transactions::transaction_components::TransactionOutput; #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/base_layer/core/src/chain_storage/tests/blockchain_database.rs b/base_layer/core/src/chain_storage/tests/blockchain_database.rs index 5bb31b4d19..ea825f0f8e 100644 --- a/base_layer/core/src/chain_storage/tests/blockchain_database.rs +++ b/base_layer/core/src/chain_storage/tests/blockchain_database.rs @@ -40,7 +40,7 @@ use crate::{ transactions::{ tari_amount::T, test_helpers::{schema_to_transaction, TransactionSchema}, - transaction::{OutputFeatures, OutputFlags, Transaction, UnblindedOutput}, + transaction_components::{OutputFeatures, OutputFlags, Transaction, UnblindedOutput}, }, txn_schema, }; @@ -708,7 +708,7 @@ mod fetch_utxo_by_unique_id { use tari_crypto::{commitment::HomomorphicCommitmentFactory, ristretto::RistrettoPublicKey}; use super::*; - use crate::transactions::transaction::OutputFlags; + use crate::transactions::transaction_components::OutputFlags; #[test] fn it_returns_none_if_empty() { diff --git a/base_layer/core/src/consensus/consensus_constants.rs b/base_layer/core/src/consensus/consensus_constants.rs index fa272cd723..4da890d10d 100644 --- a/base_layer/core/src/consensus/consensus_constants.rs +++ b/base_layer/core/src/consensus/consensus_constants.rs @@ -31,7 +31,7 @@ use crate::{ proof_of_work::{Difficulty, PowAlgorithm}, transactions::{ tari_amount::{uT, MicroTari, T}, - transaction::OutputFeatures, + transaction_components::OutputFeatures, weight::TransactionWeight, }, }; diff --git a/base_layer/core/src/consensus/consensus_manager.rs b/base_layer/core/src/consensus/consensus_manager.rs index e6bf9206d9..c4c01b0f2a 100644 --- a/base_layer/core/src/consensus/consensus_manager.rs +++ b/base_layer/core/src/consensus/consensus_manager.rs @@ -39,7 +39,7 @@ use crate::{ NetworkConsensus, }, proof_of_work::DifficultyAdjustmentError, - transactions::{tari_amount::MicroTari, transaction::TransactionKernel}, + transactions::{tari_amount::MicroTari, transaction_components::TransactionKernel}, }; #[derive(Debug, Error)] diff --git a/base_layer/core/src/covenants/context.rs b/base_layer/core/src/covenants/context.rs index c3a17b3df0..c9df25e984 100644 --- a/base_layer/core/src/covenants/context.rs +++ b/base_layer/core/src/covenants/context.rs @@ -27,7 +27,7 @@ use crate::{ filters::CovenantFilter, token::{CovenantToken, CovenantTokenCollection}, }, - transactions::transaction::TransactionInput, + transactions::transaction_components::TransactionInput, }; pub struct CovenantContext<'a> { diff --git a/base_layer/core/src/covenants/covenant.rs b/base_layer/core/src/covenants/covenant.rs index 5f993b166f..6dedb52883 100644 --- a/base_layer/core/src/covenants/covenant.rs +++ b/base_layer/core/src/covenants/covenant.rs @@ -36,7 +36,7 @@ use crate::{ output_set::OutputSet, token::{CovenantToken, CovenantTokenCollection}, }, - transactions::transaction::{TransactionInput, TransactionOutput}, + transactions::transaction_components::{TransactionInput, TransactionOutput}, }; const MAX_COVENANT_BYTES: usize = 4096; diff --git a/base_layer/core/src/covenants/fields.rs b/base_layer/core/src/covenants/fields.rs index 6bfb7048fe..1c03c7bbb6 100644 --- a/base_layer/core/src/covenants/fields.rs +++ b/base_layer/core/src/covenants/fields.rs @@ -39,7 +39,7 @@ use crate::{ encoder::CovenentWriteExt, error::CovenantError, }, - transactions::transaction::{TransactionInput, TransactionOutput}, + transactions::transaction_components::{TransactionInput, TransactionOutput}, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -330,7 +330,7 @@ mod test { use super::*; use crate::{ covenants::test::create_outputs, - transactions::{test_helpers::UtxoTestParams, transaction::OutputFeatures}, + transactions::{test_helpers::UtxoTestParams, transaction_components::OutputFeatures}, }; #[test] diff --git a/base_layer/core/src/covenants/filters/fields_hashed_eq.rs b/base_layer/core/src/covenants/filters/fields_hashed_eq.rs index 9ea32e2077..3fd6816b44 100644 --- a/base_layer/core/src/covenants/filters/fields_hashed_eq.rs +++ b/base_layer/core/src/covenants/filters/fields_hashed_eq.rs @@ -70,7 +70,7 @@ mod test { consensus::ToConsensusBytes, covenant, covenants::{filters::test::setup_filter_test, test::create_input}, - transactions::transaction::OutputFeatures, + transactions::transaction_components::OutputFeatures, }; #[test] diff --git a/base_layer/core/src/covenants/filters/fields_preserved.rs b/base_layer/core/src/covenants/filters/fields_preserved.rs index 8f38810273..0872df308b 100644 --- a/base_layer/core/src/covenants/filters/fields_preserved.rs +++ b/base_layer/core/src/covenants/filters/fields_preserved.rs @@ -41,7 +41,7 @@ mod test { use crate::{ covenant, covenants::{filters::test::setup_filter_test, test::create_input}, - transactions::transaction::OutputFlags, + transactions::transaction_components::OutputFlags, }; #[test] diff --git a/base_layer/core/src/covenants/filters/test.rs b/base_layer/core/src/covenants/filters/test.rs index 5169a14abb..38a30381ae 100644 --- a/base_layer/core/src/covenants/filters/test.rs +++ b/base_layer/core/src/covenants/filters/test.rs @@ -26,7 +26,7 @@ use crate::{ test::{create_context, create_outputs}, Covenant, }, - transactions::transaction::{TransactionInput, TransactionOutput}, + transactions::transaction_components::{TransactionInput, TransactionOutput}, }; pub fn setup_filter_test<'a, F>( diff --git a/base_layer/core/src/covenants/output_set.rs b/base_layer/core/src/covenants/output_set.rs index f086214614..30e5aa2a7a 100644 --- a/base_layer/core/src/covenants/output_set.rs +++ b/base_layer/core/src/covenants/output_set.rs @@ -27,7 +27,7 @@ use std::{ ops::{Deref, DerefMut}, }; -use crate::{covenants::error::CovenantError, transactions::transaction::TransactionOutput}; +use crate::{covenants::error::CovenantError, transactions::transaction_components::TransactionOutput}; #[derive(Debug, Clone)] pub struct OutputSet<'a>(BTreeSet>); diff --git a/base_layer/core/src/covenants/test.rs b/base_layer/core/src/covenants/test.rs index f881bd7445..96a700ca99 100644 --- a/base_layer/core/src/covenants/test.rs +++ b/base_layer/core/src/covenants/test.rs @@ -26,7 +26,7 @@ use crate::{ covenants::{context::CovenantContext, Covenant}, transactions::{ test_helpers::{TestParams, UtxoTestParams}, - transaction::{TransactionInput, TransactionOutput}, + transaction_components::{TransactionInput, TransactionOutput}, }, }; diff --git a/base_layer/core/src/mempool/error.rs b/base_layer/core/src/mempool/error.rs index f0d09db1d7..1d96ec21b9 100644 --- a/base_layer/core/src/mempool/error.rs +++ b/base_layer/core/src/mempool/error.rs @@ -24,7 +24,7 @@ use tari_service_framework::reply_channel::TransportChannelError; use thiserror::Error; use tokio::task::JoinError; -use crate::{mempool::unconfirmed_pool::UnconfirmedPoolError, transactions::transaction::TransactionError}; +use crate::{mempool::unconfirmed_pool::UnconfirmedPoolError, transactions::transaction_components::TransactionError}; #[derive(Debug, Error)] pub enum MempoolError { diff --git a/base_layer/core/src/mempool/mempool.rs b/base_layer/core/src/mempool/mempool.rs index 079aa8e21a..af6bcc691e 100644 --- a/base_layer/core/src/mempool/mempool.rs +++ b/base_layer/core/src/mempool/mempool.rs @@ -36,7 +36,7 @@ use crate::{ StatsResponse, TxStorageResponse, }, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, validation::MempoolTransactionValidation, }; diff --git a/base_layer/core/src/mempool/mempool_storage.rs b/base_layer/core/src/mempool/mempool_storage.rs index dc6a6a2c17..52c97dfd86 100644 --- a/base_layer/core/src/mempool/mempool_storage.rs +++ b/base_layer/core/src/mempool/mempool_storage.rs @@ -38,7 +38,7 @@ use crate::{ StatsResponse, TxStorageResponse, }, - transactions::{transaction::Transaction, weight::TransactionWeight}, + transactions::{transaction_components::Transaction, weight::TransactionWeight}, validation::{MempoolTransactionValidation, ValidationError}, }; diff --git a/base_layer/core/src/mempool/mod.rs b/base_layer/core/src/mempool/mod.rs index 9b00310186..52dddc432f 100644 --- a/base_layer/core/src/mempool/mod.rs +++ b/base_layer/core/src/mempool/mod.rs @@ -77,7 +77,7 @@ pub use sync_protocol::MempoolSyncInitializer; use tari_common_types::types::Signature; use tari_crypto::tari_utilities::hex::Hex; -use crate::transactions::transaction::Transaction; +use crate::transactions::transaction_components::Transaction; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct StatsResponse { diff --git a/base_layer/core/src/mempool/priority/prioritized_transaction.rs b/base_layer/core/src/mempool/priority/prioritized_transaction.rs index 381717ba02..7f48128f38 100644 --- a/base_layer/core/src/mempool/priority/prioritized_transaction.rs +++ b/base_layer/core/src/mempool/priority/prioritized_transaction.rs @@ -28,7 +28,7 @@ use std::{ use tari_common_types::types::{HashOutput, PrivateKey, PublicKey}; use tari_utilities::{hex::Hex, ByteArray}; -use crate::transactions::{transaction::Transaction, weight::TransactionWeight}; +use crate::transactions::{transaction_components::Transaction, weight::TransactionWeight}; /// Create a unique unspent transaction priority based on the transaction fee, maturity of the oldest input UTXO and the /// excess_sig. The excess_sig is included to ensure the the priority key unique so it can be used with a BTreeMap. diff --git a/base_layer/core/src/mempool/reorg_pool/reorg_pool.rs b/base_layer/core/src/mempool/reorg_pool/reorg_pool.rs index bcd68e4b69..c91d58583e 100644 --- a/base_layer/core/src/mempool/reorg_pool/reorg_pool.rs +++ b/base_layer/core/src/mempool/reorg_pool/reorg_pool.rs @@ -31,7 +31,7 @@ use serde::{Deserialize, Serialize}; use tari_common_types::types::{PrivateKey, Signature}; use tari_utilities::{hex::Hex, Hashable}; -use crate::{blocks::Block, transactions::transaction::Transaction}; +use crate::{blocks::Block, transactions::transaction_components::Transaction}; pub const LOG_TARGET: &str = "c::mp::reorg_pool::reorg_pool_storage"; diff --git a/base_layer/core/src/mempool/rpc/service.rs b/base_layer/core/src/mempool/rpc/service.rs index cb9f199f51..b82add1df9 100644 --- a/base_layer/core/src/mempool/rpc/service.rs +++ b/base_layer/core/src/mempool/rpc/service.rs @@ -28,7 +28,7 @@ use tari_comms::protocol::rpc::{Request, Response, RpcStatus}; use crate::{ mempool::{rpc::MempoolService, service::MempoolHandle}, proto, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, }; const LOG_TARGET: &str = "c::mempool::rpc"; diff --git a/base_layer/core/src/mempool/service/handle.rs b/base_layer/core/src/mempool/service/handle.rs index 96aaac6f76..c76a6b54a2 100644 --- a/base_layer/core/src/mempool/service/handle.rs +++ b/base_layer/core/src/mempool/service/handle.rs @@ -31,7 +31,7 @@ use crate::{ StatsResponse, TxStorageResponse, }, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, }; #[derive(Clone)] diff --git a/base_layer/core/src/mempool/service/inbound_handlers.rs b/base_layer/core/src/mempool/service/inbound_handlers.rs index eeecc00ebc..4388d15d16 100644 --- a/base_layer/core/src/mempool/service/inbound_handlers.rs +++ b/base_layer/core/src/mempool/service/inbound_handlers.rs @@ -35,7 +35,7 @@ use crate::{ Mempool, TxStorageResponse, }, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, }; pub const LOG_TARGET: &str = "c::mp::service::inbound_handlers"; diff --git a/base_layer/core/src/mempool/service/initializer.rs b/base_layer/core/src/mempool/service/initializer.rs index 5eaf65a149..83431f8f19 100644 --- a/base_layer/core/src/mempool/service/initializer.rs +++ b/base_layer/core/src/mempool/service/initializer.rs @@ -52,7 +52,7 @@ use crate::{ }, }, proto, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, }; const LOG_TARGET: &str = "c::bn::mempool_service::initializer"; diff --git a/base_layer/core/src/mempool/service/local_service.rs b/base_layer/core/src/mempool/service/local_service.rs index ae6645da98..cb236146df 100644 --- a/base_layer/core/src/mempool/service/local_service.rs +++ b/base_layer/core/src/mempool/service/local_service.rs @@ -30,7 +30,7 @@ use crate::{ StatsResponse, TxStorageResponse, }, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, }; pub type LocalMempoolRequester = SenderService>; diff --git a/base_layer/core/src/mempool/service/outbound_interface.rs b/base_layer/core/src/mempool/service/outbound_interface.rs index 7eb1a4bc2a..bedac7116a 100644 --- a/base_layer/core/src/mempool/service/outbound_interface.rs +++ b/base_layer/core/src/mempool/service/outbound_interface.rs @@ -26,7 +26,7 @@ use log::*; use tari_comms::peer_manager::NodeId; use tokio::sync::mpsc::UnboundedSender; -use crate::{mempool::service::MempoolServiceError, transactions::transaction::Transaction}; +use crate::{mempool::service::MempoolServiceError, transactions::transaction_components::Transaction}; pub const LOG_TARGET: &str = "c::mp::service::outbound_interface"; diff --git a/base_layer/core/src/mempool/service/request.rs b/base_layer/core/src/mempool/service/request.rs index 43941aa7db..c6a3bf783d 100644 --- a/base_layer/core/src/mempool/service/request.rs +++ b/base_layer/core/src/mempool/service/request.rs @@ -26,7 +26,7 @@ use serde::{Deserialize, Serialize}; use tari_common_types::{types::Signature, waiting_requests::RequestKey}; use tari_crypto::tari_utilities::hex::Hex; -use crate::transactions::transaction::Transaction; +use crate::transactions::transaction_components::Transaction; /// API Request enum for Mempool requests. #[derive(Debug, Serialize, Deserialize)] diff --git a/base_layer/core/src/mempool/service/service.rs b/base_layer/core/src/mempool/service/service.rs index 28168febf0..ee99073504 100644 --- a/base_layer/core/src/mempool/service/service.rs +++ b/base_layer/core/src/mempool/service/service.rs @@ -47,7 +47,7 @@ use crate::{ MempoolResponse, }, proto, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, }; const LOG_TARGET: &str = "c::mempool::service::service"; diff --git a/base_layer/core/src/mempool/sync_protocol/mod.rs b/base_layer/core/src/mempool/sync_protocol/mod.rs index 488fcd28e0..08ec64c455 100644 --- a/base_layer/core/src/mempool/sync_protocol/mod.rs +++ b/base_layer/core/src/mempool/sync_protocol/mod.rs @@ -100,7 +100,7 @@ use tokio::{ use crate::{ mempool::{metrics, proto, Mempool, MempoolServiceConfig}, proto as shared_proto, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, }; #[cfg(test)] diff --git a/base_layer/core/src/mempool/sync_protocol/test.rs b/base_layer/core/src/mempool/sync_protocol/test.rs index 0e268df30e..623e63a5d7 100644 --- a/base_layer/core/src/mempool/sync_protocol/test.rs +++ b/base_layer/core/src/mempool/sync_protocol/test.rs @@ -48,7 +48,7 @@ use crate::{ sync_protocol::{MempoolPeerProtocol, MempoolSyncProtocol, MAX_FRAME_SIZE, MEMPOOL_SYNC_PROTOCOL}, Mempool, }, - transactions::{tari_amount::uT, test_helpers::create_tx, transaction::Transaction}, + transactions::{tari_amount::uT, test_helpers::create_tx, transaction_components::Transaction}, validation::mocks::MockValidator, }; diff --git a/base_layer/core/src/mempool/unconfirmed_pool/unconfirmed_pool.rs b/base_layer/core/src/mempool/unconfirmed_pool/unconfirmed_pool.rs index 3450d20368..a8fe8ed055 100644 --- a/base_layer/core/src/mempool/unconfirmed_pool/unconfirmed_pool.rs +++ b/base_layer/core/src/mempool/unconfirmed_pool/unconfirmed_pool.rs @@ -41,7 +41,7 @@ use crate::{ unconfirmed_pool::UnconfirmedPoolError, }, transactions::{ - transaction::{Transaction, TransactionOutput}, + transaction_components::{Transaction, TransactionOutput}, weight::TransactionWeight, }, }; @@ -628,7 +628,7 @@ mod test { fee::Fee, tari_amount::MicroTari, test_helpers::{TestParams, UtxoTestParams}, - transaction::{KernelFeatures, OutputFeatures}, + transaction_components::{KernelFeatures, OutputFeatures}, weight::TransactionWeight, CryptoFactories, SenderTransactionProtocol, diff --git a/base_layer/core/src/proto/transaction.rs b/base_layer/core/src/proto/transaction.rs index b212aa1d9a..af4986efc3 100644 --- a/base_layer/core/src/proto/transaction.rs +++ b/base_layer/core/src/proto/transaction.rs @@ -40,7 +40,7 @@ use crate::{ transactions::{ aggregated_body::AggregateBody, tari_amount::MicroTari, - transaction::{ + transaction_components::{ AssetOutputFeatures, KernelFeatures, MintNonFungibleFeatures, diff --git a/base_layer/core/src/test_helpers/block_spec.rs b/base_layer/core/src/test_helpers/block_spec.rs index c590ca198d..0c28ad7532 100644 --- a/base_layer/core/src/test_helpers/block_spec.rs +++ b/base_layer/core/src/test_helpers/block_spec.rs @@ -22,7 +22,7 @@ use crate::{ proof_of_work::Difficulty, - transactions::{tari_amount::MicroTari, transaction::Transaction}, + transactions::{tari_amount::MicroTari, transaction_components::Transaction}, }; pub struct BlockSpecs { diff --git a/base_layer/core/src/test_helpers/blockchain.rs b/base_layer/core/src/test_helpers/blockchain.rs index c8fc66b6c3..229fb3f1e4 100644 --- a/base_layer/core/src/test_helpers/blockchain.rs +++ b/base_layer/core/src/test_helpers/blockchain.rs @@ -73,7 +73,7 @@ use crate::{ proof_of_work::{AchievedTargetDifficulty, Difficulty, PowAlgorithm}, test_helpers::{block_spec::BlockSpecs, create_consensus_rules, BlockSpec}, transactions::{ - transaction::{TransactionInput, TransactionKernel, UnblindedOutput}, + transaction_components::{TransactionInput, TransactionKernel, UnblindedOutput}, CryptoFactories, }, validation::{ diff --git a/base_layer/core/src/test_helpers/mod.rs b/base_layer/core/src/test_helpers/mod.rs index 503a044c49..d85d8b7436 100644 --- a/base_layer/core/src/test_helpers/mod.rs +++ b/base_layer/core/src/test_helpers/mod.rs @@ -37,7 +37,7 @@ use crate::{ consensus::{ConsensusConstants, ConsensusManager}, proof_of_work::{sha3_difficulty, AchievedTargetDifficulty, Difficulty}, transactions::{ - transaction::{Transaction, UnblindedOutput}, + transaction_components::{Transaction, UnblindedOutput}, CoinbaseBuilder, CryptoFactories, }, diff --git a/base_layer/core/src/transactions/aggregated_body.rs b/base_layer/core/src/transactions/aggregated_body.rs index dfe53734c7..53b583276c 100644 --- a/base_layer/core/src/transactions/aggregated_body.rs +++ b/base_layer/core/src/transactions/aggregated_body.rs @@ -47,7 +47,7 @@ use tari_crypto::{ use crate::transactions::{ crypto_factories::CryptoFactories, tari_amount::MicroTari, - transaction::{ + transaction_components::{ KernelFeatures, KernelSum, OutputFlags, diff --git a/base_layer/core/src/transactions/coinbase_builder.rs b/base_layer/core/src/transactions/coinbase_builder.rs index 724b07ef88..dfa08f221a 100644 --- a/base_layer/core/src/transactions/coinbase_builder.rs +++ b/base_layer/core/src/transactions/coinbase_builder.rs @@ -41,7 +41,7 @@ use crate::{ transactions::{ crypto_factories::CryptoFactories, tari_amount::{uT, MicroTari}, - transaction::{ + transaction_components::{ KernelBuilder, KernelFeatures, OutputFeatures, @@ -222,7 +222,6 @@ impl CoinbaseBuilder { 0, covenant, ); - // TODO: Verify bullet proof? let output = if let Some(rewind_data) = self.rewind_data.as_ref() { unblinded_output .as_rewindable_transaction_output(&self.factories, rewind_data, None) @@ -269,7 +268,7 @@ mod test { crypto_factories::CryptoFactories, tari_amount::uT, test_helpers::TestParams, - transaction::{KernelFeatures, OutputFeatures, OutputFlags, TransactionError}, + transaction_components::{KernelFeatures, OutputFeatures, OutputFlags, TransactionError}, transaction_protocol::RewindData, CoinbaseBuilder, }, diff --git a/base_layer/core/src/transactions/mod.rs b/base_layer/core/src/transactions/mod.rs index ee63b708c2..ec1717a870 100644 --- a/base_layer/core/src/transactions/mod.rs +++ b/base_layer/core/src/transactions/mod.rs @@ -8,7 +8,7 @@ pub use coinbase_builder::{CoinbaseBuildError, CoinbaseBuilder}; pub mod fee; pub mod tari_amount; -pub mod transaction; +pub mod transaction_components; mod format_currency; pub use format_currency::format_currency; diff --git a/base_layer/core/src/transactions/tari_amount.rs b/base_layer/core/src/transactions/tari_amount.rs index 06dca76185..472d036546 100644 --- a/base_layer/core/src/transactions/tari_amount.rs +++ b/base_layer/core/src/transactions/tari_amount.rs @@ -146,8 +146,7 @@ impl std::str::FromStr for MicroTari { if is_micro_tari { processed .parse::() - // TODO: Why we compare it with `0` here? It's unsigned. - .map(|v| MicroTari::from(v.max(0))) + .map(MicroTari::from) .map_err(|e| MicroTariError::ParseError(e.to_string())) } else { processed @@ -157,7 +156,6 @@ impl std::str::FromStr for MicroTari { if v.is_sign_negative() { Err(MicroTariError::ParseError("value cannot be negative".to_string())) } else { - // TODO: Check. It can't be `NaN` anymore. Still we need `.max(0.0)` check? Tari::from(v).try_into().map_err(MicroTariError::from) } })? @@ -262,7 +260,7 @@ impl Display for Tari { pub type TariConversionError = DecimalConvertError; -// TODO: Remove `f64` completely! Using it is the bad idea in general. +// TODO: Remove `f64` completely! Using it is the bad idea in general. #LOGGED impl TryFrom for Tari { type Error = TariConversionError; diff --git a/base_layer/core/src/transactions/test_helpers.rs b/base_layer/core/src/transactions/test_helpers.rs index 544215df6b..39349a54f9 100644 --- a/base_layer/core/src/transactions/test_helpers.rs +++ b/base_layer/core/src/transactions/test_helpers.rs @@ -42,7 +42,7 @@ use crate::{ crypto_factories::CryptoFactories, fee::Fee, tari_amount::MicroTari, - transaction::{ + transaction_components::{ KernelBuilder, KernelFeatures, OutputFeatures, @@ -334,7 +334,7 @@ macro_rules! txn_schema { to:$outputs, fee:$fee, lock:0, - features: $crate::transactions::transaction::OutputFeatures::default() + features: $crate::transactions::transaction_components::OutputFeatures::default() ) }; diff --git a/base_layer/core/src/transactions/transaction/asset_output_features.rs b/base_layer/core/src/transactions/transaction_components/asset_output_features.rs similarity index 98% rename from base_layer/core/src/transactions/transaction/asset_output_features.rs rename to base_layer/core/src/transactions/transaction_components/asset_output_features.rs index 7901727232..95de23cba4 100644 --- a/base_layer/core/src/transactions/transaction/asset_output_features.rs +++ b/base_layer/core/src/transactions/transaction_components/asset_output_features.rs @@ -30,7 +30,7 @@ use tari_common_types::types::PublicKey; use crate::{ consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized, MaxSizeVec}, - transactions::transaction::TemplateParameter, + transactions::transaction_components::TemplateParameter, }; #[derive(Debug, Clone, Hash, PartialEq, Deserialize, Serialize, Eq)] diff --git a/base_layer/core/src/transactions/transaction/error.rs b/base_layer/core/src/transactions/transaction_components/error.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/error.rs rename to base_layer/core/src/transactions/transaction_components/error.rs diff --git a/base_layer/core/src/transactions/transaction/full_rewind_result.rs b/base_layer/core/src/transactions/transaction_components/full_rewind_result.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/full_rewind_result.rs rename to base_layer/core/src/transactions/transaction_components/full_rewind_result.rs diff --git a/base_layer/core/src/transactions/transaction/kernel_builder.rs b/base_layer/core/src/transactions/transaction_components/kernel_builder.rs similarity index 97% rename from base_layer/core/src/transactions/transaction/kernel_builder.rs rename to base_layer/core/src/transactions/transaction_components/kernel_builder.rs index e4c568a02a..08b9e9623f 100644 --- a/base_layer/core/src/transactions/transaction/kernel_builder.rs +++ b/base_layer/core/src/transactions/transaction_components/kernel_builder.rs @@ -27,7 +27,7 @@ use tari_common_types::types::{Commitment, Signature}; use crate::transactions::{ tari_amount::MicroTari, - transaction::{KernelFeatures, TransactionError, TransactionKernel}, + transaction_components::{KernelFeatures, TransactionError, TransactionKernel}, }; /// A version of Transaction kernel with optional fields. This struct is only used in constructing transaction kernels diff --git a/base_layer/core/src/transactions/transaction/kernel_features.rs b/base_layer/core/src/transactions/transaction_components/kernel_features.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/kernel_features.rs rename to base_layer/core/src/transactions/transaction_components/kernel_features.rs diff --git a/base_layer/core/src/transactions/transaction/kernel_sum.rs b/base_layer/core/src/transactions/transaction_components/kernel_sum.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/kernel_sum.rs rename to base_layer/core/src/transactions/transaction_components/kernel_sum.rs diff --git a/base_layer/core/src/transactions/transaction/mint_non_fungible_features.rs b/base_layer/core/src/transactions/transaction_components/mint_non_fungible_features.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/mint_non_fungible_features.rs rename to base_layer/core/src/transactions/transaction_components/mint_non_fungible_features.rs diff --git a/base_layer/core/src/transactions/transaction/mod.rs b/base_layer/core/src/transactions/transaction_components/mod.rs similarity index 98% rename from base_layer/core/src/transactions/transaction/mod.rs rename to base_layer/core/src/transactions/transaction_components/mod.rs index eb397b8e07..5f55585f9d 100644 --- a/base_layer/core/src/transactions/transaction/mod.rs +++ b/base_layer/core/src/transactions/transaction_components/mod.rs @@ -63,8 +63,6 @@ mod output_flags; mod rewind_result; mod side_chain_checkpoint_features; mod template_parameter; -// TODO: in future, this module can be renamed -#[allow(clippy::module_inception)] mod transaction; mod transaction_builder; mod transaction_input; diff --git a/base_layer/core/src/transactions/transaction/output_features.rs b/base_layer/core/src/transactions/transaction_components/output_features.rs similarity index 99% rename from base_layer/core/src/transactions/transaction/output_features.rs rename to base_layer/core/src/transactions/transaction_components/output_features.rs index 4547151fbb..647c9890de 100644 --- a/base_layer/core/src/transactions/transaction/output_features.rs +++ b/base_layer/core/src/transactions/transaction_components/output_features.rs @@ -35,7 +35,7 @@ use tari_utilities::ByteArray; use super::OutputFeaturesVersion; use crate::{ consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized, MaxSizeBytes}, - transactions::transaction::{ + transactions::transaction_components::{ AssetOutputFeatures, MintNonFungibleFeatures, OutputFlags, diff --git a/base_layer/core/src/transactions/transaction/output_features_version.rs b/base_layer/core/src/transactions/transaction_components/output_features_version.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/output_features_version.rs rename to base_layer/core/src/transactions/transaction_components/output_features_version.rs diff --git a/base_layer/core/src/transactions/transaction/output_flags.rs b/base_layer/core/src/transactions/transaction_components/output_flags.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/output_flags.rs rename to base_layer/core/src/transactions/transaction_components/output_flags.rs diff --git a/base_layer/core/src/transactions/transaction/rewind_result.rs b/base_layer/core/src/transactions/transaction_components/rewind_result.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/rewind_result.rs rename to base_layer/core/src/transactions/transaction_components/rewind_result.rs diff --git a/base_layer/core/src/transactions/transaction/side_chain_checkpoint_features.rs b/base_layer/core/src/transactions/transaction_components/side_chain_checkpoint_features.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/side_chain_checkpoint_features.rs rename to base_layer/core/src/transactions/transaction_components/side_chain_checkpoint_features.rs diff --git a/base_layer/core/src/transactions/transaction/template_parameter.rs b/base_layer/core/src/transactions/transaction_components/template_parameter.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/template_parameter.rs rename to base_layer/core/src/transactions/transaction_components/template_parameter.rs diff --git a/base_layer/core/src/transactions/transaction/test.rs b/base_layer/core/src/transactions/transaction_components/test.rs similarity index 99% rename from base_layer/core/src/transactions/transaction/test.rs rename to base_layer/core/src/transactions/transaction_components/test.rs index 2c513bbab6..51828e0039 100644 --- a/base_layer/core/src/transactions/transaction/test.rs +++ b/base_layer/core/src/transactions/transaction_components/test.rs @@ -42,7 +42,7 @@ use crate::{ tari_amount::{uT, MicroTari, T}, test_helpers, test_helpers::{create_sender_transaction_protocol_with, create_unblinded_txos, TestParams, UtxoTestParams}, - transaction::OutputFeatures, + transaction_components::OutputFeatures, transaction_protocol::{RewindData, TransactionProtocolError}, CryptoFactories, }, diff --git a/base_layer/core/src/transactions/transaction/transaction.rs b/base_layer/core/src/transactions/transaction_components/transaction.rs similarity index 97% rename from base_layer/core/src/transactions/transaction/transaction.rs rename to base_layer/core/src/transactions/transaction_components/transaction.rs index 3f497a1e16..ec5b32bfc1 100644 --- a/base_layer/core/src/transactions/transaction/transaction.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction.rs @@ -36,7 +36,13 @@ use tari_crypto::tari_utilities::hex::Hex; use crate::transactions::{ aggregated_body::AggregateBody, tari_amount::{uT, MicroTari}, - transaction::{OutputFeatures, TransactionError, TransactionInput, TransactionKernel, TransactionOutput}, + transaction_components::{ + OutputFeatures, + TransactionError, + TransactionInput, + TransactionKernel, + TransactionOutput, + }, weight::TransactionWeight, CryptoFactories, }; diff --git a/base_layer/core/src/transactions/transaction/transaction_builder.rs b/base_layer/core/src/transactions/transaction_components/transaction_builder.rs similarity index 97% rename from base_layer/core/src/transactions/transaction/transaction_builder.rs rename to base_layer/core/src/transactions/transaction_components/transaction_builder.rs index f334ef2934..28cbf05265 100644 --- a/base_layer/core/src/transactions/transaction/transaction_builder.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_builder.rs @@ -28,7 +28,7 @@ use tari_common_types::types::{BlindingFactor, HashOutput}; use crate::transactions::{ aggregated_body::AggregateBody, tari_amount::MicroTari, - transaction::{Transaction, TransactionError, TransactionInput, TransactionKernel, TransactionOutput}, + transaction_components::{Transaction, TransactionError, TransactionInput, TransactionKernel, TransactionOutput}, CryptoFactories, }; diff --git a/base_layer/core/src/transactions/transaction/transaction_input.rs b/base_layer/core/src/transactions/transaction_components/transaction_input.rs similarity index 98% rename from base_layer/core/src/transactions/transaction/transaction_input.rs rename to base_layer/core/src/transactions/transaction_components/transaction_input.rs index 2385110592..32ff1858c9 100644 --- a/base_layer/core/src/transactions/transaction/transaction_input.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_input.rs @@ -43,8 +43,13 @@ use crate::{ consensus::ConsensusEncoding, covenants::Covenant, transactions::{ - transaction, - transaction::{transaction_output::TransactionOutput, OutputFeatures, TransactionError, UnblindedOutput}, + transaction_components, + transaction_components::{ + transaction_output::TransactionOutput, + OutputFeatures, + TransactionError, + UnblindedOutput, + }, }, }; @@ -307,7 +312,7 @@ impl TransactionInput { ref features, ref covenant, .. - } => transaction::hash_output(version, features, commitment, script, covenant).to_vec(), + } => transaction_components::hash_output(version, features, commitment, script, covenant).to_vec(), } } diff --git a/base_layer/core/src/transactions/transaction/transaction_input_version.rs b/base_layer/core/src/transactions/transaction_components/transaction_input_version.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/transaction_input_version.rs rename to base_layer/core/src/transactions/transaction_components/transaction_input_version.rs diff --git a/base_layer/core/src/transactions/transaction/transaction_kernel.rs b/base_layer/core/src/transactions/transaction_components/transaction_kernel.rs similarity index 98% rename from base_layer/core/src/transactions/transaction/transaction_kernel.rs rename to base_layer/core/src/transactions/transaction_components/transaction_kernel.rs index 5ffe7bb9dd..0eea1ee5ff 100644 --- a/base_layer/core/src/transactions/transaction/transaction_kernel.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_kernel.rs @@ -39,7 +39,7 @@ use crate::{ consensus::ConsensusEncoding, transactions::{ tari_amount::MicroTari, - transaction::{KernelFeatures, TransactionError}, + transaction_components::{KernelFeatures, TransactionError}, transaction_protocol::{build_challenge, TransactionMetadata}, }, }; diff --git a/base_layer/core/src/transactions/transaction/transaction_kernel_version.rs b/base_layer/core/src/transactions/transaction_components/transaction_kernel_version.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/transaction_kernel_version.rs rename to base_layer/core/src/transactions/transaction_components/transaction_kernel_version.rs diff --git a/base_layer/core/src/transactions/transaction/transaction_output.rs b/base_layer/core/src/transactions/transaction_components/transaction_output.rs similarity index 99% rename from base_layer/core/src/transactions/transaction/transaction_output.rs rename to base_layer/core/src/transactions/transaction_components/transaction_output.rs index 728a0d4e08..ba05a9c8d0 100644 --- a/base_layer/core/src/transactions/transaction/transaction_output.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_output.rs @@ -59,8 +59,8 @@ use crate::{ covenants::Covenant, transactions::{ tari_amount::MicroTari, - transaction, - transaction::{ + transaction_components, + transaction_components::{ full_rewind_result::FullRewindResult, rewind_result::RewindResult, OutputFeatures, @@ -365,7 +365,7 @@ impl TransactionOutput { /// Implement the canonical hashing function for TransactionOutput for use in ordering. impl Hashable for TransactionOutput { fn hash(&self) -> Vec { - transaction::hash_output( + transaction_components::hash_output( self.version, &self.features, &self.commitment, diff --git a/base_layer/core/src/transactions/transaction/transaction_output_version.rs b/base_layer/core/src/transactions/transaction_components/transaction_output_version.rs similarity index 100% rename from base_layer/core/src/transactions/transaction/transaction_output_version.rs rename to base_layer/core/src/transactions/transaction_components/transaction_output_version.rs diff --git a/base_layer/core/src/transactions/transaction/unblinded_output.rs b/base_layer/core/src/transactions/transaction_components/unblinded_output.rs similarity index 98% rename from base_layer/core/src/transactions/transaction/unblinded_output.rs rename to base_layer/core/src/transactions/transaction_components/unblinded_output.rs index 8887fb8b54..00d8f7f11c 100644 --- a/base_layer/core/src/transactions/transaction/unblinded_output.rs +++ b/base_layer/core/src/transactions/transaction_components/unblinded_output.rs @@ -46,8 +46,8 @@ use crate::{ covenants::Covenant, transactions::{ tari_amount::MicroTari, - transaction, - transaction::{ + transaction_components, + transaction_components::{ transaction_input::{SpentOutput, TransactionInput}, transaction_output::TransactionOutput, OutputFeatures, @@ -61,6 +61,7 @@ use crate::{ /// An unblinded output is one where the value and spending key (blinding factor) are known. This can be used to /// build both inputs and outputs (every input comes from an output) // TODO: Try to get rid of 'Serialize' and 'Deserialize' traits here; see related comment at 'struct RawTransactionInfo' +// #LOGGED #[derive(Clone, Serialize, Deserialize)] pub struct UnblindedOutput { pub version: TransactionOutputVersion, @@ -265,7 +266,8 @@ impl UnblindedOutput { // Note: added to the struct to ensure consistency between `commitment`, `spending_key` and `value`. pub fn hash(&self, factories: &CryptoFactories) -> Vec { let commitment = factories.commitment.commit_value(&self.spending_key, self.value.into()); - transaction::hash_output(self.version, &self.features, &commitment, &self.script, &self.covenant).to_vec() + transaction_components::hash_output(self.version, &self.features, &commitment, &self.script, &self.covenant) + .to_vec() } } diff --git a/base_layer/core/src/transactions/transaction/unblinded_output_builder.rs b/base_layer/core/src/transactions/transaction_components/unblinded_output_builder.rs similarity index 98% rename from base_layer/core/src/transactions/transaction/unblinded_output_builder.rs rename to base_layer/core/src/transactions/transaction_components/unblinded_output_builder.rs index dd59127206..8855cbd232 100644 --- a/base_layer/core/src/transactions/transaction/unblinded_output_builder.rs +++ b/base_layer/core/src/transactions/transaction_components/unblinded_output_builder.rs @@ -27,7 +27,7 @@ use crate::{ covenants::Covenant, transactions::{ tari_amount::MicroTari, - transaction::{OutputFeatures, TransactionError, TransactionOutput, UnblindedOutput}, + transaction_components::{OutputFeatures, TransactionError, TransactionOutput, UnblindedOutput}, }, }; diff --git a/base_layer/core/src/transactions/transaction_protocol/mod.rs b/base_layer/core/src/transactions/transaction_protocol/mod.rs index 285c7bd562..711f35d841 100644 --- a/base_layer/core/src/transactions/transaction_protocol/mod.rs +++ b/base_layer/core/src/transactions/transaction_protocol/mod.rs @@ -93,7 +93,7 @@ use tari_crypto::{ }; use thiserror::Error; -use crate::transactions::{tari_amount::*, transaction::TransactionError}; +use crate::transactions::{tari_amount::*, transaction_components::TransactionError}; pub mod proto; pub mod recipient; diff --git a/base_layer/core/src/transactions/transaction_protocol/proto/transaction_sender.proto b/base_layer/core/src/transactions/transaction_protocol/proto/transaction_sender.proto index dadeab0b33..af91e6fdec 100644 --- a/base_layer/core/src/transactions/transaction_protocol/proto/transaction_sender.proto +++ b/base_layer/core/src/transactions/transaction_protocol/proto/transaction_sender.proto @@ -37,9 +37,6 @@ message TransactionSenderMessage { oneof message { bool None = 1; SingleRoundSenderData single = 2; - - // TODO: Three round types - bool Multiple = 3; } } diff --git a/base_layer/core/src/transactions/transaction_protocol/recipient.rs b/base_layer/core/src/transactions/transaction_protocol/recipient.rs index 7aae24f19d..28ceac3f4a 100644 --- a/base_layer/core/src/transactions/transaction_protocol/recipient.rs +++ b/base_layer/core/src/transactions/transaction_protocol/recipient.rs @@ -30,7 +30,7 @@ use tari_common_types::{ use crate::transactions::{ crypto_factories::CryptoFactories, - transaction::TransactionOutput, + transaction_components::TransactionOutput, transaction_protocol::{ sender::{SingleRoundSenderData as SD, TransactionSenderMessage}, single_receiver::SingleReceiverTransactionProtocol, @@ -215,7 +215,7 @@ mod test { crypto_factories::CryptoFactories, tari_amount::*, test_helpers::TestParams, - transaction::OutputFeatures, + transaction_components::OutputFeatures, transaction_protocol::{ build_challenge, sender::{SingleRoundSenderData, TransactionSenderMessage}, diff --git a/base_layer/core/src/transactions/transaction_protocol/sender.rs b/base_layer/core/src/transactions/transaction_protocol/sender.rs index 8c231d5b79..ad9a768db4 100644 --- a/base_layer/core/src/transactions/transaction_protocol/sender.rs +++ b/base_layer/core/src/transactions/transaction_protocol/sender.rs @@ -42,7 +42,7 @@ use crate::{ crypto_factories::CryptoFactories, fee::Fee, tari_amount::*, - transaction::{ + transaction_components::{ KernelBuilder, KernelFeatures, OutputFeatures, @@ -69,7 +69,7 @@ use crate::{ /// This struct contains all the information that a transaction initiator (the sender) will manage throughout the /// Transaction construction process. // TODO: Investigate necessity to use the 'Serialize' and 'Deserialize' traits here; this could potentially leak -// TODO: information when least expected. +// TODO: information when least expected. #LOGGED #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub(super) struct RawTransactionInfo { pub num_recipients: usize, @@ -139,7 +139,6 @@ pub struct SingleRoundSenderData { pub enum TransactionSenderMessage { None, Single(Box), - // TODO: Three round types Multiple, } @@ -766,7 +765,7 @@ mod test { crypto_factories::CryptoFactories, tari_amount::*, test_helpers::{create_test_input, create_unblinded_output, TestParams}, - transaction::{KernelFeatures, OutputFeatures, TransactionError, TransactionOutput}, + transaction_components::{KernelFeatures, OutputFeatures, TransactionError, TransactionOutput}, transaction_protocol::{ sender::SenderTransactionProtocol, single_receiver::SingleReceiverTransactionProtocol, diff --git a/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs b/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs index 19ffc76800..b471c9e2f6 100644 --- a/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs +++ b/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs @@ -30,7 +30,7 @@ use tari_crypto::{ use crate::transactions::{ crypto_factories::CryptoFactories, - transaction::TransactionOutput, + transaction_components::TransactionOutput, transaction_protocol::{ build_challenge, recipient::RecipientSignedMessage as RD, @@ -143,7 +143,7 @@ mod test { use crate::transactions::{ crypto_factories::CryptoFactories, tari_amount::*, - transaction::OutputFeatures, + transaction_components::OutputFeatures, transaction_protocol::{ build_challenge, sender::SingleRoundSenderData, diff --git a/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs b/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs index e01e580904..7a500c03d9 100644 --- a/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs +++ b/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs @@ -47,7 +47,7 @@ use crate::{ crypto_factories::CryptoFactories, fee::Fee, tari_amount::*, - transaction::{ + transaction_components::{ OutputFeatures, TransactionInput, TransactionOutput, @@ -290,7 +290,7 @@ impl SenderTransactionInitializer { .map(|o| self.fee.weighting().round_up_metadata_size(o.metadata_byte_size())) .sum::(); - // TODO: implement iter for FixedSet to avoid the clone + // TODO: implement iter for FixedSet to avoid the clone #LOGGED size += self .recipient_scripts .clone() @@ -359,7 +359,6 @@ impl SenderTransactionInitializer { let change_amount = v.checked_sub(change_fee); let change_sender_offset_private_key = PrivateKey::random(&mut OsRng); self.change_sender_offset_private_key = Some(change_sender_offset_private_key.clone()); - // TODO: Add unique id if needed match change_amount { // You can't win. Just add the change to the fee (which is less than the cost of adding another // output and go without a change output @@ -526,7 +525,6 @@ impl SenderTransactionInitializer { // If rewind data is present we produce a rewindable output, else a standard output let change_output = if let Some(rewind_data) = self.rewind_data.as_ref() { - // TODO: Should proof be verified? match change_unblinded_output.as_rewindable_transaction_output(factories, rewind_data, None) { Ok(o) => o, Err(e) => { @@ -534,7 +532,6 @@ impl SenderTransactionInitializer { }, } } else { - // TODO: Should proof be verified? match change_unblinded_output.as_transaction_output(factories) { Ok(o) => o, Err(e) => { @@ -680,7 +677,7 @@ mod test { fee::Fee, tari_amount::*, test_helpers::{create_test_input, create_unblinded_output, TestParams, UtxoTestParams}, - transaction::{OutputFeatures, MAX_TRANSACTION_INPUTS}, + transaction_components::{OutputFeatures, MAX_TRANSACTION_INPUTS}, transaction_protocol::{ sender::SenderState, transaction_initializer::SenderTransactionInitializer, diff --git a/base_layer/core/src/validation/block_validators/async_validator.rs b/base_layer/core/src/validation/block_validators/async_validator.rs index bf1b55b376..6f2e461abb 100644 --- a/base_layer/core/src/validation/block_validators/async_validator.rs +++ b/base_layer/core/src/validation/block_validators/async_validator.rs @@ -37,7 +37,7 @@ use crate::{ iterators::NonOverlappingIntegerPairIter, transactions::{ aggregated_body::AggregateBody, - transaction::{ + transaction_components::{ KernelSum, OutputFlags, TransactionError, diff --git a/base_layer/core/src/validation/block_validators/test.rs b/base_layer/core/src/validation/block_validators/test.rs index e6c620e017..7d81691a41 100644 --- a/base_layer/core/src/validation/block_validators/test.rs +++ b/base_layer/core/src/validation/block_validators/test.rs @@ -37,7 +37,7 @@ use crate::{ aggregated_body::AggregateBody, tari_amount::T, test_helpers::{schema_to_transaction, TransactionSchema}, - transaction::{OutputFeatures, OutputFlags, TransactionError, UnblindedOutput}, + transaction_components::{OutputFeatures, OutputFlags, TransactionError, UnblindedOutput}, CoinbaseBuilder, CryptoFactories, }, diff --git a/base_layer/core/src/validation/error.rs b/base_layer/core/src/validation/error.rs index 5ef6fb3b93..44c7bdb1a5 100644 --- a/base_layer/core/src/validation/error.rs +++ b/base_layer/core/src/validation/error.rs @@ -29,7 +29,7 @@ use crate::{ chain_storage::ChainStorageError, covenants::CovenantError, proof_of_work::{monero_rx::MergeMineError, PowError}, - transactions::transaction::TransactionError, + transactions::transaction_components::TransactionError, }; #[derive(Debug, Error)] diff --git a/base_layer/core/src/validation/helpers.rs b/base_layer/core/src/validation/helpers.rs index 6e08945e33..98f040fa2e 100644 --- a/base_layer/core/src/validation/helpers.rs +++ b/base_layer/core/src/validation/helpers.rs @@ -50,7 +50,7 @@ use crate::{ transactions::{ aggregated_body::AggregateBody, tari_amount::MicroTari, - transaction::{ + transaction_components::{ KernelSum, OutputFlags, TransactionError, @@ -850,7 +850,7 @@ mod test { mod check_maturity { use super::*; - use crate::transactions::transaction::{OutputFeatures, TransactionInputVersion}; + use crate::transactions::transaction_components::{OutputFeatures, TransactionInputVersion}; #[test] fn it_checks_the_input_maturity() { diff --git a/base_layer/core/src/validation/mocks.rs b/base_layer/core/src/validation/mocks.rs index e30006c4c2..f6c07d5639 100644 --- a/base_layer/core/src/validation/mocks.rs +++ b/base_layer/core/src/validation/mocks.rs @@ -32,7 +32,7 @@ use crate::{ blocks::{Block, BlockHeader, ChainBlock}, chain_storage::BlockchainBackend, proof_of_work::{sha3_difficulty, AchievedTargetDifficulty, Difficulty, PowAlgorithm}, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, validation::{ error::ValidationError, BlockSyncBodyValidation, diff --git a/base_layer/core/src/validation/test.rs b/base_layer/core/src/validation/test.rs index 3bc8039b2c..fb46d855e4 100644 --- a/base_layer/core/src/validation/test.rs +++ b/base_layer/core/src/validation/test.rs @@ -37,7 +37,7 @@ use crate::{ transactions::{ tari_amount::{uT, MicroTari}, test_helpers::{create_random_signature_from_s_key, create_utxo}, - transaction::{KernelBuilder, KernelFeatures, OutputFeatures, TransactionKernel}, + transaction_components::{KernelBuilder, KernelFeatures, OutputFeatures, TransactionKernel}, CryptoFactories, }, validation::{header_iter::HeaderIter, ChainBalanceValidator, FinalHorizonStateValidation}, diff --git a/base_layer/core/src/validation/traits.rs b/base_layer/core/src/validation/traits.rs index 01f7b8183a..3e4fb97322 100644 --- a/base_layer/core/src/validation/traits.rs +++ b/base_layer/core/src/validation/traits.rs @@ -27,7 +27,7 @@ use crate::{ blocks::{Block, BlockHeader, ChainBlock}, chain_storage::BlockchainBackend, proof_of_work::AchievedTargetDifficulty, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, validation::{error::ValidationError, DifficultyCalculator}, }; diff --git a/base_layer/core/src/validation/transaction_validators.rs b/base_layer/core/src/validation/transaction_validators.rs index 1676ced387..7d3991fc12 100644 --- a/base_layer/core/src/validation/transaction_validators.rs +++ b/base_layer/core/src/validation/transaction_validators.rs @@ -26,7 +26,7 @@ use tari_utilities::hex::Hex; use crate::{ chain_storage::{BlockchainBackend, BlockchainDatabase, PrunedOutput}, transactions::{ - transaction::{SpentOutput, Transaction}, + transaction_components::{SpentOutput, Transaction}, CryptoFactories, }, validation::{ diff --git a/base_layer/core/tests/async_db.rs b/base_layer/core/tests/async_db.rs index a059fa4017..8d8008b063 100644 --- a/base_layer/core/tests/async_db.rs +++ b/base_layer/core/tests/async_db.rs @@ -36,7 +36,7 @@ use tari_core::{ transactions::{ tari_amount::T, test_helpers::schema_to_transaction, - transaction::{TransactionOutput, UnblindedOutput}, + transaction_components::{TransactionOutput, UnblindedOutput}, CryptoFactories, }, txn_schema, diff --git a/base_layer/core/tests/base_node_rpc.rs b/base_layer/core/tests/base_node_rpc.rs index 7e175f4df9..d82e64357d 100644 --- a/base_layer/core/tests/base_node_rpc.rs +++ b/base_layer/core/tests/base_node_rpc.rs @@ -50,7 +50,7 @@ use tari_core::{ transactions::{ tari_amount::{uT, T}, test_helpers::schema_to_transaction, - transaction::{TransactionOutput, UnblindedOutput}, + transaction_components::{TransactionOutput, UnblindedOutput}, CryptoFactories, }, txn_schema, diff --git a/base_layer/core/tests/block_validation.rs b/base_layer/core/tests/block_validation.rs index d56087ec64..5533b12f56 100644 --- a/base_layer/core/tests/block_validation.rs +++ b/base_layer/core/tests/block_validation.rs @@ -40,7 +40,7 @@ use tari_core::{ aggregated_body::AggregateBody, tari_amount::{uT, T}, test_helpers::{create_unblinded_output, schema_to_transaction, spend_utxos, TestParams, UtxoTestParams}, - transaction::OutputFeatures, + transaction_components::OutputFeatures, CryptoFactories, }, txn_schema, diff --git a/base_layer/core/tests/chain_storage_tests/chain_storage.rs b/base_layer/core/tests/chain_storage_tests/chain_storage.rs index 04b7ab2b38..1f68792a60 100644 --- a/base_layer/core/tests/chain_storage_tests/chain_storage.rs +++ b/base_layer/core/tests/chain_storage_tests/chain_storage.rs @@ -47,7 +47,7 @@ use tari_core::{ transactions::{ tari_amount::{uT, MicroTari, T}, test_helpers::{schema_to_transaction, spend_utxos}, - transaction::{OutputFeatures, OutputFlags}, + transaction_components::{OutputFeatures, OutputFlags}, CryptoFactories, }, tx, diff --git a/base_layer/core/tests/helpers/block_builders.rs b/base_layer/core/tests/helpers/block_builders.rs index f69a1f27e7..3a1acb7542 100644 --- a/base_layer/core/tests/helpers/block_builders.rs +++ b/base_layer/core/tests/helpers/block_builders.rs @@ -43,7 +43,7 @@ use tari_core::{ TestParams, TransactionSchema, }, - transaction::{ + transaction_components::{ KernelBuilder, KernelFeatures, OutputFeatures, diff --git a/base_layer/core/tests/helpers/database.rs b/base_layer/core/tests/helpers/database.rs index e1132445a3..c2af63e9ce 100644 --- a/base_layer/core/tests/helpers/database.rs +++ b/base_layer/core/tests/helpers/database.rs @@ -23,7 +23,7 @@ use tari_core::{ blocks::{Block, BlockHeader, NewBlockTemplate}, consensus::{emission::Emission, ConsensusManager}, - transactions::{tari_amount::MicroTari, transaction::Transaction, CryptoFactories}, + transactions::{tari_amount::MicroTari, transaction_components::Transaction, CryptoFactories}, }; use crate::helpers::block_builders::create_coinbase; diff --git a/base_layer/core/tests/helpers/sample_blockchains.rs b/base_layer/core/tests/helpers/sample_blockchains.rs index 10f0d7baae..d96525514b 100644 --- a/base_layer/core/tests/helpers/sample_blockchains.rs +++ b/base_layer/core/tests/helpers/sample_blockchains.rs @@ -29,7 +29,7 @@ use tari_core::{ test_helpers::blockchain::{create_store_with_consensus, TempDatabase}, transactions::{ tari_amount::{uT, T}, - transaction::UnblindedOutput, + transaction_components::UnblindedOutput, CryptoFactories, }, txn_schema, diff --git a/base_layer/core/tests/helpers/test_block_builder.rs b/base_layer/core/tests/helpers/test_block_builder.rs index 2d036d212e..c3f6457761 100644 --- a/base_layer/core/tests/helpers/test_block_builder.rs +++ b/base_layer/core/tests/helpers/test_block_builder.rs @@ -21,7 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -use tari_core::transactions::transaction::Transaction; +use tari_core::transactions::transaction_components::Transaction; #[derive(Default)] pub struct TestBlockBuilder {} diff --git a/base_layer/core/tests/helpers/test_blockchain.rs b/base_layer/core/tests/helpers/test_blockchain.rs index 9b52cfadbf..3cae2087bf 100644 --- a/base_layer/core/tests/helpers/test_blockchain.rs +++ b/base_layer/core/tests/helpers/test_blockchain.rs @@ -31,7 +31,7 @@ use tari_core::{ chain_storage::{BlockAddResult, BlockchainDatabase, ChainStorageError}, consensus::ConsensusManager, test_helpers::blockchain::TempDatabase, - transactions::{transaction::UnblindedOutput, CryptoFactories}, + transactions::{transaction_components::UnblindedOutput, CryptoFactories}, }; use tari_crypto::tari_utilities::Hashable; diff --git a/base_layer/core/tests/mempool.rs b/base_layer/core/tests/mempool.rs index 51d9fddcf5..b6634719dc 100644 --- a/base_layer/core/tests/mempool.rs +++ b/base_layer/core/tests/mempool.rs @@ -51,7 +51,7 @@ use tari_core::{ fee::Fee, tari_amount::{uT, MicroTari, T}, test_helpers::{create_unblinded_output, schema_to_transaction, spend_utxos, TestParams}, - transaction::{KernelBuilder, OutputFeatures, OutputFlags, Transaction, TransactionOutput}, + transaction_components::{KernelBuilder, OutputFeatures, OutputFlags, Transaction, TransactionOutput}, transaction_protocol::{build_challenge, TransactionMetadata}, CryptoFactories, }, diff --git a/base_layer/core/tests/node_comms_interface.rs b/base_layer/core/tests/node_comms_interface.rs index 16e2153b31..aec0d13b8e 100644 --- a/base_layer/core/tests/node_comms_interface.rs +++ b/base_layer/core/tests/node_comms_interface.rs @@ -42,7 +42,7 @@ use tari_core::{ transactions::{ tari_amount::MicroTari, test_helpers::{create_utxo, spend_utxos}, - transaction::{OutputFeatures, TransactionOutput, UnblindedOutput}, + transaction_components::{OutputFeatures, TransactionOutput, UnblindedOutput}, CryptoFactories, }, txn_schema, diff --git a/base_layer/core/tests/node_service.rs b/base_layer/core/tests/node_service.rs index bd23b961c1..c38edf8fb5 100644 --- a/base_layer/core/tests/node_service.rs +++ b/base_layer/core/tests/node_service.rs @@ -43,7 +43,7 @@ use tari_core::{ transactions::{ tari_amount::{uT, T}, test_helpers::{schema_to_transaction, spend_utxos}, - transaction::OutputFeatures, + transaction_components::OutputFeatures, CryptoFactories, }, txn_schema, diff --git a/base_layer/key_manager/Cargo.toml b/base_layer/key_manager/Cargo.toml index cd281d6ecf..b525d943e1 100644 --- a/base_layer/key_manager/Cargo.toml +++ b/base_layer/key_manager/Cargo.toml @@ -4,14 +4,14 @@ authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet key management" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.27.3" +version = "0.28.0" edition = "2021" [lib] crate-type = ["lib", "cdylib"] [dependencies] -tari_common_types = { version = "^0.27", path = "../../base_layer/common_types" } +tari_common_types = { version = "^0.28", path = "../../base_layer/common_types" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } arrayvec = "0.7.1" diff --git a/base_layer/key_manager/src/mnemonic.rs b/base_layer/key_manager/src/mnemonic.rs index 723cd6a8b8..a6577e87c4 100644 --- a/base_layer/key_manager/src/mnemonic.rs +++ b/base_layer/key_manager/src/mnemonic.rs @@ -34,6 +34,7 @@ use crate::{ /// The Mnemonic system simplifies the encoding and decoding of a secret key into and from a Mnemonic word sequence /// It can autodetect the language of the Mnemonic word sequence // TODO: Develop a language autodetection mechanism to distinguish between ChineseTraditional and ChineseSimplified +// #LOGGED #[derive(Clone, Debug, PartialEq, EnumString, Display, Copy)] pub enum MnemonicLanguage { diff --git a/base_layer/mmr/Cargo.toml b/base_layer/mmr/Cargo.toml index 0965328e9d..665567f2a4 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.27.3" +version = "0.28.0" edition = "2018" [features] diff --git a/base_layer/p2p/Cargo.toml b/base_layer/p2p/Cargo.toml index 900913dfb8..f2ade27176 100644 --- a/base_layer/p2p/Cargo.toml +++ b/base_layer/p2p/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_p2p" -version = "0.27.3" +version = "0.28.0" authors = ["The Tari Development community"] description = "Tari base layer-specific peer-to-peer communication features" repository = "https://github.com/tari-project/tari" @@ -10,13 +10,13 @@ license = "BSD-3-Clause" edition = "2018" [dependencies] -tari_comms = { version = "^0.27", path = "../../comms" } -tari_comms_dht = { version = "^0.27", path = "../../comms/dht" } -tari_common = { version = "^0.27", path = "../../common" } +tari_comms = { version = "^0.28", path = "../../comms" } +tari_comms_dht = { version = "^0.28", path = "../../comms/dht" } +tari_common = { version = "^0.28", path = "../../common" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } -tari_service_framework = { version = "^0.27", path = "../service_framework" } -tari_shutdown = { version = "^0.27", path = "../../infrastructure/shutdown" } -tari_storage = { version = "^0.27", path = "../../infrastructure/storage" } +tari_service_framework = { version = "^0.28", path = "../service_framework" } +tari_shutdown = { version = "^0.28", path = "../../infrastructure/shutdown" } +tari_storage = { version = "^0.28", path = "../../infrastructure/storage" } tari_utilities = "^0.3" anyhow = "1.0.53" @@ -38,12 +38,12 @@ tokio = { version = "1.11", features = ["macros"] } tokio-stream = { version = "0.1.7", default-features = false, features = ["time"] } tower = "0.4.11" tower-service = { version = "0.3.1" } -trust-dns-client = { version = "0.21.0-alpha.4", features = ["dns-over-rustls"] } -rustls = "0.19.1" +trust-dns-client = { version = "=0.21.0-alpha.5", features = ["dns-over-rustls"] } +rustls = "0.20.2" webpki = "0.21" [dev-dependencies] -tari_test_utils = { version = "^0.27", path = "../../infrastructure/test_utils" } +tari_test_utils = { version = "^0.28", path = "../../infrastructure/test_utils" } clap = "2.33.0" lazy_static = "1.3.0" @@ -55,7 +55,7 @@ features = ["console_appender", "file_appender", "file", "yaml_format"] default-features = false [build-dependencies] -tari_common = { version = "^0.27", path = "../../common", features = ["build"] } +tari_common = { version = "^0.28", path = "../../common", features = ["build"] } [features] test-mocks = [] diff --git a/base_layer/p2p/src/auto_update/dns.rs b/base_layer/p2p/src/auto_update/dns.rs index d75e09c55c..e3a7cd3325 100644 --- a/base_layer/p2p/src/auto_update/dns.rs +++ b/base_layer/p2p/src/auto_update/dns.rs @@ -208,9 +208,9 @@ mod test { let mut record = Record::new(); record .set_record_type(RecordType::TXT) - .set_rdata(RData::TXT(rdata::TXT::new( + .set_data(Some(RData::TXT(rdata::TXT::new( contents.into_iter().map(ToString::to_string).collect(), - ))); + )))); mock::message(resp_query, vec![record], vec![], vec![]).into() } diff --git a/base_layer/p2p/src/dns/client.rs b/base_layer/p2p/src/dns/client.rs index e9cdcb7f92..462f3afed8 100644 --- a/base_layer/p2p/src/dns/client.rs +++ b/base_layer/p2p/src/dns/client.rs @@ -23,7 +23,7 @@ use std::{sync::Arc, time::Duration}; use futures::{future, FutureExt}; -use rustls::{ClientConfig, ProtocolVersion, RootCertStore}; +use rustls::{ClientConfig, RootCertStore}; use tari_common::DnsNameServer; use tari_shutdown::Shutdown; use tokio::task; @@ -96,12 +96,18 @@ impl DnsClient { .answers() .iter() .map(|answer| { - let data = answer.rdata(); + let data = if let Some(d) = answer.data() { + d + } else { + return Err(DnsClientError::NoRecordDataPresent); + }; let mut buf = Vec::new(); let mut decoder = BinEncoder::new(&mut buf); data.emit(&mut decoder).unwrap(); - buf + Ok(buf) }) + .collect::>, DnsClientError>>()? + .iter() .filter_map(|txt| { if txt.is_empty() { return None; @@ -185,13 +191,14 @@ where C: DnsHandle fn default_client_config() -> Arc { let mut root_store = RootCertStore::empty(); - root_store.add_server_trust_anchors(&roots::TLS_SERVER_ROOTS); - let versions = vec![ProtocolVersion::TLSv1_2]; - - let mut client_config = ClientConfig::new(); - client_config.root_store = root_store; - client_config.versions = versions; - client_config.alpn_protocols.push("h2".as_bytes().to_vec()); + root_store.add_server_trust_anchors(roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { + rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(ta.subject, ta.spki, ta.name_constraints) + })); + + let client_config = ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(root_store) + .with_no_client_auth(); Arc::new(client_config) } diff --git a/base_layer/p2p/src/dns/error.rs b/base_layer/p2p/src/dns/error.rs index c49a8d81c4..4e8ebb4c45 100644 --- a/base_layer/p2p/src/dns/error.rs +++ b/base_layer/p2p/src/dns/error.rs @@ -32,4 +32,6 @@ pub enum DnsClientError { Timeout, #[error("Failed to parse name server string")] NameServerParseFailed, + #[error("No record data present")] + NoRecordDataPresent, } diff --git a/base_layer/p2p/src/peer_seeds.rs b/base_layer/p2p/src/peer_seeds.rs index 8e628a9872..3d2652b02e 100644 --- a/base_layer/p2p/src/peer_seeds.rs +++ b/base_layer/p2p/src/peer_seeds.rs @@ -218,9 +218,9 @@ mod test { let mut record = Record::new(); record .set_record_type(RecordType::TXT) - .set_rdata(RData::TXT(rdata::TXT::new( + .set_data(Some(RData::TXT(rdata::TXT::new( contents.into_iter().map(ToString::to_string).collect(), - ))); + )))); mock::message(resp_query, vec![record], vec![], vec![]).into() } diff --git a/base_layer/p2p/src/services/liveness/config.rs b/base_layer/p2p/src/services/liveness/config.rs index 3a53a8f354..87d6dda341 100644 --- a/base_layer/p2p/src/services/liveness/config.rs +++ b/base_layer/p2p/src/services/liveness/config.rs @@ -29,10 +29,6 @@ use tari_comms::peer_manager::NodeId; pub struct LivenessConfig { /// The interval to send Ping messages, or None to disable periodic pinging (default: None (disabled)) pub auto_ping_interval: Option, - /// The length of time between querying peer manager for closest neighbours. (default: 2 minutes) - pub refresh_neighbours_interval: Duration, - /// The length of time between querying peer manager for random neighbours. (default: 2 hours) - pub refresh_random_pool_interval: Duration, /// Number of peers to ping per round, excluding monitored peers (Default: 8) pub num_peers_per_round: usize, /// Peers to include in every auto ping round (Default: ) @@ -45,8 +41,6 @@ impl Default for LivenessConfig { fn default() -> Self { Self { auto_ping_interval: None, - refresh_neighbours_interval: Duration::from_secs(2 * 60), - refresh_random_pool_interval: Duration::from_secs(2 * 60 * 60), num_peers_per_round: 8, monitored_peers: Default::default(), max_allowed_ping_failures: 2, diff --git a/base_layer/service_framework/Cargo.toml b/base_layer/service_framework/Cargo.toml index 1380a58851..361d7ad4ae 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.27.3" +version = "0.28.0" authors = ["The Tari Development Community"] description = "The Tari communication stack service framework" repository = "https://github.com/tari-project/tari" @@ -10,7 +10,7 @@ license = "BSD-3-Clause" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tari_shutdown = { version = "^0.27", path = "../../infrastructure/shutdown" } +tari_shutdown = { version = "^0.28", path = "../../infrastructure/shutdown" } anyhow = "1.0.53" async-trait = "0.1.50" @@ -21,7 +21,7 @@ tokio = { version = "1.14", features = ["rt"] } tower-service = { version = "0.3" } [dev-dependencies] -tari_test_utils = { version = "^0.27", path = "../../infrastructure/test_utils" } +tari_test_utils = { version = "^0.28", path = "../../infrastructure/test_utils" } tokio = { version = "1.14", features = ["rt-multi-thread", "macros", "time"] } futures-test = { version = "0.3.3" } diff --git a/base_layer/tari_stratum_ffi/Cargo.toml b/base_layer/tari_stratum_ffi/Cargo.toml index 80b39fe5ad..b16a8603e3 100644 --- a/base_layer/tari_stratum_ffi/Cargo.toml +++ b/base_layer/tari_stratum_ffi/Cargo.toml @@ -3,11 +3,11 @@ name = "tari_stratum_ffi" authors = ["The Tari Development Community"] description = "Tari cryptocurrency miningcore C FFI bindings" license = "BSD-3-Clause" -version = "0.27.3" +version = "0.28.0" edition = "2018" [dependencies] -tari_comms = { version = "^0.27", path = "../../comms" } +tari_comms = { version = "^0.28", path = "../../comms" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } tari_common = { path = "../../common" } tari_core = { path = "../../base_layer/core", default-features = false, features = ["transactions"]} diff --git a/base_layer/wallet/Cargo.toml b/base_layer/wallet/Cargo.toml index 97d46b3d4b..5af0d488bc 100644 --- a/base_layer/wallet/Cargo.toml +++ b/base_layer/wallet/Cargo.toml @@ -3,20 +3,20 @@ name = "tari_wallet" authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet library" license = "BSD-3-Clause" -version = "0.27.3" +version = "0.28.0" edition = "2018" [dependencies] tari_common = { path = "../../common" } -tari_common_types = { version = "^0.27", path = "../../base_layer/common_types" } -tari_comms = { version = "^0.27", path = "../../comms" } -tari_comms_dht = { version = "^0.27", path = "../../comms/dht" } +tari_common_types = { version = "^0.28", path = "../../base_layer/common_types" } +tari_comms = { version = "^0.28", path = "../../comms" } +tari_comms_dht = { version = "^0.28", path = "../../comms/dht" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } -tari_key_manager = { version = "^0.27", path = "../key_manager" } -tari_p2p = { version = "^0.27", path = "../p2p", features = ["auto-update"] } -tari_service_framework = { version = "^0.27", path = "../service_framework" } -tari_shutdown = { version = "^0.27", path = "../../infrastructure/shutdown" } -tari_storage = { version = "^0.27", path = "../../infrastructure/storage" } +tari_key_manager = { version = "^0.28", path = "../key_manager" } +tari_p2p = { version = "^0.28", path = "../p2p", features = ["auto-update"] } +tari_service_framework = { version = "^0.28", path = "../service_framework" } +tari_shutdown = { version = "^0.28", path = "../../infrastructure/shutdown" } +tari_storage = { version = "^0.28", path = "../../infrastructure/storage" } tari_common_sqlite = { path = "../../common_sqlite" } tari_utilities = "0.3.0" @@ -50,14 +50,14 @@ tower = "0.4" [dependencies.tari_core] path = "../../base_layer/core" -version = "^0.27" +version = "^0.28" default-features = false features = ["transactions", "mempool_proto", "base_node_proto", ] [dev-dependencies] -tari_p2p = { version = "^0.27", path = "../p2p", features = ["test-mocks"] } -tari_comms_dht = { version = "^0.27", path = "../../comms/dht", features = ["test-mocks"] } -tari_test_utils = { version = "^0.27", path = "../../infrastructure/test_utils" } +tari_p2p = { version = "^0.28", path = "../p2p", features = ["test-mocks"] } +tari_comms_dht = { version = "^0.28", path = "../../comms/dht", features = ["test-mocks"] } +tari_test_utils = { version = "^0.28", path = "../../infrastructure/test_utils" } env_logger = "0.7.1" prost = "0.9.0" diff --git a/base_layer/wallet/migrations/2022-02-14-104456_cancellation_column_update/down.sql b/base_layer/wallet/migrations/2022-02-14-104456_cancellation_column_update/down.sql new file mode 100644 index 0000000000..291a97c5ce --- /dev/null +++ b/base_layer/wallet/migrations/2022-02-14-104456_cancellation_column_update/down.sql @@ -0,0 +1 @@ +-- This file should undo anything in `up.sql` \ No newline at end of file diff --git a/base_layer/wallet/migrations/2022-02-14-104456_cancellation_column_update/up.sql b/base_layer/wallet/migrations/2022-02-14-104456_cancellation_column_update/up.sql new file mode 100644 index 0000000000..e25d452b02 --- /dev/null +++ b/base_layer/wallet/migrations/2022-02-14-104456_cancellation_column_update/up.sql @@ -0,0 +1,60 @@ +PRAGMA foreign_keys=OFF; + +ALTER TABLE completed_transactions + RENAME TO completed_transactions_old; + +CREATE TABLE completed_transactions +( + tx_id BIGINT NOT NULL PRIMARY KEY, + source_public_key BLOB NOT NULL, + destination_public_key BLOB NOT NULL, + amount BIGINT NOT NULL, + fee BIGINT NOT NULL, + transaction_protocol TEXT NOT NULL, + status INTEGER NOT NULL, + message TEXT NOT NULL, + timestamp DATETIME NOT NULL, + cancelled INTEGER NULL, + direction INTEGER, + coinbase_block_height BIGINT, + send_count INTEGER default 0 NOT NULL, + last_send_timestamp DATETIME, + confirmations BIGINT default NULL, + mined_height BIGINT, + mined_in_block BLOB, + transaction_signature_nonce BLOB default 0 NOT NULL, + transaction_signature_key BLOB default 0 NOT NULL +); + +INSERT INTO completed_transactions (tx_id, source_public_key, destination_public_key, amount, fee, transaction_protocol, + status, message, timestamp, cancelled, direction, coinbase_block_height, send_count, + last_send_timestamp, confirmations, mined_height, mined_in_block, transaction_signature_nonce, + transaction_signature_key) +SELECT tx_id, + source_public_key, + destination_public_key, + amount, + fee, + transaction_protocol, + status, + message, + timestamp, + CASE completed_transactions_old.valid --This flag was only ever used to signify an abandoned coinbase, we will do that in the cancelled reason enum now + WHEN 0 + THEN 7 -- This is the value for AbandonedCoinbase + ELSE + NULLIF(cancelled, 0) + END, + direction, + coinbase_block_height, + send_count, + last_send_timestamp, + confirmations, + mined_height, + mined_in_block, + transaction_signature_nonce, + transaction_signature_key +FROM completed_transactions_old; + +DROP TABLE completed_transactions_old; +PRAGMA foreign_keys=ON; \ No newline at end of file diff --git a/base_layer/wallet/src/assets/asset_manager.rs b/base_layer/wallet/src/assets/asset_manager.rs index 711d15b6b6..57b5910e19 100644 --- a/base_layer/wallet/src/assets/asset_manager.rs +++ b/base_layer/wallet/src/assets/asset_manager.rs @@ -25,7 +25,7 @@ use tari_common_types::{ transaction::TxId, types::{Commitment, FixedHash, PublicKey}, }; -use tari_core::transactions::transaction::{OutputFeatures, OutputFlags, TemplateParameter, Transaction}; +use tari_core::transactions::transaction_components::{OutputFeatures, OutputFlags, TemplateParameter, Transaction}; use crate::{ assets::Asset, diff --git a/base_layer/wallet/src/assets/asset_manager_handle.rs b/base_layer/wallet/src/assets/asset_manager_handle.rs index 904a97b980..c59cbac178 100644 --- a/base_layer/wallet/src/assets/asset_manager_handle.rs +++ b/base_layer/wallet/src/assets/asset_manager_handle.rs @@ -24,7 +24,7 @@ use tari_common_types::{ transaction::TxId, types::{Commitment, FixedHash, PublicKey}, }; -use tari_core::transactions::transaction::{OutputFeatures, TemplateParameter, Transaction}; +use tari_core::transactions::transaction_components::{OutputFeatures, TemplateParameter, Transaction}; use tari_service_framework::{reply_channel::SenderService, Service}; use crate::{ diff --git a/base_layer/wallet/src/assets/infrastructure/mod.rs b/base_layer/wallet/src/assets/infrastructure/mod.rs index be43bfeab0..1ef017db39 100644 --- a/base_layer/wallet/src/assets/infrastructure/mod.rs +++ b/base_layer/wallet/src/assets/infrastructure/mod.rs @@ -26,7 +26,7 @@ use tari_common_types::{ transaction::TxId, types::{Commitment, FixedHash, PublicKey}, }; -use tari_core::transactions::transaction::{OutputFeatures, TemplateParameter, Transaction}; +use tari_core::transactions::transaction_components::{OutputFeatures, TemplateParameter, Transaction}; use crate::assets::Asset; diff --git a/base_layer/wallet/src/base_node_service/mock_base_node_service.rs b/base_layer/wallet/src/base_node_service/mock_base_node_service.rs index 18eda7a77c..db8f9ae57a 100644 --- a/base_layer/wallet/src/base_node_service/mock_base_node_service.rs +++ b/base_layer/wallet/src/base_node_service/mock_base_node_service.rs @@ -32,7 +32,7 @@ use crate::base_node_service::{ service::BaseNodeState, }; -/// TODO Move this into the test support utilities when we remove the Test Harness feature from this crate +/// TODO Move this into the test support utilities when we remove the Test Harness feature from this crate #LOGGED pub struct MockBaseNodeService { request_stream: Option>>, pub base_node_peer: Option, diff --git a/base_layer/wallet/src/connectivity_service/service.rs b/base_layer/wallet/src/connectivity_service/service.rs index df57075270..4122f9acea 100644 --- a/base_layer/wallet/src/connectivity_service/service.rs +++ b/base_layer/wallet/src/connectivity_service/service.rs @@ -24,7 +24,7 @@ use std::{mem, time::Duration}; use log::*; use tari_comms::{ - connectivity::ConnectivityRequester, + connectivity::{ConnectivityError, ConnectivityRequester}, peer_manager::{NodeId, Peer}, protocol::rpc::{RpcClientLease, RpcClientPool}, PeerConnection, @@ -116,12 +116,21 @@ impl WalletConnectivityService { } async fn check_connection(&mut self) { - if let Some(pool) = self.pools.as_ref() { - if !pool.base_node_wallet_rpc_client.is_connected().await { - debug!(target: LOG_TARGET, "Peer connection lost. Attempting to reconnect..."); + debug!(target: LOG_TARGET, "HERE1"); + match self.pools.as_ref() { + Some(pool) => { + debug!(target: LOG_TARGET, "HERE2"); + if !pool.base_node_wallet_rpc_client.is_connected().await { + debug!(target: LOG_TARGET, "Peer connection lost. Attempting to reconnect..."); + self.set_online_status(OnlineStatus::Offline); + self.setup_base_node_connection().await; + } + }, + None => { + debug!(target: LOG_TARGET, "No connection. Attempting to connect..."); self.set_online_status(OnlineStatus::Offline); self.setup_base_node_connection().await; - } + }, } } @@ -216,10 +225,12 @@ impl WalletConnectivityService { } async fn disconnect_base_node(&mut self, node_id: NodeId) { - if let Ok(Some(connection)) = self.connectivity.get_connection(node_id.clone()).await { - if connection.clone().disconnect().await.is_ok() { - debug!(target: LOG_TARGET, "Disconnected base node peer {}", node_id); + if let Ok(Some(mut connection)) = self.connectivity.get_connection(node_id.clone()).await { + match connection.disconnect().await { + Ok(_) => debug!(target: LOG_TARGET, "Disconnected base node peer {}", node_id), + Err(e) => error!(target: LOG_TARGET, "Failed to disconnect base node: {}", e), } + self.pools = None; }; } @@ -248,20 +259,29 @@ impl WalletConnectivityService { break; }, Ok(false) => { - // Retry with updated peer - self.disconnect_base_node(node_id).await; + debug!( + target: LOG_TARGET, + "The peer has changed while connecting. Attempting to connect to new base node." + ); + continue; + }, + Err(WalletConnectivityError::ConnectivityError(ConnectivityError::DialCancelled)) => { + debug!( + target: LOG_TARGET, + "Dial was cancelled. Retrying after {}s ...", + self.config.base_node_monitor_refresh_interval.as_secs() + ); + self.set_online_status(OnlineStatus::Offline); time::sleep(self.config.base_node_monitor_refresh_interval).await; continue; }, Err(e) => { - if self.current_base_node() != Some(node_id.clone()) { - self.set_online_status(OnlineStatus::Connecting); - } else { + warn!(target: LOG_TARGET, "{}", e); + if self.current_base_node().as_ref() == Some(&node_id) { + self.disconnect_base_node(node_id).await; self.set_online_status(OnlineStatus::Offline); + time::sleep(self.config.base_node_monitor_refresh_interval).await; } - warn!(target: LOG_TARGET, "{}", e); - self.disconnect_base_node(node_id).await; - time::sleep(self.config.base_node_monitor_refresh_interval).await; continue; }, } diff --git a/base_layer/wallet/src/error.rs b/base_layer/wallet/src/error.rs index 4145d8a08e..fa89fabb71 100644 --- a/base_layer/wallet/src/error.rs +++ b/base_layer/wallet/src/error.rs @@ -23,7 +23,7 @@ use diesel::result::Error as DieselError; use log::SetLoggerError; use serde_json::Error as SerdeJsonError; -use tari_common::exit_codes::ExitCodes; +use tari_common::exit_codes::{ExitCode, ExitError}; use tari_common_sqlite::error::SqliteStorageError; use tari_comms::{ connectivity::ConnectivityError, @@ -31,7 +31,7 @@ use tari_comms::{ peer_manager::{node_id::NodeIdError, PeerManagerError}, }; use tari_comms_dht::store_forward::StoreAndForwardError; -use tari_core::transactions::transaction::TransactionError; +use tari_core::transactions::transaction_components::TransactionError; use tari_crypto::tari_utilities::{hex::HexError, ByteArrayError}; use tari_key_manager::error::KeyManagerError; use tari_p2p::{initialization::CommsInitializationError, services::liveness::error::LivenessError}; @@ -105,11 +105,10 @@ pub enum WalletError { pub const LOG_TARGET: &str = "tari::application"; -impl From for ExitCodes { +impl From for ExitError { fn from(err: WalletError) -> Self { - // TODO: Log that outside log::error!(target: LOG_TARGET, "{}", err); - Self::WalletError(err.to_string()) + Self::new(ExitCode::WalletError, err) } } @@ -175,13 +174,12 @@ pub enum WalletStorageError { RecoverySeedError(String), } -impl From for ExitCodes { +impl From for ExitError { fn from(err: WalletStorageError) -> Self { use WalletStorageError::*; match err { - NoPasswordError => ExitCodes::NoPassword, - InvalidPassphrase => ExitCodes::IncorrectPassword, - e => ExitCodes::WalletError(e.to_string()), + NoPasswordError | InvalidPassphrase => ExitCode::IncorrectOrEmptyPassword.into(), + e => ExitError::new(ExitCode::WalletError, e), } } } diff --git a/base_layer/wallet/src/output_manager_service/error.rs b/base_layer/wallet/src/output_manager_service/error.rs index 8c0390566b..3d88ca6ddb 100644 --- a/base_layer/wallet/src/output_manager_service/error.rs +++ b/base_layer/wallet/src/output_manager_service/error.rs @@ -21,11 +21,11 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use diesel::result::Error as DieselError; -use tari_common::exit_codes::ExitCodes; +use tari_common::exit_codes::{ExitCode, ExitError}; use tari_comms::{connectivity::ConnectivityError, peer_manager::node_id::NodeIdError, protocol::rpc::RpcError}; use tari_comms_dht::outbound::DhtOutboundError; use tari_core::transactions::{ - transaction::TransactionError, + transaction_components::TransactionError, transaction_protocol::TransactionProtocolError, CoinbaseBuildError, }; @@ -176,10 +176,10 @@ pub enum OutputManagerStorageError { KeyManagerError(#[from] KeyManagerError), } -impl From for ExitCodes { +impl From for ExitError { fn from(err: OutputManagerError) -> Self { log::error!(target: crate::error::LOG_TARGET, "{}", err); - Self::WalletError(err.to_string()) + Self::new(ExitCode::WalletError, err) } } diff --git a/base_layer/wallet/src/output_manager_service/handle.rs b/base_layer/wallet/src/output_manager_service/handle.rs index 315c931a6a..856e6d7b8d 100644 --- a/base_layer/wallet/src/output_manager_service/handle.rs +++ b/base_layer/wallet/src/output_manager_service/handle.rs @@ -25,13 +25,19 @@ use std::{fmt, fmt::Formatter, sync::Arc}; use aes_gcm::Aes256Gcm; use tari_common_types::{ transaction::TxId, - types::{HashOutput, PublicKey}, + types::{BlockHash, HashOutput, PublicKey}, }; use tari_core::{ covenants::Covenant, transactions::{ tari_amount::MicroTari, - transaction::{OutputFeatures, Transaction, TransactionOutput, UnblindedOutput, UnblindedOutputBuilder}, + transaction_components::{ + OutputFeatures, + Transaction, + TransactionOutput, + UnblindedOutput, + UnblindedOutputBuilder, + }, transaction_protocol::{sender::TransactionSenderMessage, RewindData}, ReceiverTransactionProtocol, SenderTransactionProtocol, @@ -106,8 +112,14 @@ pub enum OutputManagerRequest { num_kernels: usize, num_outputs: usize, }, - ScanForRecoverableOutputs(Vec), - ScanOutputs(Vec), + ScanForRecoverableOutputs { + outputs: Vec, + tx_id: TxId, + }, + ScanOutputs { + outputs: Vec, + tx_id: TxId, + }, AddKnownOneSidedPaymentScript(KnownOneSidedPaymentScript), CreateOutputWithFeatures { value: MicroTari, @@ -165,8 +177,8 @@ impl fmt::Display for OutputManagerRequest { "FeeEstimate(amount: {}, fee_per_gram: {}, num_kernels: {}, num_outputs: {})", amount, fee_per_gram, num_kernels, num_outputs ), - ScanForRecoverableOutputs(_) => write!(f, "ScanForRecoverableOutputs"), - ScanOutputs(_) => write!(f, "ScanOutputs"), + ScanForRecoverableOutputs { .. } => write!(f, "ScanForRecoverableOutputs"), + ScanOutputs { .. } => write!(f, "ScanOutputs"), AddKnownOneSidedPaymentScript(_) => write!(f, "AddKnownOneSidedPaymentScript"), CreateOutputWithFeatures { value, features } => { write!(f, "CreateOutputWithFeatures({}, {})", value, features,) @@ -220,12 +232,21 @@ pub enum OutputManagerResponse { RewoundOutputs(Vec), ScanOutputs(Vec), AddKnownOneSidedPaymentScript, - CreateOutputWithFeatures { output: Box }, - CreatePayToSelfWithOutputs { transaction: Box, tx_id: TxId }, + CreateOutputWithFeatures { + output: Box, + }, + CreatePayToSelfWithOutputs { + transaction: Box, + tx_id: TxId, + }, ReinstatedCancelledInboundTx, CoinbaseAbandonedSet, ClaimHtlcTransaction((TxId, MicroTari, MicroTari, Transaction)), - OutputStatusesByTxId(Vec), + OutputStatusesByTxId { + statuses: Vec, + mined_height: Option, + block_hash: Option, + }, } pub type OutputManagerEventSender = broadcast::Sender>; @@ -642,10 +663,11 @@ impl OutputManagerHandle { pub async fn scan_for_recoverable_outputs( &mut self, outputs: Vec, + tx_id: TxId, ) -> Result, OutputManagerError> { match self .handle - .call(OutputManagerRequest::ScanForRecoverableOutputs(outputs)) + .call(OutputManagerRequest::ScanForRecoverableOutputs { outputs, tx_id }) .await?? { OutputManagerResponse::RewoundOutputs(outputs) => Ok(outputs), @@ -656,8 +678,13 @@ impl OutputManagerHandle { pub async fn scan_outputs_for_one_sided_payments( &mut self, outputs: Vec, + tx_id: TxId, ) -> Result, OutputManagerError> { - match self.handle.call(OutputManagerRequest::ScanOutputs(outputs)).await?? { + match self + .handle + .call(OutputManagerRequest::ScanOutputs { outputs, tx_id }) + .await?? + { OutputManagerResponse::ScanOutputs(outputs) => Ok(outputs), _ => Err(OutputManagerError::UnexpectedApiResponse), } @@ -749,13 +776,20 @@ impl OutputManagerHandle { } } - pub async fn get_output_statuses_by_tx_id(&mut self, tx_id: TxId) -> Result, OutputManagerError> { + pub async fn get_output_statuses_by_tx_id( + &mut self, + tx_id: TxId, + ) -> Result<(Vec, Option, Option), OutputManagerError> { match self .handle .call(OutputManagerRequest::GetOutputStatusesByTxId(tx_id)) .await?? { - OutputManagerResponse::OutputStatusesByTxId(s) => Ok(s), + OutputManagerResponse::OutputStatusesByTxId { + statuses, + mined_height, + block_hash, + } => Ok((statuses, mined_height, block_hash)), _ => Err(OutputManagerError::UnexpectedApiResponse), } } diff --git a/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs b/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs index d6f4200e0c..e112fff806 100644 --- a/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs +++ b/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs @@ -24,14 +24,18 @@ use std::{sync::Arc, time::Instant}; use log::*; use rand::rngs::OsRng; -use tari_common_types::types::{PrivateKey, PublicKey, RangeProof}; +use tari_common_types::{ + transaction::TxId, + types::{PrivateKey, PublicKey, RangeProof}, +}; use tari_core::transactions::{ - transaction::{TransactionOutput, UnblindedOutput}, + transaction_components::{TransactionOutput, UnblindedOutput}, CryptoFactories, }; use tari_crypto::{ inputs, keys::{PublicKey as PublicKeyTrait, SecretKey}, + script, tari_utilities::hex::Hex, }; @@ -73,6 +77,7 @@ where TBackend: OutputManagerBackend + 'static pub async fn scan_and_recover_outputs( &mut self, outputs: Vec, + tx_id: TxId, ) -> Result, OutputManagerError> { let start = Instant::now(); let outputs_length = outputs.len(); @@ -86,17 +91,15 @@ where TBackend: OutputManagerBackend + 'static &self.master_key_manager.rewind_data().rewind_blinding_key, ) .ok() - .map(|v| ( v, output ) ) + .map(|v| (v, output)) }) - //TODO: This needs some investigation. We assume Nop script here and recovery here might create an - //TODO: unspendable output if the script does not equal Nop. - .map( - |(rewind_result, output)| { - // Todo we need to look here that we might want to fail a specific output and not recover it as this - // will only work if the script is a Nop script. If this is not a Nop script the recovered input - // will not be spendable. - let script_key = PrivateKey::random(&mut OsRng); - (UnblindedOutput::new( + .filter_map(|(rewind_result, output)| { + if output.script != script!(Nop) { + return None; + } + let script_key = PrivateKey::random(&mut OsRng); + Some(( + UnblindedOutput::new( output.version, rewind_result.committed_value, rewind_result.blinding_factor, @@ -107,11 +110,11 @@ where TBackend: OutputManagerBackend + 'static output.sender_offset_public_key, output.metadata_signature, 0, - output.covenant + output.covenant, ), - output.proof) - }, - ) + output.proof, + )) + }) .collect(); let rewind_time = start.elapsed(); trace!( @@ -133,7 +136,7 @@ where TBackend: OutputManagerBackend + 'static Some(proof), )?; let output_hex = db_output.commitment.to_hex(); - if let Err(e) = self.db.add_unspent_output(db_output).await { + if let Err(e) = self.db.add_unspent_output_with_tx_id(tx_id, db_output).await { match e { OutputManagerStorageError::DuplicateOutput => { info!( diff --git a/base_layer/wallet/src/output_manager_service/service.rs b/base_layer/wallet/src/output_manager_service/service.rs index 3dfb07ecc1..06d17e3974 100644 --- a/base_layer/wallet/src/output_manager_service/service.rs +++ b/base_layer/wallet/src/output_manager_service/service.rs @@ -29,7 +29,7 @@ use log::*; use rand::{rngs::OsRng, RngCore}; use tari_common_types::{ transaction::TxId, - types::{HashOutput, PrivateKey, PublicKey}, + types::{BlockHash, HashOutput, PrivateKey, PublicKey}, }; use tari_comms::{types::CommsPublicKey, NodeIdentity}; use tari_core::{ @@ -39,7 +39,7 @@ use tari_core::{ transactions::{ fee::Fee, tari_amount::MicroTari, - transaction::{ + transaction_components::{ KernelFeatures, OutputFeatures, Transaction, @@ -358,16 +358,16 @@ where OutputManagerRequest::GetPublicRewindKeys => Ok(OutputManagerResponse::PublicRewindKeys(Box::new( self.resources.master_key_manager.get_rewind_public_keys(), ))), - OutputManagerRequest::ScanForRecoverableOutputs(outputs) => StandardUtxoRecoverer::new( + OutputManagerRequest::ScanForRecoverableOutputs { outputs, tx_id } => StandardUtxoRecoverer::new( self.resources.master_key_manager.clone(), self.resources.factories.clone(), self.resources.db.clone(), ) - .scan_and_recover_outputs(outputs) + .scan_and_recover_outputs(outputs, tx_id) .await .map(OutputManagerResponse::RewoundOutputs), - OutputManagerRequest::ScanOutputs(outputs) => self - .scan_outputs_for_one_sided_payments(outputs) + OutputManagerRequest::ScanOutputs { outputs, tx_id } => self + .scan_outputs_for_one_sided_payments(outputs, tx_id) .await .map(OutputManagerResponse::ScanOutputs), OutputManagerRequest::AddKnownOneSidedPaymentScript(known_script) => self @@ -415,16 +415,36 @@ where .create_htlc_refund_transaction(output, fee_per_gram) .await .map(OutputManagerResponse::ClaimHtlcTransaction), - OutputManagerRequest::GetOutputStatusesByTxId(tx_id) => self - .get_output_status_by_tx_id(tx_id) - .await - .map(OutputManagerResponse::OutputStatusesByTxId), + OutputManagerRequest::GetOutputStatusesByTxId(tx_id) => { + let (statuses, mined_height, block_hash) = self.get_output_status_by_tx_id(tx_id).await?; + Ok(OutputManagerResponse::OutputStatusesByTxId { + statuses, + mined_height, + block_hash, + }) + }, } } - async fn get_output_status_by_tx_id(&self, tx_id: TxId) -> Result, OutputManagerError> { + async fn get_output_status_by_tx_id( + &self, + tx_id: TxId, + ) -> Result<(Vec, Option, Option), OutputManagerError> { let outputs = self.resources.db.fetch_outputs_by_tx_id(tx_id).await?; - Ok(outputs.into_iter().map(|uo| uo.status).collect()) + let statuses = outputs.clone().into_iter().map(|uo| uo.status).collect(); + // We need the maximum mined height and corresponding block hash (faux transactions outputs can have different + // mined heights) + let (mut last_height, mut max_mined_height, mut block_hash) = (0u64, None, None); + for uo in outputs { + if let Some(height) = uo.mined_height { + if last_height < height { + last_height = height; + max_mined_height = uo.mined_height; + block_hash = uo.mined_in_block.clone(); + } + } + } + Ok((statuses, max_mined_height, block_hash)) } async fn claim_sha_atomic_swap_with_hash( @@ -657,7 +677,7 @@ where spending_key.clone(), single_round_sender_data.features.clone(), single_round_sender_data.script.clone(), - // TODO: The input data should be variable; this will only work for a Nop script + // TODO: The input data should be variable; this will only work for a Nop script #LOGGED inputs!(PublicKey::from_secret_key(&script_private_key)), script_private_key, single_round_sender_data.sender_offset_public_key.clone(), @@ -791,7 +811,7 @@ where ) .await?; - // TODO: improve this logic + // TODO: improve this logic #LOGGED let output_features = match unique_id { Some(ref _unique_id) => match input_selection .utxos @@ -934,21 +954,22 @@ where )?; // Clear any existing pending coinbase transactions for this blockheight if they exist - if let Err(e) = self + match self .resources .db .clear_pending_coinbase_transaction_at_block_height(block_height) .await { - match e { - OutputManagerStorageError::DieselError(DieselError::NotFound) => { - debug!( - target: LOG_TARGET, - "An existing pending coinbase was cleared for block height {}", block_height - ) - }, + Ok(_) => { + debug!( + target: LOG_TARGET, + "An existing pending coinbase was cleared for block height {}", block_height + ) + }, + Err(e) => match e { + OutputManagerStorageError::DieselError(DieselError::NotFound) => {}, _ => return Err(OutputManagerError::from(e)), - } + }, }; // Clear any matching outputs for this commitment. Even if the older output is valid @@ -1893,6 +1914,7 @@ where async fn scan_outputs_for_one_sided_payments( &mut self, outputs: Vec, + tx_id: TxId, ) -> Result, OutputManagerError> { let known_one_sided_payment_scripts: Vec = self.resources.db.get_all_known_one_sided_payment_scripts().await?; @@ -1945,7 +1967,7 @@ where )?; let output_hex = output.commitment.to_hex(); - match self.resources.db.add_unspent_output(db_output).await { + match self.resources.db.add_unspent_output_with_tx_id(tx_id, db_output).await { Ok(_) => { rewound_outputs.push(rewound_output); }, @@ -1978,7 +2000,6 @@ where } /// Different UTXO selection strategies for choosing which UTXO's are used to fulfill a transaction -/// TODO Investigate and implement more optimal strategies #[derive(Debug, PartialEq)] pub enum UTXOSelectionStrategy { // Start from the smallest UTXOs and work your way up until the amount is covered. Main benefit diff --git a/base_layer/wallet/src/output_manager_service/storage/database/backend.rs b/base_layer/wallet/src/output_manager_service/storage/database/backend.rs index 5941773396..59539aa8dd 100644 --- a/base_layer/wallet/src/output_manager_service/storage/database/backend.rs +++ b/base_layer/wallet/src/output_manager_service/storage/database/backend.rs @@ -3,7 +3,7 @@ use tari_common_types::{ transaction::TxId, types::{Commitment, PublicKey}, }; -use tari_core::transactions::transaction::{OutputFlags, TransactionOutput}; +use tari_core::transactions::transaction_components::{OutputFlags, TransactionOutput}; use crate::output_manager_service::{ error::OutputManagerStorageError, diff --git a/base_layer/wallet/src/output_manager_service/storage/database/mod.rs b/base_layer/wallet/src/output_manager_service/storage/database/mod.rs index 6f06e10460..da14e6e2a3 100644 --- a/base_layer/wallet/src/output_manager_service/storage/database/mod.rs +++ b/base_layer/wallet/src/output_manager_service/storage/database/mod.rs @@ -35,7 +35,7 @@ use tari_common_types::{ }; use tari_core::transactions::{ tari_amount::MicroTari, - transaction::{OutputFlags, TransactionOutput}, + transaction_components::{OutputFlags, TransactionOutput}, }; use tari_crypto::tari_utilities::hex::Hex; use tari_key_manager::cipher_seed::CipherSeed; diff --git a/base_layer/wallet/src/output_manager_service/storage/models.rs b/base_layer/wallet/src/output_manager_service/storage/models.rs index a013e9aa51..b36b04b4d0 100644 --- a/base_layer/wallet/src/output_manager_service/storage/models.rs +++ b/base_layer/wallet/src/output_manager_service/storage/models.rs @@ -23,7 +23,11 @@ use std::cmp::Ordering; use tari_common_types::types::{BlockHash, Commitment, HashOutput, PrivateKey, RangeProof}; -use tari_core::transactions::{transaction::UnblindedOutput, transaction_protocol::RewindData, CryptoFactories}; +use tari_core::transactions::{ + transaction_components::UnblindedOutput, + transaction_protocol::RewindData, + CryptoFactories, +}; use tari_crypto::script::{ExecutionStack, TariScript}; use tari_utilities::hash::Hashable; 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 17ea7d156a..99ddf1a350 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 @@ -36,7 +36,7 @@ use tari_common_types::{ transaction::TxId, types::{Commitment, PrivateKey, PublicKey}, }; -use tari_core::transactions::transaction::{OutputFlags, TransactionOutput}; +use tari_core::transactions::transaction_components::{OutputFlags, TransactionOutput}; use tari_crypto::{ script::{ExecutionStack, TariScript}, tari_utilities::{ @@ -271,7 +271,7 @@ impl OutputManagerBackend for OutputManagerSqliteDatabase { // TODO: This is a problem because the keymanager state does not have an index // meaning that update round trips to the database can't be found again. // I would suggest changing this to a different pattern for retrieval, perhaps - // only returning the columns that are needed. + // only returning the columns that are needed. #LOGGED Some(DbValue::KeyManagerState(KeyManagerState::try_from(km)?)) }, } @@ -1675,7 +1675,7 @@ mod test { use tari_core::transactions::{ tari_amount::MicroTari, test_helpers::{create_unblinded_output, TestParams as TestParamsHelpers}, - transaction::{OutputFeatures, TransactionInput, UnblindedOutput}, + transaction_components::{OutputFeatures, TransactionInput, UnblindedOutput}, CryptoFactories, }; use tari_crypto::script; @@ -1749,16 +1749,36 @@ mod test { o.commit(&conn).unwrap(); } - // #todo: fix tests - // assert_eq!(OutputSql::index(&conn).unwrap(), outputs); - // assert_eq!( - // OutputSql::index_status(OutputStatus::Unspent, &conn).unwrap(), - // outputs_unspent - // ); - // assert_eq!( - // OutputSql::index_status(OutputStatus::Spent, &conn).unwrap(), - // outputs_spent - // ); + assert_eq!( + OutputSql::index(&conn) + .unwrap() + .iter() + .map(|o| o.spending_key.clone()) + .collect::>>(), + outputs.iter().map(|o| o.spending_key.clone()).collect::>>() + ); + assert_eq!( + OutputSql::index_status(OutputStatus::Unspent, &conn) + .unwrap() + .iter() + .map(|o| o.spending_key.clone()) + .collect::>>(), + outputs_unspent + .iter() + .map(|o| o.spending_key.clone()) + .collect::>>() + ); + assert_eq!( + OutputSql::index_status(OutputStatus::Spent, &conn) + .unwrap() + .iter() + .map(|o| o.spending_key.clone()) + .collect::>>(), + outputs_spent + .iter() + .map(|o| o.spending_key.clone()) + .collect::>>() + ); assert_eq!( OutputSql::find(&outputs[0].spending_key, &conn).unwrap().spending_key, diff --git a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs index c33f29faa3..61e18b4231 100644 --- a/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs +++ b/base_layer/wallet/src/output_manager_service/storage/sqlite_db/output_sql.rs @@ -33,7 +33,7 @@ use tari_core::{ covenants::Covenant, transactions::{ tari_amount::MicroTari, - transaction::{OutputFeatures, OutputFlags, UnblindedOutput}, + transaction_components::{OutputFeatures, OutputFlags, UnblindedOutput}, CryptoFactories, }, }; @@ -451,7 +451,6 @@ impl OutputSql { Ok(()) } - // TODO: This method needs to be checked for concurrency pub fn update( &self, updated_output: UpdateOutput, diff --git a/base_layer/wallet/src/output_manager_service/tasks/txo_validation_task.rs b/base_layer/wallet/src/output_manager_service/tasks/txo_validation_task.rs index a30420fdef..40f0222df0 100644 --- a/base_layer/wallet/src/output_manager_service/tasks/txo_validation_task.rs +++ b/base_layer/wallet/src/output_manager_service/tasks/txo_validation_task.rs @@ -356,8 +356,6 @@ where Ok(last_mined_header_hash) } - // TODO: remove this duplicated code from transaction validation protocol - async fn get_base_node_block_at_height( &mut self, height: u64, diff --git a/base_layer/wallet/src/schema.rs b/base_layer/wallet/src/schema.rs index a93c6288e1..bc428e1516 100644 --- a/base_layer/wallet/src/schema.rs +++ b/base_layer/wallet/src/schema.rs @@ -16,12 +16,11 @@ table! { status -> Integer, message -> Text, timestamp -> Timestamp, - cancelled -> Integer, + cancelled -> Nullable, direction -> Nullable, coinbase_block_height -> Nullable, send_count -> Integer, last_send_timestamp -> Nullable, - valid -> Integer, confirmations -> Nullable, mined_height -> Nullable, mined_in_block -> Nullable, diff --git a/base_layer/wallet/src/storage/sqlite_utilities/mod.rs b/base_layer/wallet/src/storage/sqlite_utilities/mod.rs index 7d766f9097..a70cae5e03 100644 --- a/base_layer/wallet/src/storage/sqlite_utilities/mod.rs +++ b/base_layer/wallet/src/storage/sqlite_utilities/mod.rs @@ -26,7 +26,6 @@ use std::{ time::Duration, }; -use diesel::{ExpressionMethods, QueryDsl, SqliteConnection}; use fs2::FileExt; use log::*; use tari_common_sqlite::sqlite_connection_pool::SqliteConnectionPool; @@ -65,8 +64,6 @@ pub fn run_migration_and_create_sqlite_connection>( pool.create_pool()?; let connection = pool.get_pooled_connection()?; - check_for_incompatible_db_encryption(&connection)?; - embed_migrations!("./migrations"); embedded_migrations::run(&connection) .map_err(|err| WalletStorageError::DatabaseMigrationError(format!("Database migration failed {}", err)))?; @@ -162,24 +159,3 @@ pub fn initialize_sqlite_database_backends( contacts_backend, )) } - -/// This method detects if the database contains the old incompatable encryption data and errors rather than breaking -/// the DB -/// TODO remove at next testnet reset -fn check_for_incompatible_db_encryption(connection: &SqliteConnection) -> Result<(), WalletStorageError> { - use crate::{diesel::RunQueryDsl, schema::wallet_settings, storage::sqlite_db::wallet::WalletSettingSql}; - - if wallet_settings::table - .filter(wallet_settings::key.eq("MasterSecretKey".to_string())) - .first::(connection) - .is_ok() - { - return Err(WalletStorageError::AeadError( - "This wallet database is incompatible with the new form of encryption. Halting to preserve this database \ - structure. Revert to a version of tari_console_wallet prior to 0.13.0" - .to_string(), - )); - } - - Ok(()) -} diff --git a/base_layer/wallet/src/tokens/token_manager.rs b/base_layer/wallet/src/tokens/token_manager.rs index 949f00b218..217ca38a63 100644 --- a/base_layer/wallet/src/tokens/token_manager.rs +++ b/base_layer/wallet/src/tokens/token_manager.rs @@ -21,7 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use log::*; -use tari_core::transactions::transaction::OutputFlags; +use tari_core::transactions::transaction_components::OutputFlags; use crate::{ error::WalletError, diff --git a/base_layer/wallet/src/transaction_service/error.rs b/base_layer/wallet/src/transaction_service/error.rs index 406457b0b2..1351939a7a 100644 --- a/base_layer/wallet/src/transaction_service/error.rs +++ b/base_layer/wallet/src/transaction_service/error.rs @@ -26,7 +26,10 @@ use serde_json::Error as SerdeJsonError; use tari_common_types::transaction::{TransactionConversionError, TransactionDirectionError, TxId}; use tari_comms::{connectivity::ConnectivityError, peer_manager::node_id::NodeIdError, protocol::rpc::RpcError}; use tari_comms_dht::outbound::DhtOutboundError; -use tari_core::transactions::{transaction::TransactionError, transaction_protocol::TransactionProtocolError}; +use tari_core::transactions::{ + transaction_components::TransactionError, + transaction_protocol::TransactionProtocolError, +}; use tari_crypto::tari_utilities::ByteArrayError; use tari_p2p::services::liveness::error::LivenessError; use tari_service_framework::reply_channel::TransportChannelError; @@ -219,13 +222,15 @@ pub enum TransactionStorageError { TransactionNotMined(TxId), #[error("Conversion error: `{0}`")] ByteArrayError(#[from] ByteArrayError), + #[error("Not a coinbase transaction so cannot be abandoned")] + NotCoinbase, } /// This error type is used to return TransactionServiceErrors from inside a Transaction Service protocol but also /// include the ID of the protocol #[derive(Debug)] pub struct TransactionServiceProtocolError { - // TODO: Replace with T or something to account for OperationId or TxId + // TODO: Replace with T or something to account for OperationId or TxId #LOGGED pub id: u64, pub error: TransactionServiceError, } diff --git a/base_layer/wallet/src/transaction_service/handle.rs b/base_layer/wallet/src/transaction_service/handle.rs index 8a9fde45dd..ff7d774934 100644 --- a/base_layer/wallet/src/transaction_service/handle.rs +++ b/base_layer/wallet/src/transaction_service/handle.rs @@ -23,11 +23,14 @@ use std::{collections::HashMap, fmt, fmt::Formatter, sync::Arc}; use aes_gcm::Aes256Gcm; -use tari_common_types::{transaction::TxId, types::PublicKey}; +use tari_common_types::{ + transaction::{ImportStatus, TxId}, + types::PublicKey, +}; use tari_comms::types::CommsPublicKey; use tari_core::transactions::{ tari_amount::MicroTari, - transaction::{Transaction, TransactionOutput}, + transaction_components::{Transaction, TransactionOutput}, }; use tari_service_framework::reply_channel::SenderService; use tari_utilities::hex::Hex; @@ -37,8 +40,13 @@ use tower::Service; use crate::{ transaction_service::{ error::TransactionServiceError, - protocols::TxRejection, - storage::models::{CompletedTransaction, InboundTransaction, OutboundTransaction, WalletTransaction}, + storage::models::{ + CompletedTransaction, + InboundTransaction, + OutboundTransaction, + TxCancellationReason, + WalletTransaction, + }, }, OperationId, }; @@ -72,7 +80,15 @@ pub enum TransactionServiceRequest { }, SendShaAtomicSwapTransaction(CommsPublicKey, MicroTari, MicroTari, String), CancelTransaction(TxId), - ImportUtxo(MicroTari, CommsPublicKey, String, Option), + ImportUtxoWithStatus { + amount: MicroTari, + source_public_key: CommsPublicKey, + message: String, + maturity: Option, + import_status: ImportStatus, + tx_id: Option, + current_height: Option, + }, SubmitTransactionToSelf(TxId, Transaction, MicroTari, MicroTari, String), SetLowPowerMode, SetNormalPowerMode, @@ -123,12 +139,23 @@ impl fmt::Display for TransactionServiceRequest { f.write_str(&format!("SendShaAtomicSwapTransaction (to {}, {}, {})", k, v, msg)) }, Self::CancelTransaction(t) => f.write_str(&format!("CancelTransaction ({})", t)), - Self::ImportUtxo(v, k, msg, maturity) => f.write_str(&format!( - "ImportUtxo (from {}, {}, {} with maturity: {})", - k, - v, - msg, - maturity.unwrap_or(0) + Self::ImportUtxoWithStatus { + amount, + source_public_key, + message, + maturity, + import_status, + tx_id, + current_height, + } => f.write_str(&format!( + "ImportUtxo (from {}, {}, {} with maturity {} and {:?} and {:?} and {:?})", + source_public_key, + amount, + message, + maturity.unwrap_or(0), + import_status, + tx_id, + current_height, )), Self::SubmitTransactionToSelf(tx_id, _, _, _, _) => f.write_str(&format!("SubmitTransaction ({})", tx_id)), Self::SetLowPowerMode => f.write_str("SetLowPowerMode "), @@ -186,15 +213,23 @@ pub enum TransactionEvent { TransactionDirectSendResult(TxId, bool), TransactionCompletedImmediately(TxId), TransactionStoreForwardSendResult(TxId, bool), - TransactionCancelled(TxId, TxRejection), + TransactionCancelled(TxId, TxCancellationReason), TransactionBroadcast(TxId), TransactionImported(TxId), + FauxTransactionUnconfirmed { + tx_id: TxId, + num_confirmations: u64, + is_valid: bool, + }, + FauxTransactionConfirmed { + tx_id: TxId, + is_valid: bool, + }, TransactionMined { tx_id: TxId, is_valid: bool, }, TransactionMinedRequestTimedOut(TxId), - // TODO: Split into normal transaction mined and coinbase transaction mined TransactionMinedUnconfirmed { tx_id: TxId, num_confirmations: u64, @@ -242,6 +277,20 @@ impl fmt::Display for TransactionEvent { TransactionEvent::TransactionImported(tx) => { write!(f, "TransactionImported for {}", tx) }, + TransactionEvent::FauxTransactionUnconfirmed { + tx_id, + num_confirmations, + is_valid, + } => { + write!( + f, + "FauxTransactionUnconfirmed for {} with num confirmations: {}. is_valid: {}", + tx_id, num_confirmations, is_valid + ) + }, + TransactionEvent::FauxTransactionConfirmed { tx_id, is_valid } => { + write!(f, "FauxTransactionConfirmed for {}. is_valid: {}", tx_id, is_valid) + }, TransactionEvent::TransactionMined { tx_id, is_valid } => { write!(f, "TransactionMined for {}. is_valid: {}", tx_id, is_valid) }, @@ -517,21 +566,27 @@ impl TransactionServiceHandle { } } - pub async fn import_utxo( + pub async fn import_utxo_with_status( &mut self, amount: MicroTari, source_public_key: CommsPublicKey, message: String, maturity: Option, + import_status: ImportStatus, + tx_id: Option, + current_height: Option, ) -> Result { match self .handle - .call(TransactionServiceRequest::ImportUtxo( + .call(TransactionServiceRequest::ImportUtxoWithStatus { amount, source_public_key, message, maturity, - )) + import_status, + tx_id, + current_height, + }) .await?? { TransactionServiceResponse::UtxoImported(tx_id) => Ok(tx_id), diff --git a/base_layer/wallet/src/transaction_service/protocols/mod.rs b/base_layer/wallet/src/transaction_service/protocols/mod.rs index 664aab6146..15bdb1dd1c 100644 --- a/base_layer/wallet/src/transaction_service/protocols/mod.rs +++ b/base_layer/wallet/src/transaction_service/protocols/mod.rs @@ -20,17 +20,6 @@ // 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. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum TxRejection { - Unknown, // 0 - UserCancelled, // 1 - Timeout, // 2 - DoubleSpend, // 3 - Orphan, // 4 - TimeLocked, // 5 - InvalidTransaction, // 6 -} - pub mod transaction_broadcast_protocol; pub mod transaction_receive_protocol; pub mod transaction_send_protocol; diff --git a/base_layer/wallet/src/transaction_service/protocols/transaction_broadcast_protocol.rs b/base_layer/wallet/src/transaction_service/protocols/transaction_broadcast_protocol.rs index f90ab24cfd..967327b2a1 100644 --- a/base_layer/wallet/src/transaction_service/protocols/transaction_broadcast_protocol.rs +++ b/base_layer/wallet/src/transaction_service/protocols/transaction_broadcast_protocol.rs @@ -37,7 +37,7 @@ use tari_core::{ proto::wallet_rpc::{TxLocation, TxQueryResponse, TxSubmissionRejectionReason, TxSubmissionResponse}, rpc::BaseNodeWalletRpcClient, }, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, }; use tari_crypto::tari_utilities::hex::Hex; use tokio::{sync::watch, time::sleep}; @@ -47,9 +47,11 @@ use crate::{ transaction_service::{ error::{TransactionServiceError, TransactionServiceProtocolError}, handle::TransactionEvent, - protocols::TxRejection, service::TransactionServiceResources, - storage::{database::TransactionBackend, models::CompletedTransaction}, + storage::{ + database::TransactionBackend, + models::{CompletedTransaction, TxCancellationReason}, + }, }, }; @@ -218,33 +220,35 @@ where "Transaction (TxId: {}) rejected by Base Node for reason: {}", self.tx_id, response.rejection_reason ); - self.cancel_transaction().await; - - let reason = match response.rejection_reason { - TxSubmissionRejectionReason::None | TxSubmissionRejectionReason::ValidationFailed => { - TransactionServiceError::MempoolRejectionInvalidTransaction - }, - TxSubmissionRejectionReason::DoubleSpend => TransactionServiceError::MempoolRejectionDoubleSpend, - TxSubmissionRejectionReason::Orphan => TransactionServiceError::MempoolRejectionOrphan, - TxSubmissionRejectionReason::TimeLocked => TransactionServiceError::MempoolRejectionTimeLocked, - _ => TransactionServiceError::UnexpectedBaseNodeResponse, + let (reason_error, reason) = match response.rejection_reason { + TxSubmissionRejectionReason::None | TxSubmissionRejectionReason::ValidationFailed => ( + TransactionServiceError::MempoolRejectionInvalidTransaction, + TxCancellationReason::InvalidTransaction, + ), + TxSubmissionRejectionReason::DoubleSpend => ( + TransactionServiceError::MempoolRejectionDoubleSpend, + TxCancellationReason::DoubleSpend, + ), + TxSubmissionRejectionReason::Orphan => ( + TransactionServiceError::MempoolRejectionOrphan, + TxCancellationReason::Orphan, + ), + TxSubmissionRejectionReason::TimeLocked => ( + TransactionServiceError::MempoolRejectionTimeLocked, + TxCancellationReason::TimeLocked, + ), + _ => ( + TransactionServiceError::UnexpectedBaseNodeResponse, + TxCancellationReason::Unknown, + ), }; - let cancellation_event_reason = match reason { - TransactionServiceError::MempoolRejectionInvalidTransaction => TxRejection::InvalidTransaction, - TransactionServiceError::MempoolRejectionDoubleSpend => TxRejection::DoubleSpend, - TransactionServiceError::MempoolRejectionOrphan => TxRejection::Orphan, - TransactionServiceError::MempoolRejectionTimeLocked => TxRejection::TimeLocked, - _ => TxRejection::Unknown, - }; + self.cancel_transaction(reason).await; let _ = self .resources .event_publisher - .send(Arc::new(TransactionEvent::TransactionCancelled( - self.tx_id, - cancellation_event_reason, - ))) + .send(Arc::new(TransactionEvent::TransactionCancelled(self.tx_id, reason))) .map_err(|e| { trace!( target: LOG_TARGET, @@ -254,7 +258,7 @@ where e }); - return Err(TransactionServiceProtocolError::new(self.tx_id, reason)); + return Err(TransactionServiceProtocolError::new(self.tx_id, reason_error)); } else if response.rejection_reason == TxSubmissionRejectionReason::AlreadyMined { info!( target: LOG_TARGET, @@ -354,14 +358,14 @@ where cancelling transaction", self.tx_id ); - self.cancel_transaction().await; + self.cancel_transaction(TxCancellationReason::InvalidTransaction).await; let _ = self .resources .event_publisher .send(Arc::new(TransactionEvent::TransactionCancelled( self.tx_id, - TxRejection::InvalidTransaction, + TxCancellationReason::InvalidTransaction, ))) .map_err(|e| { trace!( @@ -413,7 +417,7 @@ where } } - async fn cancel_transaction(&mut self) { + async fn cancel_transaction(&mut self, reason: TxCancellationReason) { if let Err(e) = self .resources .output_manager_service @@ -425,7 +429,7 @@ where "Failed to Cancel outputs for TxId: {} after failed sending attempt with error {:?}", self.tx_id, e ); } - if let Err(e) = self.resources.db.reject_completed_transaction(self.tx_id).await { + if let Err(e) = self.resources.db.reject_completed_transaction(self.tx_id, reason).await { warn!( target: LOG_TARGET, "Failed to Cancel TxId: {} after failed sending attempt with error {:?}", self.tx_id, e diff --git a/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs b/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs index d32efc4900..c51020b37c 100644 --- a/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs +++ b/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs @@ -31,7 +31,7 @@ use tari_common_types::{ }; use tari_comms::types::CommsPublicKey; use tari_core::transactions::{ - transaction::Transaction, + transaction_components::Transaction, transaction_protocol::{recipient::RecipientState, sender::TransactionSenderMessage}, }; use tari_crypto::tari_utilities::Hashable; @@ -45,11 +45,10 @@ use crate::{ transaction_service::{ error::{TransactionServiceError, TransactionServiceProtocolError}, handle::TransactionEvent, - protocols::TxRejection, service::TransactionServiceResources, storage::{ database::TransactionBackend, - models::{CompletedTransaction, InboundTransaction}, + models::{CompletedTransaction, InboundTransaction, TxCancellationReason}, }, tasks::send_transaction_reply::send_transaction_reply, utc::utc_duration_since, @@ -451,6 +450,7 @@ where inbound_tx.timestamp, TransactionDirection::Inbound, None, + None, ); self.resources @@ -508,7 +508,7 @@ where .event_publisher .send(Arc::new(TransactionEvent::TransactionCancelled( self.id, - TxRejection::Timeout, + TxCancellationReason::Timeout, ))) .map_err(|e| { trace!( diff --git a/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs b/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs index 4007eeaa77..a83fa45811 100644 --- a/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs +++ b/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs @@ -38,7 +38,7 @@ use tari_core::{ covenants::Covenant, transactions::{ tari_amount::MicroTari, - transaction::KernelFeatures, + transaction_components::KernelFeatures, transaction_protocol::{ proto::protocol as proto, recipient::RecipientSignedMessage, @@ -60,11 +60,10 @@ use crate::{ config::TransactionRoutingMechanism, error::{TransactionServiceError, TransactionServiceProtocolError}, handle::{TransactionEvent, TransactionServiceResponse}, - protocols::TxRejection, service::TransactionServiceResources, storage::{ database::TransactionBackend, - models::{CompletedTransaction, OutboundTransaction}, + models::{CompletedTransaction, OutboundTransaction, TxCancellationReason}, }, tasks::{ send_finalized_transaction::send_finalized_transaction_message, @@ -262,7 +261,6 @@ where tx_id, self.dest_pubkey.clone(), self.amount, - // TODO: put value in here fee, sender_protocol.clone(), TransactionStatus::Pending, @@ -511,6 +509,7 @@ where Utc::now().naive_utc(), TransactionDirection::Outbound, None, + None, ); self.resources @@ -806,7 +805,7 @@ where .event_publisher .send(Arc::new(TransactionEvent::TransactionCancelled( self.id, - TxRejection::Timeout, + TxCancellationReason::Timeout, ))) .map_err(|e| { trace!( diff --git a/base_layer/wallet/src/transaction_service/protocols/transaction_validation_protocol.rs b/base_layer/wallet/src/transaction_service/protocols/transaction_validation_protocol.rs index b348c29758..0552d2263f 100644 --- a/base_layer/wallet/src/transaction_service/protocols/transaction_validation_protocol.rs +++ b/base_layer/wallet/src/transaction_service/protocols/transaction_validation_protocol.rs @@ -69,7 +69,7 @@ pub struct TransactionValidationProtocol TransactionValidationProtocol @@ -284,7 +284,6 @@ where > { let mut mined = vec![]; let mut unmined = vec![]; - let mut batch_signatures = HashMap::new(); for tx_info in batch.iter() { // Imported transactions do not have a signature; this is represented by the default signature in info @@ -391,17 +390,27 @@ where self.db .set_transaction_mined_height( tx_id, - true, mined_height, mined_in_block.clone(), num_confirmations, num_confirmations >= self.config.num_confirmations_required, + status.is_faux(), ) .await .for_protocol(self.operation_id.as_u64())?; if num_confirmations >= self.config.num_confirmations_required { - self.publish_event(TransactionEvent::TransactionMined { tx_id, is_valid: true }) + if status.is_faux() { + self.publish_event(TransactionEvent::FauxTransactionConfirmed { tx_id, is_valid: true }) + } else { + self.publish_event(TransactionEvent::TransactionMined { tx_id, is_valid: true }) + } + } else if status.is_faux() { + self.publish_event(TransactionEvent::FauxTransactionUnconfirmed { + tx_id, + num_confirmations, + is_valid: true, + }) } else { self.publish_event(TransactionEvent::TransactionMinedUnconfirmed { tx_id, @@ -436,15 +445,20 @@ where self.db .set_transaction_mined_height( tx_id, - false, mined_height, mined_in_block.clone(), num_confirmations, num_confirmations >= self.config.num_confirmations_required, + false, ) .await .for_protocol(self.operation_id.as_u64())?; + self.db + .abandon_coinbase_transaction(tx_id) + .await + .for_protocol(self.operation_id.as_u64())?; + if let Err(e) = self.output_manager_handle.set_coinbase_abandoned(tx_id, true).await { warn!( target: LOG_TARGET, @@ -454,9 +468,10 @@ where self.operation_id ); }; - - self.publish_event(TransactionEvent::TransactionCancelled(tx_id, TxRejection::Orphan)); - + self.publish_event(TransactionEvent::TransactionCancelled( + tx_id, + TxCancellationReason::AbandonedCoinbase, + )); Ok(()) } diff --git a/base_layer/wallet/src/transaction_service/service.rs b/base_layer/wallet/src/transaction_service/service.rs index 7ce9c6a77b..32a0bfd39a 100644 --- a/base_layer/wallet/src/transaction_service/service.rs +++ b/base_layer/wallet/src/transaction_service/service.rs @@ -34,7 +34,7 @@ use log::*; use rand::rngs::OsRng; use sha2::Sha256; use tari_common_types::{ - transaction::{TransactionDirection, TransactionStatus, TxId}, + transaction::{ImportStatus, TransactionDirection, TransactionStatus, TxId}, types::{PrivateKey, PublicKey}, }; use tari_comms::{peer_manager::NodeIdentity, types::CommsPublicKey}; @@ -44,7 +44,7 @@ use tari_core::{ proto::base_node as base_node_proto, transactions::{ tari_amount::MicroTari, - transaction::{KernelFeatures, OutputFeatures, Transaction, TransactionOutput, UnblindedOutput}, + transaction_components::{KernelFeatures, OutputFeatures, Transaction, TransactionOutput, UnblindedOutput}, transaction_protocol::{ proto::protocol as proto, recipient::RecipientSignedMessage, @@ -86,14 +86,13 @@ use crate::{ transaction_receive_protocol::{TransactionReceiveProtocol, TransactionReceiveProtocolStage}, transaction_send_protocol::{TransactionSendProtocol, TransactionSendProtocolStage}, transaction_validation_protocol::TransactionValidationProtocol, - TxRejection, }, storage::{ database::{TransactionBackend, TransactionDatabase}, - models::CompletedTransaction, + models::{CompletedTransaction, TxCancellationReason}, }, tasks::{ - check_imported_transaction_status::check_imported_transactions, + check_faux_transaction_status::check_faux_transactions, send_finalized_transaction::send_finalized_transaction_message, send_transaction_cancelled::send_transaction_cancelled_message, send_transaction_reply::send_transaction_reply, @@ -335,7 +334,7 @@ where }, //Incoming request Some(request_context) = request_stream.next() => { - // TODO: Remove time measurements; this is to aid in system testing only + // TODO: Remove time measurements; this is to aid in system testing only #LOGGED let start = Instant::now(); let (request, reply_tx) = request_context.split(); let event = format!("Handling Service API Request ({})", request); @@ -358,7 +357,7 @@ where }, // Incoming Transaction messages from the Comms layer Some(msg) = transaction_stream.next() => { - // TODO: Remove time measurements; this is to aid in system testing only + // TODO: Remove time measurements; this is to aid in system testing only #LOGGED let start = Instant::now(); let (origin_public_key, inner_msg) = msg.clone().into_origin_and_inner(); trace!(target: LOG_TARGET, "Handling Transaction Message, Trace: {}", msg.dht_header.message_tag); @@ -387,7 +386,7 @@ where }, // Incoming Transaction Reply messages from the Comms layer Some(msg) = transaction_reply_stream.next() => { - // TODO: Remove time measurements; this is to aid in system testing only + // TODO: Remove time measurements; this is to aid in system testing only #LOGGED let start = Instant::now(); let (origin_public_key, inner_msg) = msg.clone().into_origin_and_inner(); trace!(target: LOG_TARGET, "Handling Transaction Reply Message, Trace: {}", msg.dht_header.message_tag); @@ -417,7 +416,7 @@ where }, // Incoming Finalized Transaction messages from the Comms layer Some(msg) = transaction_finalized_stream.next() => { - // TODO: Remove time measurements; this is to aid in system testing only + // TODO: Remove time measurements; this is to aid in system testing only #LOGGED let start = Instant::now(); let (origin_public_key, inner_msg) = msg.clone().into_origin_and_inner(); trace!(target: LOG_TARGET, @@ -454,7 +453,7 @@ where }, // Incoming messages from the Comms layer Some(msg) = base_node_response_stream.next() => { - // TODO: Remove time measurements; this is to aid in system testing only + // TODO: Remove time measurements; this is to aid in system testing only #LOGGED let start = Instant::now(); let (origin_public_key, inner_msg) = msg.clone().into_origin_and_inner(); trace!(target: LOG_TARGET, "Handling Base Node Response, Trace: {}", msg.dht_header.message_tag); @@ -472,7 +471,7 @@ where } // Incoming messages from the Comms layer Some(msg) = transaction_cancelled_stream.next() => { - // TODO: Remove time measurements; this is to aid in system testing only + // TODO: Remove time measurements; this is to aid in system testing only #LOGGED let start = Instant::now(); let (origin_public_key, inner_msg) = msg.clone().into_origin_and_inner(); trace!(target: LOG_TARGET, "Handling Transaction Cancelled message, Trace: {}", msg.dht_header.message_tag); @@ -644,8 +643,24 @@ where TransactionServiceRequest::GetAnyTransaction(tx_id) => Ok(TransactionServiceResponse::AnyTransaction( Box::new(self.db.get_any_transaction(tx_id).await?), )), - TransactionServiceRequest::ImportUtxo(value, source_public_key, message, maturity) => self - .add_utxo_import_transaction(value, source_public_key, message, maturity) + TransactionServiceRequest::ImportUtxoWithStatus { + amount, + source_public_key, + message, + maturity, + import_status, + tx_id, + current_height, + } => self + .add_utxo_import_transaction_with_status( + amount, + source_public_key, + message, + maturity, + import_status, + tx_id, + current_height, + ) .await .map(TransactionServiceResponse::UtxoImported), TransactionServiceRequest::SubmitTransactionToSelf(tx_id, tx, fee, amount, message) => self @@ -748,7 +763,21 @@ where if let OutputManagerEvent::TxoValidationSuccess(_) = (*event).clone() { let db = self.db.clone(); let output_manager_handle = self.output_manager_service.clone(); - tokio::spawn(check_imported_transactions(output_manager_handle, db)); + let metadata = match self.wallet_db.get_chain_metadata().await { + Ok(data) => data, + Err(_) => None, + }; + let tip_height = match metadata { + Some(val) => val.height_of_longest_chain(), + None => 0u64, + }; + let event_publisher = self.event_publisher.clone(); + tokio::spawn(check_faux_transactions( + output_manager_handle, + db, + event_publisher, + tip_height, + )); } } @@ -812,6 +841,7 @@ where Utc::now().naive_utc(), TransactionDirection::Inbound, None, + None, ), ) .await?; @@ -918,8 +948,6 @@ where let sender_offset_private_key = stp .get_recipient_sender_offset_private_key(0) .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?; - // TODO: Add a standardized Diffie-Hellman method to the tari_crypto library that will return a private key, - // TODO: then come back and use it here. let spend_key = PrivateKey::from_bytes( CommsPublicKey::shared_secret(&sender_offset_private_key.clone(), &dest_pubkey.clone()).as_bytes(), ) @@ -1016,6 +1044,7 @@ where Utc::now().naive_utc(), TransactionDirection::Outbound, None, + None, ), ) .await?; @@ -1083,8 +1112,6 @@ where let sender_offset_private_key = stp .get_recipient_sender_offset_private_key(0) .map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?; - // TODO: Add a standardized Diffie-Hellman method to the tari_crypto library that will return a private key, - // TODO: then come back and use it here. let spend_key = PrivateKey::from_bytes( CommsPublicKey::shared_secret(&sender_offset_private_key.clone(), &dest_pubkey.clone()).as_bytes(), ) @@ -1159,6 +1186,7 @@ where Utc::now().naive_utc(), TransactionDirection::Outbound, None, + None, ), ) .await?; @@ -1215,7 +1243,7 @@ where return Ok(()); } - if ctx.cancelled { + if ctx.cancelled.is_some() { // Send a cancellation message debug!( target: LOG_TARGET, @@ -1379,7 +1407,7 @@ where .event_publisher .send(Arc::new(TransactionEvent::TransactionCancelled( tx_id, - TxRejection::UserCancelled, + TxCancellationReason::UserCancelled, ))) .map_err(|e| { trace!( @@ -2023,35 +2051,46 @@ where } /// Add a completed transaction to the Transaction Manager to record directly importing a spendable UTXO. - pub async fn add_utxo_import_transaction( + pub async fn add_utxo_import_transaction_with_status( &mut self, value: MicroTari, source_public_key: CommsPublicKey, message: String, maturity: Option, + import_status: ImportStatus, + tx_id: Option, + current_height: Option, ) -> Result { - let tx_id = TxId::new_random(); + let tx_id = if let Some(id) = tx_id { id } else { TxId::new_random() }; self.db - .add_utxo_import_transaction( + .add_utxo_import_transaction_with_status( tx_id, value, source_public_key, self.node_identity.public_key().clone(), message, maturity, + import_status.clone(), + current_height, ) .await?; - let _ = self - .event_publisher - .send(Arc::new(TransactionEvent::TransactionImported(tx_id))) - .map_err(|e| { - trace!( - target: LOG_TARGET, - "Error sending event, usually because there are no subscribers: {:?}", - e - ); + let transaction_event = match import_status { + ImportStatus::Imported => TransactionEvent::TransactionImported(tx_id), + ImportStatus::FauxUnconfirmed => TransactionEvent::FauxTransactionUnconfirmed { + tx_id, + num_confirmations: 0, + is_valid: true, + }, + ImportStatus::FauxConfirmed => TransactionEvent::FauxTransactionConfirmed { tx_id, is_valid: true }, + }; + let _ = self.event_publisher.send(Arc::new(transaction_event)).map_err(|e| { + trace!( + target: LOG_TARGET, + "Error sending event, usually because there are no subscribers: {:?}", e - }); + ); + e + }); Ok(tx_id) } @@ -2105,6 +2144,7 @@ where Utc::now().naive_utc(), TransactionDirection::Inbound, None, + None, ), ) .await?; @@ -2165,6 +2205,7 @@ where Utc::now().naive_utc(), TransactionDirection::Inbound, Some(block_height), + None, ), ) .await?; diff --git a/base_layer/wallet/src/transaction_service/storage/database.rs b/base_layer/wallet/src/transaction_service/storage/database.rs index aede6aad88..a3af2fd1d2 100644 --- a/base_layer/wallet/src/transaction_service/storage/database.rs +++ b/base_layer/wallet/src/transaction_service/storage/database.rs @@ -22,6 +22,7 @@ use std::{ collections::HashMap, + convert::TryFrom, fmt, fmt::{Display, Error, Formatter}, sync::Arc, @@ -31,16 +32,22 @@ use aes_gcm::Aes256Gcm; use chrono::Utc; use log::*; use tari_common_types::{ - transaction::{TransactionDirection, TransactionStatus, TxId}, + transaction::{ImportStatus, TransactionDirection, TransactionStatus, TxId}, types::{BlindingFactor, BlockHash}, }; use tari_comms::types::CommsPublicKey; -use tari_core::transactions::{tari_amount::MicroTari, transaction::Transaction}; +use tari_core::transactions::{tari_amount::MicroTari, transaction_components::Transaction}; use crate::transaction_service::{ error::TransactionStorageError, storage::{ - models::{CompletedTransaction, InboundTransaction, OutboundTransaction, WalletTransaction}, + models::{ + CompletedTransaction, + InboundTransaction, + OutboundTransaction, + TxCancellationReason, + WalletTransaction, + }, sqlite_db::{InboundTransactionSenderInfo, UnconfirmedTransactionInfo}, }, }; @@ -91,7 +98,11 @@ pub trait TransactionBackend: Send + Sync + Clone { /// Indicated that a completed transaction has been broadcast to the mempools fn broadcast_completed_transaction(&self, tx_id: TxId) -> Result<(), TransactionStorageError>; /// Cancel Completed transaction, this will update the transaction status - fn reject_completed_transaction(&self, tx_id: TxId) -> Result<(), TransactionStorageError>; + fn reject_completed_transaction( + &self, + tx_id: TxId, + reason: TxCancellationReason, + ) -> Result<(), TransactionStorageError>; /// Set cancellation on Pending transaction, this will update the transaction status fn set_pending_transaction_cancellation_status( &self, @@ -127,11 +138,11 @@ pub trait TransactionBackend: Send + Sync + Clone { fn update_mined_height( &self, tx_id: TxId, - is_valid: bool, mined_height: u64, mined_in_block: BlockHash, num_confirmations: u64, is_confirmed: bool, + is_faux: bool, ) -> Result<(), TransactionStorageError>; /// Clears the mined block and height of a transaction fn set_transaction_as_unmined(&self, tx_id: TxId) -> Result<(), TransactionStorageError>; @@ -142,6 +153,12 @@ pub trait TransactionBackend: Send + Sync + Clone { &self, ) -> Result, TransactionStorageError>; fn fetch_imported_transactions(&self) -> Result, TransactionStorageError>; + fn fetch_unconfirmed_faux_transactions(&self) -> Result, TransactionStorageError>; + fn fetch_confirmed_faux_transactions_from_height( + &self, + height: u64, + ) -> Result, TransactionStorageError>; + fn abandon_coinbase_transaction(&self, tx_id: TxId) -> Result<(), TransactionStorageError>; } #[derive(Clone, PartialEq)] @@ -420,7 +437,7 @@ where T: TransactionBackend + 'static let t = tokio::task::spawn_blocking(move || match db_clone.fetch(&DbKey::CompletedTransaction(tx_id)) { Ok(None) => Err(TransactionStorageError::ValueNotFound(key)), Ok(Some(DbValue::CompletedTransaction(pt))) => { - if pt.cancelled == cancelled { + if (pt.cancelled.is_some()) == cancelled { Ok(pt) } else { Err(TransactionStorageError::ValueNotFound(key)) @@ -442,6 +459,27 @@ where T: TransactionBackend + 'static Ok(t) } + pub async fn get_unconfirmed_faux_transactions( + &self, + ) -> Result, TransactionStorageError> { + let db_clone = self.db.clone(); + let t = tokio::task::spawn_blocking(move || db_clone.fetch_unconfirmed_faux_transactions()) + .await + .map_err(|err| TransactionStorageError::BlockingTaskSpawnError(err.to_string()))??; + Ok(t) + } + + pub async fn get_confirmed_faux_transactions_from_height( + &self, + height: u64, + ) -> Result, TransactionStorageError> { + let db_clone = self.db.clone(); + let t = tokio::task::spawn_blocking(move || db_clone.fetch_confirmed_faux_transactions_from_height(height)) + .await + .map_err(|err| TransactionStorageError::BlockingTaskSpawnError(err.to_string()))??; + Ok(t) + } + pub async fn fetch_last_mined_transaction(&self) -> Result, TransactionStorageError> { self.db.fetch_last_mined_transaction() } @@ -579,7 +617,6 @@ where T: TransactionBackend + 'static self.get_completed_transactions_by_cancelled(true).await } - // TODO: all the single getters should use an Option rather than an error to indicate not found. pub async fn get_any_transaction(&self, tx_id: TxId) -> Result, TransactionStorageError> { let db_clone = self.db.clone(); let key = DbKey::AnyTransaction(tx_id); @@ -660,9 +697,13 @@ where T: TransactionBackend + 'static .and_then(|inner_result| inner_result) } - pub async fn reject_completed_transaction(&self, tx_id: TxId) -> Result<(), TransactionStorageError> { + pub async fn reject_completed_transaction( + &self, + tx_id: TxId, + reason: TxCancellationReason, + ) -> Result<(), TransactionStorageError> { let db_clone = self.db.clone(); - tokio::task::spawn_blocking(move || db_clone.reject_completed_transaction(tx_id)) + tokio::task::spawn_blocking(move || db_clone.reject_completed_transaction(tx_id, reason)) .await .map_err(|err| TransactionStorageError::BlockingTaskSpawnError(err.to_string()))??; Ok(()) @@ -702,7 +743,8 @@ where T: TransactionBackend + 'static .and_then(|inner_result| inner_result) } - pub async fn add_utxo_import_transaction( + /// Faux transaction added to the database with imported status + pub async fn add_utxo_import_transaction_with_status( &self, tx_id: TxId, amount: MicroTari, @@ -710,6 +752,8 @@ where T: TransactionBackend + 'static comms_public_key: CommsPublicKey, message: String, maturity: Option, + import_status: ImportStatus, + current_height: Option, ) -> Result<(), TransactionStorageError> { let transaction = CompletedTransaction::new( tx_id, @@ -724,11 +768,12 @@ where T: TransactionBackend + 'static BlindingFactor::default(), BlindingFactor::default(), ), - TransactionStatus::Imported, + TransactionStatus::try_from(import_status)?, message, Utc::now().naive_utc(), TransactionDirection::Inbound, maturity, + current_height, ); let db_clone = self.db.clone(); @@ -811,21 +856,21 @@ where T: TransactionBackend + 'static pub async fn set_transaction_mined_height( &self, tx_id: TxId, - is_valid: bool, mined_height: u64, mined_in_block: BlockHash, num_confirmations: u64, is_confirmed: bool, + is_faux: bool, ) -> Result<(), TransactionStorageError> { let db_clone = self.db.clone(); tokio::task::spawn_blocking(move || { db_clone.update_mined_height( tx_id, - is_valid, mined_height, mined_in_block, num_confirmations, is_confirmed, + is_faux, ) }) .await @@ -846,6 +891,14 @@ where T: TransactionBackend + 'static .map_err(|err| TransactionStorageError::BlockingTaskSpawnError(err.to_string()))??; Ok(t) } + + pub async fn abandon_coinbase_transaction(&self, tx_id: TxId) -> Result<(), TransactionStorageError> { + let db_clone = self.db.clone(); + tokio::task::spawn_blocking(move || db_clone.abandon_coinbase_transaction(tx_id)) + .await + .map_err(|err| TransactionStorageError::BlockingTaskSpawnError(err.to_string()))??; + Ok(()) + } } impl Display for DbKey { diff --git a/base_layer/wallet/src/transaction_service/storage/models.rs b/base_layer/wallet/src/transaction_service/storage/models.rs index d0c0702571..fbfb0638ca 100644 --- a/base_layer/wallet/src/transaction_service/storage/models.rs +++ b/base_layer/wallet/src/transaction_service/storage/models.rs @@ -20,16 +20,21 @@ // 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::{ + convert::TryFrom, + fmt::{Display, Error, Formatter}, +}; + use chrono::NaiveDateTime; use serde::{Deserialize, Serialize}; use tari_common_types::{ - transaction::{TransactionDirection, TransactionStatus, TxId}, + transaction::{TransactionConversionError, TransactionDirection, TransactionStatus, TxId}, types::{BlockHash, PrivateKey, Signature}, }; use tari_comms::types::CommsPublicKey; use tari_core::transactions::{ tari_amount::MicroTari, - transaction::Transaction, + transaction_components::Transaction, ReceiverTransactionProtocol, SenderTransactionProtocol, }; @@ -133,12 +138,11 @@ pub struct CompletedTransaction { pub status: TransactionStatus, pub message: String, pub timestamp: NaiveDateTime, - pub cancelled: bool, + pub cancelled: Option, pub direction: TransactionDirection, pub coinbase_block_height: Option, pub send_count: u32, pub last_send_timestamp: Option, - pub valid: bool, pub transaction_signature: Signature, pub confirmations: Option, pub mined_height: Option, @@ -159,6 +163,7 @@ impl CompletedTransaction { timestamp: NaiveDateTime, direction: TransactionDirection, coinbase_block_height: Option, + mined_height: Option, ) -> Self { let transaction_signature = if let Some(excess_sig) = transaction.first_kernel_excess_sig() { excess_sig.clone() @@ -175,15 +180,14 @@ impl CompletedTransaction { status, message, timestamp, - cancelled: false, + cancelled: None, direction, coinbase_block_height, send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature, confirmations: None, - mined_height: None, + mined_height, mined_in_block: None, } } @@ -224,7 +228,7 @@ impl From for InboundTransaction { status: ct.status, message: ct.message, timestamp: ct.timestamp, - cancelled: ct.cancelled, + cancelled: ct.cancelled.is_some(), direct_send_success: false, send_count: 0, last_send_timestamp: None, @@ -243,7 +247,7 @@ impl From for OutboundTransaction { status: ct.status, message: ct.message, timestamp: ct.timestamp, - cancelled: ct.cancelled, + cancelled: ct.cancelled.is_some(), direct_send_success: false, send_count: 0, last_send_timestamp: None, @@ -275,13 +279,16 @@ impl From for CompletedTransaction { status: tx.status, message: tx.message, timestamp: tx.timestamp, - cancelled: tx.cancelled, + cancelled: if tx.cancelled { + Some(TxCancellationReason::UserCancelled) + } else { + None + }, transaction, direction: TransactionDirection::Outbound, coinbase_block_height: None, send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature, confirmations: None, mined_height: None, @@ -301,13 +308,16 @@ impl From for CompletedTransaction { status: tx.status, message: tx.message, timestamp: tx.timestamp, - cancelled: tx.cancelled, + cancelled: if tx.cancelled { + Some(TxCancellationReason::UserCancelled) + } else { + None + }, transaction: Transaction::new(vec![], vec![], vec![], PrivateKey::default(), PrivateKey::default()), direction: TransactionDirection::Inbound, coinbase_block_height: None, send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature: Signature::default(), confirmations: None, mined_height: None, @@ -333,3 +343,50 @@ impl From for CompletedTransaction { } } } + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum TxCancellationReason { + Unknown, // 0 + UserCancelled, // 1 + Timeout, // 2 + DoubleSpend, // 3 + Orphan, // 4 + TimeLocked, // 5 + InvalidTransaction, // 6 + AbandonedCoinbase, // 7 +} + +impl TryFrom for TxCancellationReason { + type Error = TransactionConversionError; + + fn try_from(value: u32) -> Result { + match value { + 0 => Ok(TxCancellationReason::Unknown), + 1 => Ok(TxCancellationReason::UserCancelled), + 2 => Ok(TxCancellationReason::Timeout), + 3 => Ok(TxCancellationReason::DoubleSpend), + 4 => Ok(TxCancellationReason::Orphan), + 5 => Ok(TxCancellationReason::TimeLocked), + 6 => Ok(TxCancellationReason::InvalidTransaction), + 7 => Ok(TxCancellationReason::AbandonedCoinbase), + code => Err(TransactionConversionError { code: code as i32 }), + } + } +} + +impl Display for TxCancellationReason { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { + use TxCancellationReason::*; + let response = match self { + Unknown => "Unknown", + UserCancelled => "User Cancelled", + Timeout => "Timeout", + DoubleSpend => "Double Spend", + Orphan => "Orphan", + TimeLocked => "TimeLocked", + InvalidTransaction => "Invalid Transaction", + AbandonedCoinbase => "Abandoned Coinbase", + }; + fmt.write_str(response) + } +} 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 8dc318d5e8..06af0ed5f0 100644 --- a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs +++ b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs @@ -57,7 +57,13 @@ use crate::{ error::{TransactionKeyError, TransactionStorageError}, storage::{ database::{DbKey, DbKeyValuePair, DbValue, TransactionBackend, WriteOperation}, - models::{CompletedTransaction, InboundTransaction, OutboundTransaction, WalletTransaction}, + models::{ + CompletedTransaction, + InboundTransaction, + OutboundTransaction, + TxCancellationReason, + WalletTransaction, + }, }, }, util::{ @@ -667,13 +673,17 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { Ok(()) } - fn reject_completed_transaction(&self, tx_id: TxId) -> Result<(), TransactionStorageError> { + fn reject_completed_transaction( + &self, + tx_id: TxId, + reason: TxCancellationReason, + ) -> Result<(), TransactionStorageError> { let start = Instant::now(); let conn = self.database_connection.get_pooled_connection()?; let acquire_lock = start.elapsed(); match CompletedTransactionSql::find_by_cancelled(tx_id, false, &conn) { Ok(v) => { - v.reject(&conn)?; + v.reject(reason, &conn)?; }, Err(TransactionStorageError::DieselError(DieselError::NotFound)) => { return Err(TransactionStorageError::ValueNotFound(DbKey::CompletedTransaction( @@ -910,7 +920,7 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { let coinbase_txs = CompletedTransactionSql::index_coinbase_at_block_height(block_height as i64, &conn)?; for c in coinbase_txs.iter() { - c.cancel(&conn)?; + c.reject(TxCancellationReason::AbandonedCoinbase, &conn)?; } if start.elapsed().as_millis() > 0 { trace!( @@ -1004,11 +1014,11 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { fn update_mined_height( &self, tx_id: TxId, - is_valid: bool, mined_height: u64, mined_in_block: BlockHash, num_confirmations: u64, is_confirmed: bool, + is_faux: bool, ) -> Result<(), TransactionStorageError> { let start = Instant::now(); let conn = self.database_connection.get_pooled_connection()?; @@ -1016,12 +1026,12 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { match CompletedTransactionSql::find(tx_id, &conn) { Ok(v) => { v.update_mined_height( - is_valid, mined_height, mined_in_block, num_confirmations, is_confirmed, &conn, + is_faux, )?; }, Err(TransactionStorageError::DieselError(DieselError::NotFound)) => { @@ -1048,6 +1058,8 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { let conn = self.database_connection.get_pooled_connection()?; let acquire_lock = start.elapsed(); let tx = completed_transactions::table + // Note: Check 'mined_in_block' as well as 'mined_height' is populated for faux transactions before it is confirmed + .filter(completed_transactions::mined_in_block.is_not_null()) .filter(completed_transactions::mined_height.is_not_null()) .filter(completed_transactions::mined_height.gt(0)) .order_by(completed_transactions::mined_height.desc()) @@ -1072,6 +1084,7 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { Ok(result) } + // This method returns completed but unconfirmed transactions that were not imported fn fetch_unconfirmed_transactions_info(&self) -> Result, TransactionStorageError> { let start = Instant::now(); let conn = self.database_connection.get_pooled_connection()?; @@ -1103,7 +1116,6 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { let conn = self.database_connection.get_pooled_connection()?; let acquire_lock = start.elapsed(); let txs = completed_transactions::table - .filter(completed_transactions::valid.eq(true as i32)) .filter( completed_transactions::status .eq(TransactionStatus::Completed as i32) @@ -1114,7 +1126,7 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { .is_null() .or(completed_transactions::coinbase_block_height.eq(0)), ) - .filter(completed_transactions::cancelled.eq(false as i32)) + .filter(completed_transactions::cancelled.is_null()) .order_by(completed_transactions::tx_id) .load::(&*conn)?; @@ -1140,7 +1152,7 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { let start = Instant::now(); let conn = self.database_connection.get_pooled_connection()?; let acquire_lock = start.elapsed(); - let result = diesel::update(completed_transactions::table.filter(completed_transactions::cancelled.eq(0))) + let result = diesel::update(completed_transactions::table.filter(completed_transactions::cancelled.is_null())) .set(( completed_transactions::mined_height.eq::>(None), completed_transactions::mined_in_block.eq::>>(None), @@ -1226,6 +1238,57 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { }) .collect::, TransactionStorageError>>() } + + fn fetch_unconfirmed_faux_transactions(&self) -> Result, TransactionStorageError> { + let conn = self.database_connection.get_pooled_connection()?; + CompletedTransactionSql::index_by_status_and_cancelled(TransactionStatus::FauxUnconfirmed, false, &conn)? + .into_iter() + .map(|mut ct: CompletedTransactionSql| { + if let Err(e) = self.decrypt_if_necessary(&mut ct) { + return Err(e); + } + CompletedTransaction::try_from(ct).map_err(TransactionStorageError::from) + }) + .collect::, TransactionStorageError>>() + } + + fn fetch_confirmed_faux_transactions_from_height( + &self, + height: u64, + ) -> Result, TransactionStorageError> { + let conn = self.database_connection.get_pooled_connection()?; + CompletedTransactionSql::index_by_status_and_cancelled_from_block_height( + TransactionStatus::FauxConfirmed, + false, + height as i64, + &conn, + )? + .into_iter() + .map(|mut ct: CompletedTransactionSql| { + if let Err(e) = self.decrypt_if_necessary(&mut ct) { + return Err(e); + } + CompletedTransaction::try_from(ct).map_err(TransactionStorageError::from) + }) + .collect::, TransactionStorageError>>() + } + + fn abandon_coinbase_transaction(&self, tx_id: TxId) -> Result<(), TransactionStorageError> { + let conn = self.database_connection.get_pooled_connection()?; + match CompletedTransactionSql::find_by_cancelled(tx_id, false, &conn) { + Ok(tx) => { + tx.abandon_coinbase(&conn)?; + }, + Err(TransactionStorageError::DieselError(DieselError::NotFound)) => { + return Err(TransactionStorageError::ValueNotFound(DbKey::CompletedTransaction( + tx_id, + ))); + }, + Err(e) => return Err(e), + }; + + Ok(()) + } } #[derive(Debug, PartialEq)] @@ -1629,12 +1692,11 @@ struct CompletedTransactionSql { status: i32, message: String, timestamp: NaiveDateTime, - cancelled: i32, + cancelled: Option, direction: Option, coinbase_block_height: Option, send_count: i32, last_send_timestamp: Option, - valid: i32, confirmations: Option, mined_height: Option, mined_in_block: Option>, @@ -1658,9 +1720,15 @@ impl CompletedTransactionSql { conn: &SqliteConnection, cancelled: bool, ) -> Result, TransactionStorageError> { - Ok(completed_transactions::table - .filter(completed_transactions::cancelled.eq(cancelled as i32)) - .load::(conn)?) + let mut query = completed_transactions::table.into_boxed(); + + query = if cancelled { + query.filter(completed_transactions::cancelled.is_not_null()) + } else { + query.filter(completed_transactions::cancelled.is_null()) + }; + + Ok(query.load::(conn)?) } pub fn index_by_status_and_cancelled( @@ -1668,12 +1736,36 @@ impl CompletedTransactionSql { cancelled: bool, conn: &SqliteConnection, ) -> Result, TransactionStorageError> { - Ok(completed_transactions::table - .filter(completed_transactions::cancelled.eq(cancelled as i32)) + let mut query = completed_transactions::table.into_boxed(); + query = if cancelled { + query.filter(completed_transactions::cancelled.is_not_null()) + } else { + query.filter(completed_transactions::cancelled.is_null()) + }; + Ok(query .filter(completed_transactions::status.eq(status as i32)) .load::(conn)?) } + pub fn index_by_status_and_cancelled_from_block_height( + status: TransactionStatus, + cancelled: bool, + block_height: i64, + conn: &SqliteConnection, + ) -> Result, TransactionStorageError> { + let mut query = completed_transactions::table.into_boxed(); + query = if cancelled { + query.filter(completed_transactions::cancelled.is_not_null()) + } else { + query.filter(completed_transactions::cancelled.is_null()) + }; + + Ok(query + .filter(completed_transactions::status.eq(status as i32)) + .filter(completed_transactions::mined_height.ge(block_height)) + .load::(conn)?) + } + pub fn index_coinbase_at_block_height( block_height: i64, conn: &SqliteConnection, @@ -1695,10 +1787,17 @@ impl CompletedTransactionSql { cancelled: bool, conn: &SqliteConnection, ) -> Result { - Ok(completed_transactions::table + let mut query = completed_transactions::table .filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)) - .filter(completed_transactions::cancelled.eq(cancelled as i32)) - .first::(conn)?) + .into_boxed(); + + query = if cancelled { + query.filter(completed_transactions::cancelled.is_not_null()) + } else { + query.filter(completed_transactions::cancelled.is_null()) + }; + + Ok(query.first::(conn)?) } pub fn delete(&self, conn: &SqliteConnection) -> Result<(), TransactionStorageError> { @@ -1725,10 +1824,10 @@ impl CompletedTransactionSql { Ok(()) } - pub fn reject(&self, conn: &SqliteConnection) -> Result<(), TransactionStorageError> { + pub fn reject(&self, reason: TxCancellationReason, conn: &SqliteConnection) -> Result<(), TransactionStorageError> { self.update( UpdateCompletedTransactionSql { - cancelled: Some(1i32), + cancelled: Some(Some(reason as i32)), status: Some(TransactionStatus::Rejected as i32), ..Default::default() }, @@ -1738,10 +1837,14 @@ impl CompletedTransactionSql { Ok(()) } - pub fn cancel(&self, conn: &SqliteConnection) -> Result<(), TransactionStorageError> { + pub fn abandon_coinbase(&self, conn: &SqliteConnection) -> Result<(), TransactionStorageError> { + if self.coinbase_block_height.is_none() { + return Err(TransactionStorageError::NotCoinbase); + } + self.update( UpdateCompletedTransactionSql { - cancelled: Some(1i32), + cancelled: Some(Some(TxCancellationReason::AbandonedCoinbase as i32)), ..Default::default() }, conn, @@ -1753,6 +1856,8 @@ impl CompletedTransactionSql { pub fn set_as_unmined(&self, conn: &SqliteConnection) -> Result<(), TransactionStorageError> { let status = if self.coinbase_block_height.is_some() { Some(TransactionStatus::Coinbase as i32) + } else if self.status == TransactionStatus::FauxConfirmed as i32 { + Some(TransactionStatus::FauxUnconfirmed as i32) } else if self.status == TransactionStatus::Broadcast as i32 { Some(TransactionStatus::Broadcast as i32) } else { @@ -1765,8 +1870,8 @@ impl CompletedTransactionSql { mined_in_block: Some(None), mined_height: Some(None), confirmations: Some(None), - // Resets to valid - valid: Some(1), + // Turns out it should not be cancelled + cancelled: Some(None), ..Default::default() }, conn, @@ -1792,17 +1897,21 @@ impl CompletedTransactionSql { pub fn update_mined_height( &self, - is_valid: bool, mined_height: u64, mined_in_block: BlockHash, num_confirmations: u64, is_confirmed: bool, conn: &SqliteConnection, + is_faux: bool, ) -> Result<(), TransactionStorageError> { - let status = if self.coinbase_block_height.is_some() && !is_valid { - TransactionStatus::Coinbase as i32 - } else if is_confirmed { - TransactionStatus::MinedConfirmed as i32 + let status = if is_confirmed { + if is_faux { + TransactionStatus::FauxConfirmed as i32 + } else { + TransactionStatus::MinedConfirmed as i32 + } + } else if is_faux { + TransactionStatus::FauxUnconfirmed as i32 } else { TransactionStatus::MinedUnconfirmed as i32 }; @@ -1813,9 +1922,8 @@ impl CompletedTransactionSql { status: Some(status), mined_height: Some(Some(mined_height as i64)), mined_in_block: Some(Some(mined_in_block)), - valid: Some(is_valid as i32), // If the tx is mined, then it can't be cancelled - cancelled: Some(0), + cancelled: None, ..Default::default() }, conn, @@ -1858,12 +1966,11 @@ impl TryFrom for CompletedTransactionSql { status: c.status as i32, message: c.message, timestamp: c.timestamp, - cancelled: c.cancelled as i32, + cancelled: c.cancelled.map(|v| v as i32), direction: Some(c.direction as i32), coinbase_block_height: c.coinbase_block_height.map(|b| b as i64), send_count: c.send_count as i32, last_send_timestamp: c.last_send_timestamp, - valid: c.valid as i32, confirmations: c.confirmations.map(|ic| ic as i64), mined_height: c.mined_height.map(|ic| ic as i64), mined_in_block: c.mined_in_block, @@ -1907,12 +2014,13 @@ impl TryFrom for CompletedTransaction { status: TransactionStatus::try_from(c.status)?, message: c.message, timestamp: c.timestamp, - cancelled: c.cancelled != 0, + cancelled: c + .cancelled + .map(|v| TxCancellationReason::try_from(v as u32).unwrap_or(TxCancellationReason::Unknown)), direction: TransactionDirection::try_from(c.direction.unwrap_or(2i32))?, coinbase_block_height: c.coinbase_block_height.map(|b| b as u64), send_count: c.send_count as u32, last_send_timestamp: c.last_send_timestamp, - valid: c.valid != 0, transaction_signature, confirmations: c.confirmations.map(|ic| ic as u64), mined_height: c.mined_height.map(|ic| ic as u64), @@ -1926,12 +2034,11 @@ impl TryFrom for CompletedTransaction { pub struct UpdateCompletedTransactionSql { status: Option, timestamp: Option, - cancelled: Option, + cancelled: Option>, direction: Option, transaction_protocol: Option, send_count: Option, last_send_timestamp: Option>, - valid: Option, confirmations: Option>, mined_height: Option>, mined_in_block: Option>>, @@ -1983,11 +2090,11 @@ pub struct UnconfirmedTransactionInfoSql { } impl UnconfirmedTransactionInfoSql { - /// This method returns completed but unconfirmed transactions + /// This method returns completed but unconfirmed transactions that were not imported or scanned pub fn fetch_unconfirmed_transactions_info( conn: &SqliteConnection, ) -> Result, TransactionStorageError> { - // TODO: Should we not return cancelled transactions as well and handle it upstream? It could be mined. + // TODO: Should we not return cancelled transactions as well and handle it upstream? It could be mined. #LOGGED let query_result = completed_transactions::table .select(( completed_transactions::tx_id, @@ -1999,13 +2106,15 @@ impl UnconfirmedTransactionInfoSql { .filter( completed_transactions::status .ne(TransactionStatus::Imported as i32) + .and(completed_transactions::status.ne(TransactionStatus::FauxUnconfirmed as i32)) + .and(completed_transactions::status.ne(TransactionStatus::FauxConfirmed as i32)) .and( completed_transactions::mined_height .is_null() .or(completed_transactions::status.eq(TransactionStatus::MinedUnconfirmed as i32)), ), ) - .filter(completed_transactions::cancelled.eq(false as i32)) + .filter(completed_transactions::cancelled.is_null()) .order_by(completed_transactions::tx_id) .load::(&*conn)?; Ok(query_result) @@ -2033,7 +2142,7 @@ mod test { transactions::{ tari_amount::MicroTari, test_helpers::{create_unblinded_output, TestParams}, - transaction::{OutputFeatures, Transaction}, + transaction_components::{OutputFeatures, Transaction}, transaction_protocol::sender::TransactionSenderMessage, CryptoFactories, ReceiverTransactionProtocol, @@ -2053,7 +2162,7 @@ mod test { test_utils::create_consensus_constants, transaction_service::storage::{ database::{DbKey, TransactionBackend}, - models::{CompletedTransaction, InboundTransaction, OutboundTransaction}, + models::{CompletedTransaction, InboundTransaction, OutboundTransaction, TxCancellationReason}, sqlite_db::{ CompletedTransactionSql, InboundTransactionSenderInfo, @@ -2236,12 +2345,11 @@ mod test { status: TransactionStatus::MinedUnconfirmed, message: "Yo!".to_string(), timestamp: Utc::now().naive_utc(), - cancelled: false, + cancelled: None, direction: TransactionDirection::Unknown, coinbase_block_height: None, send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), confirmations: None, mined_height: None, @@ -2257,12 +2365,11 @@ mod test { status: TransactionStatus::Broadcast, message: "Hey!".to_string(), timestamp: Utc::now().naive_utc(), - cancelled: false, + cancelled: None, direction: TransactionDirection::Unknown, coinbase_block_height: None, send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), confirmations: None, mined_height: None, @@ -2372,7 +2479,7 @@ mod test { assert!(CompletedTransactionSql::find_by_cancelled(completed_tx1.tx_id, true, &conn).is_err()); CompletedTransactionSql::try_from(completed_tx1.clone()) .unwrap() - .reject(&conn) + .reject(TxCancellationReason::Unknown, &conn) .unwrap(); assert!(CompletedTransactionSql::find_by_cancelled(completed_tx1.tx_id, false, &conn).is_err()); assert!(CompletedTransactionSql::find_by_cancelled(completed_tx1.tx_id, true, &conn).is_ok()); @@ -2387,12 +2494,11 @@ mod test { status: TransactionStatus::Coinbase, message: "Hey!".to_string(), timestamp: Utc::now().naive_utc(), - cancelled: false, + cancelled: None, direction: TransactionDirection::Unknown, coinbase_block_height: Some(2), send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), confirmations: None, mined_height: None, @@ -2409,12 +2515,11 @@ mod test { status: TransactionStatus::Coinbase, message: "Hey!".to_string(), timestamp: Utc::now().naive_utc(), - cancelled: false, + cancelled: None, direction: TransactionDirection::Unknown, coinbase_block_height: Some(2), send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), confirmations: None, mined_height: None, @@ -2431,12 +2536,11 @@ mod test { status: TransactionStatus::Coinbase, message: "Hey!".to_string(), timestamp: Utc::now().naive_utc(), - cancelled: false, + cancelled: None, direction: TransactionDirection::Unknown, coinbase_block_height: Some(3), send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), confirmations: None, mined_height: None, @@ -2543,12 +2647,11 @@ mod test { status: TransactionStatus::MinedUnconfirmed, message: "Yo!".to_string(), timestamp: Utc::now().naive_utc(), - cancelled: false, + cancelled: None, direction: TransactionDirection::Unknown, coinbase_block_height: None, send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature: Signature::default(), confirmations: None, mined_height: None, @@ -2634,12 +2737,11 @@ mod test { status: TransactionStatus::MinedUnconfirmed, message: "Yo!".to_string(), timestamp: Utc::now().naive_utc(), - cancelled: false, + cancelled: None, direction: TransactionDirection::Unknown, coinbase_block_height: None, send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature: Signature::default(), confirmations: None, mined_height: None, @@ -2697,19 +2799,51 @@ mod test { let mut info_list_reference: Vec = vec![]; for i in 0..1000 { - let (valid, cancelled, status, coinbase_block_height) = match i % 13 { - 0 => (true, i % 3 == 0, TransactionStatus::Completed, None), - 1 => (true, i % 5 == 0, TransactionStatus::Broadcast, None), - 2 => (true, i % 7 == 0, TransactionStatus::Completed, Some(i % 2)), - 3 => (true, i % 11 == 0, TransactionStatus::Broadcast, Some(i % 2)), - 4 => (i % 13 == 0, false, TransactionStatus::Completed, None), - 5 => (i % 17 == 0, false, TransactionStatus::Broadcast, None), - 6 => (true, false, TransactionStatus::Pending, None), - 7 => (true, false, TransactionStatus::Coinbase, None), - 8 => (true, false, TransactionStatus::MinedUnconfirmed, None), - 9 => (true, false, TransactionStatus::Imported, None), - 10 => (true, false, TransactionStatus::MinedConfirmed, None), - _ => (true, false, TransactionStatus::Completed, Some(i)), + let (cancelled, status, coinbase_block_height) = match i % 13 { + 0 => ( + if i % 3 == 0 { + Some(TxCancellationReason::Unknown) + } else { + None + }, + TransactionStatus::Completed, + None, + ), + 1 => ( + if i % 5 == 0 { + Some(TxCancellationReason::Unknown) + } else { + None + }, + TransactionStatus::Broadcast, + None, + ), + 2 => ( + if i % 7 == 0 { + Some(TxCancellationReason::Unknown) + } else { + None + }, + TransactionStatus::Completed, + Some(i % 2), + ), + 3 => ( + if i % 11 == 0 { + Some(TxCancellationReason::Unknown) + } else { + None + }, + TransactionStatus::Broadcast, + Some(i % 2), + ), + 4 => (None, TransactionStatus::Completed, None), + 5 => (None, TransactionStatus::Broadcast, None), + 6 => (None, TransactionStatus::Pending, None), + 7 => (None, TransactionStatus::Coinbase, None), + 8 => (None, TransactionStatus::MinedUnconfirmed, None), + 9 => (None, TransactionStatus::Imported, None), + 10 => (None, TransactionStatus::MinedConfirmed, None), + _ => (None, TransactionStatus::Completed, Some(i)), }; let completed_tx = CompletedTransaction { tx_id: TxId::from(i), @@ -2732,7 +2866,6 @@ mod test { coinbase_block_height, send_count: 0, last_send_timestamp: None, - valid, transaction_signature: Signature::default(), confirmations: None, mined_height: None, @@ -2745,7 +2878,7 @@ mod test { let inbound_tx_sql = InboundTransactionSql::try_from(inbound_tx.clone()).unwrap(); inbound_tx_sql.commit(&conn).unwrap(); - if !cancelled { + if cancelled.is_none() { info_list_reference.push(InboundTransactionSenderInfo { tx_id: inbound_tx.tx_id, source_public_key: inbound_tx.source_public_key, @@ -2757,11 +2890,10 @@ mod test { let db1 = TransactionServiceSqliteDatabase::new(connection, None); let txn_list = db1.get_transactions_to_be_broadcast().unwrap(); - assert_eq!(txn_list.len(), 185); + assert_eq!(txn_list.len(), 335); for txn in &txn_list { assert!(txn.status == TransactionStatus::Completed || txn.status == TransactionStatus::Broadcast); - assert!(txn.valid); - assert!(!txn.cancelled); + assert!(txn.cancelled.is_none()); assert!(txn.coinbase_block_height == None || txn.coinbase_block_height == Some(0)); } diff --git a/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs b/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs new file mode 100644 index 0000000000..370a0c941f --- /dev/null +++ b/base_layer/wallet/src/transaction_service/tasks/check_faux_transaction_status.rs @@ -0,0 +1,166 @@ +// Copyright 2021. 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 std::sync::Arc; + +use log::*; +use tari_common_types::types::BlockHash; + +use crate::{ + output_manager_service::{handle::OutputManagerHandle, storage::OutputStatus}, + transaction_service::{ + config::TransactionServiceConfig, + handle::{TransactionEvent, TransactionEventSender}, + storage::{ + database::{TransactionBackend, TransactionDatabase}, + models::CompletedTransaction, + }, + }, +}; + +const LOG_TARGET: &str = "wallet::transaction_service::service"; + +pub async fn check_faux_transactions( + mut output_manager: OutputManagerHandle, + db: TransactionDatabase, + event_publisher: TransactionEventSender, + tip_height: u64, +) { + let mut all_faux_transactions: Vec = match db.get_imported_transactions().await { + Ok(txs) => txs, + Err(e) => { + error!(target: LOG_TARGET, "Problem retrieving imported transactions: {}", e); + return; + }, + }; + let mut unconfirmed_faux = match db.get_unconfirmed_faux_transactions().await { + Ok(txs) => txs, + Err(e) => { + error!( + target: LOG_TARGET, + "Problem retrieving unconfirmed faux transactions: {}", e + ); + return; + }, + }; + all_faux_transactions.append(&mut unconfirmed_faux); + // Reorged faux transactions cannot be detected by excess signature, thus use last known confirmed transaction + // height or current tip height with safety margin to determine if these should be returned + let last_mined_transaction = match db.fetch_last_mined_transaction().await { + Ok(tx) => tx, + Err(_) => None, + }; + let height_with_margin = tip_height.saturating_sub(100); + let check_height = if let Some(tx) = last_mined_transaction { + tx.mined_height.unwrap_or(height_with_margin) + } else { + height_with_margin + }; + let mut confirmed_faux = match db.get_confirmed_faux_transactions_from_height(check_height).await { + Ok(txs) => txs, + Err(e) => { + error!( + target: LOG_TARGET, + "Problem retrieving confirmed faux transactions: {}", e + ); + return; + }, + }; + all_faux_transactions.append(&mut confirmed_faux); + + debug!( + target: LOG_TARGET, + "Checking {} faux transaction statuses", + all_faux_transactions.len() + ); + for tx in all_faux_transactions.into_iter() { + let (status, mined_height, block_hash) = match output_manager.get_output_statuses_by_tx_id(tx.tx_id).await { + Ok(s) => s, + Err(e) => { + error!(target: LOG_TARGET, "Problem retrieving output statuses: {}", e); + return; + }, + }; + if !status.iter().any(|s| s != &OutputStatus::Unspent) { + let mined_height = if let Some(height) = mined_height { + height + } else { + tip_height + }; + let mined_in_block: BlockHash = if let Some(hash) = block_hash { + hash + } else { + vec![0u8; 32] + }; + let is_valid = tip_height >= mined_height; + let is_confirmed = tip_height.saturating_sub(mined_height) >= + TransactionServiceConfig::default().num_confirmations_required; + let num_confirmations = tip_height - mined_height; + debug!( + target: LOG_TARGET, + "Updating faux transaction: TxId({}), mined_height({}), is_confirmed({}), num_confirmations({}), \ + is_valid({})", + tx.tx_id, + mined_height, + is_confirmed, + num_confirmations, + is_valid, + ); + let result = db + .set_transaction_mined_height( + tx.tx_id, + mined_height, + mined_in_block, + num_confirmations, + is_confirmed, + is_valid, + ) + .await; + if let Err(e) = result { + error!( + target: LOG_TARGET, + "Error setting faux transaction to mined confirmed: {}", e + ); + } else { + let transaction_event = match is_confirmed { + false => TransactionEvent::FauxTransactionUnconfirmed { + tx_id: tx.tx_id, + num_confirmations: 0, + is_valid, + }, + true => TransactionEvent::FauxTransactionConfirmed { + tx_id: tx.tx_id, + is_valid, + }, + }; + let _ = event_publisher.send(Arc::new(transaction_event)).map_err(|e| { + trace!( + target: LOG_TARGET, + "Error sending event, usually because there are no subscribers: {:?}", + e + ); + e + }); + } + } + } +} diff --git a/base_layer/wallet/src/transaction_service/tasks/check_imported_transaction_status.rs b/base_layer/wallet/src/transaction_service/tasks/check_imported_transaction_status.rs deleted file mode 100644 index fe1ea992b2..0000000000 --- a/base_layer/wallet/src/transaction_service/tasks/check_imported_transaction_status.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2021. 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 crate::{ - output_manager_service::{handle::OutputManagerHandle, storage::OutputStatus}, - transaction_service::{ - config::TransactionServiceConfig, - storage::database::{TransactionBackend, TransactionDatabase}, - }, -}; - -const LOG_TARGET: &str = "wallet::transaction_service::service"; - -pub async fn check_imported_transactions( - mut output_manager: OutputManagerHandle, - db: TransactionDatabase, -) { - let imported_transactions = match db.get_imported_transactions().await { - Ok(txs) => txs, - Err(e) => { - error!(target: LOG_TARGET, "Problem retrieving imported transactions: {}", e); - return; - }, - }; - - for tx in imported_transactions.into_iter() { - let status = match output_manager.get_output_statuses_by_tx_id(tx.tx_id).await { - Ok(s) => s, - Err(e) => { - error!(target: LOG_TARGET, "Problem retrieving output statuses: {}", e); - return; - }, - }; - if !status.iter().any(|s| s != &OutputStatus::Unspent) { - debug!( - target: LOG_TARGET, - "Faux Transaction (TxId: {}) updated to confirmed", tx.tx_id - ); - if let Err(e) = db - .set_transaction_mined_height( - tx.tx_id, - true, - 0, - vec![0u8; 32], - TransactionServiceConfig::default().num_confirmations_required, - true, - ) - .await - { - error!( - target: LOG_TARGET, - "Error setting faux transaction to mined confirmed: {}", e - ); - } - } - } -} diff --git a/base_layer/wallet/src/transaction_service/tasks/mod.rs b/base_layer/wallet/src/transaction_service/tasks/mod.rs index dce38a144c..292932156e 100644 --- a/base_layer/wallet/src/transaction_service/tasks/mod.rs +++ b/base_layer/wallet/src/transaction_service/tasks/mod.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. -pub mod check_imported_transaction_status; +pub mod check_faux_transaction_status; pub mod send_finalized_transaction; pub mod send_transaction_cancelled; pub mod send_transaction_reply; diff --git a/base_layer/wallet/src/transaction_service/tasks/send_finalized_transaction.rs b/base_layer/wallet/src/transaction_service/tasks/send_finalized_transaction.rs index 8ae6a31592..8a648beba7 100644 --- a/base_layer/wallet/src/transaction_service/tasks/send_finalized_transaction.rs +++ b/base_layer/wallet/src/transaction_service/tasks/send_finalized_transaction.rs @@ -30,7 +30,7 @@ use tari_comms_dht::{ domain_message::OutboundDomainMessage, outbound::{OutboundEncryption, OutboundMessageRequester, SendMessageResponse}, }; -use tari_core::transactions::{transaction::Transaction, transaction_protocol::proto}; +use tari_core::transactions::{transaction_components::Transaction, transaction_protocol::proto}; use tari_p2p::tari_message::TariMessageType; use crate::transaction_service::{ diff --git a/base_layer/wallet/src/utxo_scanner_service/service.rs b/base_layer/wallet/src/utxo_scanner_service/service.rs index 31af81c0c3..0f20d76fc7 100644 --- a/base_layer/wallet/src/utxo_scanner_service/service.rs +++ b/base_layer/wallet/src/utxo_scanner_service/service.rs @@ -52,7 +52,7 @@ pub const LOG_TARGET: &str = "wallet::utxo_scanning"; // Cache 1 days worth of headers. // TODO Determine a better strategy for maintaining a cache. Logarithmic sampling has been suggested but the problem // with it is that as you move on to the next block you need to resample say a 100 headers where a simple window like -// this only samples 1 header per new block. A ticket has been added to the backlog to think about this +// this only samples 1 header per new block. A ticket has been added to the backlog to think about this #LOGGED pub const SCANNED_BLOCK_CACHE_SIZE: u64 = 720; pub struct UtxoScannerService diff --git a/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs b/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs index a56bb36e4d..8aa78b087c 100644 --- a/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs +++ b/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs @@ -28,7 +28,10 @@ use std::{ use chrono::Utc; use futures::StreamExt; use log::*; -use tari_common_types::{transaction::TxId, types::HashOutput}; +use tari_common_types::{ + transaction::{ImportStatus, TxId}, + types::HashOutput, +}; use tari_comms::{peer_manager::NodeId, types::CommsPublicKey, PeerConnection}; use tari_core::{ base_node::rpc::BaseNodeWalletRpcClient, @@ -36,7 +39,7 @@ use tari_core::{ proto::base_node::SyncUtxosByBlockRequest, transactions::{ tari_amount::MicroTari, - transaction::{TransactionOutput, UnblindedOutput}, + transaction_components::{TransactionOutput, UnblindedOutput}, }, }; use tari_shutdown::ShutdownSignal; @@ -46,6 +49,7 @@ use tokio::sync::broadcast; use crate::{ error::WalletError, storage::database::WalletBackend, + transaction_service::error::{TransactionServiceError, TransactionStorageError}, utxo_scanner_service::{ error::UtxoScannerError, handle::UtxoScannerEvent, @@ -427,10 +431,12 @@ where TBackend: WalletBackend + 'static total_scanned += outputs.len(); let start = Instant::now(); - let found_outputs = self.scan_for_outputs(outputs).await?; + let (tx_id, found_outputs) = self.scan_for_outputs(outputs).await?; scan_for_outputs_profiling.push(start.elapsed()); - let (count, amount) = self.import_utxos_to_transaction_service(found_outputs).await?; + let (count, amount) = self + .import_utxos_to_transaction_service(found_outputs, tx_id, current_height) + .await?; self.resources .db @@ -481,17 +487,18 @@ where TBackend: WalletBackend + 'static async fn scan_for_outputs( &mut self, outputs: Vec, - ) -> Result, UtxoScannerError> { + ) -> Result<(TxId, Vec<(UnblindedOutput, String)>), UtxoScannerError> { let mut found_outputs: Vec<(UnblindedOutput, String)> = Vec::new(); + let tx_id = TxId::new_random(); if self.mode == UtxoScannerMode::Recovery { found_outputs.append( &mut self .resources .output_manager_service - .scan_for_recoverable_outputs(outputs.clone()) + .scan_for_recoverable_outputs(outputs.clone(), tx_id) .await? .into_iter() - .map(|v| (v, format!("Recovered on {}.", Utc::now().naive_utc()))) + .map(|uo| (uo, format!("Recovered output on {}.", Utc::now().naive_utc()))) .collect(), ); }; @@ -499,36 +506,54 @@ where TBackend: WalletBackend + 'static &mut self .resources .output_manager_service - .scan_outputs_for_one_sided_payments(outputs.clone()) + .scan_outputs_for_one_sided_payments(outputs.clone(), tx_id) .await? .into_iter() - .map(|v| { + .map(|uo| { ( - v, - format!("Detected one-sided transaction on {}.", Utc::now().naive_utc()), + uo, + format!("Detected one-sided transaction output on {}.", Utc::now().naive_utc()), ) }) .collect(), ); - Ok(found_outputs) + Ok((tx_id, found_outputs)) } async fn import_utxos_to_transaction_service( &mut self, utxos: Vec<(UnblindedOutput, String)>, + tx_id: TxId, + current_height: u64, ) -> Result<(u64, MicroTari), UtxoScannerError> { let mut num_recovered = 0u64; let mut total_amount = MicroTari::from(0); let source_public_key = self.resources.node_identity.public_key().clone(); - for uo in utxos { + for (uo, message) in utxos { match self - .import_unblinded_utxo_to_transaction_service(uo.0.clone(), &source_public_key, uo.1) + .import_unblinded_utxo_to_transaction_service( + uo.clone(), + &source_public_key, + message, + tx_id, + current_height, + ) .await { Ok(_) => { num_recovered = num_recovered.saturating_add(1); - total_amount += uo.0.value; + total_amount += uo.value; + }, + Err(WalletError::TransactionServiceError(TransactionServiceError::TransactionStorageError( + TransactionStorageError::DuplicateOutput, + ))) => { + info!( + target: LOG_TARGET, + "Recoverer attempted to add a duplicate output to the database for faux transaction ({}); \ + ignoring it as this is not a real error", + tx_id + ); }, Err(e) => return Err(UtxoScannerError::UtxoImportError(e.to_string())), } @@ -565,33 +590,38 @@ where TBackend: WalletBackend + 'static let _ = self.event_sender.send(event); } - /// A faux incoming transaction will be created to provide a record of the event of importing a UTXO. The TxId of - /// the generated transaction is returned. + /// A faux incoming transaction will be created to provide a record of the event of importing a scanned UTXO. The + /// TxId of the generated transaction is returned. pub async fn import_unblinded_utxo_to_transaction_service( &mut self, unblinded_output: UnblindedOutput, source_public_key: &CommsPublicKey, message: String, + tx_id: TxId, + current_height: u64, ) -> Result { let tx_id = self .resources .transaction_service - .import_utxo( + .import_utxo_with_status( unblinded_output.value, source_public_key.clone(), message, Some(unblinded_output.features.maturity), + ImportStatus::FauxUnconfirmed, + Some(tx_id), + Some(current_height), ) .await?; info!( target: LOG_TARGET, - "UTXO (Commitment: {}) imported into wallet", + "UTXO (Commitment: {}) imported into wallet as 'ImportStatus::FauxUnconfirmed'", unblinded_output .as_transaction_input(&self.resources.factories.commitment)? .commitment() .map_err(WalletError::TransactionError)? - .to_hex() + .to_hex(), ); Ok(tx_id) diff --git a/base_layer/wallet/src/wallet.rs b/base_layer/wallet/src/wallet.rs index 46801d53ab..446e4e4cb5 100644 --- a/base_layer/wallet/src/wallet.rs +++ b/base_layer/wallet/src/wallet.rs @@ -26,7 +26,7 @@ use digest::Digest; use log::*; use tari_common::configuration::bootstrap::ApplicationType; use tari_common_types::{ - transaction::TxId, + transaction::{ImportStatus, TxId}, types::{ComSignature, PrivateKey, PublicKey}, }; use tari_comms::{ @@ -43,7 +43,7 @@ use tari_core::{ covenants::Covenant, transactions::{ tari_amount::MicroTari, - transaction::{OutputFeatures, UnblindedOutput}, + transaction_components::{OutputFeatures, UnblindedOutput}, CryptoFactories, }, }; @@ -401,7 +401,15 @@ where let tx_id = self .transaction_service - .import_utxo(amount, source_public_key.clone(), message, Some(features.maturity)) + .import_utxo_with_status( + amount, + source_public_key.clone(), + message, + Some(features.maturity), + ImportStatus::Imported, + None, + None, + ) .await?; let commitment_hex = unblinded_output @@ -416,7 +424,7 @@ where info!( target: LOG_TARGET, - "UTXO (Commitment: {}) imported into wallet", commitment_hex + "UTXO (Commitment: {}) imported into wallet as 'ImportStatus::Imported'", commitment_hex ); Ok(tx_id) @@ -433,11 +441,14 @@ where ) -> Result { let tx_id = self .transaction_service - .import_utxo( + .import_utxo_with_status( unblinded_output.value, source_public_key.clone(), message, Some(unblinded_output.features.maturity), + ImportStatus::Imported, + None, + None, ) .await?; @@ -447,12 +458,12 @@ where info!( target: LOG_TARGET, - "UTXO (Commitment: {}) imported into wallet", + "UTXO (Commitment: {}) imported into wallet as 'ImportStatus::Imported'", unblinded_output .as_transaction_input(&self.factories.commitment)? .commitment() .map_err(WalletError::TransactionError)? - .to_hex() + .to_hex(), ); Ok(tx_id) diff --git a/base_layer/wallet/tests/output_manager_service_tests/service.rs b/base_layer/wallet/tests/output_manager_service_tests/service.rs index dbe7909342..35ec1dc1c0 100644 --- a/base_layer/wallet/tests/output_manager_service_tests/service.rs +++ b/base_layer/wallet/tests/output_manager_service_tests/service.rs @@ -41,7 +41,7 @@ use tari_core::{ fee::Fee, tari_amount::{uT, MicroTari}, test_helpers::{create_unblinded_output, TestParams as TestParamsHelpers}, - transaction::{OutputFeatures, OutputFlags}, + transaction_components::{OutputFeatures, OutputFlags}, transaction_protocol::sender::TransactionSenderMessage, weight::TransactionWeight, CryptoFactories, @@ -1904,12 +1904,12 @@ async fn test_get_status_by_tx_id() { let (mut oms, _, _shutdown, _, _, _, _, _) = setup_output_manager_service(backend, true).await; let (_ti, uo1) = make_input(&mut OsRng.clone(), MicroTari::from(10000), &factories.commitment); - oms.add_unvalidated_output(TxId::from(1), uo1, None).await.unwrap(); + oms.add_unvalidated_output(TxId::from(1u64), uo1, None).await.unwrap(); let (_ti, uo2) = make_input(&mut OsRng.clone(), MicroTari::from(10000), &factories.commitment); - oms.add_unvalidated_output(TxId::from(2), uo2, None).await.unwrap(); + oms.add_unvalidated_output(TxId::from(2u64), uo2, None).await.unwrap(); - let status = oms.get_output_statuses_by_tx_id(TxId::from(1)).await.unwrap(); + let (status, _, _) = oms.get_output_statuses_by_tx_id(TxId::from(1u64)).await.unwrap(); assert_eq!(status.len(), 1); assert_eq!(status[0], OutputStatus::EncumberedToBeReceived); diff --git a/base_layer/wallet/tests/support/comms_rpc.rs b/base_layer/wallet/tests/support/comms_rpc.rs index e1da122908..84f0041779 100644 --- a/base_layer/wallet/tests/support/comms_rpc.rs +++ b/base_layer/wallet/tests/support/comms_rpc.rs @@ -63,7 +63,7 @@ use tari_core::{ TransactionOutput as TransactionOutputProto, }, }, - transactions::transaction::{Transaction, TransactionOutput}, + transactions::transaction_components::{Transaction, TransactionOutput}, }; use tari_utilities::Hashable; use tokio::{sync::mpsc, time::sleep}; @@ -558,9 +558,6 @@ impl BaseNodeWalletService for BaseNodeWalletRpcMockService { &self, request: Request, ) -> Result, RpcStatus> { - // TODO: delay_lock is blocking any other RPC method from being called (as well as blocking an async task) - // until this method returns. - // Although this is sort of fine in tests it is probably unintentional let delay_lock = *acquire_lock!(self.state.response_delay); if let Some(delay) = delay_lock { sleep(delay).await; @@ -841,7 +838,7 @@ mod test { rpc::{BaseNodeWalletRpcClient, BaseNodeWalletRpcServer}, }, proto::base_node::{ChainMetadata, TipInfoResponse}, - transactions::transaction::Transaction, + transactions::transaction_components::Transaction, }; use tokio::time::Duration; diff --git a/base_layer/wallet/tests/support/output_manager_service_mock.rs b/base_layer/wallet/tests/support/output_manager_service_mock.rs index a409dd2c4c..1837418439 100644 --- a/base_layer/wallet/tests/support/output_manager_service_mock.rs +++ b/base_layer/wallet/tests/support/output_manager_service_mock.rs @@ -96,7 +96,10 @@ impl OutputManagerServiceMock { ) { info!(target: LOG_TARGET, "Handling Request: {}", request); match request { - OutputManagerRequest::ScanForRecoverableOutputs(requested_outputs) => { + OutputManagerRequest::ScanForRecoverableOutputs { + outputs: requested_outputs, + tx_id: _tx_id, + } => { let lock = acquire_lock!(self.state.recoverable_outputs); let outputs = (*lock) .clone() @@ -117,7 +120,10 @@ impl OutputManagerServiceMock { e }); }, - OutputManagerRequest::ScanOutputs(_to) => { + OutputManagerRequest::ScanOutputs { + outputs: _to, + tx_id: _tx_id, + } => { let lock = acquire_lock!(self.state.one_sided_payments); let outputs = (*lock).clone(); let _ = reply_tx diff --git a/base_layer/wallet/tests/support/transaction_service_mock.rs b/base_layer/wallet/tests/support/transaction_service_mock.rs index cce11b5707..f4bb390242 100644 --- a/base_layer/wallet/tests/support/transaction_service_mock.rs +++ b/base_layer/wallet/tests/support/transaction_service_mock.rs @@ -95,9 +95,9 @@ impl TransactionServiceMock { info!(target: LOG_TARGET, "Handling Request: {}", request); match request { - TransactionServiceRequest::ImportUtxo(_, _, _, _) => { + TransactionServiceRequest::ImportUtxoWithStatus { .. } => { let _ = reply_tx - .send(Ok(TransactionServiceResponse::UtxoImported(TxId::from(42)))) + .send(Ok(TransactionServiceResponse::UtxoImported(TxId::from(42u64)))) .map_err(|e| { warn!(target: LOG_TARGET, "Failed to send reply"); e diff --git a/base_layer/wallet/tests/support/utils.rs b/base_layer/wallet/tests/support/utils.rs index 30179dc8bf..20367c05ff 100644 --- a/base_layer/wallet/tests/support/utils.rs +++ b/base_layer/wallet/tests/support/utils.rs @@ -25,7 +25,7 @@ use tari_common_types::types::{CommitmentFactory, PrivateKey, PublicKey}; use tari_core::transactions::{ tari_amount::MicroTari, test_helpers::{create_unblinded_output, TestParams as TestParamsHelpers}, - transaction::{OutputFeatures, TransactionInput, UnblindedOutput}, + transaction_components::{OutputFeatures, TransactionInput, UnblindedOutput}, }; use tari_crypto::{ keys::{PublicKey as PublicKeyTrait, SecretKey as SecretKeyTrait}, diff --git a/base_layer/wallet/tests/transaction_service_tests/service.rs b/base_layer/wallet/tests/transaction_service_tests/service.rs index b145f8ef8c..c3c2705591 100644 --- a/base_layer/wallet/tests/transaction_service_tests/service.rs +++ b/base_layer/wallet/tests/transaction_service_tests/service.rs @@ -38,7 +38,7 @@ use prost::Message; use rand::rngs::OsRng; use tari_common_types::{ chain_metadata::ChainMetadata, - transaction::{TransactionDirection, TransactionStatus, TxId}, + transaction::{ImportStatus, TransactionDirection, TransactionStatus, TxId}, types::{PrivateKey, PublicKey, Signature}, }; use tari_comms::{ @@ -76,7 +76,7 @@ use tari_core::{ fee::Fee, tari_amount::*, test_helpers::{create_unblinded_output, TestParams as TestParamsHelpers}, - transaction::{KernelBuilder, KernelFeatures, OutputFeatures, Transaction}, + transaction_components::{KernelBuilder, KernelFeatures, OutputFeatures, Transaction}, transaction_protocol::{ proto::protocol as proto, recipient::RecipientSignedMessage, @@ -908,7 +908,7 @@ fn recover_one_sided_transaction() { let outputs = completed_tx.transaction.body.outputs().clone(); let unblinded = bob_oms - .scan_outputs_for_one_sided_payments(outputs.clone()) + .scan_outputs_for_one_sided_payments(outputs.clone(), TxId::new_random()) .await .unwrap(); // Bob should be able to claim 1 output. @@ -916,7 +916,10 @@ fn recover_one_sided_transaction() { assert_eq!(value, unblinded[0].value); // Should ignore already existing outputs - let unblinded = bob_oms.scan_outputs_for_one_sided_payments(outputs).await.unwrap(); + let unblinded = bob_oms + .scan_outputs_for_one_sided_payments(outputs, TxId::new_random()) + .await + .unwrap(); assert!(unblinded.is_empty()); }); } @@ -1934,12 +1937,11 @@ fn test_power_mode_updates() { status: TransactionStatus::Completed, message: "Yo!".to_string(), timestamp: Utc::now().naive_utc(), - cancelled: false, + cancelled: None, direction: TransactionDirection::Outbound, coinbase_block_height: None, send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), confirmations: None, mined_height: None, @@ -1956,12 +1958,11 @@ fn test_power_mode_updates() { status: TransactionStatus::Completed, message: "Yo!".to_string(), timestamp: Utc::now().naive_utc(), - cancelled: false, + cancelled: None, direction: TransactionDirection::Outbound, coinbase_block_height: None, send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), confirmations: None, mined_height: None, @@ -3483,11 +3484,9 @@ fn test_coinbase_generation_and_monitoring() { let tx = completed_txs.get(&tx_id1).unwrap(); assert_eq!(tx.status, TransactionStatus::Coinbase); - assert!(tx.valid); let tx = completed_txs.get(&tx_id2b).unwrap(); assert_eq!(tx.status, TransactionStatus::MinedUnconfirmed); - assert!(tx.valid); // Now we will have tx_id2b becoming confirmed let _ = transaction_query_batch_responses.pop(); @@ -3533,7 +3532,6 @@ fn test_coinbase_generation_and_monitoring() { let tx = completed_txs.get(&tx_id2b).unwrap(); assert_eq!(tx.status, TransactionStatus::MinedConfirmed); - assert!(tx.valid); } #[test] @@ -3545,9 +3543,6 @@ fn test_coinbase_abandoned() { let mut alice_ts_interface = setup_transaction_service_no_comms(&mut runtime, factories, connection, None); let mut alice_event_stream = alice_ts_interface.transaction_service_handle.get_event_stream(); - alice_ts_interface - .base_node_rpc_mock_state - .set_response_delay(Some(Duration::from_secs(1))); let block_height_a = 10; @@ -3640,15 +3635,14 @@ fn test_coinbase_abandoned() { assert_eq!(count, 1, "Expected a TransactionCancelled event"); }); - let tx = runtime + let txs = runtime .block_on( alice_ts_interface .transaction_service_handle - .get_completed_transaction(tx_id1), + .get_cancelled_completed_transactions(), ) .unwrap(); - assert_eq!(tx.status, TransactionStatus::Coinbase); - assert!(!tx.valid); + assert!(txs.get(&tx_id1).is_some()); let balance = runtime .block_on(alice_ts_interface.output_manager_service_handle.get_balance()) @@ -3684,7 +3678,7 @@ fn test_coinbase_abandoned() { .get_completed_transactions(), ) .unwrap(); - assert_eq!(transactions.len(), 2); + assert_eq!(transactions.len(), 1); let tx_id2 = transactions .values() .find(|tx| tx.amount == fees2 + reward2) @@ -3698,13 +3692,22 @@ fn test_coinbase_abandoned() { fees2 + reward2 ); - let transaction_query_batch_responses = vec![TxQueryBatchResponseProto { - signature: Some(SignatureProto::from(tx2.first_kernel_excess_sig().unwrap().clone())), - location: TxLocationProto::from(TxLocation::Mined) as i32, - block_hash: Some([11u8; 16].to_vec()), - confirmations: 2, - block_height: block_height_b, - }]; + let transaction_query_batch_responses = vec![ + TxQueryBatchResponseProto { + signature: Some(SignatureProto::from(tx1.first_kernel_excess_sig().unwrap().clone())), + location: TxLocationProto::from(TxLocation::NotStored) as i32, + block_hash: None, + confirmations: 0, + block_height: 0, + }, + TxQueryBatchResponseProto { + signature: Some(SignatureProto::from(tx2.first_kernel_excess_sig().unwrap().clone())), + location: TxLocationProto::from(TxLocation::Mined) as i32, + block_hash: Some([11u8; 16].to_vec()), + confirmations: 2, + block_height: block_height_b, + }, + ]; let batch_query_response = TxQueryBatchResponsesProto { responses: transaction_query_batch_responses, @@ -3724,6 +3727,7 @@ fn test_coinbase_abandoned() { block_headers.insert(i, block_header.clone()); } alice_ts_interface.base_node_rpc_mock_state.set_blocks(block_headers); + runtime .block_on(alice_ts_interface.transaction_service_handle.validate_transactions()) .expect("Validation should start"); @@ -3796,6 +3800,7 @@ fn test_coinbase_abandoned() { block_headers.insert(i, block_header.clone()); } alice_ts_interface.base_node_rpc_mock_state.set_blocks(block_headers); + runtime .block_on(alice_ts_interface.transaction_service_handle.validate_transactions()) .expect("Validation should start"); @@ -3836,15 +3841,16 @@ fn test_coinbase_abandoned() { ); }); - let tx = runtime + let txs = runtime .block_on( alice_ts_interface .transaction_service_handle - .get_completed_transaction(tx_id2), + .get_cancelled_completed_transactions(), ) .unwrap(); - assert_eq!(tx.status, TransactionStatus::Coinbase); - assert!(!tx.valid); + + assert!(txs.get(&tx_id1).is_some()); + assert!(txs.get(&tx_id2).is_some()); let balance = runtime .block_on(alice_ts_interface.output_manager_service_handle.get_balance()) @@ -3900,7 +3906,7 @@ fn test_coinbase_abandoned() { .expect("Validation should start"); runtime.block_on(async { - let delay = sleep(Duration::from_secs(30)); + let delay = sleep(Duration::from_secs(60)); tokio::pin!(delay); let mut count = 0usize; loop { @@ -5274,12 +5280,11 @@ fn broadcast_all_completed_transactions_on_startup() { status: TransactionStatus::Completed, message: "Yo!".to_string(), timestamp: Utc::now().naive_utc(), - cancelled: false, + cancelled: None, direction: TransactionDirection::Outbound, coinbase_block_height: None, send_count: 0, last_send_timestamp: None, - valid: true, transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), confirmations: None, mined_height: None, @@ -5394,52 +5399,115 @@ fn test_update_faux_tx_on_oms_validation() { let mut alice_ts_interface = setup_transaction_service_no_comms(&mut runtime, factories.clone(), connection, None); - let tx_id = runtime - .block_on(alice_ts_interface.transaction_service_handle.import_utxo( + let tx_id_1 = runtime + .block_on(alice_ts_interface.transaction_service_handle.import_utxo_with_status( MicroTari::from(10000), alice_ts_interface.base_node_identity.public_key().clone(), "blah".to_string(), None, + ImportStatus::Imported, + None, + None, )) .unwrap(); - - let (_ti, uo) = make_input(&mut OsRng.clone(), MicroTari::from(10000), &factories.commitment); - runtime - .block_on( - alice_ts_interface - .output_manager_service_handle - .add_output_with_tx_id(tx_id, uo, None), - ) + let tx_id_2 = runtime + .block_on(alice_ts_interface.transaction_service_handle.import_utxo_with_status( + MicroTari::from(20000), + alice_ts_interface.base_node_identity.public_key().clone(), + "one-sided 1".to_string(), + None, + ImportStatus::FauxUnconfirmed, + None, + None, + )) .unwrap(); - - let transaction = runtime - .block_on(alice_ts_interface.transaction_service_handle.get_any_transaction(tx_id)) - .unwrap() + let tx_id_3 = runtime + .block_on(alice_ts_interface.transaction_service_handle.import_utxo_with_status( + MicroTari::from(30000), + alice_ts_interface.base_node_identity.public_key().clone(), + "one-sided 2".to_string(), + None, + ImportStatus::FauxConfirmed, + None, + None, + )) .unwrap(); - if let WalletTransaction::Completed(tx) = transaction { - assert_eq!(tx.status, TransactionStatus::Imported); - } else { - panic!("Should find a complete transaction"); + + let (_ti, uo_1) = make_input(&mut OsRng.clone(), MicroTari::from(10000), &factories.commitment); + let (_ti, uo_2) = make_input(&mut OsRng.clone(), MicroTari::from(20000), &factories.commitment); + let (_ti, uo_3) = make_input(&mut OsRng.clone(), MicroTari::from(30000), &factories.commitment); + for (tx_id, uo) in [(tx_id_1, uo_1), (tx_id_2, uo_2), (tx_id_3, uo_3)] { + runtime + .block_on( + alice_ts_interface + .output_manager_service_handle + .add_output_with_tx_id(tx_id, uo, None), + ) + .unwrap(); } + for tx_id in [tx_id_1, tx_id_2, tx_id_3] { + let transaction = runtime + .block_on(alice_ts_interface.transaction_service_handle.get_any_transaction(tx_id)) + .unwrap() + .unwrap(); + if tx_id == tx_id_1 { + if let WalletTransaction::Completed(tx) = &transaction { + assert_eq!(tx.status, TransactionStatus::Imported); + } else { + panic!("Should find a complete Imported transaction"); + } + } + if tx_id == tx_id_2 { + if let WalletTransaction::Completed(tx) = &transaction { + assert_eq!(tx.status, TransactionStatus::FauxUnconfirmed); + } else { + panic!("Should find a complete FauxUnconfirmed transaction"); + } + } + if tx_id == tx_id_3 { + if let WalletTransaction::Completed(tx) = &transaction { + assert_eq!(tx.status, TransactionStatus::FauxConfirmed); + } else { + panic!("Should find a complete FauxConfirmed transaction"); + } + } + } + + // This will change the status of the imported transaction alice_ts_interface .output_manager_service_event_publisher - .send(Arc::new(OutputManagerEvent::TxoValidationSuccess(1))) + .send(Arc::new(OutputManagerEvent::TxoValidationSuccess(1u64))) .unwrap(); - let mut found = false; + let mut found_imported = false; + let mut found_faux_unconfirmed = false; + let mut found_faux_confirmed = false; for _ in 0..20 { runtime.block_on(async { sleep(Duration::from_secs(1)).await }); - let transaction = runtime - .block_on(alice_ts_interface.transaction_service_handle.get_any_transaction(tx_id)) - .unwrap() - .unwrap(); - if let WalletTransaction::Completed(tx) = transaction { - if tx.status == TransactionStatus::MinedConfirmed { - found = true; - break; + for tx_id in [tx_id_1, tx_id_2, tx_id_3] { + let transaction = runtime + .block_on(alice_ts_interface.transaction_service_handle.get_any_transaction(tx_id)) + .unwrap() + .unwrap(); + if let WalletTransaction::Completed(tx) = transaction { + if tx_id == tx_id_1 && tx.status == TransactionStatus::FauxUnconfirmed && !found_imported { + found_imported = true; + } + if tx_id == tx_id_2 && tx.status == TransactionStatus::FauxUnconfirmed && !found_faux_unconfirmed { + found_faux_unconfirmed = true; + } + if tx_id == tx_id_3 && tx.status == TransactionStatus::FauxConfirmed && !found_faux_confirmed { + found_faux_confirmed = true; + } } } + if found_imported && found_faux_unconfirmed && found_faux_confirmed { + break; + } } - assert!(found, "Should have found the updated status"); + assert!( + found_imported && found_faux_unconfirmed && found_faux_confirmed, + "Should have found the updated statuses" + ); } diff --git a/base_layer/wallet/tests/transaction_service_tests/storage.rs b/base_layer/wallet/tests/transaction_service_tests/storage.rs index 72b2cf2052..145acf2f23 100644 --- a/base_layer/wallet/tests/transaction_service_tests/storage.rs +++ b/base_layer/wallet/tests/transaction_service_tests/storage.rs @@ -35,7 +35,7 @@ use tari_core::{ transactions::{ tari_amount::{uT, MicroTari}, test_helpers::{create_unblinded_output, TestParams}, - transaction::{OutputFeatures, Transaction}, + transaction_components::{OutputFeatures, Transaction}, transaction_protocol::sender::TransactionSenderMessage, CryptoFactories, ReceiverTransactionProtocol, @@ -53,7 +53,13 @@ use tari_wallet::{ test_utils::create_consensus_constants, transaction_service::storage::{ database::{DbKeyValuePair, TransactionBackend, TransactionDatabase, WriteOperation}, - models::{CompletedTransaction, InboundTransaction, OutboundTransaction, WalletTransaction}, + models::{ + CompletedTransaction, + InboundTransaction, + OutboundTransaction, + TxCancellationReason, + WalletTransaction, + }, sqlite_db::TransactionServiceSqliteDatabase, }, }; @@ -266,12 +272,12 @@ pub fn test_db_backend(backend: T) { }, message: messages[i].clone(), timestamp: Utc::now().naive_utc(), - cancelled: false, + cancelled: None, direction: TransactionDirection::Outbound, coinbase_block_height: None, send_count: 0, last_send_timestamp: None, - valid: true, + transaction_signature: tx.first_kernel_excess_sig().unwrap_or(&Signature::default()).clone(), confirmations: None, mined_height: None, @@ -323,7 +329,7 @@ pub fn test_db_backend(backend: T) { assert!(runtime.block_on(db.fetch_last_mined_transaction()).unwrap().is_none()); runtime - .block_on(db.set_transaction_mined_height(completed_txs[0].tx_id, true, 10, [0u8; 16].to_vec(), 5, true)) + .block_on(db.set_transaction_mined_height(completed_txs[0].tx_id, 10, [0u8; 16].to_vec(), 5, true, false)) .unwrap(); assert_eq!( @@ -365,7 +371,7 @@ pub fn test_db_backend(backend: T) { .block_on(db.get_cancelled_completed_transaction(cancelled_tx_id)) .is_err()); runtime - .block_on(db.reject_completed_transaction(cancelled_tx_id)) + .block_on(db.reject_completed_transaction(cancelled_tx_id, TxCancellationReason::Unknown)) .unwrap(); let completed_txs_map = runtime.block_on(db.get_completed_transactions()).unwrap(); assert_eq!(completed_txs_map.len(), num_completed_txs - 1); @@ -596,7 +602,7 @@ async fn import_tx_and_read_it_from_db() { let sqlite_db = TransactionServiceSqliteDatabase::new(connection, Some(cipher)); let transaction = CompletedTransaction::new( - TxId::from(1), + TxId::from(1u64), PublicKey::default(), PublicKey::default(), MicroTari::from(100000), @@ -605,25 +611,94 @@ async fn import_tx_and_read_it_from_db() { Vec::new(), Vec::new(), Vec::new(), - PrivateKey::default(), - PrivateKey::default(), + PrivateKey::random(&mut OsRng), + PrivateKey::random(&mut OsRng), ), TransactionStatus::Imported, "message".to_string(), Utc::now().naive_utc(), TransactionDirection::Inbound, Some(0), + Some(5), ); sqlite_db .write(WriteOperation::Insert(DbKeyValuePair::CompletedTransaction( - TxId::from(1), + TxId::from(1u64), Box::new(transaction), ))) .unwrap(); - let db_tx = sqlite_db.fetch_imported_transactions().unwrap(); + let transaction = CompletedTransaction::new( + TxId::from(2u64), + PublicKey::default(), + PublicKey::default(), + MicroTari::from(100000), + MicroTari::from(0), + Transaction::new( + Vec::new(), + Vec::new(), + Vec::new(), + PrivateKey::random(&mut OsRng), + PrivateKey::random(&mut OsRng), + ), + TransactionStatus::FauxUnconfirmed, + "message".to_string(), + Utc::now().naive_utc(), + TransactionDirection::Inbound, + Some(0), + Some(6), + ); + sqlite_db + .write(WriteOperation::Insert(DbKeyValuePair::CompletedTransaction( + TxId::from(2u64), + Box::new(transaction), + ))) + .unwrap(); + + let transaction = CompletedTransaction::new( + TxId::from(3u64), + PublicKey::default(), + PublicKey::default(), + MicroTari::from(100000), + MicroTari::from(0), + Transaction::new( + Vec::new(), + Vec::new(), + Vec::new(), + PrivateKey::random(&mut OsRng), + PrivateKey::random(&mut OsRng), + ), + TransactionStatus::FauxConfirmed, + "message".to_string(), + Utc::now().naive_utc(), + TransactionDirection::Inbound, + Some(0), + Some(7), + ); + + sqlite_db + .write(WriteOperation::Insert(DbKeyValuePair::CompletedTransaction( + TxId::from(3u64), + Box::new(transaction), + ))) + .unwrap(); + + let db_tx = sqlite_db.fetch_imported_transactions().unwrap(); assert_eq!(db_tx.len(), 1); assert_eq!(db_tx.first().unwrap().tx_id, TxId::from(1)); + assert_eq!(db_tx.first().unwrap().mined_height, Some(5)); + + let db_tx = sqlite_db.fetch_unconfirmed_faux_transactions().unwrap(); + assert_eq!(db_tx.len(), 1); + assert_eq!(db_tx.first().unwrap().tx_id, TxId::from(2)); + assert_eq!(db_tx.first().unwrap().mined_height, Some(6)); + + let db_tx = sqlite_db.fetch_confirmed_faux_transactions_from_height(10).unwrap(); + assert_eq!(db_tx.len(), 0); + let db_tx = sqlite_db.fetch_confirmed_faux_transactions_from_height(4).unwrap(); + assert_eq!(db_tx.len(), 1); + assert_eq!(db_tx.first().unwrap().tx_id, TxId::from(3)); + assert_eq!(db_tx.first().unwrap().mined_height, Some(7)); } diff --git a/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs b/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs index 97f55d1c1e..5954f8d7db 100644 --- a/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs +++ b/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs @@ -77,7 +77,7 @@ use tari_wallet::{ service::TransactionServiceResources, storage::{ database::TransactionDatabase, - models::CompletedTransaction, + models::{CompletedTransaction, TxCancellationReason}, sqlite_db::TransactionServiceSqliteDatabase, }, }, @@ -176,7 +176,6 @@ pub async fn setup() -> ( pub async fn add_transaction_to_database( tx_id: TxId, amount: MicroTari, - valid: bool, status: Option, coinbase_block_height: Option, db: TransactionDatabase, @@ -185,7 +184,7 @@ pub async fn add_transaction_to_database( let (_utxo, uo0) = make_input(&mut OsRng, 10 * amount, &factories.commitment); let (txs1, _uou1) = schema_to_transaction(&[txn_schema!(from: vec![uo0.clone()], to: vec![amount])]); let tx1 = (*txs1[0]).clone(); - let mut completed_tx1 = CompletedTransaction::new( + let completed_tx1 = CompletedTransaction::new( tx_id, CommsPublicKey::default(), CommsPublicKey::default(), @@ -197,8 +196,8 @@ pub async fn add_transaction_to_database( Utc::now().naive_local(), TransactionDirection::Outbound, coinbase_block_height, + None, ); - completed_tx1.valid = valid; db.insert_completed_transaction(tx_id, completed_tx1).await.unwrap(); } @@ -252,7 +251,7 @@ async fn tx_broadcast_protocol_submit_success() { // Fails because there is no transaction in the database to be broadcast assert!(join_handle.await.unwrap().is_err()); - add_transaction_to_database(1.into(), 1 * T, true, None, None, resources.db.clone()).await; + add_transaction_to_database(1.into(), 1 * T, None, None, resources.db.clone()).await; let db_completed_tx = resources.db.get_completed_transaction(1.into()).await.unwrap(); assert!(db_completed_tx.confirmations.is_none()); @@ -321,7 +320,7 @@ async fn tx_broadcast_protocol_submit_rejection() { ) = setup().await; let mut event_stream = resources.event_publisher.subscribe(); - add_transaction_to_database(1.into(), 1 * T, true, None, None, resources.db.clone()).await; + add_transaction_to_database(1.into(), 1 * T, None, None, resources.db.clone()).await; let timeout_update_watch = Watch::new(Duration::from_secs(1)); wallet_connectivity.notify_base_node_set(server_node_identity.to_peer()); // Now we add the connection @@ -391,7 +390,7 @@ async fn tx_broadcast_protocol_restart_protocol_as_query() { wallet_connectivity, ) = setup().await; - add_transaction_to_database(1.into(), 1 * T, true, None, None, resources.db.clone()).await; + add_transaction_to_database(1.into(), 1 * T, None, None, resources.db.clone()).await; // Set Base Node query response to be not stored, as if the base node does not have the tx in its pool rpc_service_state.set_transaction_query_response(TxQueryResponse { @@ -479,7 +478,7 @@ async fn tx_broadcast_protocol_submit_success_followed_by_rejection() { ) = setup().await; let mut event_stream = resources.event_publisher.subscribe(); - add_transaction_to_database(1.into(), 1 * T, true, None, None, resources.db.clone()).await; + add_transaction_to_database(1.into(), 1 * T, None, None, resources.db.clone()).await; resources.config.transaction_mempool_resubmission_window = Duration::from_secs(3); resources.config.broadcast_monitoring_timeout = Duration::from_secs(60); @@ -567,7 +566,7 @@ async fn tx_broadcast_protocol_submit_already_mined() { _transaction_event_receiver, wallet_connectivity, ) = setup().await; - add_transaction_to_database(1.into(), 1 * T, true, None, None, resources.db.clone()).await; + add_transaction_to_database(1.into(), 1 * T, None, None, resources.db.clone()).await; // Set Base Node to respond with AlreadyMined rpc_service_state.set_submit_transaction_response(TxSubmissionResponse { @@ -632,7 +631,7 @@ async fn tx_broadcast_protocol_submit_and_base_node_gets_changed() { wallet_connectivity, ) = setup().await; - add_transaction_to_database(1.into(), 1 * T, true, None, None, resources.db.clone()).await; + add_transaction_to_database(1.into(), 1 * T, None, None, resources.db.clone()).await; resources.config.broadcast_monitoring_timeout = Duration::from_secs(60); @@ -736,7 +735,6 @@ async fn tx_validation_protocol_tx_becomes_mined_unconfirmed_then_confirmed() { add_transaction_to_database( 1.into(), 1 * T, - true, Some(TransactionStatus::Broadcast), None, resources.db.clone(), @@ -745,7 +743,6 @@ async fn tx_validation_protocol_tx_becomes_mined_unconfirmed_then_confirmed() { add_transaction_to_database( 2.into(), 2 * T, - true, Some(TransactionStatus::Completed), None, resources.db.clone(), @@ -890,7 +887,6 @@ async fn tx_revalidation() { add_transaction_to_database( 1.into(), 1 * T, - true, Some(TransactionStatus::Completed), None, resources.db.clone(), @@ -899,7 +895,6 @@ async fn tx_revalidation() { add_transaction_to_database( 2.into(), 2 * T, - true, Some(TransactionStatus::Completed), None, resources.db.clone(), @@ -1025,7 +1020,6 @@ async fn tx_validation_protocol_reorg() { add_transaction_to_database( i.into(), i * T, - true, Some(TransactionStatus::Broadcast), None, resources.db.clone(), @@ -1036,16 +1030,15 @@ async fn tx_validation_protocol_reorg() { add_transaction_to_database( 6.into(), 6 * T, - true, Some(TransactionStatus::Coinbase), Some(8), resources.db.clone(), ) .await; + add_transaction_to_database( 7.into(), 7 * T, - true, Some(TransactionStatus::Coinbase), Some(9), resources.db.clone(), @@ -1279,10 +1272,14 @@ async fn tx_validation_protocol_reorg() { ); assert_eq!(completed_txs.get(&5.into()).cloned().unwrap().mined_height.unwrap(), 8); assert_eq!(completed_txs.get(&5.into()).cloned().unwrap().confirmations.unwrap(), 1); - - assert!(!completed_txs.get(&6.into()).unwrap().valid); assert_eq!( completed_txs.get(&7.into()).unwrap().status, TransactionStatus::Coinbase ); + let cancelled_completed_txs = resources.db.get_cancelled_completed_transactions().await.unwrap(); + + assert!(matches!( + cancelled_completed_txs.get(&6.into()).unwrap().cancelled, + Some(TxCancellationReason::AbandonedCoinbase) + )); } diff --git a/base_layer/wallet/tests/utxo_scanner.rs b/base_layer/wallet/tests/utxo_scanner.rs index bfef914141..bca4d4f215 100644 --- a/base_layer/wallet/tests/utxo_scanner.rs +++ b/base_layer/wallet/tests/utxo_scanner.rs @@ -36,7 +36,7 @@ use tari_core::{ base_node::rpc::BaseNodeWalletRpcServer, blocks::BlockHeader, proto::base_node::{ChainMetadata, TipInfoResponse}, - transactions::{tari_amount::MicroTari, transaction::UnblindedOutput, CryptoFactories}, + transactions::{tari_amount::MicroTari, transaction_components::UnblindedOutput, CryptoFactories}, }; use tari_key_manager::cipher_seed::CipherSeed; use tari_service_framework::reply_channel; diff --git a/base_layer/wallet/tests/wallet.rs b/base_layer/wallet/tests/wallet.rs index f122812223..d0ff92ea36 100644 --- a/base_layer/wallet/tests/wallet.rs +++ b/base_layer/wallet/tests/wallet.rs @@ -45,8 +45,10 @@ use std::{panic, path::Path, sync::Arc, time::Duration}; use rand::rngs::OsRng; +use support::{comms_and_services::get_next_memory_address, utils::make_input}; use tari_common_types::{ chain_metadata::ChainMetadata, + transaction::TransactionStatus, types::{PrivateKey, PublicKey}, }; use tari_comms::{ @@ -55,11 +57,14 @@ use tari_comms::{ types::CommsPublicKey, }; use tari_comms_dht::{store_forward::SafConfig, DhtConfig}; -use tari_core::transactions::{ - tari_amount::{uT, MicroTari}, - test_helpers::{create_unblinded_output, TestParams}, - transaction::OutputFeatures, - CryptoFactories, +use tari_core::{ + covenants::Covenant, + transactions::{ + tari_amount::{uT, MicroTari}, + test_helpers::{create_unblinded_output, TestParams}, + transaction_components::OutputFeatures, + CryptoFactories, + }, }; use tari_crypto::{ inputs, @@ -97,11 +102,7 @@ use tari_wallet::{ }; use tempfile::tempdir; use tokio::{runtime::Runtime, time::sleep}; - pub mod support; -use support::{comms_and_services::get_next_memory_address, utils::make_input}; -use tari_common_types::transaction::TransactionStatus; -use tari_core::covenants::Covenant; use tari_wallet::output_manager_service::storage::database::OutputManagerDatabase; fn create_peer(public_key: CommsPublicKey, net_address: Multiaddr) -> Peer { @@ -763,10 +764,10 @@ async fn test_import_utxo() { .import_utxo( utxo.value, &utxo.spending_key, - script, - input, + script.clone(), + input.clone(), base_node_identity.public_key(), - features, + features.clone(), "Testing".to_string(), utxo.metadata_signature.clone(), &p.script_private_key, diff --git a/base_layer/wallet_ffi/Cargo.toml b/base_layer/wallet_ffi/Cargo.toml index 8b2e2dff53..6c42baac94 100644 --- a/base_layer/wallet_ffi/Cargo.toml +++ b/base_layer/wallet_ffi/Cargo.toml @@ -3,18 +3,18 @@ name = "tari_wallet_ffi" authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet C FFI bindings" license = "BSD-3-Clause" -version = "0.27.3" +version = "0.28.0" edition = "2018" [dependencies] -tari_comms = { version = "^0.27", path = "../../comms", features = ["c_integration"]} -tari_comms_dht = { version = "^0.27", path = "../../comms/dht", default-features = false } +tari_comms = { version = "^0.28", path = "../../comms", features = ["c_integration"]} +tari_comms_dht = { version = "^0.28", path = "../../comms/dht", default-features = false } tari_common_types = {path="../common_types"} tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } -tari_key_manager = { version = "^0.27", path = "../key_manager" } -tari_p2p = { version = "^0.27", path = "../p2p" } -tari_wallet = { version = "^0.27", path = "../wallet", features = ["c_integration"]} -tari_shutdown = { version = "^0.27", path = "../../infrastructure/shutdown" } +tari_key_manager = { version = "^0.28", path = "../key_manager" } +tari_p2p = { version = "^0.28", path = "../p2p" } +tari_wallet = { version = "^0.28", path = "../wallet", features = ["c_integration"]} +tari_shutdown = { version = "^0.28", path = "../../infrastructure/shutdown" } tari_utilities = "^0.3" chrono = { version = "0.4.19", default-features = false, features = ["serde"] } @@ -39,7 +39,7 @@ security-framework = "2.4.2" [dependencies.tari_core] path = "../../base_layer/core" -version = "^0.27" +version = "^0.28" default-features = false features = ["transactions"] @@ -49,7 +49,7 @@ crate-type = ["staticlib","cdylib"] [dev-dependencies] tempfile = "3.1.0" lazy_static = "1.3.0" -tari_key_manager = { version = "^0.27", path = "../key_manager" } -tari_common_types = { version = "^0.27", path = "../../base_layer/common_types"} -tari_test_utils = { version = "^0.27", path = "../../infrastructure/test_utils"} +tari_key_manager = { version = "^0.28", path = "../key_manager" } +tari_common_types = { version = "^0.28", path = "../../base_layer/common_types"} +tari_test_utils = { version = "^0.28", path = "../../infrastructure/test_utils"} tari_service_framework = { path = "../../base_layer/service_framework" } diff --git a/base_layer/wallet_ffi/src/callback_handler.rs b/base_layer/wallet_ffi/src/callback_handler.rs index f3a4c7d3b5..4cbaaa5232 100644 --- a/base_layer/wallet_ffi/src/callback_handler.rs +++ b/base_layer/wallet_ffi/src/callback_handler.rs @@ -40,6 +40,12 @@ //! `callback_transaction_mined` - This will be called when a Broadcast transaction is detected as mined via a base //! node request //! +//! `callback_faux_transaction_confirmed` - This will be called when an imported output, recovered output or one-sided +//! transaction is detected as mined +//! +//! `callback_faux_transaction_unconfirmed` - This will be called when a recovered output or one-sided transaction is +//! freshly imported or when an imported transaction transitions from Imported to FauxUnconfirmed +//! //! `callback_discovery_process_complete` - This will be called when a `send_transacion(..)` call is made to a peer //! whose address is not known and a discovery process must be conducted. The outcome of the discovery process is //! relayed via this callback @@ -80,6 +86,8 @@ where TBackend: TransactionBackend + 'static callback_transaction_broadcast: unsafe extern "C" fn(*mut CompletedTransaction), callback_transaction_mined: unsafe extern "C" fn(*mut CompletedTransaction), callback_transaction_mined_unconfirmed: unsafe extern "C" fn(*mut CompletedTransaction, u64), + callback_faux_transaction_confirmed: unsafe extern "C" fn(*mut CompletedTransaction), + callback_faux_transaction_unconfirmed: unsafe extern "C" fn(*mut CompletedTransaction, u64), callback_direct_send_result: unsafe extern "C" fn(u64, bool), callback_store_and_forward_send_result: unsafe extern "C" fn(u64, bool), callback_transaction_cancellation: unsafe extern "C" fn(*mut CompletedTransaction, u64), @@ -118,6 +126,8 @@ where TBackend: TransactionBackend + 'static callback_transaction_broadcast: unsafe extern "C" fn(*mut CompletedTransaction), callback_transaction_mined: unsafe extern "C" fn(*mut CompletedTransaction), callback_transaction_mined_unconfirmed: unsafe extern "C" fn(*mut CompletedTransaction, u64), + callback_faux_transaction_confirmed: unsafe extern "C" fn(*mut CompletedTransaction), + callback_faux_transaction_unconfirmed: unsafe extern "C" fn(*mut CompletedTransaction, u64), callback_direct_send_result: unsafe extern "C" fn(u64, bool), callback_store_and_forward_send_result: unsafe extern "C" fn(u64, bool), callback_transaction_cancellation: unsafe extern "C" fn(*mut CompletedTransaction, u64), @@ -151,6 +161,14 @@ where TBackend: TransactionBackend + 'static target: LOG_TARGET, "TransactionMinedUnconfirmedCallback -> Assigning Fn: {:?}", callback_transaction_mined_unconfirmed ); + info!( + target: LOG_TARGET, + "FauxTransactionConfirmedCallback -> Assigning Fn: {:?}", callback_faux_transaction_confirmed + ); + info!( + target: LOG_TARGET, + "FauxTransactionUnconfirmedCallback -> Assigning Fn: {:?}", callback_faux_transaction_unconfirmed + ); info!( target: LOG_TARGET, "DirectSendResultCallback -> Assigning Fn: {:?}", callback_direct_send_result @@ -191,6 +209,8 @@ where TBackend: TransactionBackend + 'static callback_transaction_broadcast, callback_transaction_mined, callback_transaction_mined_unconfirmed, + callback_faux_transaction_confirmed, + callback_faux_transaction_unconfirmed, callback_direct_send_result, callback_store_and_forward_send_result, callback_transaction_cancellation, @@ -262,6 +282,14 @@ where TBackend: TransactionBackend + 'static self.receive_transaction_mined_unconfirmed_event(tx_id, num_confirmations).await; self.trigger_balance_refresh().await; }, + TransactionEvent::FauxTransactionConfirmed{tx_id, is_valid: _} => { + self.receive_faux_transaction_confirmed_event(tx_id).await; + self.trigger_balance_refresh().await; + }, + TransactionEvent::FauxTransactionUnconfirmed{tx_id, num_confirmations, is_valid: _} => { + self.receive_faux_transaction_unconfirmed_event(tx_id, num_confirmations).await; + self.trigger_balance_refresh().await; + }, TransactionEvent::TransactionValidationStateChanged(_request_key) => { self.trigger_balance_refresh().await; }, @@ -272,7 +300,7 @@ where TBackend: TransactionBackend + 'static self.transaction_validation_complete_event(request_key.as_u64(), false); }, TransactionEvent::TransactionMinedRequestTimedOut(_tx_id) | - TransactionEvent::TransactionImported(_tx_id) | + TransactionEvent::TransactionImported(_tx_id)| TransactionEvent::TransactionCompletedImmediately(_tx_id) => { self.trigger_balance_refresh().await; @@ -493,7 +521,7 @@ where TBackend: TransactionBackend + 'static Ok(tx) => { debug!( target: LOG_TARGET, - "Calling Received Transaction Mined callback function for TxId: {}", tx_id + "Calling Received Transaction Mined Unconfirmed callback function for TxId: {}", tx_id ); let boxing = Box::into_raw(Box::new(tx)); unsafe { @@ -504,6 +532,38 @@ where TBackend: TransactionBackend + 'static } } + async fn receive_faux_transaction_confirmed_event(&mut self, tx_id: TxId) { + match self.db.get_completed_transaction(tx_id).await { + Ok(tx) => { + debug!( + target: LOG_TARGET, + "Calling Received Faux Transaction Confirmed callback function for TxId: {}", tx_id + ); + let boxing = Box::into_raw(Box::new(tx)); + unsafe { + (self.callback_faux_transaction_confirmed)(boxing); + } + }, + Err(e) => error!(target: LOG_TARGET, "Error retrieving Completed Transaction: {:?}", e), + } + } + + async fn receive_faux_transaction_unconfirmed_event(&mut self, tx_id: TxId, confirmations: u64) { + match self.db.get_completed_transaction(tx_id).await { + Ok(tx) => { + debug!( + target: LOG_TARGET, + "Calling Received Faux Transaction Unconfirmed callback function for TxId: {}", tx_id + ); + let boxing = Box::into_raw(Box::new(tx)); + unsafe { + (self.callback_faux_transaction_unconfirmed)(boxing, confirmations); + } + }, + Err(e) => error!(target: LOG_TARGET, "Error retrieving Completed Transaction: {:?}", e), + } + } + fn transaction_validation_complete_event(&mut self, request_key: u64, success: bool) { debug!( target: LOG_TARGET, diff --git a/base_layer/wallet_ffi/src/callback_handler_tests.rs b/base_layer/wallet_ffi/src/callback_handler_tests.rs index 64732fc9b1..1c5e39de39 100644 --- a/base_layer/wallet_ffi/src/callback_handler_tests.rs +++ b/base_layer/wallet_ffi/src/callback_handler_tests.rs @@ -37,7 +37,7 @@ mod test { use tari_comms_dht::event::DhtEvent; use tari_core::transactions::{ tari_amount::{uT, MicroTari}, - transaction::Transaction, + transaction_components::Transaction, ReceiverTransactionProtocol, SenderTransactionProtocol, }; @@ -53,10 +53,9 @@ mod test { test_utils::make_wallet_database_connection, transaction_service::{ handle::TransactionEvent, - protocols::TxRejection, storage::{ database::TransactionDatabase, - models::{CompletedTransaction, InboundTransaction, OutboundTransaction}, + models::{CompletedTransaction, InboundTransaction, OutboundTransaction, TxCancellationReason}, sqlite_db::TransactionServiceSqliteDatabase, }, }, @@ -77,6 +76,8 @@ mod test { pub broadcast_tx_callback_called: bool, pub mined_tx_callback_called: bool, pub mined_tx_unconfirmed_callback_called: u64, + pub faux_tx_confirmed_callback_called: bool, + pub faux_tx_unconfirmed_callback_called: u64, pub direct_send_callback_called: bool, pub store_and_forward_send_callback_called: bool, pub tx_cancellation_callback_called_completed: bool, @@ -98,6 +99,8 @@ mod test { broadcast_tx_callback_called: false, mined_tx_callback_called: false, mined_tx_unconfirmed_callback_called: 0, + faux_tx_confirmed_callback_called: false, + faux_tx_unconfirmed_callback_called: 0, direct_send_callback_called: false, store_and_forward_send_callback_called: false, callback_txo_validation_complete: 0, @@ -158,6 +161,20 @@ mod test { Box::from_raw(tx); } + unsafe extern "C" fn faux_confirmed_callback(tx: *mut CompletedTransaction) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.faux_tx_confirmed_callback_called = true; + drop(lock); + Box::from_raw(tx); + } + + unsafe extern "C" fn faux_unconfirmed_callback(tx: *mut CompletedTransaction, confirmations: u64) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.faux_tx_unconfirmed_callback_called = confirmations; + drop(lock); + Box::from_raw(tx); + } + unsafe extern "C" fn direct_send_callback(_tx_id: u64, _result: bool) { let mut lock = CALLBACK_STATE.lock().unwrap(); lock.direct_send_callback_called = true; @@ -230,6 +247,10 @@ mod test { "1".to_string(), Utc::now().naive_utc(), ); + runtime + .block_on(db.add_pending_inbound_transaction(1u64.into(), inbound_tx.clone())) + .unwrap(); + let completed_tx = CompletedTransaction::new( 2u64.into(), PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), @@ -248,7 +269,12 @@ mod test { Utc::now().naive_utc(), TransactionDirection::Inbound, None, + None, ); + runtime + .block_on(db.insert_completed_transaction(2u64.into(), completed_tx.clone())) + .unwrap(); + let stp = SenderTransactionProtocol::new_placeholder(); let outbound_tx = OutboundTransaction::new( 3u64.into(), @@ -261,33 +287,78 @@ mod test { Utc::now().naive_utc(), false, ); + runtime + .block_on(db.add_pending_outbound_transaction(3u64.into(), outbound_tx.clone())) + .unwrap(); + runtime.block_on(db.cancel_pending_transaction(3u64.into())).unwrap(); + let inbound_tx_cancelled = InboundTransaction { tx_id: 4u64.into(), ..inbound_tx.clone() }; + runtime + .block_on(db.add_pending_inbound_transaction(4u64.into(), inbound_tx_cancelled)) + .unwrap(); + runtime.block_on(db.cancel_pending_transaction(4u64.into())).unwrap(); + let completed_tx_cancelled = CompletedTransaction { tx_id: 5u64.into(), ..completed_tx.clone() }; - - runtime - .block_on(db.add_pending_inbound_transaction(1u64.into(), inbound_tx.clone())) - .unwrap(); runtime - .block_on(db.insert_completed_transaction(2u64.into(), completed_tx.clone())) + .block_on(db.insert_completed_transaction(5u64.into(), completed_tx_cancelled.clone())) .unwrap(); runtime - .block_on(db.add_pending_inbound_transaction(4u64.into(), inbound_tx_cancelled)) + .block_on(db.reject_completed_transaction(5u64.into(), TxCancellationReason::Unknown)) .unwrap(); - runtime.block_on(db.cancel_pending_transaction(4u64.into())).unwrap(); + + let faux_unconfirmed_tx = CompletedTransaction::new( + 6u64.into(), + PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), + PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), + MicroTari::from(100), + MicroTari::from(2000), + Transaction::new( + Vec::new(), + Vec::new(), + Vec::new(), + BlindingFactor::default(), + BlindingFactor::default(), + ), + TransactionStatus::FauxUnconfirmed, + "6".to_string(), + Utc::now().naive_utc(), + TransactionDirection::Inbound, + None, + Some(2), + ); runtime - .block_on(db.insert_completed_transaction(5u64.into(), completed_tx_cancelled.clone())) + .block_on(db.insert_completed_transaction(6u64.into(), faux_unconfirmed_tx.clone())) .unwrap(); - runtime.block_on(db.reject_completed_transaction(5u64.into())).unwrap(); + + let faux_confirmed_tx = CompletedTransaction::new( + 7u64.into(), + PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), + PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), + MicroTari::from(100), + MicroTari::from(2000), + Transaction::new( + Vec::new(), + Vec::new(), + Vec::new(), + BlindingFactor::default(), + BlindingFactor::default(), + ), + TransactionStatus::FauxConfirmed, + "7".to_string(), + Utc::now().naive_utc(), + TransactionDirection::Inbound, + None, + Some(5), + ); runtime - .block_on(db.add_pending_outbound_transaction(3u64.into(), outbound_tx.clone())) + .block_on(db.insert_completed_transaction(7u64.into(), faux_confirmed_tx.clone())) .unwrap(); - runtime.block_on(db.cancel_pending_transaction(3u64.into())).unwrap(); let (transaction_event_sender, transaction_event_receiver) = broadcast::channel(20); let (oms_event_sender, oms_event_receiver) = broadcast::channel(20); @@ -330,6 +401,8 @@ mod test { broadcast_callback, mined_callback, mined_unconfirmed_callback, + faux_confirmed_callback, + faux_unconfirmed_callback, direct_send_callback, store_and_forward_send_callback, tx_cancellation_callback, @@ -439,7 +512,7 @@ mod test { transaction_event_sender .send(Arc::new(TransactionEvent::TransactionCancelled( 3u64.into(), - TxRejection::UserCancelled, + TxCancellationReason::UserCancelled, ))) .unwrap(); let start = Instant::now(); @@ -458,14 +531,14 @@ mod test { transaction_event_sender .send(Arc::new(TransactionEvent::TransactionCancelled( 4u64.into(), - TxRejection::UserCancelled, + TxCancellationReason::UserCancelled, ))) .unwrap(); transaction_event_sender .send(Arc::new(TransactionEvent::TransactionCancelled( 5u64.into(), - TxRejection::UserCancelled, + TxCancellationReason::UserCancelled, ))) .unwrap(); @@ -478,7 +551,7 @@ mod test { .unwrap(); balance.available_balance -= completed_tx_cancelled.amount; - mock_output_manager_service_state.set_balance(balance); + mock_output_manager_service_state.set_balance(balance.clone()); // Balance updated should be detected with following event, total = 5 times oms_event_sender .send(Arc::new(OutputManagerEvent::TxoValidationSuccess(1u64))) @@ -520,6 +593,51 @@ mod test { .send(Arc::new(TransactionEvent::TransactionValidationCompleted(4u64.into()))) .unwrap(); + balance.pending_incoming_balance += faux_unconfirmed_tx.amount; + mock_output_manager_service_state.set_balance(balance.clone()); + // Balance updated should be detected with following event, total = 6 times + transaction_event_sender + .send(Arc::new(TransactionEvent::FauxTransactionUnconfirmed { + tx_id: 6u64.into(), + num_confirmations: 2, + is_valid: true, + })) + .unwrap(); + let start = Instant::now(); + while start.elapsed().as_secs() < 10 { + { + let lock = CALLBACK_STATE.lock().unwrap(); + if lock.callback_balance_updated == 6 { + callback_balance_updated = 6; + break; + } + } + thread::sleep(Duration::from_millis(100)); + } + assert_eq!(callback_balance_updated, 6); + + balance.available_balance += faux_confirmed_tx.amount; + mock_output_manager_service_state.set_balance(balance.clone()); + // Balance updated should be detected with following event, total = 7 times + transaction_event_sender + .send(Arc::new(TransactionEvent::FauxTransactionConfirmed { + tx_id: 7u64.into(), + is_valid: true, + })) + .unwrap(); + let start = Instant::now(); + while start.elapsed().as_secs() < 10 { + { + let lock = CALLBACK_STATE.lock().unwrap(); + if lock.callback_balance_updated == 7 { + callback_balance_updated = 7; + break; + } + } + thread::sleep(Duration::from_millis(100)); + } + assert_eq!(callback_balance_updated, 7); + dht_event_sender .send(Arc::new(DhtEvent::StoreAndForwardMessagesReceived)) .unwrap(); @@ -541,6 +659,8 @@ mod test { assert!(lock.broadcast_tx_callback_called); assert!(lock.mined_tx_callback_called); assert_eq!(lock.mined_tx_unconfirmed_callback_called, 22u64); + assert!(lock.faux_tx_confirmed_callback_called); + assert_eq!(lock.faux_tx_unconfirmed_callback_called, 2u64); assert!(lock.direct_send_callback_called); assert!(lock.store_and_forward_send_callback_called); assert!(lock.tx_cancellation_callback_called_inbound); @@ -548,7 +668,7 @@ mod test { assert!(lock.tx_cancellation_callback_called_outbound); assert!(lock.saf_messages_received); assert_eq!(lock.callback_txo_validation_complete, 3); - assert_eq!(lock.callback_balance_updated, 5); + assert_eq!(lock.callback_balance_updated, 7); assert_eq!(lock.callback_transaction_validation_complete, 7); assert_eq!(lock.connectivity_status_callback_called, 7); diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index 5041dd5084..8c0bdec891 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -122,7 +122,7 @@ use tari_comms::{ use tari_comms_dht::{store_forward::SafConfig, DbConnectionUrl, DhtConfig}; use tari_core::{ covenants::Covenant, - transactions::{tari_amount::MicroTari, transaction::OutputFeatures, CryptoFactories}, + transactions::{tari_amount::MicroTari, transaction_components::OutputFeatures, CryptoFactories}, }; use tari_crypto::{ inputs, @@ -184,10 +184,10 @@ const LOG_TARGET: &str = "wallet_ffi"; pub type TariTransportType = tari_p2p::transport::TransportType; pub type TariPublicKey = tari_common_types::types::PublicKey; pub type TariPrivateKey = tari_common_types::types::PrivateKey; -pub type TariOutputFeatures = tari_core::transactions::transaction::OutputFeatures; +pub type TariOutputFeatures = tari_core::transactions::transaction_components::OutputFeatures; pub type TariCommsConfig = tari_p2p::initialization::P2pConfig; pub type TariCommitmentSignature = tari_common_types::types::ComSignature; -pub type TariTransactionKernel = tari_core::transactions::transaction::TransactionKernel; +pub type TariTransactionKernel = tari_core::transactions::transaction_components::TransactionKernel; pub type TariCovenant = tari_core::covenants::Covenant; pub struct TariContacts(Vec); @@ -2071,10 +2071,10 @@ pub unsafe extern "C" fn completed_transaction_get_message( result.into_raw() } -/// Check if a TariCompletedTransaction is Valid or not +/// This function checks to determine if a TariCompletedTransaction was originally a TariPendingOutboundTransaction /// /// ## Arguments -/// `transaction` - The pointer to a TariCompletedTransaction +/// `tx` - The TariCompletedTransaction /// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions /// as an out parameter. /// @@ -2084,23 +2084,27 @@ pub unsafe extern "C" fn completed_transaction_get_message( /// # Safety /// None #[no_mangle] -pub unsafe extern "C" fn completed_transaction_is_valid( - transaction: *mut TariCompletedTransaction, +pub unsafe extern "C" fn completed_transaction_is_outbound( + tx: *mut TariCompletedTransaction, error_out: *mut c_int, ) -> bool { let mut error = 0; ptr::swap(error_out, &mut error as *mut c_int); - if transaction.is_null() { - error = LibWalletError::from(InterfaceError::NullError("transaction".to_string())).code; + if tx.is_null() { + error = LibWalletError::from(InterfaceError::NullError("tx".to_string())).code; ptr::swap(error_out, &mut error as *mut c_int); return false; } - (*transaction).valid + if (*tx).direction == TransactionDirection::Outbound { + return true; + } + + false } -/// This function checks to determine if a TariCompletedTransaction was originally a TariPendingOutboundTransaction +/// Gets the number of confirmations of a TariCompletedTransaction /// /// ## Arguments /// `tx` - The TariCompletedTransaction @@ -2108,32 +2112,28 @@ pub unsafe extern "C" fn completed_transaction_is_valid( /// as an out parameter. /// /// ## Returns -/// `bool` - Returns if the transaction was originally sent from the wallet +/// `c_ulonglong` - Returns the number of confirmations of a Completed Transaction /// /// # Safety /// None #[no_mangle] -pub unsafe extern "C" fn completed_transaction_is_outbound( +pub unsafe extern "C" fn completed_transaction_get_confirmations( tx: *mut TariCompletedTransaction, error_out: *mut c_int, -) -> bool { +) -> c_ulonglong { let mut error = 0; ptr::swap(error_out, &mut error as *mut c_int); if tx.is_null() { error = LibWalletError::from(InterfaceError::NullError("tx".to_string())).code; ptr::swap(error_out, &mut error as *mut c_int); - return false; - } - - if (*tx).direction == TransactionDirection::Outbound { - return true; + return 0; } - false + (*tx).confirmations.unwrap_or(0) } -/// Gets the number of confirmations of a TariCompletedTransaction +/// Gets the reason a TariCompletedTransaction is cancelled, if it is indeed cancelled /// /// ## Arguments /// `tx` - The TariCompletedTransaction @@ -2141,15 +2141,25 @@ pub unsafe extern "C" fn completed_transaction_is_outbound( /// as an out parameter. /// /// ## Returns -/// `c_ulonglong` - Returns the number of confirmations of a Completed Transaction -/// +/// `c_int` - Returns the reason for cancellation which corresponds to: +/// | Value | Interpretation | +/// |---|---| +/// | -1 | Not Cancelled | +/// | 0 | Unknown | +/// | 1 | UserCancelled | +/// | 2 | Timeout | +/// | 3 | DoubleSpend | +/// | 4 | Orphan | +/// | 5 | TimeLocked | +/// | 6 | InvalidTransaction | +/// | 7 | AbandonedCoinbase | /// # Safety /// None #[no_mangle] -pub unsafe extern "C" fn completed_transaction_get_confirmations( +pub unsafe extern "C" fn completed_transaction_get_cancellation_reason( tx: *mut TariCompletedTransaction, error_out: *mut c_int, -) -> c_ulonglong { +) -> c_int { let mut error = 0; ptr::swap(error_out, &mut error as *mut c_int); @@ -2159,7 +2169,10 @@ pub unsafe extern "C" fn completed_transaction_get_confirmations( return 0; } - (*tx).confirmations.unwrap_or(0) + match (*tx).cancelled { + None => -1i32, + Some(reason) => reason as i32, + } } /// Frees memory for a TariCompletedTransaction @@ -3025,7 +3038,7 @@ pub unsafe extern "C" fn comms_config_create( ..Default::default() }, // TODO: This should be set to false for non-test wallets. See the `allow_test_addresses` field - // docstring for more info. + // docstring for more info. #LOGGED allow_test_addresses: true, listener_liveness_allowlist_cidrs: Vec::new(), listener_liveness_max_sessions: 0, @@ -3231,7 +3244,11 @@ unsafe fn init_logging( /// `callback_transaction_mined` - The callback function pointer matching the function signature. This will be called /// when a Broadcast transaction is detected as mined AND confirmed. /// `callback_transaction_mined_unconfirmed` - The callback function pointer matching the function signature. This will -/// be called when a Broadcast transaction is detected as mined but not yet confirmed. +/// be called when a Broadcast transaction is detected as mined but not yet confirmed. +/// `callback_faux_transaction_confirmed` - The callback function pointer matching the function signature. This will be +/// called when a one-sided transaction is detected as mined AND confirmed. +/// `callback_faux_transaction_unconfirmed` - The callback function pointer matching the function signature. This +/// will be called when a one-sided transaction is detected as mined but not yet confirmed. /// `callback_direct_send_result` - The callback function pointer matching the function signature. This is called /// when a direct send is completed. The first parameter is the transaction id and the second is whether if was /// successful or not. @@ -3240,8 +3257,8 @@ unsafe fn init_logging( /// is whether if was successful or not. /// `callback_transaction_cancellation` - The callback function pointer matching /// the function signature. This is called when a transaction is cancelled. The first parameter is a pointer to the -/// cancelled transaction, the second is a reason as to why said transaction failed that is mapped to the `TxRejection` -/// enum: pub enum TxRejection { +/// cancelled transaction, the second is a reason as to why said transaction failed that is mapped to the +/// `TxCancellationReason` enum: pub enum TxCancellationReason { /// Unknown, // 0 /// UserCancelled, // 1 /// Timeout, // 2 @@ -3293,6 +3310,8 @@ pub unsafe extern "C" fn wallet_create( callback_transaction_broadcast: unsafe extern "C" fn(*mut TariCompletedTransaction), callback_transaction_mined: unsafe extern "C" fn(*mut TariCompletedTransaction), callback_transaction_mined_unconfirmed: unsafe extern "C" fn(*mut TariCompletedTransaction, u64), + callback_faux_transaction_confirmed: unsafe extern "C" fn(*mut TariCompletedTransaction), + callback_faux_transaction_unconfirmed: unsafe extern "C" fn(*mut TariCompletedTransaction, u64), callback_direct_send_result: unsafe extern "C" fn(c_ulonglong, bool), callback_store_and_forward_send_result: unsafe extern "C" fn(c_ulonglong, bool), callback_transaction_cancellation: unsafe extern "C" fn(*mut TariCompletedTransaction, u64), @@ -3499,6 +3518,8 @@ pub unsafe extern "C" fn wallet_create( callback_transaction_broadcast, callback_transaction_mined, callback_transaction_mined_unconfirmed, + callback_faux_transaction_confirmed, + callback_faux_transaction_unconfirmed, callback_direct_send_result, callback_store_and_forward_send_result, callback_transaction_cancellation, @@ -6053,6 +6074,8 @@ mod test { pub broadcast_tx_callback_called: bool, pub mined_tx_callback_called: bool, pub mined_tx_unconfirmed_callback_called: bool, + pub scanned_tx_callback_called: bool, + pub scanned_tx_unconfirmed_callback_called: bool, pub direct_send_callback_called: bool, pub store_and_forward_send_callback_called: bool, pub tx_cancellation_callback_called: bool, @@ -6070,6 +6093,8 @@ mod test { broadcast_tx_callback_called: false, mined_tx_callback_called: false, mined_tx_unconfirmed_callback_called: false, + scanned_tx_callback_called: false, + scanned_tx_unconfirmed_callback_called: false, direct_send_callback_called: false, store_and_forward_send_callback_called: false, tx_cancellation_callback_called: false, @@ -6177,6 +6202,48 @@ mod test { completed_transaction_destroy(tx); } + unsafe extern "C" fn scanned_callback(tx: *mut TariCompletedTransaction) { + assert!(!tx.is_null()); + assert_eq!( + type_of((*tx).clone()), + std::any::type_name::() + ); + assert_eq!((*tx).status, TransactionStatus::FauxConfirmed); + let mut lock = CALLBACK_STATE_FFI.lock().unwrap(); + lock.scanned_tx_callback_called = true; + drop(lock); + completed_transaction_destroy(tx); + } + + unsafe extern "C" fn scanned_unconfirmed_callback(tx: *mut TariCompletedTransaction, _confirmations: u64) { + assert!(!tx.is_null()); + assert_eq!( + type_of((*tx).clone()), + std::any::type_name::() + ); + assert_eq!((*tx).status, TransactionStatus::FauxUnconfirmed); + let mut lock = CALLBACK_STATE_FFI.lock().unwrap(); + lock.scanned_tx_unconfirmed_callback_called = true; + let mut error = 0; + let error_ptr = &mut error as *mut c_int; + let kernel = completed_transaction_get_transaction_kernel(tx, error_ptr); + let excess_hex_ptr = transaction_kernel_get_excess_hex(kernel, error_ptr); + let excess_hex = CString::from_raw(excess_hex_ptr).to_str().unwrap().to_owned(); + assert!(!excess_hex.is_empty()); + let nonce_hex_ptr = transaction_kernel_get_excess_public_nonce_hex(kernel, error_ptr); + let nonce_hex = CString::from_raw(nonce_hex_ptr).to_str().unwrap().to_owned(); + assert!(!nonce_hex.is_empty()); + let sig_hex_ptr = transaction_kernel_get_excess_signature_hex(kernel, error_ptr); + let sig_hex = CString::from_raw(sig_hex_ptr).to_str().unwrap().to_owned(); + assert!(!sig_hex.is_empty()); + string_destroy(excess_hex_ptr as *mut c_char); + string_destroy(sig_hex_ptr as *mut c_char); + string_destroy(nonce_hex_ptr); + transaction_kernel_destroy(kernel); + drop(lock); + completed_transaction_destroy(tx); + } + unsafe extern "C" fn direct_send_callback(_tx_id: c_ulonglong, _result: bool) { // assert!(true); //optimized out by compiler } @@ -6579,6 +6646,8 @@ mod test { broadcast_callback, mined_callback, mined_unconfirmed_callback, + scanned_callback, + scanned_unconfirmed_callback, direct_send_callback, store_and_forward_send_callback, tx_cancellation_callback, @@ -6616,6 +6685,8 @@ mod test { broadcast_callback, mined_callback, mined_unconfirmed_callback, + scanned_callback, + scanned_unconfirmed_callback, direct_send_callback, store_and_forward_send_callback, tx_cancellation_callback, @@ -6719,6 +6790,8 @@ mod test { broadcast_callback, mined_callback, mined_unconfirmed_callback, + scanned_callback, + scanned_unconfirmed_callback, direct_send_callback, store_and_forward_send_callback, tx_cancellation_callback, @@ -6767,6 +6840,8 @@ mod test { broadcast_callback, mined_callback, mined_unconfirmed_callback, + scanned_callback, + scanned_unconfirmed_callback, direct_send_callback, store_and_forward_send_callback, tx_cancellation_callback, @@ -6798,6 +6873,8 @@ mod test { broadcast_callback, mined_callback, mined_unconfirmed_callback, + scanned_callback, + scanned_unconfirmed_callback, direct_send_callback, store_and_forward_send_callback, tx_cancellation_callback, @@ -6824,6 +6901,8 @@ mod test { broadcast_callback, mined_callback, mined_unconfirmed_callback, + scanned_callback, + scanned_unconfirmed_callback, direct_send_callback, store_and_forward_send_callback, tx_cancellation_callback, @@ -6871,6 +6950,8 @@ mod test { broadcast_callback, mined_callback, mined_unconfirmed_callback, + scanned_callback, + scanned_unconfirmed_callback, direct_send_callback, store_and_forward_send_callback, tx_cancellation_callback, @@ -6947,6 +7028,8 @@ mod test { broadcast_callback, mined_callback, mined_unconfirmed_callback, + scanned_callback, + scanned_unconfirmed_callback, direct_send_callback, store_and_forward_send_callback, tx_cancellation_callback, @@ -7154,6 +7237,8 @@ mod test { broadcast_callback, mined_callback, mined_unconfirmed_callback, + scanned_callback, + scanned_unconfirmed_callback, direct_send_callback, store_and_forward_send_callback, tx_cancellation_callback, @@ -7209,6 +7294,8 @@ mod test { broadcast_callback, mined_callback, mined_unconfirmed_callback, + scanned_callback, + scanned_unconfirmed_callback, direct_send_callback, store_and_forward_send_callback, tx_cancellation_callback, diff --git a/base_layer/wallet_ffi/wallet.h b/base_layer/wallet_ffi/wallet.h index 889aaea741..a8b5d36d67 100644 --- a/base_layer/wallet_ffi/wallet.h +++ b/base_layer/wallet_ffi/wallet.h @@ -30,7 +30,6 @@ //! of Callbacks that the client must implement and provide to the Wallet module to receive asynchronous replies and //! updates. -// TODO: Improve documentation #ifndef wallet_ffi_h #define wallet_ffi_h @@ -263,14 +262,19 @@ unsigned long long completed_transaction_get_fee(struct TariCompletedTransaction const char *completed_transaction_get_message(struct TariCompletedTransaction *transaction, int *error_out); // Gets the status of a TariCompletedTransaction -// | Value | Interpretation | +// | Value | Interpretation | // |---|---| -// | -1 | TxNullError | -// | 0 | Completed | -// | 1 | Broadcast | -// | 2 | Mined | -// | 3 | Imported | -// | 4 | Pending | +// | -1 | TxNullError | +// | 0 | Completed | +// | 1 | Broadcast | +// | 2 | MinedUnconfirmed | +// | 3 | Imported | +// | 4 | Pending | +// | 5 | Coinbase | +// | 6 | MinedConfirmed | +// | 7 | Rejected | +// | 8 | FauxUnconfirmed | +// | 9 | FauxConfirmed | int completed_transaction_get_status(struct TariCompletedTransaction *transaction, int *error_out); // Gets the TransactionID of a TariCompletedTransaction @@ -279,9 +283,6 @@ unsigned long long completed_transaction_get_transaction_id(struct TariCompleted // Gets the timestamp of a TariCompletedTransaction unsigned long long completed_transaction_get_timestamp(struct TariCompletedTransaction *transaction, int *error_out); -// Check if a TariCompletedTransaction is Valid or not -bool completed_transaction_is_valid(struct TariCompletedTransaction *tx, int *error_out); - // Checks if a TariCompletedTransaction was originally a TariPendingOutboundTransaction, // i.e the transaction was originally sent from the wallet bool completed_transaction_is_outbound(struct TariCompletedTransaction *tx, int *error_out); @@ -292,6 +293,30 @@ unsigned long long completed_transaction_get_confirmations(struct TariCompletedT // Gets the TariTransactionKernel of a TariCompletedTransaction struct TariTransactionKernel *completed_transaction_get_transaction_kernel(struct TariCompletedTransaction *transaction, int *error_out); +/// Gets the reason a TariCompletedTransaction is cancelled, if it is indeed cancelled +/// +/// ## Arguments +/// `tx` - The TariCompletedTransaction +/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions +/// as an out parameter. +/// +/// ## Returns +/// `c_int` - Returns the reason for cancellation which corresponds to: +/// | Value | Interpretation | +/// |--- |--- | +/// | -1 | Not Cancelled | +/// | 0 | Unknown | +/// | 1 | UserCancelled | +/// | 2 | Timeout | +/// | 3 | DoubleSpend | +/// | 4 | Orphan | +/// | 5 | TimeLocked | +/// | 6 | InvalidTransaction | +/// | 7 | AbandonedCoinbase | +/// # Safety +/// None +int completed_transaction_get_cancellation_reason(struct TariCompletedTransaction *transaction, int *error_out); + // Frees memory for a TariCompletedTransaction void completed_transaction_destroy(struct TariCompletedTransaction *transaction); @@ -341,14 +366,19 @@ const char *pending_outbound_transaction_get_message(struct TariPendingOutboundT unsigned long long pending_outbound_transaction_get_timestamp(struct TariPendingOutboundTransaction *transaction, int *error_out); // Gets the status of a TariPendingOutboundTransaction -// | Value | Interpretation | +// | Value | Interpretation | // |---|---| -// | -1 | TxNullError | -// | 0 | Completed | -// | 1 | Broadcast | -// | 2 | Mined | -// | 3 | Imported | -// | 4 | Pending | +// | -1 | TxNullError | +// | 0 | Completed | +// | 1 | Broadcast | +// | 2 | MinedUnconfirmed | +// | 3 | Imported | +// | 4 | Pending | +// | 5 | Coinbase | +// | 6 | MinedConfirmed | +// | 7 | Rejected | +// | 8 | FauxUnconfirmed | +// | 9 | FauxConfirmed | int pending_outbound_transaction_get_status(struct TariPendingOutboundTransaction *transaction, int *error_out); // Frees memory for a TariPendingOutboundTactions @@ -383,14 +413,19 @@ unsigned long long pending_inbound_transaction_get_amount(struct TariPendingInbo unsigned long long pending_inbound_transaction_get_timestamp(struct TariPendingInboundTransaction *transaction, int *error_out); // Gets the status of a TariPendingInboundTransaction -// | Value | Interpretation | +// | Value | Interpretation | // |---|---| -// | -1 | TxNullError | -// | 0 | Completed | -// | 1 | Broadcast | -// | 2 | Mined | -// | 3 | Imported | -// | 4 | Pending | +// | -1 | TxNullError | +// | 0 | Completed | +// | 1 | Broadcast | +// | 2 | MinedUnconfirmed | +// | 3 | Imported | +// | 4 | Pending | +// | 5 | Coinbase | +// | 6 | MinedConfirmed | +// | 7 | Rejected | +// | 8 | FauxUnconfirmed | +// | 9 | FauxConfirmed | int pending_inbound_transaction_get_status(struct TariPendingInboundTransaction *transaction, int *error_out); // Frees memory for a TariPendingInboundTransaction @@ -451,14 +486,18 @@ struct TariPublicKeys *comms_list_connected_public_keys(struct TariWallet *walle /// when a Broadcast transaction is detected as mined AND confirmed. /// `callback_transaction_mined_unconfirmed` - The callback function pointer matching the function signature. This will /// be called when a Broadcast transaction is detected as mined but not yet confirmed. +/// `callback_faux_transaction_confirmed` - The callback function pointer matching the function signature. This will be called +/// when a one-sided transaction is detected as mined AND confirmed. +/// `callback_faux_transaction_unconfirmed` - The callback function pointer matching the function signature. This will +/// be called when a one-sided transaction is detected as mined but not yet confirmed. /// `callback_direct_send_result` - The callback function pointer matching the function signature. This is called /// when a direct send is completed. The first parameter is the transaction id and the second is whether if was successful or not. /// `callback_store_and_forward_send_result` - The callback function pointer matching the function signature. This is called /// when a direct send is completed. The first parameter is the transaction id and the second is whether if was successful or not. /// `callback_transaction_cancellation` - The callback function pointer matching the function signature. This is called /// when a transaction is cancelled. The first parameter is a pointer to the cancelled transaction, the second is a reason as to -/// why said transaction failed that is mapped to the `TxRejection` enum: -/// pub enum TxRejection { +/// why said transaction failed that is mapped to the `TxCancellationReason` enum: +/// pub enum TxCancellationReason { /// Unknown, // 0 /// UserCancelled, // 1 /// Timeout, // 2 @@ -515,6 +554,8 @@ struct TariWallet *wallet_create(struct TariCommsConfig *config, void (*callback_transaction_broadcast)(struct TariCompletedTransaction *), void (*callback_transaction_mined)(struct TariCompletedTransaction *), void (*callback_transaction_mined_unconfirmed)(struct TariCompletedTransaction *, unsigned long long), + void (*callback_faux_transaction_confirmed)(struct TariCompletedTransaction *), + void (*callback_faux_transaction_unconfirmed)(struct TariCompletedTransaction *, unsigned long long), void (*callback_direct_send_result)(unsigned long long, bool), void (*callback_store_and_forward_send_result)(unsigned long long, bool), void (*callback_transaction_cancellation)(struct TariCompletedTransaction *, unsigned long long), diff --git a/changelog.md b/changelog.md index 5c2fbd5f24..17a59c8846 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,43 @@ # Changelog +## [0.28.0](https://github.com/tari-project/tari/compare/v0.27.2...v0.28.0) (2022-02-10) + + +### ⚠ BREAKING CHANGES + +* add scanned transaction handling for one-sided payments with callbacks (#3794) +* **wallet_ffi:** add base node connectivity callback to wallet ffi (#3796) + +### Features + +* ability to compile on stable rust ([#3759](https://github.com/tari-project/tari/issues/3759)) ([c19db92](https://github.com/tari-project/tari/commit/c19db9257d2f98b2d1a456816f6ef50018bdcbfe)) +* add logging and config to collectibles ([#3781](https://github.com/tari-project/tari/issues/3781)) ([96a1e4e](https://github.com/tari-project/tari/commit/96a1e4ec144dc17190f396f94ec25c62fb142ce3)) +* add scanned transaction handling for one-sided payments with callbacks ([#3794](https://github.com/tari-project/tari/issues/3794)) ([5453c9e](https://github.com/tari-project/tari/commit/5453c9e05b7d35b7586ff9375ba30ed7ecc7a9dd)) +* add specific LibWallet error code for “Fee is greater than amount” ([#3793](https://github.com/tari-project/tari/issues/3793)) ([5aa2a66](https://github.com/tari-project/tari/commit/5aa2a661cdae869a877dda5f3cadc3abb97c374a)) +* **base-node:** add base node prometheus metrics ([#3773](https://github.com/tari-project/tari/issues/3773)) ([7502c02](https://github.com/tari-project/tari/commit/7502c020eb5f531c4ebe1a50235ab8493c8f5fd5)) +* **base-node:** add number of active sync peers metric ([#3784](https://github.com/tari-project/tari/issues/3784)) ([3495e85](https://github.com/tari-project/tari/commit/3495e85707f3ffba622feeab42e17276181654c2)) +* **collectibles:** add delete committee member button ([#3786](https://github.com/tari-project/tari/issues/3786)) ([51f2f91](https://github.com/tari-project/tari/commit/51f2f91e9b2e6289b74cf9148b23335cccea5c40)) +* prevent ambiguous output features in transaction protocols ([#3765](https://github.com/tari-project/tari/issues/3765)) ([f5b6ab6](https://github.com/tari-project/tari/commit/f5b6ab629f78497faef62f10b805d1c9a7c242c3)) +* re-use scanned range proofs ([#3764](https://github.com/tari-project/tari/issues/3764)) ([ffd502d](https://github.com/tari-project/tari/commit/ffd502d61a709d41723e67c8ec6b2d5004a87edc)) +* read asset definitions from base layer ([#3802](https://github.com/tari-project/tari/issues/3802)) ([86de08b](https://github.com/tari-project/tari/commit/86de08baa5e7648f68efcbec150d7b8652437ca9)) +* **validator_node:** add get_sidechain_block p2p rpc method ([#3803](https://github.com/tari-project/tari/issues/3803)) ([74df1d0](https://github.com/tari-project/tari/commit/74df1d0705d7acad452564e71d6fea79fc7a8daa)) +* **wallet_ffi:** add base node connectivity callback to wallet ffi ([#3796](https://github.com/tari-project/tari/issues/3796)) ([66ea697](https://github.com/tari-project/tari/commit/66ea697395286ca89b34c77f3d857f1c3f16b421)) + + +### Bug Fixes + +* bump flood ban messages config ([#3799](https://github.com/tari-project/tari/issues/3799)) ([bbd0e1e](https://github.com/tari-project/tari/commit/bbd0e1e54e3eded861b004fd2d4aeba41bc6e423)) +* coinbase output recovery bug ([#3789](https://github.com/tari-project/tari/issues/3789)) ([beb299e](https://github.com/tari-project/tari/commit/beb299e69ee1af7ec4e46889191051ce49dd1d50)) +* **comms:** minor edge-case fix to handle inbound connection while dialing ([#3785](https://github.com/tari-project/tari/issues/3785)) ([2f9603b](https://github.com/tari-project/tari/commit/2f9603b88a8db0064f1783df0b8f18be19a24497)) +* **core:** fetch_header_containing_*_mmr functions now take a 0-based mmr position ([#3749](https://github.com/tari-project/tari/issues/3749)) ([f5b72d9](https://github.com/tari-project/tari/commit/f5b72d9dd302eed0b0da612734b128b3078318ae)) +* **core:** fix potential panic for sidechain merkle root with incorrect length ([#3788](https://github.com/tari-project/tari/issues/3788)) ([b3cc6f2](https://github.com/tari-project/tari/commit/b3cc6f27359ad33fc1c3fdf49d00478f8e27994f)) +* **core:** reduce one block behind waiting period ([#3798](https://github.com/tari-project/tari/issues/3798)) ([cc41f36](https://github.com/tari-project/tari/commit/cc41f36b01a42a6f8d48b02d0ed6fe73c99f061d)) +* **ffi:** missing param in header.h ([#3774](https://github.com/tari-project/tari/issues/3774)) ([7645a83](https://github.com/tari-project/tari/commit/7645a832e4c90319ad41e74db93c1ee61daa7b2a)) +* **ffi:** mut pointers should be const ([#3775](https://github.com/tari-project/tari/issues/3775)) ([d09ba30](https://github.com/tari-project/tari/commit/d09ba304b07d9681d84f71addbe1c9c70e3c4c67)) +* fix rustls and trust-dns-client after version bump ([#3816](https://github.com/tari-project/tari/issues/3816)) ([e6e845c](https://github.com/tari-project/tari/commit/e6e845ceb219842021f5a0b359c00079a7b7eb70)) +* improved image handling in collectibles ([#3808](https://github.com/tari-project/tari/issues/3808)) ([4b22252](https://github.com/tari-project/tari/commit/4b2225291eb61955b5ff575f134d68aa47deedfe)) +* minor fixes on collectibles ([#3795](https://github.com/tari-project/tari/issues/3795)) ([cfc42dd](https://github.com/tari-project/tari/commit/cfc42ddcc5d6fd96d05922662eea43929b46c81a)) +* text explorer show sha-3 correctly + minor fixes ([#3779](https://github.com/tari-project/tari/issues/3779)) ([a5dacf2](https://github.com/tari-project/tari/commit/a5dacf2bcc51ae754d88f9af66cd0632a49b8a1b)) ### [0.27.2](https://github.com/tari-project/tari/compare/v0.27.1...v0.27.2) (2022-01-28) diff --git a/common/Cargo.toml b/common/Cargo.toml index b8cdb837e1..f2a12317c8 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.27.3" +version = "0.28.0" edition = "2018" [features] @@ -25,7 +25,7 @@ log4rs = { version = "1.0.0", default_features = false, features = ["config_pars multiaddr = { version = "0.13.0" } sha2 = "0.9.5" path-clean = "0.1.0" -tari_storage = { version = "^0.27", path = "../infrastructure/storage"} +tari_storage = { version = "^0.28", path = "../infrastructure/storage"} anyhow = { version = "1.0.53", optional = true } git2 = { version = "0.8", optional = true } @@ -36,5 +36,5 @@ fs2 = "0.4.3" tempfile = "3.1.0" [dev-dependencies] -tari_test_utils = { version = "^0.27", path = "../infrastructure/test_utils"} +tari_test_utils = { version = "^0.28", path = "../infrastructure/test_utils"} anyhow = "1.0.53" diff --git a/common/src/configuration/validator_node_config.rs b/common/src/configuration/validator_node_config.rs index 79c9eba215..6ca54043b8 100644 --- a/common/src/configuration/validator_node_config.rs +++ b/common/src/configuration/validator_node_config.rs @@ -25,7 +25,7 @@ use std::{ path::PathBuf, }; -use config::Config; +use config::{Config, ConfigError}; use serde::Deserialize; use crate::ConfigurationError; @@ -62,10 +62,12 @@ impl ValidatorNodeConfig { pub fn convert_if_present(cfg: Config) -> Result, ConfigurationError> { let section: Self = match cfg.get("validator_node") { Ok(s) => s, - Err(_e) => { - // dbg!(e); + Err(ConfigError::NotFound(_)) => { return Ok(None); }, + Err(err) => { + return Err(err.into()); + }, }; Ok(Some(section)) // dbg!(§ion); diff --git a/common/src/exit_codes.rs b/common/src/exit_codes.rs index f4792e36d9..8d6f039ff2 100644 --- a/common/src/exit_codes.rs +++ b/common/src/exit_codes.rs @@ -1,113 +1,116 @@ +use std::fmt; + use thiserror::Error; -/// Enum to show failure information #[derive(Debug, Clone, Error)] -pub enum ExitCodes { - #[error("There is an error in the configuration: {0}")] - ConfigError(String), - #[error("The application exited because an unknown error occurred: {0}. Check the logs for more details.")] - UnknownError(String), - #[error("The application exited because an interface error occurred. Check the logs for details.")] - InterfaceError, - #[error("The application exited. {0}")] - WalletError(String), - #[error("The application was not able to start the GRPC server. {0}")] - GrpcError(String), - #[error("The application did not accept the command input: {0}")] - InputError(String), - #[error("Invalid command: {0}")] - CommandError(String), - #[error("IO error: {0}")] - IOError(String), - #[error("Recovery failed: {0}")] - RecoveryError(String), - #[error("The application exited because of an internal network error: {0}")] - NetworkError(String), - #[error("The application exited because it received a message it could not interpret: {0}")] - ConversionError(String), - #[error("Your password was incorrect.")] - IncorrectPassword, - #[error("Your wallet is encrypted but no password was provided.")] - NoPassword, - #[error("The application encountered a database error: {0}")] - DatabaseError(String), - #[error("Tor connection is offline")] - TorOffline, - #[error("Database is in an inconsistent state!: {0}")] - DbInconsistentState(String), +pub struct ExitError { + pub exit_code: ExitCode, + pub details: Option, } -impl ExitCodes { - pub fn as_i32(&self) -> i32 { - match self { - Self::ConfigError(_) => 101, - Self::UnknownError(_) => 102, - Self::InterfaceError => 103, - Self::WalletError(_) => 104, - Self::GrpcError(_) => 105, - Self::InputError(_) => 106, - Self::CommandError(_) => 107, - Self::IOError(_) => 108, - Self::RecoveryError(_) => 109, - Self::NetworkError(_) => 110, - Self::ConversionError(_) => 111, - Self::IncorrectPassword | Self::NoPassword => 112, - Self::TorOffline => 113, - Self::DatabaseError(_) => 114, - Self::DbInconsistentState(_) => 115, +impl ExitError { + pub fn new(exit_code: ExitCode, details: impl ToString) -> Self { + let details = Some(details.to_string()); + Self { exit_code, details } + } +} + +impl From for ExitError { + fn from(exit_code: ExitCode) -> Self { + Self { + exit_code, + details: None, } } +} + +impl fmt::Display for ExitError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let details = self.details.as_ref().map(String::as_ref).unwrap_or(""); + write!(f, "{} {}", self.exit_code, details) + } +} - pub fn eprint_details(&self) { - use ExitCodes::*; +const TOR_HINT: &str = r#"\ +Unable to connect to the Tor control port. + +Please check that you have the Tor proxy running and \ +that access to the Tor control port is turned on. + +If you are unsure of what to do, use the following \ +command to start the Tor proxy: +tor --allow-missing-torrc --ignore-missing-torrc \ +--clientonly 1 --socksport 9050 --controlport \ +127.0.0.1:9051 --log \"warn stdout\" --clientuseipv6 1 +"#; + +impl ExitCode { + pub fn hint(&self) -> &str { + use ExitCode::*; match self { - TorOffline => { - eprintln!("Unable to connect to the Tor control port."); - eprintln!( - "Please check that you have the Tor proxy running and that access to the Tor control port is \ - turned on.", - ); - eprintln!("If you are unsure of what to do, use the following command to start the Tor proxy:"); - eprintln!( - "tor --allow-missing-torrc --ignore-missing-torrc --clientonly 1 --socksport 9050 --controlport \ - 127.0.0.1:9051 --log \"warn stdout\" --clientuseipv6 1", - ); - }, - e => { - eprintln!("{}", e); - }, + TorOffline => TOR_HINT, + _ => "", } } } -impl From for ExitCodes { +/// Enum to show failure information +#[derive(Debug, Clone, Copy, Error)] +pub enum ExitCode { + #[error("There is an error in the configuration.")] + ConfigError = 101, + #[error("The application exited because an unknown error occurred. Check the logs for more details.")] + UnknownError = 102, + #[error("The application exited because an interface error occurred. Check the logs for details.")] + InterfaceError = 103, + #[error("The application exited.")] + WalletError = 104, + #[error("The application was not able to start the GRPC server.")] + GrpcError = 105, + #[error("The application did not accept the command input.")] + InputError = 106, + #[error("Invalid command.")] + CommandError = 107, + #[error("IO error.")] + IOError = 108, + #[error("Recovery failed.")] + RecoveryError = 109, + #[error("The application exited because of an internal network error.")] + NetworkError = 110, + #[error("The application exited because it received a message it could not interpret.")] + ConversionError = 111, + #[error("Your password was incorrect or required, but not provided.")] + IncorrectOrEmptyPassword = 112, + #[error("Tor connection is offline")] + TorOffline = 113, + #[error("The application encountered a database error.")] + DatabaseError = 114, + #[error("Database is in an inconsistent state!")] + DbInconsistentState = 115, +} + +impl From for ExitError { fn from(err: super::ConfigError) -> Self { // TODO: Move it out // error!(target: LOG_TARGET, "{}", err); - Self::ConfigError(err.to_string()) + Self::new(ExitCode::ConfigError, err) } } -impl From for ExitCodes { +impl From for ExitError { fn from(err: crate::ConfigurationError) -> Self { - Self::ConfigError(err.to_string()) + Self::new(ExitCode::ConfigError, err) } } -impl From for ExitCodes { +impl From for ExitError { fn from(err: multiaddr::Error) -> Self { - Self::ConfigError(err.to_string()) + Self::new(ExitCode::ConfigError, err) } } -impl From for ExitCodes { +impl From for ExitError { fn from(err: std::io::Error) -> Self { - Self::IOError(err.to_string()) - } -} - -impl ExitCodes { - pub fn grpc(err: M) -> Self { - ExitCodes::GrpcError(format!("GRPC connection error: {}", err)) + Self::new(ExitCode::IOError, err) } } diff --git a/common_sqlite/Cargo.toml b/common_sqlite/Cargo.toml index 5463081ab8..0877e5ea31 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.27.3" +version = "0.28.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/comms/Cargo.toml b/comms/Cargo.toml index 8210503733..ff3263137d 100644 --- a/comms/Cargo.toml +++ b/comms/Cargo.toml @@ -6,13 +6,13 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.27.3" +version = "0.28.0" edition = "2018" [dependencies] tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } -tari_storage = { version = "^0.27", path = "../infrastructure/storage" } -tari_shutdown = { version = "^0.27", path = "../infrastructure/shutdown" } +tari_storage = { version = "^0.28", path = "../infrastructure/storage" } +tari_shutdown = { version = "^0.28", path = "../infrastructure/shutdown" } anyhow = "1.0.53" async-trait = "0.1.36" @@ -52,7 +52,7 @@ yamux = "=0.9.0" tari_metrics = { path = "../infrastructure/metrics" } [dev-dependencies] -tari_test_utils = { version = "^0.27", path = "../infrastructure/test_utils" } +tari_test_utils = { version = "^0.28", path = "../infrastructure/test_utils" } tari_comms_rpc_macros = { version = "*", path = "./rpc_macros" } env_logger = "0.7.0" @@ -60,7 +60,7 @@ serde_json = "1.0.39" tempfile = "3.1.0" [build-dependencies] -tari_common = { version = "^0.27", path = "../common", features = ["build"] } +tari_common = { version = "^0.28", path = "../common", features = ["build"] } [features] c_integration = [] diff --git a/comms/dht/Cargo.toml b/comms/dht/Cargo.toml index 1b0ed31c25..8fc7685d55 100644 --- a/comms/dht/Cargo.toml +++ b/comms/dht/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_comms_dht" -version = "0.27.3" +version = "0.28.0" authors = ["The Tari Development Community"] description = "Tari comms DHT module" repository = "https://github.com/tari-project/tari" @@ -10,12 +10,12 @@ license = "BSD-3-Clause" edition = "2018" [dependencies] -tari_comms = { version = "^0.27", path = "../", features = ["rpc"] } -tari_comms_rpc_macros = { version = "^0.27", path = "../rpc_macros" } +tari_comms = { version = "^0.28", path = "../", features = ["rpc"] } +tari_comms_rpc_macros = { version = "^0.28", path = "../rpc_macros" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } tari_utilities = { version = "^0.3" } -tari_shutdown = { version = "^0.27", path = "../../infrastructure/shutdown" } -tari_storage = { version = "^0.27", path = "../../infrastructure/storage" } +tari_shutdown = { version = "^0.28", path = "../../infrastructure/shutdown" } +tari_storage = { version = "^0.28", path = "../../infrastructure/storage" } tari_common_sqlite = { path = "../../common_sqlite" } anyhow = "1.0.53" @@ -43,7 +43,7 @@ tower = { version = "0.4", features = ["full"] } pin-project = "0.4" [dev-dependencies] -tari_test_utils = { version = "^0.27", path = "../../infrastructure/test_utils" } +tari_test_utils = { version = "^0.28", path = "../../infrastructure/test_utils" } env_logger = "0.7.0" futures-test = { version = "0.3.5" } @@ -56,7 +56,7 @@ petgraph = "0.5.1" clap = "2.33.0" [build-dependencies] -tari_common = { version = "^0.27", path = "../../common" } +tari_common = { version = "^0.28", path = "../../common" } [features] test-mocks = [] diff --git a/comms/dht/src/dedup/dedup_cache.rs b/comms/dht/src/dedup/dedup_cache.rs index 7d6221eaf1..ef56369a25 100644 --- a/comms/dht/src/dedup/dedup_cache.rs +++ b/comms/dht/src/dedup/dedup_cache.rs @@ -133,8 +133,7 @@ impl DedupCacheDatabase { dedup_cache::last_hit_at.eq(Utc::now().naive_utc()), )) .execute(&conn)?; - // TODO: Diesel support for RETURNING statements would remove this query, but is not - // TODO: available for Diesel + SQLite yet + let hits = dedup_cache::table .select(dedup_cache::number_of_hits) .filter(dedup_cache::body_hash.eq(&body_hash)) diff --git a/comms/dht/src/proto/envelope.proto b/comms/dht/src/proto/envelope.proto index c1e6407d7d..7be368c9e4 100644 --- a/comms/dht/src/proto/envelope.proto +++ b/comms/dht/src/proto/envelope.proto @@ -42,7 +42,7 @@ message DhtHeader { DhtMessageType message_type = 8; uint32 flags = 10; // Message trace ID - // TODO: Remove for mainnet or when testing message traces is not required + // TODO: Remove for mainnet or when testing message traces is not required #LOGGED uint64 message_tag = 11; // Expiry timestamp for the message google.protobuf.Timestamp expires = 12; diff --git a/comms/rpc_macros/Cargo.toml b/comms/rpc_macros/Cargo.toml index 3f14ba0927..ac8c0f2719 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.27.3" +version = "0.28.0" edition = "2018" [lib] @@ -19,8 +19,8 @@ quote = "1.0.7" syn = { version = "1.0.38", features = ["fold"] } [dev-dependencies] -tari_comms = { version = "^0.27", path = "../", features = ["rpc"] } -tari_test_utils = { version = "^0.27", path = "../../infrastructure/test_utils" } +tari_comms = { version = "^0.28", path = "../", features = ["rpc"] } +tari_test_utils = { version = "^0.28", path = "../../infrastructure/test_utils" } futures = "0.3.5" prost = "0.9.0" diff --git a/comms/src/connectivity/manager.rs b/comms/src/connectivity/manager.rs index b0ae56ea5b..2872ff58cd 100644 --- a/comms/src/connectivity/manager.rs +++ b/comms/src/connectivity/manager.rs @@ -228,6 +228,21 @@ impl ConnectivityManagerActor { let span = span!(Level::TRACE, "handle_request"); span.follows_from(tracing_id); async move { + match self.peer_manager.is_peer_banned(&node_id).await { + Ok(true) => { + if let Some(reply) = reply_tx { + let _ = reply.send(Err(ConnectionManagerError::PeerBanned)); + } + return; + }, + Ok(false) => {}, + Err(err) => { + if let Some(reply) = reply_tx { + let _ = reply.send(Err(err.into())); + } + return; + }, + } match self.pool.get(&node_id) { Some(state) if state.is_connected() => { debug!( diff --git a/comms/src/peer_manager/manager.rs b/comms/src/peer_manager/manager.rs index e10b0be988..6dc1a3d5c5 100644 --- a/comms/src/peer_manager/manager.rs +++ b/comms/src/peer_manager/manager.rs @@ -264,6 +264,10 @@ impl PeerManager { .ban_peer_by_node_id(node_id, duration, reason) } + pub async fn is_peer_banned(&self, node_id: &NodeId) -> Result { + self.peer_storage.read().await.is_peer_banned(node_id) + } + /// Changes the offline flag bit of the peer. Return the previous offline state. pub async fn set_offline(&self, node_id: &NodeId, is_offline: bool) -> Result { self.peer_storage.write().await.set_offline(node_id, is_offline) diff --git a/comms/src/peer_manager/node_identity.rs b/comms/src/peer_manager/node_identity.rs index 2b39ce7085..3fd7d8aadd 100644 --- a/comms/src/peer_manager/node_identity.rs +++ b/comms/src/peer_manager/node_identity.rs @@ -41,7 +41,7 @@ use crate::{ }; /// The public and private identity of this node on the network -#[derive(Debug, Serialize, Deserialize)] +#[derive(Serialize, Deserialize)] pub struct NodeIdentity { #[serde(serialize_with = "serialize_to_hex")] #[serde(deserialize_with = "deserialize_node_id_from_hex")] @@ -221,3 +221,16 @@ impl fmt::Display for NodeIdentity { Ok(()) } } + +impl fmt::Debug for NodeIdentity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NodeIdentity") + .field("public_key", &self.public_key) + .field("node_id", &self.node_id) + .field("public_address", &self.public_address) + .field("features", &self.features) + .field("secret_key", &"") + .field("identity_signature", &*acquire_read_lock!(self.identity_signature)) + .finish() + } +} diff --git a/comms/src/peer_manager/peer_storage.rs b/comms/src/peer_manager/peer_storage.rs index 0f9ca71ac3..75e6413705 100644 --- a/comms/src/peer_manager/peer_storage.rs +++ b/comms/src/peer_manager/peer_storage.rs @@ -498,6 +498,13 @@ where DS: KeyValueStore Ok(node_id) } + pub fn is_peer_banned(&self, node_id: &NodeId) -> Result { + let peer = self + .find_by_node_id(node_id)? + .ok_or(PeerManagerError::PeerNotFoundError)?; + Ok(peer.is_banned()) + } + /// Changes the OFFLINE flag bit of the peer. pub fn set_offline(&mut self, node_id: &NodeId, offline: bool) -> Result { let peer_key = *self diff --git a/dan_layer/common_types/proto/tips/tip002.proto b/dan_layer/common_types/proto/tips/tip002.proto index ff5f621bd1..64a02c5e98 100644 --- a/dan_layer/common_types/proto/tips/tip002.proto +++ b/dan_layer/common_types/proto/tips/tip002.proto @@ -7,7 +7,7 @@ service Tip002 { rpc Init(InitRequest) returns (Empty); // rpc Info(InfoRequest) returns (InfoResponse); rpc BalanceOf(BalanceOfRequest) returns (BalanceOfResponse); - rpc Tranfer(TransferRequest) returns (TransferResponse); + rpc Transfer(TransferRequest) returns (TransferResponse); } @@ -47,4 +47,4 @@ message BalanceOfRequest { message BalanceOfResponse { uint64 balance = 1; -} \ No newline at end of file +} diff --git a/dan_layer/core/Cargo.toml b/dan_layer/core/Cargo.toml index 59c417fb27..fa3c69eb8e 100644 --- a/dan_layer/core/Cargo.toml +++ b/dan_layer/core/Cargo.toml @@ -31,6 +31,7 @@ log = { version = "0.4.8", features = ["std"] } lmdb-zero = "0.4.4" prost = "0.9" prost-types = "0.9" +rand = "0.8.4" serde = "1.0.126" thiserror = "^1.0.20" tokio = { version="1.10", features = ["macros", "time"]} diff --git a/dan_layer/core/src/digital_assets_error.rs b/dan_layer/core/src/digital_assets_error.rs index 470958b557..65fcf6d072 100644 --- a/dan_layer/core/src/digital_assets_error.rs +++ b/dan_layer/core/src/digital_assets_error.rs @@ -20,14 +20,9 @@ // 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 tari_comms::{ - connectivity::ConnectivityError, - protocol::rpc::{RpcError, RpcStatus}, -}; -use tari_comms_dht::DhtDiscoveryError; use thiserror::Error; -use crate::{models::ModelError, storage::StorageError}; +use crate::{models::ModelError, services::ValidatorNodeClientError, storage::StorageError, workers::StateSyncError}; #[derive(Debug, Error)] pub enum DigitalAssetError { @@ -71,18 +66,16 @@ pub enum DigitalAssetError { NoCommitteeForAsset, #[error("None of the committee responded")] NoResponsesFromCommittee, - #[error("Connectivity error:{0}")] - ConnectivityError(#[from] ConnectivityError), - #[error("RpcError: {0}")] - RpcError(#[from] RpcError), - #[error("Remote node returned error: {0}")] - RpcStatusError(#[from] RpcStatus), - #[error("Dht Discovery error: {0}")] - DhtDiscoveryError(#[from] DhtDiscoveryError), #[error("Fatal error: {0}")] FatalError(String), #[error(transparent)] ModelError(#[from] ModelError), + #[error("UTXO missing checkpoint data")] + UtxoNoCheckpointData, + #[error("Failed to synchronize state: {0}")] + StateSyncError(#[from] StateSyncError), + #[error("Validator node client error: {0}")] + ValidatorNodeClientError(#[from] ValidatorNodeClientError), } impl From for DigitalAssetError { diff --git a/dan_layer/core/src/fixed_hash.rs b/dan_layer/core/src/fixed_hash.rs index 66281ab5b9..ea642e2c3f 100644 --- a/dan_layer/core/src/fixed_hash.rs +++ b/dan_layer/core/src/fixed_hash.rs @@ -31,7 +31,7 @@ const ZERO_HASH: [u8; FixedHash::byte_size()] = [0u8; FixedHash::byte_size()]; #[error("Invalid size")] pub struct FixedHashSizeError; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)] pub struct FixedHash([u8; FixedHash::byte_size()]); impl FixedHash { @@ -50,7 +50,7 @@ impl FixedHash { impl From<[u8; FixedHash::byte_size()]> for FixedHash { fn from(hash: [u8; FixedHash::byte_size()]) -> Self { - hash.into() + Self(hash) } } @@ -58,12 +58,20 @@ impl TryFrom> for FixedHash { type Error = FixedHashSizeError; fn try_from(value: Vec) -> Result { - if value.len() != FixedHash::byte_size() { + TryFrom::try_from(value.as_slice()) + } +} + +impl TryFrom<&[u8]> for FixedHash { + type Error = FixedHashSizeError; + + fn try_from(bytes: &[u8]) -> Result { + if bytes.len() != FixedHash::byte_size() { return Err(FixedHashSizeError); } let mut buf = [0u8; FixedHash::byte_size()]; - buf.copy_from_slice(&value); + buf.copy_from_slice(bytes); Ok(Self(buf)) } } diff --git a/dan_layer/core/src/models/asset_definition.rs b/dan_layer/core/src/models/asset_definition.rs index c88cdb9810..5896e09c88 100644 --- a/dan_layer/core/src/models/asset_definition.rs +++ b/dan_layer/core/src/models/asset_definition.rs @@ -24,7 +24,7 @@ use std::{fmt, marker::PhantomData}; use serde::{self, de, Deserialize, Deserializer, Serialize}; use tari_common_types::types::PublicKey; -use tari_core::transactions::transaction::TemplateParameter; +use tari_core::transactions::transaction_components::TemplateParameter; use tari_crypto::tari_utilities::hex::Hex; #[derive(Deserialize, Clone, Debug)] @@ -94,6 +94,17 @@ pub struct SchemaState { pub items: Vec, } +impl SchemaState { + pub fn new(name: String, items: Vec) -> Self { + Self { name, items } + } + + pub fn push_key_value(&mut self, key_value: KeyValue) -> &mut Self { + self.items.push(key_value); + self + } +} + #[derive(Serialize, Deserialize, Default, Clone, Debug)] pub struct KeyValue { pub key: Vec, diff --git a/dan_layer/core/src/models/base_layer_output.rs b/dan_layer/core/src/models/base_layer_output.rs index 963b7b8a50..99055828ac 100644 --- a/dan_layer/core/src/models/base_layer_output.rs +++ b/dan_layer/core/src/models/base_layer_output.rs @@ -21,9 +21,14 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //! A trait to allow abstraction from a specific base layer output +use std::convert::TryFrom; + use tari_common_types::types::PublicKey; -use tari_core::transactions::transaction::OutputFeatures; +use tari_core::transactions::transaction_components::{OutputFeatures, OutputFlags}; + +use crate::{fixed_hash::FixedHash, models::ModelError}; +#[derive(Debug)] pub struct BaseLayerOutput { pub features: OutputFeatures, } @@ -35,4 +40,54 @@ impl BaseLayerOutput { .as_ref() .map(|s| s.committee.as_slice()) } + + pub fn get_checkpoint_merkle_root(&self) -> Option { + self.features + .sidechain_checkpoint + .as_ref() + .map(|cp| cp.merkle_root.into()) + } + + pub fn get_parent_public_key(&self) -> Option<&PublicKey> { + self.features.parent_public_key.as_ref() + } +} + +#[derive(Debug, Clone)] +pub struct CheckpointOutput { + pub flags: OutputFlags, + pub parent_public_key: PublicKey, + pub merkle_root: FixedHash, + pub committee: Vec, +} + +impl TryFrom for CheckpointOutput { + type Error = ModelError; + + fn try_from(output: BaseLayerOutput) -> Result { + if !output.features.flags.contains(OutputFlags::SIDECHAIN_CHECKPOINT) { + return Err(ModelError::NotCheckpointOutput); + } + + let parent_public_key = output + .get_parent_public_key() + .cloned() + .ok_or(ModelError::CheckpointOutputMissingParentPublicKey)?; + + let merkle_root = output + .get_checkpoint_merkle_root() + .ok_or(ModelError::CheckpointOutputMissingCheckpointMerkleRoot)?; + + let committee = output + .get_side_chain_committee() + .ok_or(ModelError::CheckpointOutputMissingSidechainCommittee)? + .to_vec(); + + Ok(Self { + flags: output.features.flags, + parent_public_key, + merkle_root, + committee, + }) + } } diff --git a/dan_layer/core/src/models/domain_events/consensus_worker_domain_event.rs b/dan_layer/core/src/models/domain_events/consensus_worker_domain_event.rs index 978e4a5c95..abeb9def29 100644 --- a/dan_layer/core/src/models/domain_events/consensus_worker_domain_event.rs +++ b/dan_layer/core/src/models/domain_events/consensus_worker_domain_event.rs @@ -27,8 +27,8 @@ use crate::models::{ConsensusWorkerState, Event}; #[derive(Debug, Clone, PartialEq)] pub enum ConsensusWorkerDomainEvent { StateChanged { - old: ConsensusWorkerState, - new: ConsensusWorkerState, + from: ConsensusWorkerState, + to: ConsensusWorkerState, }, } @@ -37,7 +37,7 @@ impl Event for ConsensusWorkerDomainEvent {} impl fmt::Display for ConsensusWorkerDomainEvent { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - ConsensusWorkerDomainEvent::StateChanged { old, new } => { + ConsensusWorkerDomainEvent::StateChanged { from: old, to: new } => { write!(f, "State changed from {:?} to {:?}", old, new) }, } diff --git a/dan_layer/core/src/models/error.rs b/dan_layer/core/src/models/error.rs index d0fd37ec53..c6ffc8b6fa 100644 --- a/dan_layer/core/src/models/error.rs +++ b/dan_layer/core/src/models/error.rs @@ -26,4 +26,12 @@ pub enum ModelError { InvalidTemplateIdNumber { value: i64 }, #[error("Failed to parse string: {details}")] StringParseError { details: String }, + #[error("Checkpoint output is missing parent public key")] + CheckpointOutputMissingParentPublicKey, + #[error("Checkpoint output is missing checkpoint merkle root")] + CheckpointOutputMissingCheckpointMerkleRoot, + #[error("Checkpoint output is missing side chain committee")] + CheckpointOutputMissingSidechainCommittee, + #[error("Output is not flagged as a checkpoint output")] + NotCheckpointOutput, } diff --git a/dan_layer/core/src/models/hot_stuff_tree_node.rs b/dan_layer/core/src/models/hot_stuff_tree_node.rs index 9cc9543e3b..19d319ad16 100644 --- a/dan_layer/core/src/models/hot_stuff_tree_node.rs +++ b/dan_layer/core/src/models/hot_stuff_tree_node.rs @@ -52,7 +52,7 @@ impl HotStuffTreeNode { parent: TreeNodeHash::zero(), payload, hash: TreeNodeHash::zero(), - state_root: StateRoot::default(), + state_root: StateRoot::initial(), height: 0, }; s.hash = s.calculate_hash(); @@ -73,6 +73,7 @@ impl HotStuffTreeNode { .chain(self.parent.as_bytes()) .chain(self.payload.consensus_hash()) .chain(self.height.to_le_bytes()) + .chain(self.state_root.as_bytes()) .finalize_fixed(); result.into() } diff --git a/dan_layer/core/src/models/mod.rs b/dan_layer/core/src/models/mod.rs index 007452bdef..7f6f0c870e 100644 --- a/dan_layer/core/src/models/mod.rs +++ b/dan_layer/core/src/models/mod.rs @@ -38,6 +38,7 @@ mod hot_stuff_tree_node; mod instruction; mod instruction_set; mod node; +mod op_log; mod payload; mod quorum_certificate; mod sidechain_block; @@ -48,9 +49,9 @@ mod tree_node_hash; mod view; mod view_id; -pub use asset_definition::AssetDefinition; +pub use asset_definition::{AssetDefinition, InitialState, KeyValue, SchemaState}; pub use base_layer_metadata::BaseLayerMetadata; -pub use base_layer_output::BaseLayerOutput; +pub use base_layer_output::{BaseLayerOutput, CheckpointOutput}; pub use committee::Committee; pub use error::ModelError; pub use hot_stuff_message::HotStuffMessage; @@ -58,6 +59,7 @@ pub use hot_stuff_tree_node::HotStuffTreeNode; pub use instruction::Instruction; pub use instruction_set::InstructionSet; pub use node::Node; +pub use op_log::{StateOpLogEntry, StateOperation}; pub use payload::Payload; pub use quorum_certificate::QuorumCertificate; pub use sidechain_block::SideChainBlock; @@ -211,6 +213,7 @@ pub trait Event: Clone + Send + Sync {} #[derive(Debug, Clone, Copy, PartialEq)] pub enum ConsensusWorkerState { Starting, + Synchronizing, Prepare, PreCommit, Commit, diff --git a/dan_layer/core/src/models/op_log.rs b/dan_layer/core/src/models/op_log.rs new file mode 100644 index 0000000000..0479a7b442 --- /dev/null +++ b/dan_layer/core/src/models/op_log.rs @@ -0,0 +1,69 @@ +// Copyright 2022, 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 crate::storage::state::{DbStateOpLogEntry, DbStateOperation}; + +#[derive(Debug)] +pub struct StateOpLogEntry { + inner: DbStateOpLogEntry, +} + +impl StateOpLogEntry { + pub fn operation(&self) -> StateOperation { + self.inner.operation.into() + } + + pub fn into_inner(self) -> DbStateOpLogEntry { + self.inner + } +} + +impl From for StateOpLogEntry { + fn from(inner: DbStateOpLogEntry) -> Self { + Self { inner } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum StateOperation { + Set, + Delete, +} + +impl StateOperation { + pub fn as_op_str(&self) -> &str { + use StateOperation::*; + match self { + Set => "S", + Delete => "D", + } + } +} + +impl From for StateOperation { + fn from(op: DbStateOperation) -> Self { + match op { + DbStateOperation::Set => StateOperation::Set, + DbStateOperation::Delete => StateOperation::Delete, + } + } +} diff --git a/dan_layer/core/src/models/state_root.rs b/dan_layer/core/src/models/state_root.rs index 801e42b888..a16ce23caa 100644 --- a/dan_layer/core/src/models/state_root.rs +++ b/dan_layer/core/src/models/state_root.rs @@ -20,17 +20,25 @@ // 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. -#[derive(Default, PartialEq, Debug, Clone)] +use crate::fixed_hash::FixedHash; + +#[derive(PartialEq, Debug, Clone)] pub struct StateRoot { - root: Vec, + root: FixedHash, } impl StateRoot { - pub fn new(root: Vec) -> Self { + pub fn new(root: FixedHash) -> Self { Self { root } } pub fn as_bytes(&self) -> &[u8] { self.root.as_slice() } + + pub fn initial() -> Self { + Self { + root: FixedHash::zero(), + } + } } diff --git a/dan_layer/core/src/models/tari_dan_payload.rs b/dan_layer/core/src/models/tari_dan_payload.rs index 167793e9bf..f04d59012b 100644 --- a/dan_layer/core/src/models/tari_dan_payload.rs +++ b/dan_layer/core/src/models/tari_dan_payload.rs @@ -25,11 +25,14 @@ use std::fmt::Debug; use digest::Digest; use tari_crypto::common::Blake256; -use crate::models::{ConsensusHash, Instruction, InstructionSet, Payload}; +use crate::{ + fixed_hash::FixedHash, + models::{ConsensusHash, Instruction, InstructionSet, Payload}, +}; #[derive(Debug, Clone)] pub struct TariDanPayload { - hash: Vec, + hash: FixedHash, instruction_set: InstructionSet, checkpoint: Option, } @@ -37,7 +40,7 @@ pub struct TariDanPayload { impl TariDanPayload { pub fn new(instruction_set: InstructionSet, checkpoint: Option) -> Self { let mut result = Self { - hash: vec![], + hash: FixedHash::zero(), instruction_set, checkpoint, }; @@ -53,12 +56,12 @@ impl TariDanPayload { self.instruction_set.instructions() } - fn calculate_hash(&self) -> Vec { + fn calculate_hash(&self) -> FixedHash { let result = Blake256::new().chain(self.instruction_set.consensus_hash()); if let Some(ref ck) = self.checkpoint { - result.chain(ck.consensus_hash()).finalize().to_vec() + result.chain(ck.consensus_hash()).finalize().into() } else { - result.finalize().to_vec() + result.finalize().into() } } } @@ -73,7 +76,7 @@ impl Payload for TariDanPayload {} #[derive(Debug, Clone, Default)] pub struct CheckpointData { - hash: Vec, + hash: FixedHash, } impl ConsensusHash for CheckpointData { diff --git a/dan_layer/core/src/services/asset_processor.rs b/dan_layer/core/src/services/asset_processor.rs index 8e1f66b42d..8d15ebd3ca 100644 --- a/dan_layer/core/src/services/asset_processor.rs +++ b/dan_layer/core/src/services/asset_processor.rs @@ -22,12 +22,12 @@ use std::convert::TryInto; -use tari_core::transactions::transaction::TemplateParameter; +use tari_core::transactions::transaction_components::TemplateParameter; use crate::{ digital_assets_error::DigitalAssetError, models::{AssetDefinition, Instruction, TemplateId}, - storage::state::StateDbUnitOfWork, + storage::state::{StateDbUnitOfWork, StateDbUnitOfWorkReader}, template_command::ExecutionResult, templates::{tip002_template, tip004_template, tip721_template}, }; @@ -48,12 +48,12 @@ pub trait AssetProcessor: Sync + Send + 'static { db: &mut TUnitOfWork, ) -> Result<(), DigitalAssetError>; - fn invoke_read_method( + fn invoke_read_method( &self, template_id: TemplateId, method: String, args: &[u8], - state_db: &mut TUnifOfWork, + state_db: &mut TUnitOfWorkReader, ) -> Result>, DigitalAssetError>; } @@ -89,12 +89,12 @@ impl AssetProcessor for ConcreteAssetProcessor { ) } - fn invoke_read_method( + fn invoke_read_method( &self, template_id: TemplateId, method: String, args: &[u8], - state_db: &mut TUnifOfWork, + state_db: &mut TUnitOfWork, ) -> Result>, DigitalAssetError> { match template_id { TemplateId::Tip002 => tip002_template::invoke_read_method(method, args, state_db), diff --git a/dan_layer/core/src/services/asset_proxy.rs b/dan_layer/core/src/services/asset_proxy.rs index f7b548c2d3..cb4890f7ae 100644 --- a/dan_layer/core/src/services/asset_proxy.rs +++ b/dan_layer/core/src/services/asset_proxy.rs @@ -101,9 +101,10 @@ impl> ConcreteAsse args: Vec, ) -> Result>, DigitalAssetError> { let mut client = self.validator_node_client_factory.create_client(member); - client + let resp = client .invoke_read_method(asset_public_key, template_id, method, args) - .await + .await?; + Ok(resp) } async fn forward_invoke_to_node( @@ -115,7 +116,10 @@ impl> ConcreteAsse args: Vec, ) -> Result>, DigitalAssetError> { let mut client = self.validator_node_client_factory.create_client(member); - client.invoke_method(asset_public_key, template_id, method, args).await + let resp = client + .invoke_method(asset_public_key, template_id, method, args) + .await?; + Ok(resp) } #[allow(clippy::for_loops_over_fallibles)] diff --git a/dan_layer/core/src/services/base_node_client.rs b/dan_layer/core/src/services/base_node_client.rs index ae77144a8d..2afbacab4d 100644 --- a/dan_layer/core/src/services/base_node_client.rs +++ b/dan_layer/core/src/services/base_node_client.rs @@ -43,4 +43,9 @@ pub trait BaseNodeClient { &mut self, dan_node_public_key: PublicKey, ) -> Result, DigitalAssetError>; + + async fn get_asset_registration( + &mut self, + asset_public_key: PublicKey, + ) -> Result, DigitalAssetError>; } diff --git a/dan_layer/core/src/services/events_publisher.rs b/dan_layer/core/src/services/events_publisher.rs index 73da7dcd08..866a5af2cb 100644 --- a/dan_layer/core/src/services/events_publisher.rs +++ b/dan_layer/core/src/services/events_publisher.rs @@ -48,6 +48,6 @@ impl Default for LoggingEventsPublisher { impl EventsPublisher for LoggingEventsPublisher { fn publish(&mut self, event: TEvent) { - debug!(target: LOG_TARGET, "[Event] Event received:{}", event); + debug!(target: LOG_TARGET, "[Event] Event received: {}", event); } } diff --git a/dan_layer/core/src/services/mocks/mod.rs b/dan_layer/core/src/services/mocks/mod.rs index 50097ba479..36db7254da 100644 --- a/dan_layer/core/src/services/mocks/mod.rs +++ b/dan_layer/core/src/services/mocks/mod.rs @@ -28,7 +28,7 @@ use std::{ use async_trait::async_trait; use tari_common_types::types::PublicKey; -use tari_core::transactions::transaction::TemplateParameter; +use tari_core::transactions::transaction_components::TemplateParameter; use super::CommitteeManager; use crate::{ @@ -57,7 +57,7 @@ use crate::{ PayloadProvider, SigningService, }, - storage::state::StateDbUnitOfWork, + storage::state::{StateDbUnitOfWork, StateDbUnitOfWorkReader}, }; #[derive(Debug, Clone)] @@ -207,6 +207,13 @@ impl BaseNodeClient for MockBaseNodeClient { ) -> Result, DigitalAssetError> { todo!(); } + + async fn get_asset_registration( + &mut self, + _asset_public_key: PublicKey, + ) -> Result, DigitalAssetError> { + todo!() + } } pub fn mock_base_node_client() -> MockBaseNodeClient { @@ -289,7 +296,7 @@ impl AssetProcessor for MockAssetProcessor { todo!() } - fn invoke_read_method( + fn invoke_read_method( &self, _template_id: TemplateId, _method: String, diff --git a/dan_layer/core/src/services/mod.rs b/dan_layer/core/src/services/mod.rs index 57ef78dbb9..34a809df4a 100644 --- a/dan_layer/core/src/services/mod.rs +++ b/dan_layer/core/src/services/mod.rs @@ -48,5 +48,5 @@ mod validator_node_rpc_client; mod wallet_client; pub use checkpoint_manager::{CheckpointManager, ConcreteCheckpointManager}; pub use service_specification::ServiceSpecification; -pub use validator_node_rpc_client::{ValidatorNodeClientFactory, ValidatorNodeRpcClient}; +pub use validator_node_rpc_client::{ValidatorNodeClientError, ValidatorNodeClientFactory, ValidatorNodeRpcClient}; pub use wallet_client::WalletClient; diff --git a/dan_layer/core/src/services/payload_processor.rs b/dan_layer/core/src/services/payload_processor.rs index 1c3641b5ee..c2c79daeda 100644 --- a/dan_layer/core/src/services/payload_processor.rs +++ b/dan_layer/core/src/services/payload_processor.rs @@ -21,7 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use async_trait::async_trait; -use tari_core::transactions::transaction::TemplateParameter; +use tari_core::transactions::transaction_components::TemplateParameter; use crate::{ digital_assets_error::DigitalAssetError, diff --git a/dan_layer/core/src/services/validator_node_rpc_client.rs b/dan_layer/core/src/services/validator_node_rpc_client.rs index 9392fcb730..672b29351d 100644 --- a/dan_layer/core/src/services/validator_node_rpc_client.rs +++ b/dan_layer/core/src/services/validator_node_rpc_client.rs @@ -22,11 +22,16 @@ use async_trait::async_trait; use tari_common_types::types::PublicKey; +use tari_comms::{ + connectivity::ConnectivityError, + protocol::rpc::{RpcError, RpcStatus}, + types::CommsPublicKey, +}; +use tari_comms_dht::DhtDiscoveryError; use crate::{ - models::{SideChainBlock, TemplateId, TreeNodeHash}, + models::{Node, SchemaState, SideChainBlock, StateOpLogEntry, TemplateId, TreeNodeHash}, services::infrastructure_services::NodeAddressable, - DigitalAssetError, }; pub trait ValidatorNodeClientFactory { @@ -43,7 +48,7 @@ pub trait ValidatorNodeRpcClient { template_id: TemplateId, method: String, args: Vec, - ) -> Result>, DigitalAssetError>; + ) -> Result>, ValidatorNodeClientError>; async fn invoke_method( &mut self, @@ -51,12 +56,41 @@ pub trait ValidatorNodeRpcClient { template_id: TemplateId, method: String, args: Vec, - ) -> Result>, DigitalAssetError>; + ) -> Result>, ValidatorNodeClientError>; async fn get_sidechain_blocks( &mut self, asset_public_key: &PublicKey, start_hash: TreeNodeHash, end_hash: Option, - ) -> Result, DigitalAssetError>; + ) -> Result, ValidatorNodeClientError>; + + async fn get_sidechain_state( + &mut self, + asset_public_key: &PublicKey, + ) -> Result, ValidatorNodeClientError>; + + async fn get_op_logs( + &mut self, + asset_public_key: &PublicKey, + height: u64, + ) -> Result, ValidatorNodeClientError>; + + async fn get_tip_node(&mut self, asset_public_key: &PublicKey) -> Result, ValidatorNodeClientError>; +} + +#[derive(Debug, thiserror::Error)] +pub enum ValidatorNodeClientError { + #[error("Protocol violations for peer {peer}: {details}")] + ProtocolViolation { peer: CommsPublicKey, details: String }, + #[error("Peer sent an invalid message: {0}")] + InvalidPeerMessage(String), + #[error("Connectivity error:{0}")] + ConnectivityError(#[from] ConnectivityError), + #[error("RpcError: {0}")] + RpcError(#[from] RpcError), + #[error("Remote node returned error: {0}")] + RpcStatusError(#[from] RpcStatus), + #[error("Dht Discovery error: {0}")] + DhtDiscoveryError(#[from] DhtDiscoveryError), } diff --git a/dan_layer/core/src/storage/chain/chain_db.rs b/dan_layer/core/src/storage/chain/chain_db.rs index 866591974f..3e85921a62 100644 --- a/dan_layer/core/src/storage/chain/chain_db.rs +++ b/dan_layer/core/src/storage/chain/chain_db.rs @@ -19,7 +19,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - models::{QuorumCertificate, SideChainBlock, TreeNodeHash}, + models::{Node, QuorumCertificate, SideChainBlock, TreeNodeHash}, storage::{ chain::{chain_db_unit_of_work::ChainDbUnitOfWorkImpl, ChainDbBackendAdapter}, StorageError, @@ -97,6 +97,11 @@ impl ChainDb { Ok(Some(SideChainBlock::new(node.into(), instructions))) } + + pub fn get_tip_node(&self) -> Result, StorageError> { + let db_node = self.adapter.get_tip_node().map_err(TBackendAdapter::Error::into)?; + Ok(db_node.map(Into::into)) + } } impl ChainDb { diff --git a/dan_layer/core/src/storage/chain/chain_db_backend_adapter.rs b/dan_layer/core/src/storage/chain/chain_db_backend_adapter.rs index 70e3846ddf..031a8c96c6 100644 --- a/dan_layer/core/src/storage/chain/chain_db_backend_adapter.rs +++ b/dan_layer/core/src/storage/chain/chain_db_backend_adapter.rs @@ -37,8 +37,9 @@ pub trait ChainDbBackendAdapter: Send + Sync + Clone { type Payload: Payload; fn is_empty(&self) -> Result; - fn node_exists(&self, node_hash: &TreeNodeHash) -> Result; fn create_transaction(&self) -> Result; + fn node_exists(&self, node_hash: &TreeNodeHash) -> Result; + fn get_tip_node(&self) -> Result, Self::Error>; fn insert_node(&self, item: &DbNode, transaction: &Self::BackendTransaction) -> Result<(), Self::Error>; fn update_node( &self, diff --git a/dan_layer/core/src/storage/chain/chain_db_unit_of_work.rs b/dan_layer/core/src/storage/chain/chain_db_unit_of_work.rs index f7cbe41e83..db812fe1df 100644 --- a/dan_layer/core/src/storage/chain/chain_db_unit_of_work.rs +++ b/dan_layer/core/src/storage/chain/chain_db_unit_of_work.rs @@ -27,7 +27,7 @@ use std::{ }; use crate::{ - models::{Instruction, QuorumCertificate, TreeNodeHash}, + models::{Instruction, Node, QuorumCertificate, TreeNodeHash}, storage::{ chain::{db_node::DbNode, ChainDbBackendAdapter, DbInstruction, DbQc}, unit_of_work_tracker::UnitOfWorkTracker, @@ -45,6 +45,7 @@ pub trait ChainDbUnitOfWork: Clone + Send + Sync { fn set_prepare_qc(&mut self, qc: &QuorumCertificate) -> Result<(), StorageError>; fn commit_node(&mut self, node_hash: &TreeNodeHash) -> Result<(), StorageError>; // fn find_proposed_node(&mut self, node_hash: TreeNodeHash) -> Result<(Self::Id, UnitOfWorkTracker), StorageError>; + fn get_tip_node(&self) -> Result, StorageError>; } // Cloneable, Send, Sync wrapper @@ -286,6 +287,11 @@ impl ChainDbUnitOfWork for ChainDbUnitOf node.is_committed = true; Ok(()) } + + fn get_tip_node(&self) -> Result, StorageError> { + let inner = self.inner.read().unwrap(); + inner.get_tip_node() + } } pub struct ChainDbUnitOfWorkInner { @@ -331,4 +337,12 @@ impl ChainDbUnitOfWorkInner Result, StorageError> { + let node = self + .backend_adapter + .get_tip_node() + .map_err(TBackendAdapter::Error::into)?; + Ok(node.map(Into::into)) + } } diff --git a/dan_layer/core/src/storage/mocks/chain_db.rs b/dan_layer/core/src/storage/mocks/chain_db.rs index f2de215bb9..70eeb830a0 100644 --- a/dan_layer/core/src/storage/mocks/chain_db.rs +++ b/dan_layer/core/src/storage/mocks/chain_db.rs @@ -180,4 +180,19 @@ impl ChainDbBackendAdapter for MockChainDbBackupAdapter { lock.locked_qc.update(id, locked_qc.clone()); Ok(()) } + + fn get_tip_node(&self) -> Result, Self::Error> { + let lock = self.db.read().unwrap(); + let found = lock + .nodes + .rows() + .fold(None, |val: Option<&DbNode>, row| match val { + Some(v) if v.height < row.height => Some(row), + Some(v) => Some(v), + None => Some(row), + }) + .cloned(); + + Ok(found) + } } diff --git a/dan_layer/core/src/storage/mocks/state_db.rs b/dan_layer/core/src/storage/mocks/state_db.rs index d4e272e4cf..2ca153cec0 100644 --- a/dan_layer/core/src/storage/mocks/state_db.rs +++ b/dan_layer/core/src/storage/mocks/state_db.rs @@ -23,7 +23,7 @@ use patricia_tree::PatriciaMap; use crate::storage::{ - state::{DbKeyValue, StateDbBackendAdapter}, + state::{DbKeyValue, DbStateOpLogEntry, StateDbBackendAdapter}, StorageError, }; @@ -83,4 +83,24 @@ impl StateDbBackendAdapter for MockStateDbBackupAdapter { ) -> Result, Self::Error> { todo!() } + + fn get_state_op_logs_by_height( + &self, + _height: u64, + _tx: &Self::BackendTransaction, + ) -> Result, Self::Error> { + todo!() + } + + fn add_state_oplog_entry( + &self, + _entry: DbStateOpLogEntry, + _tx: &Self::BackendTransaction, + ) -> Result<(), Self::Error> { + todo!() + } + + fn clear_all_state(&self, _tx: &Self::BackendTransaction) -> Result<(), Self::Error> { + todo!() + } } diff --git a/dan_layer/core/src/storage/state/db_key_value.rs b/dan_layer/core/src/storage/state/db_key_value.rs index 9193353544..496b53554b 100644 --- a/dan_layer/core/src/storage/state/db_key_value.rs +++ b/dan_layer/core/src/storage/state/db_key_value.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. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct DbKeyValue { pub schema: String, pub key: Vec, diff --git a/dan_layer/core/src/storage/state/mod.rs b/dan_layer/core/src/storage/state/mod.rs index 3bbfad5d62..00eaeb630a 100644 --- a/dan_layer/core/src/storage/state/mod.rs +++ b/dan_layer/core/src/storage/state/mod.rs @@ -20,10 +20,16 @@ // 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. mod state_db_unit_of_work; -pub use state_db_unit_of_work::{StateDbUnitOfWork, StateDbUnitOfWorkImpl}; +pub use state_db_unit_of_work::{StateDbUnitOfWork, StateDbUnitOfWorkImpl, StateDbUnitOfWorkReader, UnitOfWorkContext}; + mod db_key_value; pub use db_key_value::DbKeyValue; + mod state_db; pub use state_db::StateDb; + mod state_db_backend_adapter; pub use state_db_backend_adapter::StateDbBackendAdapter; + +mod state_op_log; +pub use state_op_log::{DbStateOpLogEntry, DbStateOperation}; diff --git a/dan_layer/core/src/storage/state/state_db.rs b/dan_layer/core/src/storage/state/state_db.rs index 4efbce10b1..a6452eff81 100644 --- a/dan_layer/core/src/storage/state/state_db.rs +++ b/dan_layer/core/src/storage/state/state_db.rs @@ -20,9 +20,12 @@ // 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 crate::storage::state::{state_db_unit_of_work::StateDbUnitOfWorkImpl, StateDbBackendAdapter}; +use crate::storage::state::{ + state_db_unit_of_work::{StateDbUnitOfWorkImpl, StateDbUnitOfWorkReader, UnitOfWorkContext}, + StateDbBackendAdapter, +}; -pub struct StateDb { +pub struct StateDb { backend_adapter: TStateDbBackendAdapter, } @@ -31,14 +34,13 @@ impl StateDb StateDbUnitOfWorkImpl { - StateDbUnitOfWorkImpl::new(self.backend_adapter.clone()) + pub fn new_unit_of_work(&self, height: u64) -> StateDbUnitOfWorkImpl { + StateDbUnitOfWorkImpl::new(UnitOfWorkContext::new(height), self.backend_adapter.clone()) + } - // let mut unit_of_work = self.current_unit_of_work_mut(); - // if unit_of_work.is_none() { - // self.unit_of_work = Some(StateDbUnitOfWork {}); - // unit_of_work = self.unit_of_work - // }; - // unit_of_work.as_mut().unwrap() + pub fn reader(&self) -> impl StateDbUnitOfWorkReader { + // TODO: A reader doesnt need the current context, should perhaps make a read-only implementation that the + // writable implementation also uses + StateDbUnitOfWorkImpl::new(UnitOfWorkContext::new(0), self.backend_adapter.clone()) } } diff --git a/dan_layer/core/src/storage/state/state_db_backend_adapter.rs b/dan_layer/core/src/storage/state/state_db_backend_adapter.rs index 02a41406a7..df8b0080aa 100644 --- a/dan_layer/core/src/storage/state/state_db_backend_adapter.rs +++ b/dan_layer/core/src/storage/state/state_db_backend_adapter.rs @@ -22,7 +22,10 @@ use patricia_tree::PatriciaMap; -use crate::storage::{state::db_key_value::DbKeyValue, StorageError}; +use crate::storage::{ + state::{db_key_value::DbKeyValue, DbStateOpLogEntry}, + StorageError, +}; pub trait StateDbBackendAdapter: Send + Sync + Clone { type BackendTransaction; @@ -52,4 +55,12 @@ pub trait StateDbBackendAdapter: Send + Sync + Clone { schema: &str, tx: &Self::BackendTransaction, ) -> Result, Self::Error>; + fn get_state_op_logs_by_height( + &self, + height: u64, + tx: &Self::BackendTransaction, + ) -> Result, Self::Error>; + fn add_state_oplog_entry(&self, entry: DbStateOpLogEntry, tx: &Self::BackendTransaction) + -> Result<(), Self::Error>; + fn clear_all_state(&self, tx: &Self::BackendTransaction) -> Result<(), Self::Error>; } diff --git a/dan_layer/core/src/storage/state/state_db_unit_of_work.rs b/dan_layer/core/src/storage/state/state_db_unit_of_work.rs index 4c715951d9..b973386be6 100644 --- a/dan_layer/core/src/storage/state/state_db_unit_of_work.rs +++ b/dan_layer/core/src/storage/state/state_db_unit_of_work.rs @@ -20,40 +20,67 @@ // 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, RwLock, RwLockReadGuard}; +use std::{ + convert::TryInto, + ops::Deref, + sync::{Arc, RwLock, RwLockReadGuard}, +}; use digest::Digest; +use log::*; use tari_common_types::types::HashDigest; use tari_crypto::common::Blake256; use tari_mmr::{MemBackendVec, MerkleMountainRange}; +use tari_utilities::hex::Hex; use crate::{ - models::StateRoot, + models::{KeyValue, SchemaState, StateOpLogEntry, StateRoot}, storage::{ - state::{db_key_value::DbKeyValue, StateDbBackendAdapter}, + state::{db_key_value::DbKeyValue, DbStateOpLogEntry, StateDbBackendAdapter}, StorageError, UnitOfWorkTracker, }, }; -pub trait StateDbUnitOfWork: Clone + Send + Sync { +const LOG_TARGET: &str = "tari::dan::state_db"; + +pub trait StateDbUnitOfWork: StateDbUnitOfWorkReader { fn set_value(&mut self, schema: String, key: Vec, value: Vec) -> Result<(), StorageError>; + fn set_u64(&mut self, schema: &str, key: &[u8], value: u64) -> Result<(), StorageError>; + fn commit(&mut self) -> Result<(), StorageError>; + fn clear_all_state(&self) -> Result<(), StorageError>; +} + +pub trait StateDbUnitOfWorkReader: Clone + Send + Sync { fn get_value(&mut self, schema: &str, key: &[u8]) -> Result>, StorageError>; fn get_u64(&mut self, schema: &str, key: &[u8]) -> Result, StorageError>; - fn set_u64(&mut self, schema: &str, key: &[u8], value: u64) -> Result<(), StorageError>; fn find_keys_by_value(&self, schema: &str, value: &[u8]) -> Result>, StorageError>; - fn commit(&mut self) -> Result<(), StorageError>; fn calculate_root(&self) -> Result; + fn get_all_state(&self) -> Result, StorageError>; + fn get_op_logs_for_height(&self, height: u64) -> Result, StorageError>; +} + +#[derive(Debug, Clone)] +pub struct UnitOfWorkContext { + pub height: u64, +} + +impl UnitOfWorkContext { + pub fn new(height: u64) -> Self { + Self { height } + } } pub struct StateDbUnitOfWorkImpl { inner: Arc>>, + context: UnitOfWorkContext, } impl StateDbUnitOfWorkImpl { - pub fn new(backend_adapter: TBackendAdapter) -> Self { + pub fn new(context: UnitOfWorkContext, backend_adapter: TBackendAdapter) -> Self { Self { inner: Arc::new(RwLock::new(StateDbUnitOfWorkInner::new(backend_adapter))), + context, } } } @@ -62,6 +89,7 @@ impl Clone for StateDbUnitOfWorkImpl Self { Self { inner: self.inner.clone(), + context: self.context.clone(), } } } @@ -76,6 +104,69 @@ impl StateDbUnitOfWork for StateDbUnitOf Ok(()) } + fn set_u64(&mut self, schema: &str, key: &[u8], value: u64) -> Result<(), StorageError> { + self.set_value(schema.to_string(), Vec::from(key), Vec::from(value.to_le_bytes())) + } + + fn commit(&mut self) -> Result<(), StorageError> { + let mut inner = self.inner.write().unwrap(); + let tx = inner + .backend_adapter + .create_transaction() + .map_err(TBackendAdapter::Error::into)?; + // let mut current_tree = inner + // .backend_adapter + // .get_current_state_tree(&tx) + // .map_err(TBackendAdapter::Error::into)?; + debug!(target: LOG_TARGET, "Committing {} state update(s)", inner.updates.len()); + for item in &inner.updates { + let i = item.get(); + inner + .backend_adapter + .update_key_value(&i.schema, &i.key, &i.value, &tx) + .map_err(TBackendAdapter::Error::into)?; + + inner + .backend_adapter + .add_state_oplog_entry( + DbStateOpLogEntry::set_operation(self.context.height, i.deref().clone()), + &tx, + ) + .map_err(TBackendAdapter::Error::into)?; + // let key = format!("{}.{}", &i.schema, bs58::encode(&i.key).into_string()); + // current_tree.insert(key, i.value.clone()); + } + + // inner + // .backend_adapter + // .set_current_state_tree(current_tree, &tx) + // .map_err(TBackendAdapter::Error::into)?; + + inner + .backend_adapter + .commit(&tx) + .map_err(TBackendAdapter::Error::into)?; + inner.updates = vec![]; + + Ok(()) + } + + /// Clears the state db immediately (before commit) - this will not be needed in future when build up the state from + /// instructions/op logs + fn clear_all_state(&self) -> Result<(), StorageError> { + let inner = self.inner.write().unwrap(); + let tx = inner + .backend_adapter + .create_transaction() + .map_err(TBackendAdapter::Error::into)?; + inner + .backend_adapter + .clear_all_state(&tx) + .map_err(TBackendAdapter::Error::into) + } +} + +impl StateDbUnitOfWorkReader for StateDbUnitOfWorkImpl { fn get_value(&mut self, schema: &str, key: &[u8]) -> Result>, StorageError> { let mut inner = self.inner.write().unwrap(); for v in &inner.updates { @@ -110,17 +201,12 @@ impl StateDbUnitOfWork for StateDbUnitOf Some(data) => { let mut data2: [u8; 8] = [0; 8]; data2.copy_from_slice(&data); - Ok(Some(u64::from_le_bytes(data2))) }, None => Ok(None), } } - fn set_u64(&mut self, schema: &str, key: &[u8], value: u64) -> Result<(), StorageError> { - self.set_value(schema.to_string(), Vec::from(key), Vec::from(value.to_le_bytes())) - } - fn find_keys_by_value(&self, schema: &str, value: &[u8]) -> Result>, StorageError> { let inner = self.inner.read().unwrap(); inner @@ -129,40 +215,6 @@ impl StateDbUnitOfWork for StateDbUnitOf .map_err(TBackendAdapter::Error::into) } - fn commit(&mut self) -> Result<(), StorageError> { - let mut inner = self.inner.write().unwrap(); - let tx = inner - .backend_adapter - .create_transaction() - .map_err(TBackendAdapter::Error::into)?; - // let mut current_tree = inner - // .backend_adapter - // .get_current_state_tree(&tx) - // .map_err(TBackendAdapter::Error::into)?; - for item in &inner.updates { - let i = item.get(); - inner - .backend_adapter - .update_key_value(&i.schema, &i.key, &i.value, &tx) - .map_err(TBackendAdapter::Error::into)?; - // let key = format!("{}.{}", &i.schema, bs58::encode(&i.key).into_string()); - // current_tree.insert(key, i.value.clone()); - } - - // inner - // .backend_adapter - // .set_current_state_tree(current_tree, &tx) - // .map_err(TBackendAdapter::Error::into)?; - - inner - .backend_adapter - .commit(&tx) - .map_err(TBackendAdapter::Error::into)?; - inner.updates = vec![]; - - Ok(()) - } - fn calculate_root(&self) -> Result { let inner = self.inner.read().unwrap(); let tx = inner @@ -173,18 +225,30 @@ impl StateDbUnitOfWork for StateDbUnitOf // omg it's an MMR of MMRs let mut top_level_mmr = MerkleMountainRange::::new(MemBackendVec::new()); - - for schema in inner + let schemas = inner .backend_adapter .get_all_schemas(&tx) - .map_err(TBackendAdapter::Error::into)? - { + .map_err(TBackendAdapter::Error::into)?; + debug!( + target: LOG_TARGET, + "calculate_root: {} key value schemas loaded", + schemas.len() + ); + + for schema in schemas { let mut mmr = MerkleMountainRange::::new(MemBackendVec::new()); for key_value in inner .backend_adapter .get_all_values_for_schema(&schema, &tx) .map_err(TBackendAdapter::Error::into)? { + debug!( + target: LOG_TARGET, + "schema = {}, key = {}, value = {}", + schema, + key_value.key.to_hex(), + key_value.value.to_hex() + ); if let Some(updated_value) = find_update(&inner, &schema, &key_value.key) { let hasher = HashDigest::new(); mmr.push(hasher.chain(&key_value.key).chain(updated_value).finalize().to_vec())?; @@ -196,7 +260,59 @@ impl StateDbUnitOfWork for StateDbUnitOf let hasher = HashDigest::new(); top_level_mmr.push(hasher.chain(schema).chain(mmr.get_merkle_root()?).finalize().to_vec())?; } - Ok(StateRoot::new(top_level_mmr.get_merkle_root()?)) + Ok(StateRoot::new( + top_level_mmr + .get_merkle_root()? + .try_into() + .expect("MMR output incorrect size"), + )) + } + + fn get_all_state(&self) -> Result, StorageError> { + let inner = self.inner.read().unwrap(); + let tx = inner + .backend_adapter + .create_transaction() + .map_err(TBackendAdapter::Error::into)?; + + let schemas = inner + .backend_adapter + .get_all_schemas(&tx) + .map_err(TBackendAdapter::Error::into)?; + let mut schema_state = Vec::with_capacity(schemas.len()); + for schema in schemas { + let key_values = inner + .backend_adapter + .get_all_values_for_schema(&schema, &tx) + .map_err(TBackendAdapter::Error::into)?; + + let key_values = key_values + .into_iter() + .map(|kv| { + let value = find_update(&inner, &schema, &kv.key).unwrap_or(kv.value); + KeyValue { key: kv.key, value } + }) + .collect(); + + schema_state.push(SchemaState::new(schema, key_values)); + } + Ok(schema_state) + } + + fn get_op_logs_for_height(&self, height: u64) -> Result, StorageError> { + let inner = self.inner.read().unwrap(); + let tx = inner + .backend_adapter + .create_transaction() + .map_err(TBackendAdapter::Error::into)?; + + let op_logs = inner + .backend_adapter + .get_state_op_logs_by_height(height, &tx) + .map_err(TBackendAdapter::Error::into)?; + + let op_logs = op_logs.into_iter().map(Into::into).collect(); + Ok(op_logs) } } diff --git a/dan_layer/core/src/storage/state/state_op_log.rs b/dan_layer/core/src/storage/state/state_op_log.rs new file mode 100644 index 0000000000..53a5431d7c --- /dev/null +++ b/dan_layer/core/src/storage/state/state_op_log.rs @@ -0,0 +1,77 @@ +// Copyright 2022, 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 std::str::FromStr; + +use crate::{models::TreeNodeHash, storage::state::DbKeyValue}; + +#[derive(Debug)] +pub struct DbStateOpLogEntry { + pub height: u64, + pub merkle_root: Option, + pub operation: DbStateOperation, + pub schema: String, + pub key: Vec, + pub value: Option>, +} + +impl DbStateOpLogEntry { + pub fn set_operation(height: u64, key_value: DbKeyValue) -> Self { + Self { + height, + merkle_root: None, + operation: DbStateOperation::Set, + schema: key_value.schema, + key: key_value.key, + value: Some(key_value.value), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum DbStateOperation { + Set, + Delete, +} + +impl DbStateOperation { + pub fn as_op_str(&self) -> &str { + use DbStateOperation::*; + match self { + Set => "S", + Delete => "D", + } + } +} + +impl FromStr for DbStateOperation { + type Err = (); + + fn from_str(s: &str) -> Result { + use DbStateOperation::*; + match s { + "S" => Ok(Set), + "D" => Ok(Delete), + _ => Err(()), + } + } +} diff --git a/dan_layer/core/src/templates/tip002_template.rs b/dan_layer/core/src/templates/tip002_template.rs index b20b951cf6..abe073b841 100644 --- a/dan_layer/core/src/templates/tip002_template.rs +++ b/dan_layer/core/src/templates/tip002_template.rs @@ -21,11 +21,15 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use prost::Message; -use tari_core::transactions::transaction::TemplateParameter; +use tari_core::transactions::transaction_components::TemplateParameter; use tari_crypto::tari_utilities::{hex::Hex, ByteArray}; use tari_dan_common_types::proto::tips::tip002; -use crate::{models::AssetDefinition, storage::state::StateDbUnitOfWork, DigitalAssetError}; +use crate::{ + models::AssetDefinition, + storage::state::{StateDbUnitOfWork, StateDbUnitOfWorkReader}, + DigitalAssetError, +}; pub fn init( template_parameter: &TemplateParameter, @@ -47,7 +51,7 @@ pub fn init( Ok(()) } -pub fn invoke_read_method( +pub fn invoke_read_method( method: String, args: &[u8], state_db: &mut TUnitOfWork, @@ -69,7 +73,7 @@ pub fn invoke_method( } } -fn balance_of( +fn balance_of( args: &[u8], state_db: &mut TUnitOfWork, ) -> Result>, DigitalAssetError> { diff --git a/dan_layer/core/src/templates/tip004_template.rs b/dan_layer/core/src/templates/tip004_template.rs index 48175ff461..f59473b0d2 100644 --- a/dan_layer/core/src/templates/tip004_template.rs +++ b/dan_layer/core/src/templates/tip004_template.rs @@ -26,7 +26,10 @@ use prost::Message; use tari_crypto::{common::Blake256, tari_utilities::hex::Hex}; use tari_dan_common_types::proto::tips::tip004; -use crate::{storage::state::StateDbUnitOfWork, DigitalAssetError}; +use crate::{ + storage::state::{StateDbUnitOfWork, StateDbUnitOfWorkReader}, + DigitalAssetError, +}; const LOG_TARGET: &str = "tari::dan_layer::core::templates::tip004_template"; @@ -41,7 +44,7 @@ pub fn invoke_method( } } -pub fn invoke_read_method( +pub fn invoke_read_method( method: String, args: &[u8], state_db: &mut TUnitOfWork, @@ -91,7 +94,7 @@ fn hash_of(s: &str) -> Vec { Blake256::new().chain(s).finalize().to_vec() } -fn balance_of( +fn balance_of( args: &[u8], state_db: &mut TUnitOfWork, ) -> Result>, DigitalAssetError> { @@ -111,7 +114,7 @@ fn balance_of( Ok(Some(response_bytes)) } -fn token_of_owner_by_index( +fn token_of_owner_by_index( args: &[u8], state_db: &mut TUnitOfWork, ) -> Result>, DigitalAssetError> { diff --git a/dan_layer/core/src/templates/tip721_template.rs b/dan_layer/core/src/templates/tip721_template.rs index d7a7f6bca4..9fd13a216f 100644 --- a/dan_layer/core/src/templates/tip721_template.rs +++ b/dan_layer/core/src/templates/tip721_template.rs @@ -25,7 +25,10 @@ use prost::Message; use tari_crypto::tari_utilities::{hex::Hex, ByteArray}; use tari_dan_common_types::proto::tips::tip721; -use crate::{storage::state::StateDbUnitOfWork, DigitalAssetError}; +use crate::{ + storage::state::{StateDbUnitOfWork, StateDbUnitOfWorkReader}, + DigitalAssetError, +}; const LOG_TARGET: &str = "tari::dan_layer::core::templates::tip721_template"; @@ -40,7 +43,7 @@ pub fn invoke_method( } } -pub fn invoke_read_method( +pub fn invoke_read_method( method: String, args: &[u8], state_db: &mut TUnitOfWork, @@ -61,7 +64,7 @@ pub fn invoke_read_method( } } -fn owner_of( +fn owner_of( token_id: Vec, state_db: &mut TUnitOfWork, ) -> Result, DigitalAssetError> { diff --git a/dan_layer/core/src/workers/consensus_worker.rs b/dan_layer/core/src/workers/consensus_worker.rs index 3fb0278d5f..f10939c49d 100644 --- a/dan_layer/core/src/workers/consensus_worker.rs +++ b/dan_layer/core/src/workers/consensus_worker.rs @@ -21,6 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use log::*; +use tari_common_types::types::PublicKey; use tari_shutdown::ShutdownSignal; use tokio::time::Duration; @@ -30,7 +31,7 @@ use crate::{ services::{CheckpointManager, CommitteeManager, EventsPublisher, PayloadProvider, ServiceSpecification}, storage::{ chain::ChainDbUnitOfWork, - state::{StateDbUnitOfWork, StateDbUnitOfWorkImpl}, + state::{StateDbUnitOfWork, StateDbUnitOfWorkImpl, StateDbUnitOfWorkReader}, DbFactory, }, workers::{states, states::ConsensusWorkerStateEvent}, @@ -45,7 +46,7 @@ pub struct ConsensusWorker { current_view_id: ViewId, committee_manager: TSpecification::CommitteeManager, timeout: Duration, - node_id: TSpecification::Addr, + node_address: TSpecification::Addr, payload_provider: TSpecification::PayloadProvider, events_publisher: TSpecification::EventsPublisher, signing_service: TSpecification::SigningService, @@ -56,9 +57,10 @@ pub struct ConsensusWorker { chain_storage_service: TSpecification::ChainStorageService, state_db_unit_of_work: Option>, checkpoint_manager: TSpecification::CheckpointManager, + validator_node_client_factory: TSpecification::ValidatorNodeClientFactory, } -impl ConsensusWorker { +impl> ConsensusWorker { pub fn new( inbound_connections: TSpecification::InboundConnectionService, outbound_service: TSpecification::OutboundService, @@ -74,6 +76,7 @@ impl ConsensusWorker { db_factory: TSpecification::DbFactory, chain_storage_service: TSpecification::ChainStorageService, checkpoint_manager: TSpecification::CheckpointManager, + validator_node_client_factory: TSpecification::ValidatorNodeClientFactory, ) -> Self { Self { inbound_connections, @@ -82,7 +85,7 @@ impl ConsensusWorker { timeout, outbound_service, committee_manager, - node_id, + node_address: node_id, payload_provider, events_publisher, signing_service, @@ -93,6 +96,7 @@ impl ConsensusWorker { chain_storage_service, state_db_unit_of_work: None, checkpoint_manager, + validator_node_client_factory, } } @@ -103,7 +107,7 @@ impl ConsensusWorker { .committee_manager .current_committee()? .leader_for_view(self.current_view_id) == - &self.node_id, + &self.node_address, }) } @@ -128,13 +132,11 @@ impl ConsensusWorker { ); break; } - let trns = self.transition(next_event)?; - debug!(target: LOG_TARGET, "Transitioning from {:?} to {:?}", trns.0, trns.1); + let (from, to) = self.transition(next_event)?; + debug!(target: LOG_TARGET, "Transitioning from {:?} to {:?}", from, to); - self.events_publisher.publish(ConsensusWorkerDomainEvent::StateChanged { - old: trns.0, - new: trns.1, - }); + self.events_publisher + .publish(ConsensusWorkerDomainEvent::StateChanged { from, to }); } Ok(()) @@ -156,7 +158,18 @@ impl ConsensusWorker { &self.payload_provider, &self.payload_processor, &self.chain_storage_service, - &self.node_id, + &self.node_address, + ) + .await + }, + Synchronizing => { + states::Synchronizing::new() + .next_event( + &mut self.base_node_client, + &self.asset_definition, + &self.db_factory, + &self.validator_node_client_factory, + &self.node_address, ) .await }, @@ -169,9 +182,9 @@ impl ConsensusWorker { .db_factory .get_state_db(&self.asset_definition.public_key)? .ok_or(DigitalAssetError::MissingDatabase)? - .new_unit_of_work(); + .new_unit_of_work(self.current_view_id.as_u64()); - let mut p = states::Prepare::new(self.node_id.clone(), self.asset_definition.public_key.clone()); + let mut p = states::Prepare::new(self.node_address.clone(), self.asset_definition.public_key.clone()); let res = p .next_event( &self.get_current_view()?, @@ -199,7 +212,7 @@ impl ConsensusWorker { .get_or_create_chain_db(&self.asset_definition.public_key)?; let mut unit_of_work = db.new_unit_of_work(); let mut state = states::PreCommitState::new( - self.node_id.clone(), + self.node_address.clone(), self.committee_manager.current_committee()?.clone(), self.asset_definition.public_key.clone(), ); @@ -223,7 +236,7 @@ impl ConsensusWorker { .get_or_create_chain_db(&self.asset_definition.public_key)?; let mut unit_of_work = db.new_unit_of_work(); let mut state = states::CommitState::new( - self.node_id.clone(), + self.node_address.clone(), self.asset_definition.public_key.clone(), self.committee_manager.current_committee()?.clone(), ); @@ -248,7 +261,7 @@ impl ConsensusWorker { .get_or_create_chain_db(&self.asset_definition.public_key)?; let mut unit_of_work = db.new_unit_of_work(); let mut state = states::DecideState::new( - self.node_id.clone(), + self.node_address.clone(), self.asset_definition.public_key.clone(), self.committee_manager.current_committee()?.clone(), ); @@ -295,7 +308,7 @@ impl ConsensusWorker { &self.db_factory, &mut self.outbound_service, self.committee_manager.current_committee()?, - self.node_id.clone(), + self.node_address.clone(), &self.asset_definition, shutdown, ) @@ -317,7 +330,8 @@ impl ConsensusWorker { use ConsensusWorkerStateEvent::*; let from = self.state; self.state = match (&self.state, event) { - (Starting, Initialized) => NextView, + (Starting, Initialized) => Synchronizing, + (Synchronizing, Synchronized) => NextView, (_, NotPartOfCommittee) => Idle, (Idle, TimedOut) => Starting, (_, TimedOut) => { @@ -332,7 +346,7 @@ impl ConsensusWorker { (PreCommit, PreCommitted) => Commit, (Commit, Committed) => Decide, (Decide, Decided) => NextView, - (Starting, BaseLayerCheckpointNotFound) => { + (_, BaseLayerCheckpointNotFound | BaseLayerAssetRegistrationNotFound) => { unimplemented!("Base layer checkpoint not found!") }, (s, e) => { @@ -454,7 +468,7 @@ mod test { fn assert_state_change(events: &[ConsensusWorkerDomainEvent], states: Vec) { dbg!(events); let mapped_events = events.iter().map(|e| match e { - ConsensusWorkerDomainEvent::StateChanged { old: _, new } => Some(new), + ConsensusWorkerDomainEvent::StateChanged { from: _, to: new } => Some(new), }); for (state, event) in states.iter().zip(mapped_events) { assert_eq!(state, event.unwrap()) diff --git a/dan_layer/core/src/workers/mod.rs b/dan_layer/core/src/workers/mod.rs index 9ad4bd59b5..e1afe1c1a6 100644 --- a/dan_layer/core/src/workers/mod.rs +++ b/dan_layer/core/src/workers/mod.rs @@ -24,3 +24,6 @@ mod consensus_worker; pub mod states; pub use consensus_worker::ConsensusWorker; + +mod state_sync; +pub use state_sync::StateSyncError; diff --git a/dan_layer/core/src/workers/state_sync/error.rs b/dan_layer/core/src/workers/state_sync/error.rs new file mode 100644 index 0000000000..6a68292dba --- /dev/null +++ b/dan_layer/core/src/workers/state_sync/error.rs @@ -0,0 +1,39 @@ +// Copyright 2022, 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 crate::{services::ValidatorNodeClientError, storage::StorageError}; + +#[derive(Debug, thiserror::Error)] +pub enum StateSyncError { + #[error( + "This validator node is the only committee member but its state is not synchronized. Unable to recover state." + )] + NoOtherCommitteeMembersToSync, + #[error("Storage error: {0}")] + StorageError(#[from] StorageError), + #[error("Invalid state Merkle root")] + InvalidStateMerkleRoot, + #[error("Remote peer does not have tip node")] + RemotePeerDoesNotHaveTipNode, + #[error("Validator node client call failed: {0}")] + ValidatorNodeClientError(#[from] ValidatorNodeClientError), +} diff --git a/dan_layer/core/src/workers/state_sync/mod.rs b/dan_layer/core/src/workers/state_sync/mod.rs new file mode 100644 index 0000000000..9577cc79af --- /dev/null +++ b/dan_layer/core/src/workers/state_sync/mod.rs @@ -0,0 +1,141 @@ +// Copyright 2022, 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. + +mod error; +pub use error::StateSyncError; +use log::*; +use rand::{rngs::OsRng, seq::SliceRandom}; +use tari_common_types::types::PublicKey; +use tari_utilities::hex::Hex; + +use crate::{ + models::CheckpointOutput, + services::{ValidatorNodeClientFactory, ValidatorNodeRpcClient}, + storage::{ + state::{StateDb, StateDbBackendAdapter, StateDbUnitOfWork, StateDbUnitOfWorkReader}, + StorageError, + }, +}; + +const LOG_TARGET: &str = "tari::dan::workers::state_sync"; + +pub struct StateSynchronizer<'a, TStateDbBackendAdapter, TValidatorNodeClientFactory: ValidatorNodeClientFactory> { + last_checkpoint: &'a CheckpointOutput, + state_db: &'a mut StateDb, + validator_node_client_factory: &'a TValidatorNodeClientFactory, + our_address: &'a TValidatorNodeClientFactory::Addr, +} + +impl<'a, TStateDbBackendAdapter, TValidatorNodeClientFactory> + StateSynchronizer<'a, TStateDbBackendAdapter, TValidatorNodeClientFactory> +where + TStateDbBackendAdapter: StateDbBackendAdapter, + TValidatorNodeClientFactory: ValidatorNodeClientFactory, +{ + pub fn new( + last_checkpoint: &'a CheckpointOutput, + state_db: &'a mut StateDb, + validator_node_client_factory: &'a TValidatorNodeClientFactory, + our_address: &'a TValidatorNodeClientFactory::Addr, + ) -> Self { + Self { + last_checkpoint, + state_db, + validator_node_client_factory, + our_address, + } + } + + pub async fn sync(&self) -> Result<(), StateSyncError> { + let mut committee = self + .last_checkpoint + .committee + .iter() + .filter(|address| *self.our_address != **address) + .collect::>(); + + if committee.is_empty() { + return Err(StateSyncError::NoOtherCommitteeMembersToSync); + } + + committee.shuffle(&mut OsRng); + + for member in committee { + match self.try_sync_from(member).await { + Ok(_) => { + info!(target: LOG_TARGET, "Sync complete from committee member {}", member); + break; + }, + Err(err) => { + error!(target: LOG_TARGET, "Error syncing from {}: {}", member, err); + continue; + }, + } + } + + Ok(()) + } + + async fn try_sync_from(&self, member: &TValidatorNodeClientFactory::Addr) -> Result<(), StateSyncError> { + info!( + target: LOG_TARGET, + "Attempting to sync asset '{}' from peer '{}'", self.last_checkpoint.parent_public_key, member + ); + let mut client = self.validator_node_client_factory.create_client(member); + let tip_node = client + .get_tip_node(&self.last_checkpoint.parent_public_key) + .await? + .ok_or(StateSyncError::RemotePeerDoesNotHaveTipNode)?; + + // TODO: should rather download the op logs for a checkpoint and reply over initial/current state + let state_schemas = client + .get_sidechain_state(&self.last_checkpoint.parent_public_key) + .await?; + + let mut uow = self.state_db.new_unit_of_work(tip_node.height() as u64); + + for schema in state_schemas { + let name = schema.name; + for item in schema.items { + debug!( + target: LOG_TARGET, + "Adding schema={}, key={}, value={}", + name, + item.key.to_hex(), + item.value.to_hex() + ); + uow.set_value(name.clone(), item.key, item.value)?; + } + } + // TODO: Check merkle root before commit + + uow.clear_all_state().map_err(StorageError::from)?; + uow.commit().map_err(StorageError::from)?; + + let merkle_root = uow.calculate_root()?; + if self.last_checkpoint.merkle_root.as_slice() != merkle_root.as_bytes() { + return Err(StateSyncError::InvalidStateMerkleRoot); + } + + Ok(()) + } +} diff --git a/dan_layer/core/src/workers/states/commit_state.rs b/dan_layer/core/src/workers/states/commit_state.rs index 373cc98883..c79796f1c3 100644 --- a/dan_layer/core/src/workers/states/commit_state.rs +++ b/dan_layer/core/src/workers/states/commit_state.rs @@ -97,32 +97,31 @@ where let next_event_result; loop { tokio::select! { - r = inbound_services.wait_for_message(HotStuffMessageType::PreCommit, current_view.view_id()) => { - let (from, message) = r?; - if current_view.is_leader() { - if let Some(result) = self.process_leader_message(current_view, message.clone(), &from, outbound_service - ).await?{ - next_event_result = result; - break; - } + r = inbound_services.wait_for_message(HotStuffMessageType::PreCommit, current_view.view_id()) => { + let (from, message) = r?; + if current_view.is_leader() { + if let Some(result) = self.process_leader_message(current_view, message.clone(), &from, outbound_service + ).await?{ + next_event_result = result; + break; + } - } - }, - r = inbound_services.wait_for_qc(HotStuffMessageType::PreCommit, current_view.view_id()) => { - let (from, message) = r?; - let leader= self.committee.leader_for_view(current_view.view_id).clone(); - if let Some(result) = self.process_replica_message(&message, current_view, &from, &leader, outbound_service, signing_service, &mut unit_of_work).await? { - next_event_result = result; - break; - } - - } - _ = sleep(timeout.saturating_sub(Instant::now() - started)) => { - // TODO: perhaps this should be from the time the state was entered - next_event_result = ConsensusWorkerStateEvent::TimedOut; - break; - } - } + } + }, + r = inbound_services.wait_for_qc(HotStuffMessageType::PreCommit, current_view.view_id()) => { + let (from, message) = r?; + let leader = self.committee.leader_for_view(current_view.view_id).clone(); + if let Some(result) = self.process_replica_message(&message, current_view, &from, &leader, outbound_service, signing_service, &mut unit_of_work).await? { + next_event_result = result; + break; + } + } + _ = sleep(timeout.saturating_sub(Instant::now() - started)) => { + // TODO: perhaps this should be from the time the state was entered + next_event_result = ConsensusWorkerStateEvent::TimedOut; + break; + } + } } Ok(next_event_result) } diff --git a/dan_layer/core/src/workers/states/mod.rs b/dan_layer/core/src/workers/states/mod.rs index f42db59d7e..1f1c2852d4 100644 --- a/dan_layer/core/src/workers/states/mod.rs +++ b/dan_layer/core/src/workers/states/mod.rs @@ -38,6 +38,7 @@ mod next_view; mod pre_commit_state; mod prepare; mod starting; +mod synchronizing; pub use commit_state::CommitState; pub use decide_state::DecideState; @@ -46,11 +47,14 @@ pub use next_view::NextViewState; pub use pre_commit_state::PreCommitState; pub use prepare::Prepare; pub use starting::Starting; +pub use synchronizing::Synchronizing; #[derive(Debug, PartialEq)] pub enum ConsensusWorkerStateEvent { Initialized, + Synchronized, BaseLayerCheckpointNotFound, + BaseLayerAssetRegistrationNotFound, NotPartOfCommittee, Errored { reason: String }, Prepared, diff --git a/dan_layer/core/src/workers/states/pre_commit_state.rs b/dan_layer/core/src/workers/states/pre_commit_state.rs index 60ffa1ad28..d84785a22c 100644 --- a/dan_layer/core/src/workers/states/pre_commit_state.rs +++ b/dan_layer/core/src/workers/states/pre_commit_state.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::{collections::HashMap, marker::PhantomData, time::Instant}; +use std::{collections::HashMap, marker::PhantomData}; use log::*; use tari_common_types::types::PublicKey; @@ -91,39 +91,35 @@ where unit_of_work: TUnitOfWork, ) -> Result { self.received_new_view_messages.clear(); - let started = Instant::now(); let mut unit_of_work = unit_of_work; let next_event_result; + let timeout = sleep(timeout); + futures::pin_mut!(timeout); loop { tokio::select! { - r = inbound_services.wait_for_message(HotStuffMessageType::Prepare, current_view.view_id()) => { + r = inbound_services.wait_for_message(HotStuffMessageType::Prepare, current_view.view_id()) => { let (from, message) = r?; - debug!(target: LOG_TARGET, "Received message: {:?} view:{}", message.message_type(), - message.view_number()); + debug!(target: LOG_TARGET, "Received message: {:?} view:{}", message.message_type(), message.view_number()); if current_view.is_leader() { - - if let Some(result) = self.process_leader_message(current_view, message.clone(), &from, outbound_service - ).await?{ - next_event_result = result; - break; - } - - } - }, - r = inbound_services.wait_for_qc(HotStuffMessageType::Prepare, current_view.view_id()) => { - let (from, message) = r?; - let leader= self.committee.leader_for_view(current_view.view_id).clone(); - if let Some(result) = self.process_replica_message(&message, current_view, &from, &leader, outbound_service, signing_service, &mut unit_of_work).await? { - next_event_result = result; - break; - } - - }, - _ = sleep(timeout.saturating_sub(Instant::now() - started)) => { - next_event_result = ConsensusWorkerStateEvent::TimedOut; - break; - } - } + if let Some(result) = self.process_leader_message(current_view, message.clone(), &from, outbound_service).await? { + next_event_result = result; + break; + } + } + }, + r = inbound_services.wait_for_qc(HotStuffMessageType::Prepare, current_view.view_id()) => { + let (from, message) = r?; + let leader = self.committee.leader_for_view(current_view.view_id).clone(); + if let Some(result) = self.process_replica_message(&message, current_view, &from, &leader, outbound_service, signing_service, &mut unit_of_work).await? { + next_event_result = result; + break; + } + }, + _ = &mut timeout => { + next_event_result = ConsensusWorkerStateEvent::TimedOut; + break; + } + } } Ok(next_event_result) } diff --git a/dan_layer/core/src/workers/states/prepare.rs b/dan_layer/core/src/workers/states/prepare.rs index 4fc82dd2e3..f72ba0f401 100644 --- a/dan_layer/core/src/workers/states/prepare.rs +++ b/dan_layer/core/src/workers/states/prepare.rs @@ -154,10 +154,9 @@ where if current_view.is_leader() { if let Some(result) = self.process_leader_message(current_view, message.clone(), &from, committee, payload_provider, payload_processor, outbound_service, db_factory).await?{ - next_event_result = result; + next_event_result = result; break; } - } }, r = inbound_services.wait_for_message(HotStuffMessageType::Prepare, current_view.view_id()) => { @@ -220,13 +219,13 @@ where let temp_state_tx = db_factory .get_or_create_state_db(&self.asset_public_key)? - .new_unit_of_work(); + .new_unit_of_work(current_view.view_id.as_u64()); let proposal = self .create_proposal( *high_qc.node_hash(), payload_provider, payload_processor, - 0, + current_view.view_id.as_u64() as u32, temp_state_tx, ) .await?; diff --git a/dan_layer/core/src/workers/states/starting.rs b/dan_layer/core/src/workers/states/starting.rs index 915df3d8fd..101e4925c0 100644 --- a/dan_layer/core/src/workers/states/starting.rs +++ b/dan_layer/core/src/workers/states/starting.rs @@ -105,6 +105,7 @@ where TBaseNodeClient: BaseNodeClient ); return Ok(ConsensusWorkerStateEvent::NotPartOfCommittee); } + info!( target: LOG_TARGET, "Validator node is a committee member for asset public key '{}'", @@ -118,7 +119,7 @@ where TBaseNodeClient: BaseNodeClient let mut tx = chain_db.new_unit_of_work(); let state_db = db_factory.get_or_create_state_db(&asset_definition.public_key)?; - let mut state_tx = state_db.new_unit_of_work(); + let mut state_tx = state_db.new_unit_of_work(0); info!(target: LOG_TARGET, "Loading initial state"); let initial_state = asset_definition.initial_state(); diff --git a/dan_layer/core/src/workers/states/synchronizing.rs b/dan_layer/core/src/workers/states/synchronizing.rs new file mode 100644 index 0000000000..e08ec84592 --- /dev/null +++ b/dan_layer/core/src/workers/states/synchronizing.rs @@ -0,0 +1,119 @@ +// Copyright 2022, 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 std::convert::TryFrom; + +use log::*; +use tari_common_types::types::PublicKey; + +use crate::{ + models::{AssetDefinition, CheckpointOutput}, + services::{BaseNodeClient, ValidatorNodeClientFactory}, + storage::{state::StateDbUnitOfWorkReader, DbFactory}, + workers::{state_sync::StateSynchronizer, states::ConsensusWorkerStateEvent}, + DigitalAssetError, +}; + +const LOG_TARGET: &str = "tari::dan::workers::states::starting"; + +#[derive(Debug, Clone, Default)] +pub struct Synchronizing; + +impl Synchronizing { + pub fn new() -> Self { + Self + } + + #[allow(unreachable_code, unused_variables)] + pub async fn next_event( + &mut self, + base_node_client: &mut TBaseNodeClient, + asset_definition: &AssetDefinition, + db_factory: &TDbFactory, + validator_node_client_factory: &TValidatorNodeClientFactory, + our_address: &TValidatorNodeClientFactory::Addr, + ) -> Result + where + TDbFactory: DbFactory, + TBaseNodeClient: BaseNodeClient, + TValidatorNodeClientFactory: ValidatorNodeClientFactory, + { + // TODO: The collectibles app does not post a valid initial merkle root for the initial asset checkpoint. So + // this is always out-of-sync. + // return Ok(ConsensusWorkerStateEvent::Synchronized); + + let tip = base_node_client.get_tip_info().await?; + let last_checkpoint = base_node_client + .get_current_checkpoint( + tip.height_of_longest_chain - asset_definition.base_layer_confirmation_time, + asset_definition.public_key.clone(), + asset_definition.checkpoint_unique_id.clone(), + ) + .await?; + + let last_checkpoint = match last_checkpoint { + Some(cp) => CheckpointOutput::try_from(cp)?, + None => return Ok(ConsensusWorkerStateEvent::BaseLayerCheckpointNotFound), + }; + + let asset_registration = base_node_client + .get_asset_registration(asset_definition.public_key.clone()) + .await?; + + let mut state_db = db_factory.get_or_create_state_db(&asset_definition.public_key)?; + { + let state_reader = state_db.reader(); + let our_merkle_root = state_reader.calculate_root()?; + if our_merkle_root.as_bytes() == last_checkpoint.merkle_root.as_slice() { + info!(target: LOG_TARGET, "Our state database is up-to-date."); + return Ok(ConsensusWorkerStateEvent::Synchronized); + } + let registration_merkle_root = asset_registration.and_then(|ar| ar.get_checkpoint_merkle_root()); + if registration_merkle_root + .map(|mr| our_merkle_root.as_bytes() == mr.as_slice()) + .unwrap_or(false) + { + info!( + target: LOG_TARGET, + "Our state database is up-to-date (at initial state)." + ); + return Ok(ConsensusWorkerStateEvent::Synchronized); + } + } + + info!( + target: LOG_TARGET, + "Our state database for asset '{}' is out of sync. Attempting to contact a committee member to synchronize", + asset_definition.public_key + ); + + let synchronizer = StateSynchronizer::new( + &last_checkpoint, + &mut state_db, + validator_node_client_factory, + our_address, + ); + synchronizer.sync().await?; + + Ok(ConsensusWorkerStateEvent::Synchronized) + } +} diff --git a/dan_layer/storage_sqlite/migrations/2022-02-09-105823_create_state_op_log/down.sql b/dan_layer/storage_sqlite/migrations/2022-02-09-105823_create_state_op_log/down.sql new file mode 100644 index 0000000000..291a97c5ce --- /dev/null +++ b/dan_layer/storage_sqlite/migrations/2022-02-09-105823_create_state_op_log/down.sql @@ -0,0 +1 @@ +-- This file should undo anything in `up.sql` \ No newline at end of file diff --git a/dan_layer/storage_sqlite/migrations/2022-02-09-105823_create_state_op_log/up.sql b/dan_layer/storage_sqlite/migrations/2022-02-09-105823_create_state_op_log/up.sql new file mode 100644 index 0000000000..e15f19bb7f --- /dev/null +++ b/dan_layer/storage_sqlite/migrations/2022-02-09-105823_create_state_op_log/up.sql @@ -0,0 +1,13 @@ +create table state_op_log +( + id integer primary key autoincrement not null, + height bigint not null, + merkle_root blob(32) null, + operation varchar(30) not null, + schema varchar(255) not null, + key blob not null, + value blob null +); + +create index state_op_log_height_index on state_op_log (height); +create index state_op_log_merkle_root_index on state_op_log (merkle_root); diff --git a/dan_layer/storage_sqlite/src/error.rs b/dan_layer/storage_sqlite/src/error.rs index 4bc6f3d904..827e66d435 100644 --- a/dan_layer/storage_sqlite/src/error.rs +++ b/dan_layer/storage_sqlite/src/error.rs @@ -44,6 +44,8 @@ pub enum SqliteStorageError { DecodeError(#[from] bytecodec::Error), #[error("Encountered malformed hash data")] MalformedHashData, + #[error("Malformed DB data: {0}")] + MalformedDbData(String), #[error(transparent)] ModelError(#[from] ModelError), } diff --git a/dan_layer/storage_sqlite/src/models/mod.rs b/dan_layer/storage_sqlite/src/models/mod.rs index e7372965ac..00613a6de0 100644 --- a/dan_layer/storage_sqlite/src/models/mod.rs +++ b/dan_layer/storage_sqlite/src/models/mod.rs @@ -25,4 +25,5 @@ pub mod locked_qc; pub mod node; pub mod prepare_qc; pub mod state_key; +pub mod state_op_log; pub mod state_tree; diff --git a/dan_layer/storage_sqlite/src/models/node.rs b/dan_layer/storage_sqlite/src/models/node.rs index 9c665ba800..e310ab0d2e 100644 --- a/dan_layer/storage_sqlite/src/models/node.rs +++ b/dan_layer/storage_sqlite/src/models/node.rs @@ -22,7 +22,7 @@ use crate::schema::*; -#[derive(Identifiable, Queryable)] +#[derive(Debug, Clone, Identifiable, Queryable)] pub struct Node { pub id: i32, pub hash: Vec, @@ -31,7 +31,7 @@ pub struct Node { pub is_committed: bool, } -#[derive(Insertable)] +#[derive(Debug, Clone, Insertable)] #[table_name = "nodes"] pub struct NewNode { pub hash: Vec, diff --git a/dan_layer/storage_sqlite/src/models/state_op_log.rs b/dan_layer/storage_sqlite/src/models/state_op_log.rs new file mode 100644 index 0000000000..86b1ab2d40 --- /dev/null +++ b/dan_layer/storage_sqlite/src/models/state_op_log.rs @@ -0,0 +1,86 @@ +use std::convert::TryFrom; + +use tari_dan_core::models::TreeNodeHash; +// Copyright 2022, 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 tari_dan_core::storage::state::DbStateOpLogEntry; + +use crate::{error::SqliteStorageError, schema::*}; + +#[derive(Debug, Clone, Identifiable, Queryable)] +#[table_name = "state_op_log"] +pub struct StateOpLogEntry { + pub id: i32, + pub height: i64, + pub merkle_root: Option>, + pub operation: String, + pub schema: String, + pub key: Vec, + pub value: Option>, +} + +#[derive(Debug, Clone, Insertable)] +#[table_name = "state_op_log"] +pub struct NewStateOpLogEntry { + pub height: i64, + pub merkle_root: Option>, + pub operation: String, + pub schema: String, + pub key: Vec, + pub value: Option>, +} + +impl From for NewStateOpLogEntry { + fn from(entry: DbStateOpLogEntry) -> Self { + Self { + height: entry.height as i64, + merkle_root: entry.merkle_root.map(|r| r.as_bytes().to_vec()), + operation: entry.operation.as_op_str().to_string(), + schema: entry.schema, + key: entry.key, + value: entry.value, + } + } +} + +impl TryFrom for DbStateOpLogEntry { + type Error = SqliteStorageError; + + fn try_from(entry: StateOpLogEntry) -> Result { + Ok(Self { + height: entry.height as u64, + merkle_root: entry + .merkle_root + .map(TreeNodeHash::try_from) + .transpose() + .map_err(|_| SqliteStorageError::MalformedHashData)?, + operation: entry + .operation + .parse() + .map_err(|_| SqliteStorageError::MalformedDbData("Invalid OpLog operation".to_string()))?, + schema: entry.schema, + key: entry.key, + value: entry.value, + }) + } +} diff --git a/dan_layer/storage_sqlite/src/schema.rs b/dan_layer/storage_sqlite/src/schema.rs index 0b97932414..9cb548dc3c 100644 --- a/dan_layer/storage_sqlite/src/schema.rs +++ b/dan_layer/storage_sqlite/src/schema.rs @@ -47,6 +47,18 @@ table! { } } +table! { + state_op_log (id) { + id -> Integer, + height -> BigInt, + merkle_root -> Nullable, + operation -> Text, + schema -> Text, + key -> Binary, + value -> Nullable, + } +} + table! { state_tree (id) { id -> Integer, @@ -58,4 +70,12 @@ table! { joinable!(instructions -> nodes (node_id)); -allow_tables_to_appear_in_same_query!(instructions, locked_qc, nodes, prepare_qc, state_keys, state_tree,); +allow_tables_to_appear_in_same_query!( + instructions, + locked_qc, + nodes, + prepare_qc, + state_keys, + state_op_log, + state_tree, +); diff --git a/dan_layer/storage_sqlite/src/sqlite_chain_backend_adapter.rs b/dan_layer/storage_sqlite/src/sqlite_chain_backend_adapter.rs index ac57779dd2..83ece5b6da 100644 --- a/dan_layer/storage_sqlite/src/sqlite_chain_backend_adapter.rs +++ b/dan_layer/storage_sqlite/src/sqlite_chain_backend_adapter.rs @@ -52,6 +52,10 @@ impl SqliteChainBackendAdapter { pub fn new(database_url: String) -> SqliteChainBackendAdapter { Self { database_url } } + + pub fn get_connection(&self) -> ConnectionResult { + SqliteConnection::establish(self.database_url.as_str()) + } } impl ChainDbBackendAdapter for SqliteChainBackendAdapter { @@ -61,7 +65,7 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { type Payload = TariDanPayload; fn is_empty(&self) -> Result { - let connection = SqliteConnection::establish(self.database_url.as_str())?; + let connection = self.get_connection()?; let n: Option = nodes::table .first(&connection) @@ -73,8 +77,26 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { Ok(n.is_none()) } + fn create_transaction(&self) -> Result { + let connection = self.get_connection()?; + connection + .execute("PRAGMA foreign_keys = ON;") + .map_err(|source| SqliteStorageError::DieselError { + source, + operation: "set pragma".to_string(), + })?; + connection + .execute("BEGIN EXCLUSIVE TRANSACTION;") + .map_err(|source| SqliteStorageError::DieselError { + source, + operation: "begin transaction".to_string(), + })?; + + Ok(SqliteTransaction::new(connection)) + } + fn node_exists(&self, node_hash: &TreeNodeHash) -> Result { - let connection = SqliteConnection::establish(self.database_url.as_str())?; + let connection = self.get_connection()?; use crate::schema::nodes::dsl; let count = dsl::nodes .filter(nodes::parent.eq(node_hash.as_bytes())) @@ -89,22 +111,28 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { Ok(count > 0) } - fn create_transaction(&self) -> Result { - let connection = SqliteConnection::establish(self.database_url.as_str())?; - connection - .execute("PRAGMA foreign_keys = ON;") - .map_err(|source| SqliteStorageError::DieselError { - source, - operation: "set pragma".to_string(), - })?; - connection - .execute("BEGIN EXCLUSIVE TRANSACTION;") + fn get_tip_node(&self) -> Result, Self::Error> { + use crate::schema::nodes::dsl; + + let connection = self.get_connection()?; + let node = dsl::nodes + .order_by(dsl::height.desc()) + .first::(&connection) + .optional() .map_err(|source| SqliteStorageError::DieselError { source, - operation: "begin transaction".to_string(), + operation: "get_tip_node".to_string(), })?; - Ok(SqliteTransaction::new(connection)) + match node { + Some(node) => Ok(Some(DbNode { + hash: node.hash.try_into()?, + parent: node.parent.try_into()?, + height: node.height as u32, + is_committed: node.is_committed, + })), + None => Ok(None), + } } fn insert_node(&self, item: &DbNode, transaction: &Self::BackendTransaction) -> Result<(), Self::Error> { @@ -224,7 +252,7 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { } fn get_prepare_qc(&self) -> Result, Self::Error> { - let connection = SqliteConnection::establish(self.database_url.as_str())?; + let connection = self.get_connection()?; use crate::schema::prepare_qc::dsl; let qc: Option = dsl::prepare_qc .find(1) @@ -249,7 +277,7 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { debug!(target: LOG_TARGET, "Committing transaction"); transaction .connection() - .execute("COMMIT TRANSACTION;") + .execute("COMMIT TRANSACTION") .map_err(|source| SqliteStorageError::DieselError { source, operation: "commit::chain".to_string(), @@ -267,7 +295,7 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { fn find_highest_prepared_qc(&self) -> Result { use crate::schema::locked_qc::dsl; - let connection = SqliteConnection::establish(self.database_url.as_str())?; + let connection = self.get_connection()?; // TODO: this should be a single row let result: Option = prepare_qc::table .order_by(prepare_qc::view_number.desc()) @@ -307,7 +335,7 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { fn get_locked_qc(&self) -> Result { use crate::schema::locked_qc::dsl; - let connection = SqliteConnection::establish(self.database_url.as_str())?; + let connection = self.get_connection()?; let qc: LockedQc = dsl::locked_qc .find(self.locked_qc_id()) .first(&connection) @@ -325,7 +353,7 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { fn find_node_by_hash(&self, parent_hash: &TreeNodeHash) -> Result, Self::Error> { use crate::schema::nodes::dsl; - let connection = SqliteConnection::establish(self.database_url.as_str())?; + let connection = self.get_connection()?; let node = dsl::nodes .filter(nodes::parent.eq(parent_hash.as_bytes())) .first::(&connection) @@ -348,7 +376,7 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { fn find_node_by_parent_hash(&self, node_hash: &TreeNodeHash) -> Result, Self::Error> { use crate::schema::nodes::dsl; - let connection = SqliteConnection::establish(self.database_url.as_str())?; + let connection = self.get_connection()?; let node = dsl::nodes .filter(nodes::parent.eq(node_hash.as_bytes())) .first::(&connection) @@ -402,7 +430,7 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { fn find_all_instructions_by_node(&self, node_id: Self::Id) -> Result, Self::Error> { use crate::schema::{instructions::dsl as instructions_dsl, nodes::dsl as nodes_dsl}; - let connection = SqliteConnection::establish(self.database_url.as_str())?; + let connection = self.get_connection()?; let node = nodes_dsl::nodes .filter(nodes::id.eq(node_id)) .first::(&connection) diff --git a/dan_layer/storage_sqlite/src/sqlite_state_db_backend_adapter.rs b/dan_layer/storage_sqlite/src/sqlite_state_db_backend_adapter.rs index 62a6b4fa02..3b5b9af7b6 100644 --- a/dan_layer/storage_sqlite/src/sqlite_state_db_backend_adapter.rs +++ b/dan_layer/storage_sqlite/src/sqlite_state_db_backend_adapter.rs @@ -20,6 +20,8 @@ // 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::convert::TryInto; + use bytecodec::{ bincode_codec::{BincodeDecoder, BincodeEncoder}, DecodeExt, @@ -31,12 +33,13 @@ use patricia_tree::{ node::{Node, NodeDecoder, NodeEncoder}, PatriciaMap, }; -use tari_dan_core::storage::state::{DbKeyValue, StateDbBackendAdapter}; +use tari_dan_core::storage::state::{DbKeyValue, DbStateOpLogEntry, StateDbBackendAdapter}; use crate::{ error::SqliteStorageError, models::{ state_key::StateKey, + state_op_log::{NewStateOpLogEntry, StateOpLogEntry}, state_tree::{NewStateTree, StateTree}, }, schema::*, @@ -257,4 +260,57 @@ impl StateDbBackendAdapter for SqliteStateDbBackendAdapter { .map(|(schema, key, value)| DbKeyValue { schema, key, value }) .collect()) } + + fn get_state_op_logs_by_height( + &self, + height: u64, + tx: &Self::BackendTransaction, + ) -> Result, Self::Error> { + use crate::schema::state_op_log::dsl; + let op_logs = dsl::state_op_log + .filter(dsl::height.eq(height as i64)) + .order_by(dsl::key.asc()) + .load::(tx.connection()) + .map_err(|source| SqliteStorageError::DieselError { + source, + operation: "get_all_values_for_schema".to_string(), + })?; + + op_logs.into_iter().map(TryInto::try_into).collect() + } + + fn add_state_oplog_entry( + &self, + entry: DbStateOpLogEntry, + tx: &Self::BackendTransaction, + ) -> Result<(), Self::Error> { + use crate::schema::state_op_log::dsl; + diesel::insert_into(dsl::state_op_log) + .values(NewStateOpLogEntry::from(entry)) + .execute(tx.connection()) + .map_err(|source| SqliteStorageError::DieselError { + source, + operation: "add_state_oplog_entry".to_string(), + })?; + + Ok(()) + } + + fn clear_all_state(&self, tx: &Self::BackendTransaction) -> Result<(), Self::Error> { + diesel::delete(state_keys::dsl::state_keys) + .execute(tx.connection()) + .map_err(|source| SqliteStorageError::DieselError { + source, + operation: "clear_all_state::state_keys".to_string(), + })?; + + diesel::delete(state_op_log::dsl::state_op_log) + .execute(tx.connection()) + .map_err(|source| SqliteStorageError::DieselError { + source, + operation: "clear_all_state::state_op_logs".to_string(), + })?; + + Ok(()) + } } diff --git a/infrastructure/derive/Cargo.toml b/infrastructure/derive/Cargo.toml index 8f064c558e..ee6afa6303 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.27.3" +version = "0.28.0" edition = "2018" [lib] diff --git a/infrastructure/libtor/Cargo.toml b/infrastructure/libtor/Cargo.toml index 8e71a142c1..31f9a53cb7 100644 --- a/infrastructure/libtor/Cargo.toml +++ b/infrastructure/libtor/Cargo.toml @@ -11,7 +11,7 @@ multiaddr = { version = "0.13.0" } # NB: make sure this crate is not included in any other crate used by wallet_ffi [target.'cfg(unix)'.dependencies] -tari_shutdown = { version = "^0.27", path = "../shutdown"} +tari_shutdown = { version = "^0.28", path = "../shutdown"} libtor = { version = "46.9.0", optional = true } rand = "0.8" tempfile = "3.1.0" diff --git a/infrastructure/libtor/src/tor.rs b/infrastructure/libtor/src/tor.rs index a407db3283..397132060e 100644 --- a/infrastructure/libtor/src/tor.rs +++ b/infrastructure/libtor/src/tor.rs @@ -26,7 +26,11 @@ use libtor::{LogDestination, LogLevel, TorFlag}; use log::*; use multiaddr::Multiaddr; use rand::{distributions::Alphanumeric, thread_rng, Rng}; -use tari_common::{exit_codes::ExitCodes, CommsTransport, TorControlAuthentication}; +use tari_common::{ + exit_codes::{ExitCode, ExitError}, + CommsTransport, + TorControlAuthentication, +}; use tari_shutdown::ShutdownSignal; use tempfile::{tempdir, NamedTempFile, TempDir, TempPath}; use tor_hash_passwd::EncryptedKey; @@ -74,7 +78,7 @@ impl Tor { /// Two TCP ports will be provided by the operating system. /// These ports are used for the control and socks ports, the onion address and port info are still loaded from the /// node identity file. - pub fn initialize() -> Result { + pub fn initialize() -> Result { debug!(target: LOG_TARGET, "Initializing libtor"); let mut instance = Tor::default(); @@ -108,7 +112,7 @@ impl Tor { } /// Override a given Tor comms transport with the control address and auth from this instance - pub fn update_comms_transport(&self, transport: CommsTransport) -> Result { + pub fn update_comms_transport(&self, transport: CommsTransport) -> Result { debug!(target: LOG_TARGET, "updating comms transport"); if let CommsTransport::TorHiddenService { socks_address_override, @@ -139,12 +143,12 @@ impl Tor { Ok(transport) } else { let e = format!("Expected a TorHiddenService comms transport, received: {:?}", transport); - Err(ExitCodes::ConfigError(e)) + Err(ExitError::new(ExitCode::ConfigError, e)) } } /// Run the Tor instance until the shutdown signal is received - pub async fn run(self, mut shutdown_signal: ShutdownSignal) -> Result<(), ExitCodes> { + pub async fn run(self, mut shutdown_signal: ShutdownSignal) -> Result<(), ExitError> { info!(target: LOG_TARGET, "Starting Tor instance"); let Tor { diff --git a/infrastructure/shutdown/Cargo.toml b/infrastructure/shutdown/Cargo.toml index b07254e6dd..9d959c79b3 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.27.3" +version = "0.28.0" 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 86b8b4e071..ba54e3a5ab 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.27.3" +version = "0.28.0" edition = "2018" [dependencies] diff --git a/infrastructure/test_utils/Cargo.toml b/infrastructure/test_utils/Cargo.toml index e0aa464c61..b135eb0172 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.27.3" +version = "0.28.0" authors = ["The Tari Development Community"] edition = "2018" license = "BSD-3-Clause" diff --git a/integration_tests/features/WalletCli.feature b/integration_tests/features/WalletCli.feature index 6ab1d20cdf..902da40406 100644 --- a/integration_tests/features/WalletCli.feature +++ b/integration_tests/features/WalletCli.feature @@ -45,8 +45,8 @@ Feature: Wallet CLI And I wait 30 seconds And I stop wallet SENDER And I send 1000000 uT from SENDER to RECEIVER via command line - Then wallet SENDER has at least 1 transactions that are all TRANSACTION_STATUS_BROADCAST and valid - Then wallet RECEIVER has at least 1 transactions that are all TRANSACTION_STATUS_BROADCAST and valid + Then wallet SENDER has at least 1 transactions that are all TRANSACTION_STATUS_BROADCAST and not cancelled + Then wallet RECEIVER has at least 1 transactions that are all TRANSACTION_STATUS_BROADCAST and not cancelled And mining node MINE mines 5 blocks Then I wait for wallet RECEIVER to have at least 1000000 uT @@ -64,7 +64,7 @@ Feature: Wallet CLI And I wait 30 seconds And I stop wallet SENDER And I send one-sided 1000000 uT from SENDER to RECEIVER via command line - Then wallet SENDER has at least 1 transactions that are all TRANSACTION_STATUS_BROADCAST and valid + Then wallet SENDER has at least 1 transactions that are all TRANSACTION_STATUS_BROADCAST and not cancelled And mining node MINE mines 5 blocks Then I wait for wallet RECEIVER to have at least 1000000 uT @@ -82,8 +82,8 @@ Feature: Wallet CLI And I wait 30 seconds And I stop wallet SENDER And I make it rain from wallet SENDER 1 tx per sec 10 sec 8000 uT 100 increment to RECEIVER via command line - Then wallet SENDER has at least 10 transactions that are all TRANSACTION_STATUS_BROADCAST and valid - Then wallet RECEIVER has at least 10 transactions that are all TRANSACTION_STATUS_BROADCAST and valid + Then wallet SENDER has at least 10 transactions that are all TRANSACTION_STATUS_BROADCAST and not cancelled + Then wallet RECEIVER has at least 10 transactions that are all TRANSACTION_STATUS_BROADCAST and not cancelled And mining node MINE mines 5 blocks Then I wait for wallet RECEIVER to have at least 84500 uT @@ -100,9 +100,9 @@ Feature: Wallet CLI And I wait 30 seconds And I stop wallet WALLET And I do coin split on wallet WALLET to 10000 uT 10 coins via command line - Then wallet WALLET has at least 1 transactions that are all TRANSACTION_STATUS_BROADCAST and valid + Then wallet WALLET has at least 1 transactions that are all TRANSACTION_STATUS_BROADCAST and not cancelled And mining node MINE mines 5 blocks - Then wallet WALLET has at least 1 transactions that are all TRANSACTION_STATUS_MINED_CONFIRMED and valid + Then wallet WALLET has at least 1 transactions that are all TRANSACTION_STATUS_MINED_CONFIRMED and not cancelled And I stop wallet WALLET Then I get count of utxos of wallet WALLET and it's at least 10 via command line diff --git a/integration_tests/features/WalletFFI.feature b/integration_tests/features/WalletFFI.feature index 9e96c20e7d..27fce2ac0b 100644 --- a/integration_tests/features/WalletFFI.feature +++ b/integration_tests/features/WalletFFI.feature @@ -61,7 +61,7 @@ Feature: Wallet FFI And mining node MINER mines 10 blocks Then I wait for wallet SENDER to have at least 1000000 uT And I send 2000000 uT without waiting for broadcast from wallet SENDER to wallet FFI_WALLET at fee 20 - Then ffi wallet FFI_WALLET detects AT_LEAST 1 ffi transactions to be Broadcast + Then ffi wallet FFI_WALLET detects AT_LEAST 1 ffi transactions to be TRANSACTION_STATUS_BROADCAST And wallet SENDER detects all transactions are at least Broadcast And mining node MINER mines 10 blocks Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT @@ -94,11 +94,11 @@ Feature: Wallet FFI And mining node MINER mines 10 blocks Then I wait for wallet SENDER to have at least 1000000 uT And I send 2000000 uT from wallet SENDER to wallet FFI_WALLET at fee 20 - Then ffi wallet FFI_WALLET detects AT_LEAST 1 ffi transactions to be Broadcast + Then ffi wallet FFI_WALLET detects AT_LEAST 1 ffi transactions to be TRANSACTION_STATUS_BROADCAST And mining node MINER mines 10 blocks Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT And I send 1000000 uT from ffi wallet FFI_WALLET to wallet RECEIVER at fee 20 - Then ffi wallet FFI_WALLET detects AT_LEAST 2 ffi transactions to be Broadcast + Then ffi wallet FFI_WALLET detects AT_LEAST 2 ffi transactions to be TRANSACTION_STATUS_BROADCAST # The broadcast check does not include delivery; create some holding points to ensure it was received And mining node MINER mines 2 blocks Then all nodes are at height 22 @@ -134,6 +134,7 @@ Feature: Wallet FFI Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT And I stop ffi wallet FFI_WALLET + @critical Scenario: As a client I want to send a one-sided transaction Given I have a seed node SEED And I have a base node BASE1 connected to all seed nodes @@ -143,21 +144,43 @@ Feature: Wallet FFI And I have wallet RECEIVER connected to base node BASE2 And I have mining node MINER connected to base node BASE1 and wallet SENDER And mining node MINER mines 10 blocks - Then I wait for wallet SENDER to have at least 1000000 uT - And I send 2000000 uT from wallet SENDER to wallet FFI_WALLET at fee 20 - Then ffi wallet FFI_WALLET detects AT_LEAST 1 ffi transactions to be Broadcast + Then I wait for wallet SENDER to have at least 5000000 uT + And I send 2400000 uT from wallet SENDER to wallet FFI_WALLET at fee 20 + And I send 2400000 uT from wallet SENDER to wallet FFI_WALLET at fee 20 + Then ffi wallet FFI_WALLET detects AT_LEAST 2 ffi transactions to be TRANSACTION_STATUS_BROADCAST And mining node MINER mines 10 blocks - Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT + Then I wait for ffi wallet FFI_WALLET to have at least 4000000 uT And I send 1000000 uT from ffi wallet FFI_WALLET to wallet RECEIVER at fee 20 via one-sided transactions + Then ffi wallet FFI_WALLET detects AT_LEAST 2 ffi transactions to be TRANSACTION_STATUS_BROADCAST And mining node MINER mines 2 blocks Then all nodes are at height 22 - And mining node MINER mines 2 blocks - Then all nodes are at height 24 - And mining node MINER mines 6 blocks - Then I wait for wallet RECEIVER to have at least 1000000 uT - Then I wait for ffi wallet FFI_WALLET to receive 2 mined + Then wallet RECEIVER has at least 1 transactions that are all TRANSACTION_STATUS_FAUX_UNCONFIRMED and not cancelled + And mining node MINER mines 5 blocks + Then all nodes are at height 27 + Then wallet RECEIVER has at least 1 transactions that are all TRANSACTION_STATUS_FAUX_CONFIRMED and not cancelled And I stop ffi wallet FFI_WALLET + @critical + Scenario: As a client I want to receive a one-sided transaction + Given I have a seed node SEED + And I have a base node BASE1 connected to all seed nodes + And I have a base node BASE2 connected to all seed nodes + And I have wallet SENDER connected to base node BASE1 + And I have a ffi wallet FFI_RECEIVER connected to base node BASE2 + And I have mining node MINER connected to base node BASE1 and wallet SENDER + And mining node MINER mines 10 blocks + Then I wait for wallet SENDER to have at least 5000000 uT + Then I send a one-sided transaction of 1000000 uT from SENDER to FFI_RECEIVER at fee 20 + And mining node MINER mines 2 blocks + Then all nodes are at height 12 + Then ffi wallet FFI_RECEIVER detects AT_LEAST 1 ffi transactions to be TRANSACTION_STATUS_FAUX_UNCONFIRMED + And I send 1000000 uT from wallet SENDER to wallet FFI_RECEIVER at fee 20 + Then ffi wallet FFI_RECEIVER detects AT_LEAST 1 ffi transactions to be TRANSACTION_STATUS_BROADCAST + And mining node MINER mines 5 blocks + Then all nodes are at height 17 + Then ffi wallet FFI_RECEIVER detects AT_LEAST 1 ffi transactions to be TRANSACTION_STATUS_FAUX_CONFIRMED + And I stop ffi wallet FFI_RECEIVER + # Scenario: As a client I want to get my balance # It's a subtest of "As a client I want to retrieve a list of transactions I have made and received" diff --git a/integration_tests/features/WalletMonitoring.feature b/integration_tests/features/WalletMonitoring.feature index b22e3eab0a..89c0b09e5f 100644 --- a/integration_tests/features/WalletMonitoring.feature +++ b/integration_tests/features/WalletMonitoring.feature @@ -46,7 +46,7 @@ Feature: Wallet Monitoring When I wait 30 seconds And I list all COINBASE transactions for wallet WALLET_A1 And I list all COINBASE transactions for wallet WALLET_B1 - Then all COINBASE transactions for wallet WALLET_A1 and wallet WALLET_B1 have consistent but opposing validity + Then all COINBASE transactions for wallet WALLET_A1 and wallet WALLET_B1 have consistent but opposing cancellation # 18+ mins on circle ci @long-running @@ -108,11 +108,11 @@ Feature: Wallet Monitoring And I list all NORMAL transactions for wallet WALLET_A1 And I list all NORMAL transactions for wallet WALLET_B1 # TODO: Uncomment this step when wallets can handle reorg -# Then all NORMAL transactions for wallet WALLET_A1 and wallet WALLET_B1 have consistent but opposing validity +# Then all NORMAL transactions for wallet WALLET_A1 and wallet WALLET_B1 have consistent but opposing cancellation And I list all NORMAL transactions for wallet WALLET_A2 And I list all NORMAL transactions for wallet WALLET_B2 # TODO: Uncomment this step when wallets can handle reorg -# Then all NORMAL transactions for wallet WALLET_A2 and wallet WALLET_B2 have consistent but opposing validity +# Then all NORMAL transactions for wallet WALLET_A2 and wallet WALLET_B2 have consistent but opposing cancellation When I wait 1 seconds Scenario Outline: Verify all coinbases in hybrid mining are accounted for diff --git a/integration_tests/features/WalletQuery.feature b/integration_tests/features/WalletQuery.feature index 71f812be96..a0e56a0d5c 100644 --- a/integration_tests/features/WalletQuery.feature +++ b/integration_tests/features/WalletQuery.feature @@ -8,7 +8,7 @@ Feature: Wallet Querying Then node WalletSeedA is at height 1 Then the UTXO CB1 has been mined according to WalletSeedA - @critical @broken + @critical Scenario: As a wallet I want to submit a transaction Given I have a seed node SeedA When I mine a block on SeedA with coinbase CB1 @@ -20,7 +20,7 @@ Feature: Wallet Querying Then the UTXO UTX1 has been mined according to SeedA - @critical @broken + @critical Scenario: As a wallet I cannot submit a locked coinbase transaction # Using GRPC Given I have a seed node SeedA diff --git a/integration_tests/features/support/ffi_steps.js b/integration_tests/features/support/ffi_steps.js index 1853b77eda..7ecb6459ed 100644 --- a/integration_tests/features/support/ffi_steps.js +++ b/integration_tests/features/support/ffi_steps.js @@ -3,16 +3,6 @@ const expect = require("chai").expect; const { sleep, waitForIterate } = require("../../helpers/util"); -When( - "I have ffi wallet {word} connected to base node {word}", - { timeout: 20 * 1000 }, - async function (name, node) { - let wallet = await this.createAndAddFFIWallet(name); - let peer = this.nodes[node].peerAddress().split("::"); - wallet.addBaseNodePeer(peer[0], peer[1]); - } -); - Then("I want to get emoji id of ffi wallet {word}", async function (name) { let wallet = this.getWallet(name); let emoji_id = wallet.identifyEmoji(); @@ -479,13 +469,21 @@ Then( ); Then( - "ffi wallet {word} detects {word} {int} ffi transactions to be Broadcast", + "ffi wallet {word} detects {word} {int} ffi transactions to be {word}", { timeout: 125 * 1000 }, - async function (walletName, comparison, amount) { + async function (walletName, comparison, amount, status) { // Pending -> Completed -> Broadcast -> Mined Unconfirmed -> Mined Confirmed const atLeast = "AT_LEAST"; const exactly = "EXACTLY"; expect(comparison === atLeast || comparison === exactly).to.equal(true); + const broadcast = "TRANSACTION_STATUS_BROADCAST"; + const fauxUnconfirmed = "TRANSACTION_STATUS_FAUX_UNCONFIRMED"; + const fauxConfirmed = "TRANSACTION_STATUS_FAUX_CONFIRMED"; + expect( + status === broadcast || + status === fauxUnconfirmed || + status === fauxConfirmed + ).to.equal(true); const wallet = this.getWallet(walletName); console.log("\n"); @@ -496,27 +494,53 @@ Then( comparison + " " + amount + - " broadcast transaction(s)" + " " + + status + + " transaction(s)" ); await waitForIterate( () => { - return wallet.getCounters().broadcast >= amount; + switch (status) { + case broadcast: + return wallet.getCounters().broadcast >= amount; + case fauxUnconfirmed: + return wallet.getCounters().fauxUnconfirmed >= amount; + case fauxConfirmed: + return wallet.getCounters().fauxConfirmed >= amount; + default: + expect(status).to.equal("please add this<< TransactionStatus"); + } }, true, 1000, 120 ); - if (!(wallet.getCounters().broadcast >= amount)) { - console.log("Counter not adequate!"); + let amountOfCallbacks; + switch (status) { + case broadcast: + amountOfCallbacks = wallet.getCounters().broadcast; + break; + case fauxUnconfirmed: + amountOfCallbacks = wallet.getCounters().fauxUnconfirmed; + break; + case fauxConfirmed: + amountOfCallbacks = wallet.getCounters().fauxConfirmed; + break; + default: + expect(status).to.equal("please add this<< TransactionStatus"); + } + + if (!(amountOfCallbacks >= amount)) { + console.log("\nCounter not adequate!", wallet.getCounters()); } else { console.log(wallet.getCounters()); } if (comparison === atLeast) { - expect(wallet.getCounters().broadcast >= amount).to.equal(true); + expect(amountOfCallbacks >= amount).to.equal(true); } else { - expect(wallet.getCounters().broadcast === amount).to.equal(true); + expect(amountOfCallbacks === amount).to.equal(true); } } ); diff --git a/integration_tests/features/support/wallet_steps.js b/integration_tests/features/support/wallet_steps.js index 1828e32fc4..5dd9f68a6e 100644 --- a/integration_tests/features/support/wallet_steps.js +++ b/integration_tests/features/support/wallet_steps.js @@ -1993,7 +1993,7 @@ Then( ); Then( - /wallet (.*) has at least (.*) transactions that are all (.*) and valid/, + /wallet (.*) has at least (.*) transactions that are all (.*) and not cancelled/, { timeout: 610 * 1000 }, async function (walletName, numberOfTransactions, transactionStatus) { const walletClient = await this.getWallet(walletName).connectClient(); @@ -2003,7 +2003,7 @@ Then( numberOfTransactions + " transactions to be " + transactionStatus + - " and valid..." + " and not cancelled..." ); var transactions; var numberCorrect; @@ -2026,7 +2026,7 @@ Then( for (let i = 0; i < transactions.length; i++) { if ( transactions[i]["status"] !== transactionStatus || - !transactions[i]["valid"] + transactions[i]["is_cancelled"] ) { console.log( "Transaction " + @@ -2034,8 +2034,10 @@ Then( 1 + " has " + transactions[i]["status"] + - " and is valid(" + - transactions[i]["valid"] + + " (need " + + transactionStatus + + ") and is not cancelled(" + + transactions[i]["is_cancelled"] + ")" ); statusCorrect = false; @@ -2058,7 +2060,7 @@ Then( ); Then( - /all (.*) transactions for wallet (.*) and wallet (.*) have consistent but opposing validity/, + /all (.*) transactions for wallet (.*) and wallet (.*) have consistent but opposing cancellation status/, async function (transaction_type, walletNameA, walletNameB) { let walletClientA = await this.getWallet(walletNameA).connectClient(); let walletClientB = await this.getWallet(walletNameB).connectClient(); @@ -2077,31 +2079,31 @@ Then( if (transactionsA === undefined || transactionsB === undefined) { expect("\nNo `" + type + "` transactions found!").to.equal(""); } - let validA = transactionsA[0]["valid"]; + let cancelledA = transactionsA[0]["is_cancelled"]; for (let i = 0; i < transactionsA.length; i++) { - if (validA !== transactionsA[i]["valid"]) { + if (cancelledA !== transactionsA[i]["is_cancelled"]) { expect( "\n" + walletNameA + "'s `" + type + - "` transactions do not have a consistent validity status" + "` transactions do not have a consistent cancellation status" ).to.equal(""); } } - let validB = transactionsB[0]["valid"]; + let cancelledB = transactionsB[0]["is_cancelled"]; for (let i = 0; i < transactionsB.length; i++) { - if (validB !== transactionsB[i]["valid"]) { + if (cancelledB !== transactionsB[i]["is_cancelled"]) { expect( "\n" + walletNameB + "'s `" + type + - "` transactions do not have a consistent validity status" + "` transactions do not have a consistent cancellation status" ).to.equal(""); } } - expect(validA).to.equal(!validB); + expect(cancelledA).to.equal(!cancelledB); } ); @@ -2122,7 +2124,7 @@ Then( expect("\nNo `" + type + "` transactions found!").to.equal(""); } for (let i = 0; i < transactions.length; i++) { - expect(transactions[i]["valid"]).to.equal(true); + expect(transactions[i]["is_cancelled"]).to.equal(false); } } ); diff --git a/integration_tests/helpers/ffi/completedTransaction.js b/integration_tests/helpers/ffi/completedTransaction.js index 8d0defdeb3..70362f6657 100644 --- a/integration_tests/helpers/ffi/completedTransaction.js +++ b/integration_tests/helpers/ffi/completedTransaction.js @@ -62,10 +62,6 @@ class CompletedTransaction { return InterfaceFFI.completedTransactionGetTimestamp(this.ptr); } - isValid() { - return InterfaceFFI.completedTransactionIsValid(this.ptr); - } - getConfirmations() { return InterfaceFFI.completedTransactionGetConfirmations(this.ptr); } diff --git a/integration_tests/helpers/ffi/ffiInterface.js b/integration_tests/helpers/ffi/ffiInterface.js index 2f2f455fa2..f1480e2128 100644 --- a/integration_tests/helpers/ffi/ffiInterface.js +++ b/integration_tests/helpers/ffi/ffiInterface.js @@ -152,7 +152,6 @@ class InterfaceFFI { this.ulonglong, [this.ptr, this.intPtr], ], - completed_transaction_is_valid: [this.bool, [this.ptr, this.intPtr]], completed_transaction_is_outbound: [this.bool, [this.ptr, this.intPtr]], completed_transaction_get_confirmations: [ this.ulonglong, @@ -163,6 +162,10 @@ class InterfaceFFI { this.ptr, [this.ptr, this.intPtr], ], + completed_transaction_get_cancellation_reason: [ + this.ptr, + [this.ptr, this.intPtr], + ], completed_transactions_get_length: [this.uint, [this.ptr, this.intPtr]], completed_transactions_get_at: [ this.ptr, @@ -292,6 +295,8 @@ class InterfaceFFI { this.ptr, this.ptr, this.ptr, + this.ptr, + this.ptr, this.boolPtr, this.intPtr, ], @@ -852,17 +857,10 @@ class InterfaceFFI { return result; } - static completedTransactionIsValid(ptr) { - let error = this.initError(); - let result = this.fn.completed_transaction_is_valid(ptr, error); - this.checkErrorResult(error, `completedTransactionIsValid`); - return result; - } - static completedTransactionIsOutbound(ptr) { let error = this.initError(); let result = this.fn.completed_transaction_is_outbound(ptr, error); - this.checkErrorResult(error, `completedTransactionGetConfirmations`); + this.checkErrorResult(error, `completedTransactionGetIsOutbound`); return result; } @@ -879,7 +877,17 @@ class InterfaceFFI { ptr, error ); - this.checkErrorResult(error, `completedTransactionGetConfirmations`); + this.checkErrorResult(error, `completedTransactionGetKernel`); + return result; + } + + static completedTransactionGetCancellationReason(ptr) { + let error = this.initError(); + let result = this.fn.completed_transaction_get_cancellation_reason( + ptr, + error + ); + this.checkErrorResult(error, `completedTransactionGetCancellationReason`); return result; } @@ -1136,6 +1144,14 @@ class InterfaceFFI { return ffi.Callback(this.void, [this.ptr, this.ulonglong], fn); } + static createCallbackFauxTransactionConfirmed(fn) { + return ffi.Callback(this.void, [this.ptr], fn); + } + + static createCallbackFauxTransactionUnconfirmed(fn) { + return ffi.Callback(this.void, [this.ptr, this.ulonglong], fn); + } + static createCallbackDirectSendResult(fn) { return ffi.Callback(this.void, [this.ulonglong, this.bool], fn); } @@ -1184,6 +1200,8 @@ class InterfaceFFI { callback_transaction_broadcast, callback_transaction_mined, callback_transaction_mined_unconfirmed, + callback_faux_transaction_confirmed, + callback_faux_transaction_unconfirmed, callback_direct_send_result, callback_store_and_forward_send_result, callback_transaction_cancellation, @@ -1209,6 +1227,8 @@ class InterfaceFFI { callback_transaction_broadcast, callback_transaction_mined, callback_transaction_mined_unconfirmed, + callback_faux_transaction_confirmed, + callback_faux_transaction_unconfirmed, callback_direct_send_result, callback_store_and_forward_send_result, callback_transaction_cancellation, diff --git a/integration_tests/helpers/ffi/wallet.js b/integration_tests/helpers/ffi/wallet.js index d307660dd2..fc19fda279 100644 --- a/integration_tests/helpers/ffi/wallet.js +++ b/integration_tests/helpers/ffi/wallet.js @@ -22,11 +22,16 @@ class Wallet { ptr; balance = new WalletBalance(); log_path = ""; - receivedTransaction = 0; - receivedTransactionReply = 0; + transactionReceived = 0; + transactionReplyReceived = 0; transactionBroadcast = 0; transactionMined = 0; - saf_messages = 0; + transactionMinedUnconfirmed = 0; + transactionFauxConfirmed = 0; + transactionFauxUnconfirmed = 0; + transactionSafMessageReceived = 0; + transactionCancelled = 0; + transactionFinalized = 0; txo_validation_complete = false; txo_validation_result = 0; tx_validation_complete = false; @@ -37,6 +42,8 @@ class Wallet { callback_transaction_broadcast; callback_transaction_mined; callback_transaction_mined_unconfirmed; + callback_faux_transaction_confirmed; + callback_faux_transaction_unconfirmed; callback_direct_send_result; callback_store_and_forward_send_result; callback_transaction_cancellation; @@ -61,27 +68,31 @@ class Wallet { } clearCallbackCounters() { - this.receivedTransaction = - this.receivedTransactionReply = + this.transactionReceived = + this.transactionReplyReceived = this.transactionBroadcast = this.transactionMined = - this.saf_messages = - this.cancelled = - this.minedunconfirmed = - this.finalized = + this.transactionFauxConfirmed = + this.transactionSafMessageReceived = + this.transactionCancelled = + this.transactionMinedUnconfirmed = + this.transactionFauxUnconfirmed = + this.transactionFinalized = 0; } getCounters() { return { - received: this.receivedTransaction, - replyreceived: this.receivedTransactionReply, + received: this.transactionReceived, + replyReceived: this.transactionReplyReceived, broadcast: this.transactionBroadcast, - finalized: this.finalized, - minedunconfirmed: this.minedunconfirmed, - cancelled: this.cancelled, + finalized: this.transactionFinalized, + minedUnconfirmed: this.transactionMinedUnconfirmed, + fauxUnconfirmed: this.transactionFauxUnconfirmed, + cancelled: this.transactionCancelled, mined: this.transactionMined, - saf: this.saf_messages, + fauxConfirmed: this.transactionFauxConfirmed, + saf: this.transactionSafMessageReceived, }; } @@ -116,6 +127,14 @@ class Wallet { InterfaceFFI.createCallbackTransactionMinedUnconfirmed( this.onTransactionMinedUnconfirmed ); + this.callback_faux_transaction_confirmed = + InterfaceFFI.createCallbackFauxTransactionConfirmed( + this.onFauxTransactionConfirmed + ); + this.callback_faux_transaction_unconfirmed = + InterfaceFFI.createCallbackFauxTransactionUnconfirmed( + this.onFauxTransactionUnconfirmed + ); this.callback_direct_send_result = InterfaceFFI.createCallbackDirectSendResult(this.onDirectSendResult); this.callback_store_and_forward_send_result = @@ -148,14 +167,16 @@ class Wallet { ); //endregion - this.receivedTransaction = 0; - this.receivedTransactionReply = 0; + this.transactionReceived = 0; + this.transactionReplyReceived = 0; this.transactionBroadcast = 0; this.transactionMined = 0; - this.saf_messages = 0; - this.cancelled = 0; - this.minedunconfirmed = 0; - this.finalized = 0; + this.transactionFauxConfirmed = 0; + this.transactionSafMessageReceived = 0; + this.transactionCancelled = 0; + this.transactionMinedUnconfirmed = 0; + this.transactionFauxUnconfirmed = 0; + this.transactionFinalized = 0; this.recoveryFinished = true; let sanitize = null; let words = null; @@ -179,6 +200,8 @@ class Wallet { this.callback_transaction_broadcast, this.callback_transaction_mined, this.callback_transaction_mined_unconfirmed, + this.callback_faux_transaction_confirmed, + this.callback_faux_transaction_unconfirmed, this.callback_direct_send_result, this.callback_store_and_forward_send_result, this.callback_transaction_cancellation, @@ -198,7 +221,7 @@ class Wallet { `${new Date().toISOString()} received Transaction with txID ${tx.getTransactionID()}` ); tx.destroy(); - this.receivedTransaction += 1; + this.transactionReceived += 1; }; onReceivedTransactionReply = (ptr) => { @@ -208,7 +231,7 @@ class Wallet { `${new Date().toISOString()} received reply for Transaction with txID ${tx.getTransactionID()}.` ); tx.destroy(); - this.receivedTransactionReply += 1; + this.transactionReplyReceived += 1; }; onReceivedFinalizedTransaction = (ptr) => { @@ -218,7 +241,7 @@ class Wallet { `${new Date().toISOString()} received finalization for Transaction with txID ${tx.getTransactionID()}.` ); tx.destroy(); - this.finalized += 1; + this.transactionFinalized += 1; }; onTransactionBroadcast = (ptr) => { @@ -248,7 +271,27 @@ class Wallet { `${new Date().toISOString()} Transaction with txID ${tx.getTransactionID()} is mined unconfirmed with ${confirmations} confirmations.` ); tx.destroy(); - this.minedunconfirmed += 1; + this.transactionMinedUnconfirmed += 1; + }; + + onFauxTransactionConfirmed = (ptr) => { + let tx = new CompletedTransaction(); + tx.pointerAssign(ptr); + console.log( + `${new Date().toISOString()} Faux transaction with txID ${tx.getTransactionID()} was confirmed.` + ); + tx.destroy(); + this.transactionFauxConfirmed += 1; + }; + + onFauxTransactionUnconfirmed = (ptr, confirmations) => { + let tx = new CompletedTransaction(); + tx.pointerAssign(ptr); + console.log( + `${new Date().toISOString()} Faux transaction with txID ${tx.getTransactionID()} is unconfirmed with ${confirmations} confirmations.` + ); + tx.destroy(); + this.transactionFauxUnconfirmed += 1; }; onTransactionCancellation = (ptr, reason) => { @@ -258,7 +301,7 @@ class Wallet { `${new Date().toISOString()} Transaction with txID ${tx.getTransactionID()} was cancelled with reason code ${reason}.` ); tx.destroy(); - this.cancelled += 1; + this.transactionCancelled += 1; }; onDirectSendResult = (id, success) => { @@ -308,7 +351,7 @@ class Wallet { onSafMessageReceived = () => { console.log(`${new Date().toISOString()} callbackSafMessageReceived()`); - this.saf_messages += 1; + this.transactionSafMessageReceived += 1; }; onRecoveryProgress = (a, b, c) => { @@ -465,6 +508,8 @@ class Wallet { this.callback_transaction_broadcast = this.callback_transaction_mined = this.callback_transaction_mined_unconfirmed = + this.callback_faux_transaction_confirmed = + this.callback_faux_transaction_unconfirmed = this.callback_direct_send_result = this.callback_store_and_forward_send_result = this.callback_transaction_cancellation = diff --git a/integration_tests/helpers/util.js b/integration_tests/helpers/util.js index 7b6d808b68..d042b30add 100644 --- a/integration_tests/helpers/util.js +++ b/integration_tests/helpers/util.js @@ -1,6 +1,7 @@ const net = require("net"); const { blake2bInit, blake2bUpdate, blake2bFinal } = require("blakejs"); +const { expect } = require("chai"); const NO_CONNECTION = 14; @@ -200,24 +201,94 @@ const getFreePort = function () { }); }; +const encodeOption = function (value) { + let buffer; + if (value) { + buffer = Buffer.concat([Buffer.from([1]), Buffer.from(value, "utf8")]); + } else { + buffer = Buffer.from([0]); + } + return buffer; +}; + const getTransactionOutputHash = function (output) { const KEY = null; // optional key const OUTPUT_LENGTH = 32; // bytes const context = blake2bInit(OUTPUT_LENGTH, KEY); - const flags = Buffer.alloc(1); - flags[0] = output.features.flags; - const buffer = Buffer.concat([ - Buffer.from([0]), // base_layer\core\src\transactions\transaction\output_features.rs:64 CONSENSUS_ENCODING_VERSION : u8 = 0 + let encodedBytesLength = 0; + // version + const version = Buffer.from([0]); + encodedBytesLength += version.length; + blake2bUpdate(context, version); + // features + let features = Buffer.concat([ + // features.version + Buffer.from([0]), + // features.maturity Buffer.from([parseInt(output.features.maturity)]), + // features.flags Buffer.from([output.features.flags]), ]); - let nopScriptBytes = Buffer.from([0x73]); - - blake2bUpdate(context, buffer); + // features.parent_public_key + features = Buffer.concat([ + Buffer.from(features), + encodeOption(output.features.parent_public_key), + ]); + // features.unique_id + features = Buffer.concat([ + Buffer.from(features), + encodeOption(output.features.unique_id), + ]); + // features.asset + features = Buffer.concat([ + Buffer.from(features), + encodeOption(output.features.asset), + ]); + // features.mint_non_fungible + features = Buffer.concat([ + Buffer.from(features), + encodeOption(output.features.mint_non_fungible), + ]); + // features.sidechain_checkpoint + features = Buffer.concat([ + Buffer.from(features), + encodeOption(output.features.sidechain_checkpoint), + ]); + // features.metadata + features = Buffer.concat([ + Buffer.from(features), + Buffer.from([output.features.metadata.length]), + Buffer.from(output.features.metadata), + ]); + encodedBytesLength += features.length; + blake2bUpdate(context, features); + // commitment + encodedBytesLength += output.commitment.length; blake2bUpdate(context, output.commitment); - blake2bUpdate(context, nopScriptBytes); - let final = blake2bFinal(context); - return Buffer.from(final); + // script + const script = Buffer.concat([ + Buffer.from([output.script.length]), + Buffer.from(output.script), + ]); + encodedBytesLength += script.length; + blake2bUpdate(context, script); + // covenant + const covenant = Buffer.concat([ + Buffer.from([output.covenant.length]), + Buffer.from(output.covenant), + ]); + encodedBytesLength += covenant.length; + blake2bUpdate(context, covenant); + + expect(context.c).to.equal(encodedBytesLength); + const hash = blake2bFinal(context); + const hashBuffer = Buffer.from(hash); + // console.log( + // "\ngetTransactionOutputHash - hash", + // hashBuffer.toString("hex"), + // "\n" + // ); + return hashBuffer; }; function consoleLogTransactionDetails(txnDetails) { @@ -227,9 +298,7 @@ function consoleLogTransactionDetails(txnDetails) { " has status " + pad("'" + txnDetails.status + "'", 40) + " and " + - pad("is_cancelled(" + txnDetails.is_cancelled + ")", 21) + - " and " + - pad("is_valid(" + txnDetails.valid + ")", 16) + pad("is_cancelled(" + txnDetails.is_cancelled + ")", 21) ); } diff --git a/integration_tests/helpers/walletClient.js b/integration_tests/helpers/walletClient.js index 030e2ae253..df69471130 100644 --- a/integration_tests/helpers/walletClient.js +++ b/integration_tests/helpers/walletClient.js @@ -57,7 +57,6 @@ class WalletClient { Number(data[i].transaction.timestamp.seconds) * 1000 ), message: data[i].transaction.message, - valid: data[i].transaction.valid, }); } return transactions; @@ -81,10 +80,7 @@ class WalletClient { const data = await this.getAllCoinbaseTransactions(); const transactions = []; for (let i = 0; i < data.length; i++) { - if ( - transactionStatus().indexOf(data[i].status) === 6 && - data[i].valid === true - ) { + if (transactionStatus().indexOf(data[i].status) === 6) { transactions.push(data[i]); } } @@ -109,10 +105,7 @@ class WalletClient { const data = await this.getAllCoinbaseTransactions(); let count = 0; for (let i = 0; i < data.length; i++) { - if ( - transactionStatus().indexOf(data[i].status) == 6 && - data[i].valid == true - ) { + if (transactionStatus().indexOf(data[i].status) == 6) { count += 1; } } @@ -229,10 +222,7 @@ class WalletClient { const txnDetails = await this.getTransactionInfo({ transaction_ids: [tx_id.toString()], }); - if ( - transactionStatus().indexOf(txnDetails.transactions[0].status) >= 2 && - txnDetails.transactions[0].valid - ) { + if (transactionStatus().indexOf(txnDetails.transactions[0].status) >= 2) { return true; } else { return false; @@ -248,10 +238,7 @@ class WalletClient { const txnDetails = await this.getTransactionInfo({ transaction_ids: [tx_id.toString()], }); - if ( - transactionStatus().indexOf(txnDetails.transactions[0].status) == 2 && - txnDetails.transactions[0].valid - ) { + if (transactionStatus().indexOf(txnDetails.transactions[0].status) == 2) { return true; } else { return false; @@ -267,10 +254,7 @@ class WalletClient { const txnDetails = await this.getTransactionInfo({ transaction_ids: [tx_id.toString()], }); - if ( - transactionStatus().indexOf(txnDetails.transactions[0].status) >= 3 && - txnDetails.transactions[0].valid - ) { + if (transactionStatus().indexOf(txnDetails.transactions[0].status) >= 3) { return true; } else { return false; @@ -286,10 +270,7 @@ class WalletClient { const txnDetails = await this.getTransactionInfo({ transaction_ids: [tx_id.toString()], }); - if ( - transactionStatus().indexOf(txnDetails.transactions[0].status) >= 4 && - txnDetails.transactions[0].valid - ) { + if (transactionStatus().indexOf(txnDetails.transactions[0].status) >= 4) { return true; } else { return false; @@ -305,10 +286,7 @@ class WalletClient { const txnDetails = await this.getTransactionInfo({ transaction_ids: [tx_id.toString()], }); - if ( - transactionStatus().indexOf(txnDetails.transactions[0].status) >= 5 && - txnDetails.transactions[0].valid - ) { + if (transactionStatus().indexOf(txnDetails.transactions[0].status) >= 5) { return true; } else { return false; @@ -324,10 +302,7 @@ class WalletClient { const txnDetails = await this.getTransactionInfo({ transaction_ids: [tx_id.toString()], }); - if ( - transactionStatus().indexOf(txnDetails.transactions[0].status) == 5 && - txnDetails.transactions[0].valid - ) { + if (transactionStatus().indexOf(txnDetails.transactions[0].status) == 5) { return true; } else { return false; @@ -343,10 +318,7 @@ class WalletClient { const txnDetails = await this.getTransactionInfo({ transaction_ids: [tx_id.toString()], }); - if ( - transactionStatus().indexOf(txnDetails.transactions[0].status) == 6 && - txnDetails.transactions[0].valid - ) { + if (transactionStatus().indexOf(txnDetails.transactions[0].status) == 6) { return true; } else { return false; diff --git a/integration_tests/helpers/walletFFIClient.js b/integration_tests/helpers/walletFFIClient.js index 6bfd907f12..9f3ef79329 100644 --- a/integration_tests/helpers/walletFFIClient.js +++ b/integration_tests/helpers/walletFFIClient.js @@ -157,7 +157,7 @@ class WalletFFIClient { seed_words_text, pass_phrase, rolling_log_files = 50, - byte_size_per_log = 102400 + byte_size_per_log = 1048576 ) { this.pass_phrase = pass_phrase; if (seed_words_text) { @@ -180,6 +180,10 @@ class WalletFFIClient { return this.wallet.getOutboundTransactions(); } + getCancelledTransactions() { + return this.wallet.walletGetCancelledTransactions(); + } + cancelPendingTransaction(tx_id) { return this.wallet.cancelPendingTransaction(tx_id); } diff --git a/integration_tests/package-lock.json b/integration_tests/package-lock.json index 868ccd2cda..243dcff76c 100644 --- a/integration_tests/package-lock.json +++ b/integration_tests/package-lock.json @@ -1820,9 +1820,9 @@ "dev": true }, "follow-redirects": { - "version": "1.14.4", - "resolved": false, - "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==" + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" }, "fs-constants": { "version": "1.0.0", @@ -1946,7 +1946,7 @@ }, "globals": { "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "resolved": false, "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, @@ -2252,7 +2252,7 @@ }, "jsesc": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "resolved": false, "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, @@ -3038,7 +3038,7 @@ }, "source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "resolved": false, "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, @@ -3290,7 +3290,7 @@ }, "to-fast-properties": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "resolved": false, "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, @@ -3440,7 +3440,7 @@ "dependencies": { "@grpc/grpc-js": { "version": "1.3.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.3.6.tgz", "integrity": "sha512-v7+LQFbqZKmd/Tvf5/j1Xlbq6jXL/4d+gUtm2TNX4QiEC3ELWADmGr2dGlUyLl6aKTuYfsN72vAsO5zmavYkEg==", "requires": { "@types/node": ">=12.12.47" @@ -3448,7 +3448,7 @@ }, "@grpc/proto-loader": { "version": "0.5.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.6.tgz", "integrity": "sha512-DT14xgw3PSzPxwS13auTEwxhMMOoz33DPUKNtmYK/QYbBSpLXJy78FGGs5yVoxVobEqPm4iW9MOIoz0A3bLTRQ==", "requires": { "lodash.camelcase": "^4.3.0", @@ -3457,27 +3457,27 @@ }, "@protobufjs/aspromise": { "version": "1.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" }, "@protobufjs/base64": { "version": "1.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" }, "@protobufjs/codegen": { "version": "2.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" }, "@protobufjs/eventemitter": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" }, "@protobufjs/fetch": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", "requires": { "@protobufjs/aspromise": "^1.1.1", @@ -3486,57 +3486,57 @@ }, "@protobufjs/float": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" }, "@protobufjs/inquire": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" }, "@protobufjs/path": { "version": "1.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" }, "@protobufjs/pool": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" }, "@protobufjs/utf8": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" }, "@types/long": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, "@types/node": { "version": "16.3.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.2.tgz", "integrity": "sha512-jJs9ErFLP403I+hMLGnqDRWT0RYKSvArxuBVh2veudHV7ifEC1WAmjJADacZ7mRbA2nWgHtn8xyECMAot0SkAw==" }, "grpc-promise": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/grpc-promise/-/grpc-promise-1.4.0.tgz", "integrity": "sha512-4BBXHXb5OjjBh7luylu8vFqL6H6aPn/LeqpQaSBeRzO/Xv95wHW/WkU9TJRqaCTMZ5wq9jTSvlJWp0vRJy1pVA==" }, "lodash.camelcase": { "version": "4.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" }, "long": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "protobufjs": { "version": "6.11.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", "requires": { "@protobufjs/aspromise": "^1.1.2", diff --git a/package-lock.json b/package-lock.json index d3287a6b0b..befbdd2466 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "tari", - "version": "0.27.2", + "version": "0.28.0", "lockfileVersion": 2, "requires": true, "packages": {} diff --git a/package.json b/package.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/package.json +++ /dev/null @@ -1 +0,0 @@ -{}