diff --git a/.circleci/config.yml b/.circleci/config.yml index dfb1666bb3..3db41d9a40 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 defaults: - rust_image: &rust_image quay.io/tarilabs/rust_tari-build-with-deps:nightly-2021-08-17 + rust_image: &rust_image quay.io/tarilabs/rust_tari-build-with-deps:nightly-2021-09-18 commands: test: @@ -76,13 +76,13 @@ commands: - run: name: Cargo fmt command: | - TOOLCHAIN=$(cat rust-toolchain) + TOOLCHAIN=$(awk '/channel = /{print $NF}' rust-toolchain.toml) rustup component add --toolchain $TOOLCHAIN rustfmt cargo fmt --all -- --check - run: name: Run clippy (main source) command: | - TOOLCHAIN=$(cat rust-toolchain) + TOOLCHAIN=$(awk '/channel = /{print $NF}' rust-toolchain.toml) rustup component add --toolchain $TOOLCHAIN clippy cargo clippy -- -D warnings -W clippy::cognitive_complexity when: always @@ -134,7 +134,7 @@ commands: - run: name: Run cucumber scenarios no_output_timeout: 20m - command: cd integration_tests && mkdir -p cucumber_output && node_modules/.bin/cucumber-js --profile "ci" --tags "not @long-running and not @broken and not @wallet-ffi" --format json:cucumber_output/tests.cucumber --exit --retry 2 --retryTagFilter "@flaky and not @broken" + command: cd integration_tests && mkdir -p cucumber_output && node_modules/.bin/cucumber-js --profile "ci" --tags "not @long-running and not @broken and not @wallet-ffi" --format json:cucumber_output/tests.cucumber --exit --retry 3 --retry-tag-filter "@flaky and not @broken" - run: name: Generate report command: cd integration_tests && node ./generate_report.js @@ -142,7 +142,7 @@ commands: # Below step requires NodeJS v12 to run correctly, see explanation in WalletFFI.feature - run: name: Run FFI wallet library cucumber scenarios - command: cd integration_tests && mkdir -p cucumber_output && node_modules/.bin/cucumber-js --profile "ci" --tags "not @long-running and not @broken and not @flaky and @wallet-ffi" --format json:cucumber_output/tests_ffi.cucumber --exit + command: cd integration_tests && mkdir -p cucumber_output && node_modules/.bin/cucumber-js --profile "ci" --tags "not @long-running and not @broken and @wallet-ffi" --format json:cucumber_output/tests_ffi.cucumber --exit --retry 3 --retry-tag-filter "@flaky and not @broken" when: always - run: name: Generate report (ffi) diff --git a/.clog.toml b/.clog.toml deleted file mode 100644 index d8ef68f8e9..0000000000 --- a/.clog.toml +++ /dev/null @@ -1,9 +0,0 @@ -[clog] -# A repository link with the trailing '.git' which will be used to generate -# all commit and issue links -repository = "https://github.com/tari-project/tari" - -# specify the style of commit links to generate, defaults to "github" if omitted -link-style = "github" -#changelog = "changelog.md" -from-latest-tag = true diff --git a/.github/wip_integration_tests.yml b/.github/wip_integration_tests.yml index b04b8d5fa0..227fea6db2 100644 --- a/.github/wip_integration_tests.yml +++ b/.github/wip_integration_tests.yml @@ -23,7 +23,7 @@ jobs: - name: toolchain uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2021-08-17 + toolchain: nightly-2021-08-18 components: clippy, rustfmt override: true - name: dependencies diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index ce18c6b5e0..8323812244 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -7,7 +7,7 @@ jobs: security_audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - uses: actions-rs/audit-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/base_node_binaries.yml b/.github/workflows/base_node_binaries.yml index dc59715a0d..e1bc225ae9 100644 --- a/.github/workflows/base_node_binaries.yml +++ b/.github/workflows/base_node_binaries.yml @@ -61,7 +61,7 @@ jobs: - name: Setup Rust toolchain uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2021-08-17 + toolchain: nightly-2021-09-18 components: rustfmt override: true @@ -87,7 +87,7 @@ jobs: # sudo apt-get -y upgrade - name: Install macOS dependencies if: startsWith(runner.os,'macOS') - run: brew install cmake zip + run: brew install cmake zip coreutils - name: Install Windows dependencies if: startsWith(runner.os,'Windows') @@ -141,13 +141,13 @@ jobs: #cargo build --release --bin tari_base_node --features ${{ matrix.features}} cargo build --release - # - name: Prepare Archives - # shell: bash - # run: | - # ls -la "$GITHUB_WORKSPACE" - # mkdir -p "$GITHUB_WORKSPACE${TBN_DIST}/archives" - # export distDir="$GITHUB_WORKSPACE${TBN_DIST}/archives" - # "$GITHUB_WORKSPACE/scripts/build_dists_tarball.sh" noBuild + # - name: Prepare Archives + # shell: bash + # run: | + # ls -la "$GITHUB_WORKSPACE" + # mkdir -p "$GITHUB_WORKSPACE${TBN_DIST}/archives" + # export distDir="$GITHUB_WORKSPACE${TBN_DIST}/archives" + # "$GITHUB_WORKSPACE/scripts/build_dists_tarball.sh" noBuild - name: Prepare binaries shell: bash @@ -162,7 +162,7 @@ jobs: #BINFILE="${TBN_FILENAME}-${VERSION}-${VSHA_SHORT}-${{ matrix.os }}-${{ matrix.target_cpu }}-${{ matrix.features }}${TBN_EXT}" BINFILE="${TBN_FILENAME}-${VERSION}-${VSHA_SHORT}-${{ matrix.os }}-${{ matrix.target_cpu }}${TBN_EXT}" echo "BINFILE=${BINFILE}" >> $GITHUB_ENV - echo "Copying files for ${BINFILE} too $(pwd)" + echo "Copying files for ${BINFILE} to $(pwd)" #cp -v "$GITHUB_WORKSPACE/target/release/${TBN_FILENAME}${TBN_EXT}" "./${BINFILE}" ls -la "$GITHUB_WORKSPACE/target/release/" cp -v "$GITHUB_WORKSPACE/target/release/tari_base_node${TBN_EXT}" . @@ -170,11 +170,51 @@ jobs: cp -v "$GITHUB_WORKSPACE/target/release/tari_merge_mining_proxy${TBN_EXT}" . cp -v "$GITHUB_WORKSPACE/target/release/tari_mining_node${TBN_EXT}" . + - name: Build the macos pkg + if: startsWith(runner.os,'macOS') + env: + MACOS_KEYCHAIN_PASS: ${{ secrets.MACOS_KEYCHAIN_PASS }} + MACOS_APPLICATION_CERT: ${{ secrets.MACOS_APPLICATION_CERT }} + MACOS_APPLICATION_PASS: ${{ secrets.MACOS_APPLICATION_PASS }} + MACOS_INSTALLER_CERT: ${{ secrets.MACOS_INSTALLER_CERT }} + MACOS_INSTALLER_PASS: ${{ secrets.MACOS_INSTALLER_PASS }} + run: | + echo $MACOS_APPLICATION_CERT | base64 --decode > application.p12 + echo $MACOS_INSTALLER_CERT | base64 --decode > installer.p12 + security create-keychain -p $MACOS_KEYCHAIN_PASS build.keychain + security default-keychain -s build.keychain + security unlock-keychain -p $MACOS_KEYCHAIN_PASS build.keychain + security import application.p12 -k build.keychain -P $MACOS_APPLICATION_PASS -T /usr/bin/codesign + security import installer.p12 -k build.keychain -P $MACOS_INSTALLER_PASS -T /usr/bin/pkgbuild + 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") + for FILE in "${FILES[@]}"; do + codesign --force -s "Developer ID Application: Tari Labs, LLC (8XGMD9X2H2)" "/tmp/tari_testnet/runtime/$FILE" -v + codesign --verify --deep --display --verbose=4 "/tmp/tari_testnet/runtime/$FILE" + done + pkgbuild --root /tmp/tari_testnet \ + --identifier "com.tarilabs.pkg" \ + --version "$VERSION" \ + --install-location "/tmp/tari" \ + --scripts "/tmp/tari_testnet/scripts" \ + --sign "Developer ID Installer: Tari Labs, LLC (8XGMD9X2H2)" \ + "${{ github.workspace }}${{ env.TBN_DIST }}/tari-${{ env.VERSION }}.pkg" + - name: Artifact macos pkg + if: startsWith(runner.os,'macOS') + 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 shell: cmd if: startsWith(runner.os,'Windows') run: | cd buildtools + 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 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c14c092d66..51478d0c1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,10 @@ on: name: CI +env: + CARGO_HTTP_MULTIPLEXING: false + toolchain: nightly-2021-09-18 + jobs: clippy: name: clippy @@ -27,9 +31,17 @@ jobs: - name: toolchain uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2021-08-17 + toolchain: ${{ env.toolchain }} components: clippy, rustfmt override: true + - name: Caching + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-${{ runner.cpu-model }}-${{ env.toolchain }}-${{ hashFiles('**/Cargo.lock') }} - name: cargo fmt uses: actions-rs/cargo@v1 with: @@ -39,86 +51,25 @@ jobs: # uses: actions-rs/cargo@v1 # with: # command: check - - name: cargo clippy - uses: actions-rs/cargo@v1 - with: - command: clippy - args: -- -D warnings -W clippy::cognitive_complexity - - name: cargo clippy --all-targets - uses: actions-rs/cargo@v1 - with: - command: clippy - args: --all-targets -- -D warnings - build: - name: build - strategy: - fail-fast: false - matrix: - os: [ubuntu-18.04, macos-10.15, windows-2019] - runs-on: ${{ matrix.os }} - steps: - - name: checkout - uses: actions/checkout@v2 - - - name: ubuntu dependencies - if: startsWith(matrix.os,'ubuntu') - run: | - sudo apt-get update && \ - sudo apt-get -y install \ - build-essential \ - libgtk-3-dev \ - libwebkit2gtk-4.0-dev \ - libsoup2.4-dev - - - name: macOS dependencies - if: startsWith(matrix.os,'macos') - run: brew install cmake zip - - - name: windows dependencies - if: startsWith(matrix.os,'windows') - run: | - vcpkg.exe install sqlite3:x64-windows zlib:x64-windows - choco upgrade llvm zip psutils strawberryperl -y - - - name: windows env - if: startsWith(matrix.os,'Windows') - shell: bash - run: | - echo "SQLITE3_LIB_DIR=C:\vcpkg\installed\x64-windows\lib" >> $GITHUB_ENV - echo "LIBCLANG_PATH=C:\Program Files\LLVM\bin" >> $GITHUB_ENV - - - name: toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly-2021-08-17 - components: clippy, rustfmt - override: true - - - name: cargo build - uses: actions-rs/cargo@v1 - with: - command: build - args: --release - - - name: cargo build wallet - uses: actions-rs/cargo@v1 - with: - command: build - args: --release -p tari_wallet - - - name: cargo build wallet ffi - uses: actions-rs/cargo@v1 + - name: Clippy check + uses: actions-rs/clippy-check@v1 with: - command: build - args: --release -p tari_wallet_ffi - + token: ${{ secrets.GITHUB_TOKEN }} + args: --all-features test: name: test runs-on: ubuntu-18.04 steps: - name: checkout uses: actions/checkout@v2 - + - name: Caching + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-${{ runner.cpu-model }}-${{ env.toolchain }}-${{ hashFiles('**/Cargo.lock') }} - name: ubuntu dependencies run: | sudo apt-get update && \ @@ -131,7 +82,7 @@ jobs: - name: toolchain uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2021-08-17 + toolchain: ${{ env.toolchain }} components: clippy, rustfmt override: true diff --git a/.github/workflows/libwallet.yml b/.github/workflows/libwallet.yml index e4fa375100..b2df3d7182 100644 --- a/.github/workflows/libwallet.yml +++ b/.github/workflows/libwallet.yml @@ -7,6 +7,8 @@ on: # - development tags: - "libwallet-*" + schedule: + - cron: "05 00 * * *" jobs: android: runs-on: ubuntu-latest @@ -28,6 +30,7 @@ jobs: path: ${{ github.workspace }}/libwallet/ # Copy tarballs to S3 - name: Sync to S3 + if: ${{ startsWith(github.ref, 'refs/tags/v') }} continue-on-error: true # Don't break if s3 upload fails uses: jakejarvis/s3-sync-action@v0.5.1 with: @@ -45,13 +48,13 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2021-08-17 + toolchain: nightly-2021-09-18 target: aarch64-apple-ios components: rustfmt override: true - uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2021-08-17 + toolchain: nightly-2021-09-18 target: x86_64-apple-ios components: rustfmt override: true diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml deleted file mode 100644 index ad1bbf01f6..0000000000 --- a/.github/workflows/version.yml +++ /dev/null @@ -1,54 +0,0 @@ -on: - push: - branches: - - development - -name: Version - -jobs: - bump: - name: patch crate versions - runs-on: ubuntu-20.04 - steps: - - name: checkout - uses: actions/checkout@v2 - - name: gpg - uses: crazy-max/ghaction-import-gpg@v4 - with: - gpg_private_key: ${{ secrets.TARI_DEPLOY_SECRET_KEY }} - git_user_signingkey: true - git_commit_gpgsign: true - git_push_gpgsign: false - - name: install - run: | - echo "This is a lot faster than building from source ⚡" - curl -o /tmp/cargo-workspaces -L https://github.com/tari-project/cargo-workspaces/releases/download/v0.2.24/cargo-workspaces-v0.2.24-x86_64-linux-gnu - HASH=$(shasum /tmp/cargo-workspaces) - EXPECTED="94901503e751564153392c8f93bfebdc349e650c /tmp/cargo-workspaces" - if [ "$HASH" != "$EXPECTED" ]; then - echo "Well, this is awkward."; - echo "The hash of the downloaded binary doesn't match what's expected."; - echo "Either the binary has been innocently changed without updating the expected hash," - echo "or it's compromised and you're under attack!" - echo "Bailing out." - exit 1 - fi - chmod +x /tmp/cargo-workspaces - - name: git config - run: | - git config --global user.name "tari-deploy" - git config --global user.email "bug_reports@tari.com" - - name: crates list - run: | - pwd - /tmp/cargo-workspaces workspaces list - - name: bump patch version - run: | - /tmp/cargo-workspaces workspaces version patch \ - --no-git-tag \ - --sign-commit \ - --no-global-tag \ - --force "*" \ - -y \ - -m "ci: bump crate versions to %v [skip ci]" \ - --allow-branch development diff --git a/Cargo.lock b/Cargo.lock index 6714a10b0e..6247fd0eac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,9 +177,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "async-io" @@ -216,9 +216,9 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -227,9 +227,9 @@ version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -372,7 +372,7 @@ dependencies = [ "lazycell", "log 0.4.14", "peeking_take_while", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "regex", "rustc-hash", @@ -433,7 +433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2607a74355ce2e252d0c483b2d8a348e1bba36036e786ccc2dcd777213c86ffd" dependencies = [ "arrayref", - "arrayvec 0.7.1", + "arrayvec 0.7.2", "cc", "cfg-if 1.0.0", "constant_time_eq", @@ -671,11 +671,11 @@ dependencies = [ "heck", "indexmap", "log 0.4.14", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "serde 1.0.130", "serde_json", - "syn 1.0.80", + "syn 1.0.81", "tempfile", "toml 0.5.8", ] @@ -899,7 +899,7 @@ dependencies = [ "block", "cocoa-foundation", "core-foundation 0.9.2", - "core-graphics 0.22.2", + "core-graphics 0.22.3", "foreign-types", "libc", "objc", @@ -942,8 +942,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7606b05842fea68ddcc89e8053b8860ebcb2a0ba8d6abfe3a148e5d5a8d3f0c1" dependencies = [ "com_macros_support", - "proc-macro2 1.0.30", - "syn 1.0.80", + "proc-macro2 1.0.32", + "syn 1.0.81", ] [[package]] @@ -952,9 +952,9 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97e9a6d20f4ac8830e309a455d7e9416e65c6af5a97c88c55fbb4c2012e107da" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1046,9 +1046,9 @@ dependencies = [ [[package]] name = "core-graphics" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" dependencies = [ "bitflags 1.3.2", "core-foundation 0.9.2", @@ -1336,10 +1336,10 @@ dependencies = [ "itoa", "matches", "phf 0.8.0", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "smallvec", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1349,7 +1349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e" dependencies = [ "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1454,10 +1454,10 @@ checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "strsim 0.9.3", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1468,7 +1468,7 @@ checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1515,9 +1515,9 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1539,9 +1539,9 @@ checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0" dependencies = [ "darling", "derive_builder_core", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1551,9 +1551,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef" dependencies = [ "darling", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1563,10 +1563,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40eebddd2156ce1bb37b20bbe5151340a31828b1f2d22ba4141f3531710e38df" dependencies = [ "convert_case", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "rustc_version 0.3.3", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1603,9 +1603,9 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1675,6 +1675,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "dtoa" version = "0.4.8" @@ -1747,9 +1753,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" dependencies = [ "heck", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1768,9 +1774,9 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -2100,9 +2106,9 @@ checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" dependencies = [ "autocfg 1.0.1", "proc-macro-hack", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -2448,9 +2454,9 @@ dependencies = [ "heck", "proc-macro-crate 1.1.0", "proc-macro-error", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -2565,9 +2571,9 @@ dependencies = [ "heck", "proc-macro-crate 1.1.0", "proc-macro-error", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -2584,7 +2590,7 @@ dependencies = [ "http", "indexmap", "slab", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-util", "tracing", ] @@ -2648,9 +2654,9 @@ dependencies = [ "log 0.4.14", "mac", "markup5ever", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -2745,7 +2751,7 @@ dependencies = [ "itoa", "pin-project-lite 0.2.7", "socket2", - "tokio 1.12.0", + "tokio 1.13.0", "tower-service", "tracing", "want", @@ -2759,7 +2765,7 @@ checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ "hyper 0.14.14", "pin-project-lite 0.2.7", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-io-timeout", ] @@ -2772,7 +2778,7 @@ dependencies = [ "bytes 1.1.0", "hyper 0.14.14", "native-tls", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-native-tls", ] @@ -3380,9 +3386,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c" dependencies = [ "migrations_internals", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -3532,9 +3538,9 @@ checksum = "424f6e86263cd5294cbd7f1e95746b95aca0e0d66bff31e5a40d6baa87b4aa99" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro-error", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", "synstructure", ] @@ -3607,9 +3613,9 @@ checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" dependencies = [ "darling", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -3801,9 +3807,9 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -3894,9 +3900,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9" dependencies = [ "proc-macro-crate 1.1.0", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -4008,7 +4014,7 @@ dependencies = [ "pin-project 1.0.8", "rand 0.8.4", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-stream", ] @@ -4024,7 +4030,7 @@ dependencies = [ "opentelemetry-semantic-conventions", "thiserror", "thrift", - "tokio 1.12.0", + "tokio 1.13.0", ] [[package]] @@ -4347,9 +4353,9 @@ dependencies = [ "phf_generator 0.8.0", "phf_shared 0.8.0", "proc-macro-hack", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -4361,9 +4367,9 @@ dependencies = [ "phf_generator 0.10.0", "phf_shared 0.10.0", "proc-macro-hack", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -4408,9 +4414,9 @@ version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be26700300be6d9d23264c73211d8190e755b6b5ca7a1b28230025511b52a5e" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -4419,9 +4425,9 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -4557,9 +4563,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", "version_check 0.9.3", ] @@ -4569,7 +4575,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "version_check 0.9.3", ] @@ -4597,9 +4603,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.30" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid 0.2.2", ] @@ -4640,9 +4646,9 @@ checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba" dependencies = [ "anyhow", "itertools 0.10.1", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -4692,7 +4698,7 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", ] [[package]] @@ -4986,7 +4992,7 @@ dependencies = [ "serde 1.0.130", "serde_json", "serde_urlencoded 0.7.0", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-native-tls", "url 2.2.2", "wasm-bindgen", @@ -5195,7 +5201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "688599bdab9f42105d0ae1494335a9ffafdeb7d36325e6b10fd4abc5829d6284" dependencies = [ "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -5388,9 +5394,9 @@ version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -5410,9 +5416,9 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -5700,7 +5706,7 @@ checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" dependencies = [ "phf_generator 0.8.0", "phf_shared 0.8.0", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", ] @@ -5735,9 +5741,9 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck", "proc-macro-error", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -5768,9 +5774,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" dependencies = [ "heck", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -5780,9 +5786,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" dependencies = [ "heck", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -5792,9 +5798,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "339f799d8b549e3744c7ac7feb216383e4005d94bdb22561b3ab8f3b808ae9fb" dependencies = [ "heck", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -5839,11 +5845,11 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "unicode-xid 0.2.2", ] @@ -5863,9 +5869,9 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", "unicode-xid 0.2.2", ] @@ -5913,7 +5919,7 @@ dependencies = [ "cc", "cocoa", "core-foundation 0.9.2", - "core-graphics 0.22.2", + "core-graphics 0.22.3", "core-video-sys", "crossbeam-channel 0.5.1", "dispatch", @@ -5954,7 +5960,7 @@ dependencies = [ [[package]] name = "tari_app_grpc" -version = "0.11.0" +version = "0.12.0" dependencies = [ "chrono", "prost", @@ -5970,7 +5976,7 @@ dependencies = [ [[package]] name = "tari_app_utilities" -version = "0.11.0" +version = "0.12.0" dependencies = [ "config", "dirs-next 1.0.2", @@ -5990,13 +5996,13 @@ dependencies = [ "tari_p2p", "tari_utilities", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tonic", ] [[package]] name = "tari_base_node" -version = "0.11.0" +version = "0.12.0" dependencies = [ "anyhow", "bincode", @@ -6027,7 +6033,7 @@ dependencies = [ "tari_shutdown", "tari_utilities", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tonic", "tracing", "tracing-opentelemetry", @@ -6072,7 +6078,7 @@ dependencies = [ [[package]] name = "tari_common" -version = "0.11.0" +version = "0.12.0" dependencies = [ "anyhow", "config", @@ -6092,7 +6098,7 @@ dependencies = [ "sha2", "structopt", "tari_storage", - "tari_test_utils 0.11.0", + "tari_test_utils 0.12.0", "tempfile", "thiserror", "toml 0.5.8", @@ -6103,7 +6109,7 @@ dependencies = [ [[package]] name = "tari_common_types" -version = "0.11.0" +version = "0.12.0" dependencies = [ "digest", "futures 0.3.17", @@ -6112,12 +6118,12 @@ dependencies = [ "serde 1.0.130", "tari_crypto", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", ] [[package]] name = "tari_comms" -version = "0.11.0" +version = "0.12.0" dependencies = [ "anyhow", "async-trait", @@ -6151,10 +6157,10 @@ dependencies = [ "tari_crypto", "tari_shutdown", "tari_storage", - "tari_test_utils 0.11.0", + "tari_test_utils 0.12.0", "tempfile", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-stream", "tokio-util", "tower 0.3.1", @@ -6166,7 +6172,7 @@ dependencies = [ [[package]] name = "tari_comms_dht" -version = "0.11.0" +version = "0.12.0" dependencies = [ "anyhow", "bitflags 1.3.2", @@ -6199,11 +6205,11 @@ dependencies = [ "tari_crypto", "tari_shutdown", "tari_storage", - "tari_test_utils 0.11.0", + "tari_test_utils 0.12.0", "tari_utilities", "tempfile", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-stream", "tokio-test 0.4.2", "tower 0.4.10", @@ -6213,22 +6219,22 @@ dependencies = [ [[package]] name = "tari_comms_rpc_macros" -version = "0.11.0" +version = "0.12.0" dependencies = [ "futures 0.3.17", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "prost", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", "tari_comms", - "tari_test_utils 0.11.0", - "tokio 1.12.0", + "tari_test_utils 0.12.0", + "tokio 1.13.0", "tower-service", ] [[package]] name = "tari_console_wallet" -version = "0.11.0" +version = "0.12.0" dependencies = [ "bitflags 1.3.2", "chrono", @@ -6259,7 +6265,7 @@ dependencies = [ "tari_utilities", "tari_wallet", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tonic", "tracing", "tracing-opentelemetry", @@ -6271,7 +6277,7 @@ dependencies = [ [[package]] name = "tari_core" -version = "0.11.0" +version = "0.12.0" dependencies = [ "async-trait", "bincode", @@ -6315,11 +6321,11 @@ dependencies = [ "tari_service_framework", "tari_shutdown", "tari_storage", - "tari_test_utils 0.11.0", + "tari_test_utils 0.12.0", "tari_utilities", "tempfile", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tracing", "tracing-attributes", "tracing-futures", @@ -6351,9 +6357,45 @@ dependencies = [ "thiserror", ] +[[package]] +name = "tari_dan_core" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "blake2", + "bytecodec", + "clap", + "digest", + "futures 0.3.17", + "lmdb-zero", + "log 0.4.14", + "patricia_tree", + "prost", + "prost-types", + "serde 1.0.130", + "serde_json", + "tari_common", + "tari_comms", + "tari_comms_dht", + "tari_comms_rpc_macros", + "tari_core", + "tari_crypto", + "tari_mmr", + "tari_p2p", + "tari_service_framework", + "tari_shutdown", + "tari_storage", + "tari_test_utils 0.8.1", + "thiserror", + "tokio 1.13.0", + "tokio-stream", + "tonic", +] + [[package]] name = "tari_infra_derive" -version = "0.11.0" +version = "0.12.0" dependencies = [ "blake2", "proc-macro2 0.4.30", @@ -6363,7 +6405,7 @@ dependencies = [ [[package]] name = "tari_key_manager" -version = "0.11.0" +version = "0.12.0" dependencies = [ "digest", "rand 0.8.4", @@ -6377,7 +6419,7 @@ dependencies = [ [[package]] name = "tari_merge_mining_proxy" -version = "0.11.0" +version = "0.12.0" dependencies = [ "anyhow", "bincode", @@ -6404,7 +6446,7 @@ dependencies = [ "tari_crypto", "tari_utilities", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tonic", "tracing", "tracing-futures", @@ -6414,7 +6456,7 @@ dependencies = [ [[package]] name = "tari_mining_node" -version = "0.11.1" +version = "0.12.0" dependencies = [ "bufstream", "chrono", @@ -6439,13 +6481,13 @@ dependencies = [ "tari_utilities", "thiserror", "time", - "tokio 1.12.0", + "tokio 1.13.0", "tonic", ] [[package]] name = "tari_mmr" -version = "0.11.0" +version = "0.12.0" dependencies = [ "bincode", "blake2", @@ -6464,7 +6506,7 @@ dependencies = [ [[package]] name = "tari_p2p" -version = "0.11.0" +version = "0.12.0" dependencies = [ "anyhow", "bytes 0.5.6", @@ -6493,11 +6535,11 @@ dependencies = [ "tari_service_framework", "tari_shutdown", "tari_storage", - "tari_test_utils 0.11.0", + "tari_test_utils 0.12.0", "tari_utilities", "tempfile", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-stream", "tower 0.3.1", "tower-service", @@ -6506,7 +6548,7 @@ dependencies = [ [[package]] name = "tari_service_framework" -version = "0.11.0" +version = "0.12.0" dependencies = [ "anyhow", "async-trait", @@ -6514,24 +6556,24 @@ dependencies = [ "futures-test", "log 0.4.14", "tari_shutdown", - "tari_test_utils 0.11.0", + "tari_test_utils 0.12.0", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tower 0.3.1", "tower-service", ] [[package]] name = "tari_shutdown" -version = "0.11.0" +version = "0.12.0" dependencies = [ "futures 0.3.17", - "tokio 1.12.0", + "tokio 1.13.0", ] [[package]] name = "tari_storage" -version = "0.11.0" +version = "0.12.0" dependencies = [ "bincode", "bytes 0.5.6", @@ -6549,7 +6591,7 @@ dependencies = [ [[package]] name = "tari_stratum_ffi" -version = "0.11.0" +version = "0.12.0" dependencies = [ "hex", "libc", @@ -6591,7 +6633,7 @@ dependencies = [ "tari_crypto", "tari_utilities", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tonic", "tonic-build", "tracing", @@ -6616,7 +6658,7 @@ dependencies = [ [[package]] name = "tari_test_utils" -version = "0.11.0" +version = "0.12.0" dependencies = [ "futures 0.3.17", "futures-test", @@ -6624,7 +6666,7 @@ dependencies = [ "rand 0.8.4", "tari_shutdown", "tempfile", - "tokio 1.12.0", + "tokio 1.13.0", ] [[package]] @@ -6671,6 +6713,7 @@ dependencies = [ "tari_comms_rpc_macros", "tari_core", "tari_crypto", + "tari_dan_core", "tari_mmr", "tari_p2p", "tari_service_framework", @@ -6678,7 +6721,7 @@ dependencies = [ "tari_storage", "tari_test_utils 0.8.1", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-stream", "tonic", "tonic-build", @@ -6686,7 +6729,7 @@ dependencies = [ [[package]] name = "tari_wallet" -version = "0.11.0" +version = "0.12.0" dependencies = [ "aes-gcm 0.8.0", "async-trait", @@ -6721,18 +6764,18 @@ dependencies = [ "tari_service_framework", "tari_shutdown", "tari_storage", - "tari_test_utils 0.11.0", + "tari_test_utils 0.12.0", "tari_utilities", "tempfile", "thiserror", "time", - "tokio 1.12.0", + "tokio 1.13.0", "tower 0.3.1", ] [[package]] name = "tari_wallet_ffi" -version = "0.19.0" +version = "0.20.0" dependencies = [ "chrono", "env_logger 0.7.1", @@ -6750,13 +6793,14 @@ dependencies = [ "tari_crypto", "tari_key_manager", "tari_p2p", + "tari_service_framework", "tari_shutdown", - "tari_test_utils 0.11.0", + "tari_test_utils 0.12.0", "tari_utilities", "tari_wallet", "tempfile", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", ] [[package]] @@ -6802,7 +6846,7 @@ dependencies = [ "tauri-utils", "tempfile", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "url 2.2.2", "uuid", "zip", @@ -6815,7 +6859,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c9c9a9bea25b9d6f5845b8662e18447e17218f99860cab37e39e2b57a9fcd49" dependencies = [ "anyhow", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "serde_json", "tauri-utils", @@ -6830,7 +6874,7 @@ checksum = "1663739ab53e281919676f216fb56a031104d0d2cd1a2dd5b012d279bcdb0ea4" dependencies = [ "blake3", "kuchiki", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "regex", "serde 1.0.130", @@ -6847,9 +6891,9 @@ version = "1.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bddf9f5868402323f35ef94fa6ab1d5d10b29aea9de598d829723aa1db5693b4" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", "tauri-codegen", ] @@ -6897,7 +6941,7 @@ dependencies = [ "html5ever", "kuchiki", "phf 0.10.0", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "serde 1.0.130", "serde_json", @@ -6942,7 +6986,7 @@ dependencies = [ [[package]] name = "test_faucet" -version = "0.11.0" +version = "0.12.0" dependencies = [ "rand 0.8.4", "serde 1.0.130", @@ -6951,7 +6995,7 @@ dependencies = [ "tari_core", "tari_crypto", "tari_utilities", - "tokio 1.12.0", + "tokio 1.13.0", ] [[package]] @@ -6984,9 +7028,9 @@ version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -7094,9 +7138,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" +checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee" dependencies = [ "autocfg 1.0.1", "bytes 1.1.0", @@ -7118,18 +7162,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90c49f106be240de154571dd31fbe48acb10ba6c6dd6f6517ad603abffa42de9" dependencies = [ "pin-project-lite 0.2.7", - "tokio 1.12.0", + "tokio 1.13.0", ] [[package]] name = "tokio-macros" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2dd85aeaba7b68df939bd357c6afb36c87951be9e80bf9c859f2fc3e9fca0fd" +checksum = "114383b041aa6212c579467afa0075fbbdd0718de036100bc0ba7961d8cb9095" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -7139,7 +7183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" dependencies = [ "native-tls", - "tokio 1.12.0", + "tokio 1.13.0", ] [[package]] @@ -7149,19 +7193,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ "rustls", - "tokio 1.12.0", + "tokio 1.13.0", "webpki", ] [[package]] name = "tokio-stream" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" dependencies = [ "futures-core", "pin-project-lite 0.2.7", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-util", ] @@ -7185,15 +7229,15 @@ dependencies = [ "async-stream", "bytes 1.1.0", "futures-core", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-stream", ] [[package]] name = "tokio-util" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ "bytes 1.1.0", "futures-core", @@ -7201,7 +7245,7 @@ dependencies = [ "futures-sink", "log 0.4.14", "pin-project-lite 0.2.7", - "tokio 1.12.0", + "tokio 1.13.0", ] [[package]] @@ -7243,7 +7287,7 @@ dependencies = [ "pin-project 1.0.8", "prost", "prost-derive", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-stream", "tokio-util", "tower 0.4.10", @@ -7259,10 +7303,10 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12b52d07035516c2b74337d2ac7746075e7dcae7643816c1b12c5ff8a7484c08" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "prost-build", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -7297,7 +7341,7 @@ dependencies = [ "pin-project-lite 0.2.7", "rand 0.8.4", "slab", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-stream", "tokio-util", "tower-layer", @@ -7461,9 +7505,9 @@ version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -7567,7 +7611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebeb235c5847e2f82cfe0f07eb971d1e5f6804b18dac2ae16349cc604380f82f" dependencies = [ "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -7594,7 +7638,7 @@ dependencies = [ "ring", "rustls", "thiserror", - "tokio 1.12.0", + "tokio 1.13.0", "trust-dns-proto", "webpki", ] @@ -7622,7 +7666,7 @@ dependencies = [ "smallvec", "thiserror", "tinyvec", - "tokio 1.12.0", + "tokio 1.13.0", "tokio-rustls", "url 2.2.2", "webpki", @@ -7845,6 +7889,14 @@ dependencies = [ "getrandom 0.2.3", ] +[[package]] +name = "validator_node_sqlite" +version = "0.1.0" +dependencies = [ + "diesel", + "dotenv", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -7945,9 +7997,9 @@ dependencies = [ "bumpalo", "lazy_static 1.4.0", "log 0.4.14", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", "wasm-bindgen-shared", ] @@ -7979,9 +8031,9 @@ version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -8193,7 +8245,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cc2357b1b03c19f056cb0e6d06011f80f54beadb4e36aee2ca98493c7cfc3c" dependencies = [ - "syn 1.0.80", + "syn 1.0.81", "windows_gen", "windows_quote", "windows_reader", @@ -8247,7 +8299,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f9549393a3917b5303277abb0267f8eecf9fd629b25f1c04e5284aa58b61915" dependencies = [ "cocoa", - "core-graphics 0.22.2", + "core-graphics 0.22.3", "gdk", "gio", "glib", @@ -8370,9 +8422,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a482c56029e48681b89b92b5db3c446db0915e8dd1052c0328a574eda38d5f93" dependencies = [ "proc-macro-crate 0.1.5", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -8390,9 +8442,9 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdff2024a851a322b08f179173ae2ba620445aef1e838f0c196820eade4ae0c7" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", "synstructure", ] @@ -8460,7 +8512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46ee71e0e88747ec582d290dbe98ff7907ff28770c7a35f16da41e5e6f1f4fa3" dependencies = [ "proc-macro-crate 1.1.0", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] diff --git a/Cargo.toml b/Cargo.toml index a77f85da2a..d066db85dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,8 @@ members = [ "comms", "comms/dht", "comms/rpc_macros", + "dan_layer/core", + "dan_layer/validator_node_sqlite", "infrastructure/shutdown", "infrastructure/storage", "infrastructure/test_utils", diff --git a/applications/ffi_client/index.js b/applications/ffi_client/index.js index 0c1b750df5..20aeaf6c39 100644 --- a/applications/ffi_client/index.js +++ b/applications/ffi_client/index.js @@ -16,6 +16,8 @@ try { let err = ref.alloc(i32); // console.log(err); + let recoveryInProgress = ref.alloc(bool); + console.log("Create Tor transport..."); let tor = lib.transport_tor_create( "/ip4/127.0.0.1/tcp/9051", @@ -79,17 +81,13 @@ try { const txCancelled = ffi.Callback("void", ["pointer"], function (ptr) { console.log("txCancelled: ", ptr); }); - // callback_utxo_validation_complete: unsafe extern "C" fn(u64, u8), - const utxoValidation = ffi.Callback("void", [u64, u8], function (i, j) { + // callback_txo_validation_complete: unsafe extern "C" fn(u64, u8), + const txoValidation = ffi.Callback("void", [u64, u8], function (i, j) { console.log("utxoValidation: ", i, j); }); - // callback_stxo_validation_complete: unsafe extern "C" fn(u64, u8), - const stxoValidation = ffi.Callback("void", [u64, u8], function (i, j) { - console.log("stxoValidation: ", i, j); - }); - // callback_invalid_txo_validation_complete: unsafe extern "C" fn(u64, u8), - const itxoValidation = ffi.Callback("void", [u64, u8], function (i, j) { - console.log("itxoValidation: ", i, j); + // callback_balance_updated: unsafe extern "C" fn(*mut Balance), + const balanceUpdated = ffi.Callback("void", ["pointer"], function (ptr) { + console.log("balanceUpdated: ", ptr); }); // callback_transaction_validation_complete: unsafe extern "C" fn(u64, u8), const txValidation = ffi.Callback("void", [u64, u8], function (i, j) { @@ -117,11 +115,11 @@ try { directSendResult, safResult, txCancelled, - utxoValidation, - stxoValidation, - itxoValidation, + txoValidation, + balanceUpdated, txValidation, safsReceived, + recoveryInProgress, err ); diff --git a/applications/tari_app_grpc/Cargo.toml b/applications/tari_app_grpc/Cargo.toml index a4c3853d79..95171c630f 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.11.0" +version = "0.12.0" edition = "2018" [dependencies] -tari_common_types = { version = "^0.11", path = "../../base_layer/common_types"} +tari_common_types = { version = "^0.12", 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_utilities/Cargo.toml b/applications/tari_app_utilities/Cargo.toml index 5465acdd0e..cea00dc921 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.11.0" +version = "0.12.0" authors = ["The Tari Development Community"] edition = "2018" diff --git a/applications/tari_base_node/Cargo.toml b/applications/tari_base_node/Cargo.toml index 09b6666807..b44eeb0e1f 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.11.0" +version = "0.12.0" edition = "2018" [dependencies] diff --git a/applications/tari_base_node/src/main.rs b/applications/tari_base_node/src/main.rs index 6512d32049..4e79e09c91 100644 --- a/applications/tari_base_node/src/main.rs +++ b/applications/tari_base_node/src/main.rs @@ -265,6 +265,8 @@ async fn run_node(node_config: Arc, bootstrap: ConfigBootstrap) -> fn enable_tracing() { // To run: // docker run -d -p6831:6831/udp -p6832:6832/udp -p16686:16686 -p14268:14268 jaegertracing/all-in-one:latest + // To view the UI after starting the container (default): + // http://localhost:16686 global::set_text_map_propagator(opentelemetry_jaeger::Propagator::new()); let tracer = opentelemetry_jaeger::new_pipeline() .with_service_name("tari::base_node") diff --git a/applications/tari_console_wallet/Cargo.toml b/applications/tari_console_wallet/Cargo.toml index 2db0b2841b..a5b36a8ae6 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.11.0" +version = "0.12.0" authors = ["The Tari Development Community"] edition = "2018" diff --git a/applications/tari_console_wallet/src/automation/commands.rs b/applications/tari_console_wallet/src/automation/commands.rs index 67f9aa9c58..4486494027 100644 --- a/applications/tari_console_wallet/src/automation/commands.rs +++ b/applications/tari_console_wallet/src/automation/commands.rs @@ -96,10 +96,7 @@ pub enum TransactionStage { } #[derive(Debug)] -pub struct SentTransaction { - id: TxId, - stage: TransactionStage, -} +pub struct SentTransaction {} fn get_transaction_parameters( args: Vec, @@ -452,10 +449,7 @@ pub async fn monitor_transactions( "tx direct send event for tx_id: {}, success: {}", *id, success ); if wait_stage == TransactionStage::DirectSendOrSaf { - results.push(SentTransaction { - id: *id, - stage: TransactionStage::DirectSendOrSaf, - }); + results.push(SentTransaction {}); if results.len() == tx_ids.len() { break; } @@ -467,10 +461,7 @@ pub async fn monitor_transactions( "tx store and forward event for tx_id: {}, success: {}", *id, success ); if wait_stage == TransactionStage::DirectSendOrSaf { - results.push(SentTransaction { - id: *id, - stage: TransactionStage::DirectSendOrSaf, - }); + results.push(SentTransaction {}); if results.len() == tx_ids.len() { break; } @@ -479,10 +470,7 @@ pub async fn monitor_transactions( TransactionEvent::ReceivedTransactionReply(id) if tx_ids.contains(id) => { debug!(target: LOG_TARGET, "tx reply event for tx_id: {}", *id); if wait_stage == TransactionStage::Negotiated { - results.push(SentTransaction { - id: *id, - stage: TransactionStage::Negotiated, - }); + results.push(SentTransaction {}); if results.len() == tx_ids.len() { break; } @@ -491,10 +479,7 @@ pub async fn monitor_transactions( TransactionEvent::TransactionBroadcast(id) if tx_ids.contains(id) => { debug!(target: LOG_TARGET, "tx mempool broadcast event for tx_id: {}", *id); if wait_stage == TransactionStage::Broadcast { - results.push(SentTransaction { - id: *id, - stage: TransactionStage::Broadcast, - }); + results.push(SentTransaction {}); if results.len() == tx_ids.len() { break; } @@ -513,10 +498,7 @@ pub async fn monitor_transactions( is_valid ); if wait_stage == TransactionStage::MinedUnconfirmed { - results.push(SentTransaction { - id: *tx_id, - stage: TransactionStage::MinedUnconfirmed, - }); + results.push(SentTransaction {}); if results.len() == tx_ids.len() { break; } @@ -528,10 +510,7 @@ pub async fn monitor_transactions( "tx mined confirmed event for tx_id: {}, is_valid:{}", *tx_id, is_valid ); if wait_stage == TransactionStage::Mined { - results.push(SentTransaction { - id: *tx_id, - stage: TransactionStage::Mined, - }); + results.push(SentTransaction {}); if results.len() == tx_ids.len() { break; } diff --git a/applications/tari_console_wallet/src/main.rs b/applications/tari_console_wallet/src/main.rs index 59b857eaef..fc28868f09 100644 --- a/applications/tari_console_wallet/src/main.rs +++ b/applications/tari_console_wallet/src/main.rs @@ -1,3 +1,25 @@ +// 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. + #![cfg_attr(not(debug_assertions), deny(unused_variables))] #![cfg_attr(not(debug_assertions), deny(unused_imports))] #![cfg_attr(not(debug_assertions), deny(dead_code))] @@ -48,7 +70,7 @@ fn main() { eprintln!("{:?}", exit_code); error!( target: LOG_TARGET, - "Exiting with code ({}): {:?}", + "Exiting with code ({:?}): {:?}", exit_code.as_i32(), exit_code ); @@ -65,6 +87,10 @@ fn main_inner() -> Result<(), ExitCodes> { let (bootstrap, global_config, _) = init_configuration(ApplicationType::ConsoleWallet)?; + if bootstrap.tracing_enabled { + enable_tracing(); + } + info!( target: LOG_TARGET, "== {} ({}) ==", @@ -91,7 +117,6 @@ fn main_inner() -> Result<(), ExitCodes> { info!(target: LOG_TARGET, "Default configuration created. Done."); } - enable_tracing_if_specified(&bootstrap); // get command line password if provided let arg_password = bootstrap.password.clone(); let seed_words_file_name = bootstrap.seed_words_file_name.clone(); @@ -185,21 +210,21 @@ fn get_recovery_master_key( } } -fn enable_tracing_if_specified(bootstrap: &ConfigBootstrap) { - if bootstrap.tracing_enabled { - // To run: docker run -d -p6831:6831/udp -p6832:6832/udp -p16686:16686 -p14268:14268 \ - // jaegertracing/all-in-one:latest - 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() - .unwrap(); - let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); - let subscriber = Registry::default().with(telemetry); - tracing::subscriber::set_global_default(subscriber) - .expect("Tracing could not be set. Try running without `--tracing-enabled`"); - } +fn enable_tracing() { + // To run: + // docker run -d -p6831:6831/udp -p6832:6832/udp -p16686:16686 -p14268:14268 jaegertracing/all-in-one:latest + // To view the UI after starting the container (default): + // http://localhost:16686 + 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() + .unwrap(); + let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); + let subscriber = Registry::default().with(telemetry); + tracing::subscriber::set_global_default(subscriber) + .expect("Tracing could not be set. Try running without `--tracing-enabled`"); } 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 5ba9f52a4b..b98e331775 100644 --- a/applications/tari_console_wallet/src/ui/state/app_state.rs +++ b/applications/tari_console_wallet/src/ui/state/app_state.rs @@ -92,7 +92,6 @@ pub struct AppState { node_config: GlobalConfig, config: AppStateConfig, wallet_connectivity: WalletConnectivityHandle, - output_manager_service: OutputManagerHandle, balance_enquiry_debouncer: BalanceEnquiryDebouncer, } @@ -119,7 +118,6 @@ impl AppState { node_config: node_config.clone(), config: AppStateConfig::default(), wallet_connectivity, - output_manager_service: output_manager_service.clone(), balance_enquiry_debouncer: BalanceEnquiryDebouncer::new( inner, Duration::from_secs(node_config.wallet_balance_enquiry_cooldown_period), diff --git a/applications/tari_console_wallet/src/wallet_modes.rs b/applications/tari_console_wallet/src/wallet_modes.rs index 2193021b02..75a3fee67c 100644 --- a/applications/tari_console_wallet/src/wallet_modes.rs +++ b/applications/tari_console_wallet/src/wallet_modes.rs @@ -212,8 +212,14 @@ pub fn tui_mode(config: WalletModeConfig, mut wallet: WalletSqlite) -> Result<() notify_script, .. } = config; - let grpc = WalletGrpcServer::new(wallet.clone()); - handle.spawn(run_grpc(grpc, global_config.grpc_console_wallet_address)); + if let Some(grpc_address) = global_config + .wallet_config + .as_ref() + .and_then(|c| c.grpc_address.as_ref()) + { + let grpc = WalletGrpcServer::new(wallet.clone()); + handle.spawn(run_grpc(grpc, *grpc_address)); + } let notifier = Notifier::new(notify_script, handle.clone(), wallet.clone()); @@ -286,10 +292,14 @@ pub fn grpc_mode(config: WalletModeConfig, wallet: WalletSqlite) -> Result<(), E global_config, handle, .. } = config; println!("Starting grpc server"); - let grpc = WalletGrpcServer::new(wallet); - handle - .block_on(run_grpc(grpc, global_config.grpc_console_wallet_address)) - .map_err(ExitCodes::GrpcError)?; + if let Some(grpc_address) = global_config.wallet_config.and_then(|c| c.grpc_address) { + let grpc = WalletGrpcServer::new(wallet); + handle + .block_on(run_grpc(grpc, grpc_address)) + .map_err(ExitCodes::GrpcError)?; + } else { + println!("No grpc address specified"); + } println!("Shutting down"); Ok(()) } diff --git a/applications/tari_explorer/app.js b/applications/tari_explorer/app.js index f2d3eb0a6d..ea31c6f69a 100644 --- a/applications/tari_explorer/app.js +++ b/applications/tari_explorer/app.js @@ -8,6 +8,7 @@ const asciichart = require('asciichart') var indexRouter = require('./routes/index'); var blocksRouter = require('./routes/blocks'); var assetsRouter = require('./routes/assets'); +var validatorRouter = require('./routes/validator'); var hbs = require('hbs') hbs.registerHelper('hex', function (buffer) { @@ -63,6 +64,7 @@ app.use(express.static(path.join(__dirname, 'public'))) app.use('/', indexRouter); app.use('/blocks', blocksRouter); app.use('/assets', assetsRouter); +app.use('/validator', validatorRouter); // catch 404 and forward to error handler app.use(function (req, res, next) { diff --git a/applications/tari_explorer/package-lock.json b/applications/tari_explorer/package-lock.json index f9f72d72a6..2f8eb007ed 100644 --- a/applications/tari_explorer/package-lock.json +++ b/applications/tari_explorer/package-lock.json @@ -1484,6 +1484,2913 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "validator-node-grpc-client": { + "version": "file:../../clients/validator_node_grpc_client", + "requires": { + "@grpc/grpc-js": "^1.2.3", + "@grpc/proto-loader": "^0.5.5", + "grpc-promise": "^1.4.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/compat-data": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", + "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==" + }, + "@babel/core": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", + "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", + "requires": { + "@babel/code-frame": "^7.15.8", + "@babel/generator": "^7.15.8", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.8", + "@babel/helpers": "^7.15.4", + "@babel/parser": "^7.15.8", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "@babel/generator": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", + "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", + "requires": { + "@babel/types": "^7.15.6", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", + "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", + "requires": { + "@babel/compat-data": "^7.15.0", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", + "semver": "^6.3.0" + } + }, + "@babel/helper-function-name": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", + "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "requires": { + "@babel/helper-get-function-arity": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", + "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", + "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", + "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-module-imports": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", + "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-module-transforms": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", + "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", + "requires": { + "@babel/helper-module-imports": "^7.15.4", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/helper-validator-identifier": "^7.15.7", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", + "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==" + }, + "@babel/helper-replace-supers": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", + "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", + "requires": { + "@babel/helper-member-expression-to-functions": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-simple-access": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", + "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", + "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" + }, + "@babel/helper-validator-option": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==" + }, + "@babel/helpers": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", + "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "requires": { + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", + "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==" + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/template": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", + "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/traverse": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", + "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, + "@grpc/grpc-js": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.4.1.tgz", + "integrity": "sha512-/chkA48TdAvATHA7RXJPeHQLdfFhpu51974s8htjO/XTDHA41j5+SkR5Io+lr9XsLmkZD6HxLyRAFGmA9wjO2w==", + "requires": { + "@grpc/proto-loader": "^0.6.4", + "@types/node": ">=12.12.47" + }, + "dependencies": { + "@grpc/proto-loader": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.6.tgz", + "integrity": "sha512-cdMaPZ8AiFz6ua6PUbP+LKbhwJbFXnrQ/mlnKGUyzDUZ3wp7vPLksnmLCBX6SHgSmjX7CbNVNLFYD5GmmjO4GQ==", + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.10.0", + "yargs": "^16.1.1" + } + } + } + }, + "@grpc/proto-loader": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.6.tgz", + "integrity": "sha512-DT14xgw3PSzPxwS13auTEwxhMMOoz33DPUKNtmYK/QYbBSpLXJy78FGGs5yVoxVobEqPm4iW9MOIoz0A3bLTRQ==", + "requires": { + "lodash.camelcase": "^4.3.0", + "protobufjs": "^6.8.6" + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==" + }, + "@jest/console": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.3.1.tgz", + "integrity": "sha512-RkFNWmv0iui+qsOr/29q9dyfKTTT5DCuP31kUwg7rmOKPT/ozLeGLKJKVIiOfbiKyleUZKIrHwhmiZWVe8IMdw==", + "requires": { + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.3.1", + "jest-util": "^27.3.1", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.3.1.tgz", + "integrity": "sha512-DMNE90RR5QKx0EA+wqe3/TNEwiRpOkhshKNxtLxd4rt3IZpCt+RSL+FoJsGeblRZmqdK4upHA/mKKGPPRAifhg==", + "requires": { + "@jest/console": "^27.3.1", + "@jest/reporters": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^27.3.0", + "jest-config": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-resolve-dependencies": "^27.3.1", + "jest-runner": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "jest-watcher": "^27.3.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.3.1.tgz", + "integrity": "sha512-BCKCj4mOVLme6Tanoyc9k0ultp3pnmuyHw73UHRPeeZxirsU/7E3HC4le/VDb/SMzE1JcPnto+XBKFOcoiJzVw==", + "requires": { + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "jest-mock": "^27.3.0" + } + }, + "@jest/fake-timers": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.3.1.tgz", + "integrity": "sha512-M3ZFgwwlqJtWZ+QkBG5NmC23A9w+A6ZxNsO5nJxJsKYt4yguBd3i8TpjQz5NfCX91nEve1KqD9RA2Q+Q1uWqoA==", + "requires": { + "@jest/types": "^27.2.5", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.3.1", + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1" + } + }, + "@jest/globals": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.3.1.tgz", + "integrity": "sha512-Q651FWiWQAIFiN+zS51xqhdZ8g9b88nGCobC87argAxA7nMfNQq0Q0i9zTfQYgLa6qFXk2cGANEqfK051CZ8Pg==", + "requires": { + "@jest/environment": "^27.3.1", + "@jest/types": "^27.2.5", + "expect": "^27.3.1" + } + }, + "@jest/reporters": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.3.1.tgz", + "integrity": "sha512-m2YxPmL9Qn1emFVgZGEiMwDntDxRRQ2D58tiDQlwYTg5GvbFOKseYCcHtn0WsI8CG4vzPglo3nqbOiT8ySBT/w==", + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + } + }, + "@jest/source-map": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", + "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.3.1.tgz", + "integrity": "sha512-mLn6Thm+w2yl0opM8J/QnPTqrfS4FoXsXF2WIWJb2O/GBSyResL71BRuMYbYRsGt7ELwS5JGcEcGb52BNrumgg==", + "requires": { + "@jest/console": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.3.1.tgz", + "integrity": "sha512-siySLo07IMEdSjA4fqEnxfIX8lB/lWYsBPwNFtkOvsFQvmBrL3yj3k3uFNZv/JDyApTakRpxbKLJ3CT8UGVCrA==", + "requires": { + "@jest/test-result": "^27.3.1", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.3.1", + "jest-runtime": "^27.3.1" + } + }, + "@jest/transform": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.3.1.tgz", + "integrity": "sha512-3fSvQ02kuvjOI1C1ssqMVBKJpZf6nwoCiSu00zAKh5nrp3SptNtZy/8s5deayHnqxhjD9CWDJ+yqQwuQ0ZafXQ==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.2.5", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-util": "^27.3.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } + }, + "@jest/types": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.5.tgz", + "integrity": "sha512-nmuM4VuDtCZcY+eTpw+0nvstwReMsjPoj7ZR80/BbixulhLaiX+fbv8oeLW8WZlJMcsGQsTmMKT/iTZu1Uy/lQ==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "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": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.0.1.tgz", + "integrity": "sha512-AU7kwFxreVd6OAXcAFlKSmZquiRUU0FvYm44k1Y1QbK7Co4m0aqfGMhjykIeQp/H6rcl+nFmj0zfdUcGVs9Dew==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + }, + "@types/babel__core": { + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", + "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", + "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==" + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "@types/node": { + "version": "16.11.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz", + "integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==" + }, + "@types/prettier": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==" + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" + }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" + }, + "acorn": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==" + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + } + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "babel-jest": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.3.1.tgz", + "integrity": "sha512-SjIF8hh/ir0peae2D6S6ZKRhUy7q/DnpH7k/V6fT4Bgs/LXXUztOpX4G2tCgq8mLo5HA9mN6NmlFMeYtKmIsTQ==", + "requires": { + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^27.2.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "dependencies": { + "istanbul-lib-instrument": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.0.4.tgz", + "integrity": "sha512-W6jJF9rLGEISGoCyXRqa/JCGQGmmxPO10TMu7izaUTynxvBvTjqzAIIGCK9USBmIbQAaSWD6XJPrM9Pv5INknw==", + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + } + } + }, + "babel-plugin-jest-hoist": { + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz", + "integrity": "sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==", + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz", + "integrity": "sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg==", + "requires": { + "babel-plugin-jest-hoist": "^27.2.0", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, + "browserslist": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz", + "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==", + "requires": { + "caniuse-lite": "^1.0.30001271", + "electron-to-chromium": "^1.3.878", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "caniuse-lite": { + "version": "1.0.30001271", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz", + "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==" + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==" + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + } + } + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==" + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=" + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==" + }, + "diff-sequences": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", + "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==" + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==" + } + } + }, + "electron-to-chromium": { + "version": "1.3.879", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.879.tgz", + "integrity": "sha512-zJo+D9GwbJvM31IdFmwcGvychhk4KKbKYo2GWlsn+C/dxz2NwmbhGJjWwTfFSF2+eFH7VvfA8MCZ8SOqTrlnpw==" + }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" + }, + "expect": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.3.1.tgz", + "integrity": "sha512-MrNXV2sL9iDRebWPGOGFdPQRl2eDQNu/uhxIMShjjx74T6kC6jFIkmQ6OqXDtevjGUkyB2IT56RzDBqXf/QPCg==", + "requires": { + "@jest/types": "^27.2.5", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-regex-util": "^27.0.6" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "requires": { + "bser": "2.1.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + }, + "grpc-promise": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/grpc-promise/-/grpc-promise-1.4.0.tgz", + "integrity": "sha512-4BBXHXb5OjjBh7luylu8vFqL6H6aPn/LeqpQaSBeRzO/Xv95wHW/WkU9TJRqaCTMZ5wq9jTSvlJWp0vRJy1pVA==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "import-local": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", + "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "requires": { + "has": "^1.0.3" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==" + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", + "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.3.1.tgz", + "integrity": "sha512-U2AX0AgQGd5EzMsiZpYt8HyZ+nSVIh5ujQ9CPp9EQZJMjXIiSZpJNweZl0swatKRoqHWgGKM3zaSwm4Zaz87ng==", + "requires": { + "@jest/core": "^27.3.1", + "import-local": "^3.0.2", + "jest-cli": "^27.3.1" + }, + "dependencies": { + "jest-cli": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.3.1.tgz", + "integrity": "sha512-WHnCqpfK+6EvT62me6WVs8NhtbjAS4/6vZJnk7/2+oOr50cwAzG4Wxt6RXX0hu6m1169ZGMlhYYUNeKBXCph/Q==", + "requires": { + "@jest/core": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "jest-config": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + } + } + } + }, + "jest-changed-files": { + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.3.0.tgz", + "integrity": "sha512-9DJs9garMHv4RhylUMZgbdCJ3+jHSkpL9aaVKp13xtXAD80qLTLrqcDZL1PHA9dYA0bCI86Nv2BhkLpLhrBcPg==", + "requires": { + "@jest/types": "^27.2.5", + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "jest-circus": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.3.1.tgz", + "integrity": "sha512-v1dsM9II6gvXokgqq6Yh2jHCpfg7ZqV4jWY66u7npz24JnhP3NHxI0sKT7+ZMQ7IrOWHYAaeEllOySbDbWsiXw==", + "requires": { + "@jest/environment": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.3.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + } + }, + "jest-config": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.3.1.tgz", + "integrity": "sha512-KY8xOIbIACZ/vdYCKSopL44I0xboxC751IX+DXL2+Wx6DKNycyEfV3rryC3BPm5Uq/BBqDoMrKuqLEUNJmMKKg==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.3.1", + "@jest/types": "^27.2.5", + "babel-jest": "^27.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-circus": "^27.3.1", + "jest-environment-jsdom": "^27.3.1", + "jest-environment-node": "^27.3.1", + "jest-get-type": "^27.3.1", + "jest-jasmine2": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-runner": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "micromatch": "^4.0.4", + "pretty-format": "^27.3.1" + } + }, + "jest-diff": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.3.1.tgz", + "integrity": "sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ==", + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.0.6", + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" + } + }, + "jest-docblock": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", + "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.3.1.tgz", + "integrity": "sha512-E4SwfzKJWYcvOYCjOxhZcxwL+AY0uFMvdCOwvzgutJiaiodFjkxQQDxHm8FQBeTqDnSmKsQWn7ldMRzTn2zJaQ==", + "requires": { + "@jest/types": "^27.2.5", + "chalk": "^4.0.0", + "jest-get-type": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1" + } + }, + "jest-environment-jsdom": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.3.1.tgz", + "integrity": "sha512-3MOy8qMzIkQlfb3W1TfrD7uZHj+xx8Olix5vMENkj5djPmRqndMaXtpnaZkxmxM+Qc3lo+yVzJjzuXbCcZjAlg==", + "requires": { + "@jest/environment": "^27.3.1", + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1", + "jsdom": "^16.6.0" + } + }, + "jest-environment-node": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.3.1.tgz", + "integrity": "sha512-T89F/FgkE8waqrTSA7/ydMkcc52uYPgZZ6q8OaZgyiZkJb5QNNCF6oPZjH9IfPFfcc9uBWh1574N0kY0pSvTXw==", + "requires": { + "@jest/environment": "^27.3.1", + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1" + } + }, + "jest-get-type": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz", + "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==" + }, + "jest-haste-map": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.3.1.tgz", + "integrity": "sha512-lYfNZIzwPccDJZIyk9Iz5iQMM/MH56NIIcGj7AFU1YyA4ewWFBl8z+YPJuSCRML/ee2cCt2y3W4K3VXPT6Nhzg==", + "requires": { + "@jest/types": "^27.2.5", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^27.0.6", + "jest-serializer": "^27.0.6", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.3.1.tgz", + "integrity": "sha512-WK11ZUetDQaC09w4/j7o4FZDUIp+4iYWH/Lik34Pv7ukL+DuXFGdnmmi7dT58J2ZYKFB5r13GyE0z3NPeyJmsg==", + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^27.3.1", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.3.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1", + "throat": "^6.0.1" + } + }, + "jest-leak-detector": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.3.1.tgz", + "integrity": "sha512-78QstU9tXbaHzwlRlKmTpjP9k4Pvre5l0r8Spo4SbFFVy/4Abg9I6ZjHwjg2QyKEAMg020XcjP+UgLZIY50yEg==", + "requires": { + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" + } + }, + "jest-matcher-utils": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.3.1.tgz", + "integrity": "sha512-hX8N7zXS4k+8bC1Aj0OWpGb7D3gIXxYvPNK1inP5xvE4ztbz3rc4AkI6jGVaerepBnfWB17FL5lWFJT3s7qo8w==", + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.3.1", + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" + } + }, + "jest-message-util": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.3.1.tgz", + "integrity": "sha512-bh3JEmxsTZ/9rTm0jQrPElbY2+y48Rw2t47uMfByNyUVR+OfPh4anuyKsGqsNkXk/TI4JbLRZx+7p7Hdt6q1yg==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.2.5", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "pretty-format": "^27.3.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.3.0.tgz", + "integrity": "sha512-ziZiLk0elZOQjD08bLkegBzv5hCABu/c8Ytx45nJKkysQwGaonvmTxwjLqEA4qGdasq9o2I8/HtdGMNnVsMTGw==", + "requires": { + "@jest/types": "^27.2.5", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==" + }, + "jest-regex-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", + "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==" + }, + "jest-resolve": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.3.1.tgz", + "integrity": "sha512-Dfzt25CFSPo3Y3GCbxynRBZzxq9AdyNN+x/v2IqYx6KVT5Z6me2Z/PsSGFSv3cOSUZqJ9pHxilao/I/m9FouLw==", + "requires": { + "@jest/types": "^27.2.5", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.3.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.3.1.tgz", + "integrity": "sha512-X7iLzY8pCiYOnvYo2YrK3P9oSE8/3N2f4pUZMJ8IUcZnT81vlSonya1KTO9ZfKGuC+svE6FHK/XOb8SsoRUV1A==", + "requires": { + "@jest/types": "^27.2.5", + "jest-regex-util": "^27.0.6", + "jest-snapshot": "^27.3.1" + } + }, + "jest-runner": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.3.1.tgz", + "integrity": "sha512-r4W6kBn6sPr3TBwQNmqE94mPlYVn7fLBseeJfo4E2uCTmAyDFm2O5DYAQAFP7Q3YfiA/bMwg8TVsciP7k0xOww==", + "requires": { + "@jest/console": "^27.3.1", + "@jest/environment": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-docblock": "^27.0.6", + "jest-environment-jsdom": "^27.3.1", + "jest-environment-node": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-leak-detector": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + } + }, + "jest-runtime": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.3.1.tgz", + "integrity": "sha512-qtO6VxPbS8umqhEDpjA4pqTkKQ1Hy4ZSi9mDVeE9Za7LKBo2LdW2jmT+Iod3XFaJqINikZQsn2wEi0j9wPRbLg==", + "requires": { + "@jest/console": "^27.3.1", + "@jest/environment": "^27.3.1", + "@jest/globals": "^27.3.1", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-mock": "^27.3.0", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^16.2.0" + } + }, + "jest-serializer": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", + "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + } + }, + "jest-snapshot": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.3.1.tgz", + "integrity": "sha512-APZyBvSgQgOT0XumwfFu7X3G5elj6TGhCBLbBdn3R1IzYustPGPE38F51dBWMQ8hRXa9je0vAdeVDtqHLvB6lg==", + "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.3.1", + "graceful-fs": "^4.2.4", + "jest-diff": "^27.3.1", + "jest-get-type": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-util": "^27.3.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.3.1", + "semver": "^7.3.2" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "jest-util": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz", + "integrity": "sha512-8fg+ifEH3GDryLQf/eKZck1DEs2YuVPBCMOaHQxVVLmQwl/CDhWzrvChTX4efLZxGrw+AA0mSXv78cyytBt/uw==", + "requires": { + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.4", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.3.1.tgz", + "integrity": "sha512-3H0XCHDFLA9uDII67Bwi1Vy7AqwA5HqEEjyy934lgVhtJ3eisw6ShOF1MDmRPspyikef5MyExvIm0/TuLzZ86Q==", + "requires": { + "@jest/types": "^27.2.5", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.3.1", + "leven": "^3.1.0", + "pretty-format": "^27.3.1" + }, + "dependencies": { + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==" + } + } + }, + "jest-watcher": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.3.1.tgz", + "integrity": "sha512-9/xbV6chABsGHWh9yPaAGYVVKurWoP3ZMCv6h+O1v9/+pkOroigs6WzZ0e9gLP/njokUwM7yQhr01LKJVMkaZA==", + "requires": { + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.3.1", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz", + "integrity": "sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "requires": { + "tmpl": "1.0.5" + } + }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mime-db": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", + "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==" + }, + "mime-types": { + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", + "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "requires": { + "mime-db": "1.50.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=" + }, + "node-releases": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "pretty-format": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz", + "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==", + "requires": { + "@jest/types": "^27.2.5", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" + } + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + }, + "resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "requires": { + "xmlchars": "^2.2.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "signal-exit": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==" + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + } + } + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==" + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + } + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "requires": { + "punycode": "^2.1.1" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "v8-to-istanbul": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", + "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "requires": { + "makeerror": "1.0.12" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", + "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==" + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + } + } + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/applications/tari_explorer/package.json b/applications/tari_explorer/package.json index bb0b46b929..f62a2a1cf4 100644 --- a/applications/tari_explorer/package.json +++ b/applications/tari_explorer/package.json @@ -9,6 +9,7 @@ "dependencies": { "asciichart": "^1.5.25", "base-node-grpc-client": "file:../../clients/base_node_grpc_client", + "validator-node-grpc-client": "file:../../clients/validator_node_grpc_client", "cookie-parser": "~1.4.4", "debug": "~2.6.9", "express": "~4.16.1", diff --git a/applications/tari_explorer/routes/assets.js b/applications/tari_explorer/routes/assets.js index e02cad2bc5..fb91877ceb 100644 --- a/applications/tari_explorer/routes/assets.js +++ b/applications/tari_explorer/routes/assets.js @@ -20,18 +20,19 @@ // 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. -var { createClient } = require('../baseNodeClient') +var { createClient: createBaseNodeClient } = require('../baseNodeClient') var express = require('express') var router = express.Router() /* GET home page. */ router.get('/:asset_public_key', async function (req, res, next) { - let client = createClient() + let baseNodeClient = createBaseNodeClient() + // let validatorNodeClient = createValidatorNodeClient() let asset_public_key = req.params.asset_public_key try { - let tokens = await client.getTokens({ asset_public_key: Buffer.from(asset_public_key, "hex") }) + let tokens = await baseNodeClient.getTokens({ asset_public_key: Buffer.from(asset_public_key, "hex") }) console.log(tokens) if (!tokens || tokens.length === 0) { @@ -40,9 +41,12 @@ router.get('/:asset_public_key', async function (req, res, next) { return; } + // let headers = validatorNodeClient.listHeaders({ from_height: 0, num_headers: 101 }) + res.render('assets', { title: `Asset with pub key: ${asset_public_key}`, - tokens: tokens + tokens: tokens, + // headers }) diff --git a/applications/tari_explorer/routes/validator.js b/applications/tari_explorer/routes/validator.js new file mode 100644 index 0000000000..9bd11d2518 --- /dev/null +++ b/applications/tari_explorer/routes/validator.js @@ -0,0 +1,44 @@ +// 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. +var {createClient: createValidatorNodeClient} = require('../validatorNodeClient') + +var express = require('express') +var router = express.Router() + +router.get("/", async function (req, res) { + try { + let client = createValidatorNodeClient(); + let metadata = await client.getMetadata(); + console.log(metadata); + + res.render('validator', { + title: `Validator node`, + sidechains: metadata.sidechains + }) + + } catch (error) { + res.status(500) + res.render('error', {error: error}) + } +}); + +module.exports = router diff --git a/applications/tari_explorer/validatorNodeClient.js b/applications/tari_explorer/validatorNodeClient.js new file mode 100644 index 0000000000..2a83954d29 --- /dev/null +++ b/applications/tari_explorer/validatorNodeClient.js @@ -0,0 +1,10 @@ +var {Client} = require("validator-node-grpc-client"); + +function createClient() { + return Client.connect("localhost:18144"); +} + +module.exports = { + createClient +} + diff --git a/applications/tari_explorer/views/validator.hbs b/applications/tari_explorer/views/validator.hbs new file mode 100644 index 0000000000..42a6818462 --- /dev/null +++ b/applications/tari_explorer/views/validator.hbs @@ -0,0 +1,21 @@ +

{{this.title}}

+ +{{#each sidechains }} +
+

Asset: {{hex this.asset_public_key}}

+ + + + + + + + + + + + + +
Committed HeightCommitted Hash
{{this.committed_height}}{{hex this.committed_hash}}
+
+{{/each}} \ No newline at end of file diff --git a/applications/tari_merge_mining_proxy/Cargo.toml b/applications/tari_merge_mining_proxy/Cargo.toml index 48ce565282..e6a3dec749 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.11.0" +version = "0.12.0" edition = "2018" [features] diff --git a/applications/tari_mining_node/Cargo.toml b/applications/tari_mining_node/Cargo.toml index a442a3bcdc..e062df66e4 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.11.1" +version = "0.12.0" edition = "2018" [dependencies] diff --git a/applications/tari_stratum_transcoder/src/proxy.rs b/applications/tari_stratum_transcoder/src/proxy.rs index 200543cfc2..6136c5c3aa 100644 --- a/applications/tari_stratum_transcoder/src/proxy.rs +++ b/applications/tari_stratum_transcoder/src/proxy.rs @@ -84,8 +84,8 @@ impl StratumTranscoderProxyService { ) -> Self { Self { inner: InnerService { - config, - http_client, + _config: config, + _http_client: http_client, base_node_client, wallet_client, }, @@ -130,8 +130,8 @@ impl Service> for StratumTranscoderProxyService { #[derive(Debug, Clone)] struct InnerService { - config: StratumTranscoderProxyConfig, - http_client: reqwest::Client, + _config: StratumTranscoderProxyConfig, + _http_client: reqwest::Client, base_node_client: grpc::base_node_client::BaseNodeClient, wallet_client: grpc::wallet_client::WalletClient, } diff --git a/applications/tari_validator_node/Cargo.toml b/applications/tari_validator_node/Cargo.toml index 9691966055..e4cc848be8 100644 --- a/applications/tari_validator_node/Cargo.toml +++ b/applications/tari_validator_node/Cargo.toml @@ -21,6 +21,7 @@ tari_service_framework = { path = "../../base_layer/service_framework" } tari_shutdown = { path = "../../infrastructure/shutdown" } tari_storage = { path = "../../infrastructure/storage" } tari_core = {path = "../../base_layer/core"} +tari_dan_core = {path = "../../dan_layer/core"} anyhow = "1.0.32" async-trait = "0.1.50" diff --git a/applications/tari_validator_node/proto/grpc/validator_node.proto b/applications/tari_validator_node/proto/grpc/validator_node.proto index ac1d9ead42..c0971aeeb9 100644 --- a/applications/tari_validator_node/proto/grpc/validator_node.proto +++ b/applications/tari_validator_node/proto/grpc/validator_node.proto @@ -24,10 +24,25 @@ syntax = "proto3"; package tari.validator_node.rpc; service ValidatorNode { + rpc GetMetadata(GetMetadataRequest) returns (GetMetadataResponse); rpc GetTokenData(GetTokenDataRequest) returns (GetTokenDataResponse); rpc ExecuteInstruction(ExecuteInstructionRequest) returns (ExecuteInstructionResponse); } +message GetMetadataRequest { + // empty +} + +message GetMetadataResponse { + repeated SidechainMetadata sidechains = 1; +} + +message SidechainMetadata { + bytes asset_public_key =1; + uint64 committed_height = 2; + bytes committed_hash = 3; +} + message GetTokenDataRequest { bytes asset_pub_key = 1; bytes unique_id = 2; @@ -38,12 +53,12 @@ message GetTokenDataResponse { } message ExecuteInstructionRequest{ - bytes asset_public_key =1; - string method =2; - repeated bytes args = 3; - bytes token_id = 4; - bytes signature = 5; - uint64 id = 6; + bytes asset_public_key = 1; + uint32 template_id = 2; + string method = 3; + repeated bytes args = 4; +// bytes token_id = 5; +// bytes signature = 6; } message ExecuteInstructionResponse { diff --git a/applications/tari_validator_node/proto/p2p/dan_consensus.proto b/applications/tari_validator_node/proto/p2p/dan_consensus.proto index 99b695d1e4..3657ec34b6 100644 --- a/applications/tari_validator_node/proto/p2p/dan_consensus.proto +++ b/applications/tari_validator_node/proto/p2p/dan_consensus.proto @@ -49,9 +49,10 @@ message InstructionSet{ repeated Instruction instructions = 1; } message Instruction { - bytes asset_id = 1; - string method = 2; - repeated bytes args = 3; - bytes from = 4; - bytes signature = 5; + bytes asset_public_key = 1; + uint32 template_id = 2; + string method = 3; + repeated bytes args = 4; +// bytes token_id = 5; +// bytes signature = 6; } diff --git a/applications/tari_validator_node/proto/p2p/validator_node.proto b/applications/tari_validator_node/proto/p2p/validator_node.proto index e818081ce2..b48a4d6275 100644 --- a/applications/tari_validator_node/proto/p2p/validator_node.proto +++ b/applications/tari_validator_node/proto/p2p/validator_node.proto @@ -37,11 +37,11 @@ message GetTokenDataResponse {} message SubmitInstructionRequest { bytes asset_public_key = 1; - string method = 2; - repeated bytes args = 3; - bytes token_id = 4; - bytes signature = 5; - uint64 id = 6; + uint32 template_id = 2; + string method = 3; + repeated bytes args = 4; +// bytes token_id = 5; +// bytes signature = 6; } enum Status { diff --git a/applications/tari_validator_node/src/dan_layer/services/asset_processor.rs b/applications/tari_validator_node/src/dan_layer/services/asset_processor.rs deleted file mode 100644 index e97982a30e..0000000000 --- a/applications/tari_validator_node/src/dan_layer/services/asset_processor.rs +++ /dev/null @@ -1,122 +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 crate::{ - dan_layer::{ - models::{AssetDefinition, Instruction, InstructionCaller, InstructionId, TemplateId}, - storage::AssetStore, - template_command::{ExecutionResult, TemplateCommand}, - templates::editable_metadata_template::_EditableMetadataTemplate, - }, - digital_assets_error::DigitalAssetError, -}; -use async_trait::async_trait; -use std::collections::VecDeque; - -// TODO: Better name needed -#[async_trait] -pub trait AssetProcessor { - async fn execute_instruction(&mut self, instruction: &Instruction) -> Result<(), DigitalAssetError>; -} - -pub struct ConcreteAssetProcessor { - _asset_definition: AssetDefinition, - _template_factory: TemplateFactory, - _instruction_log: TInstructionLog, - _data_store: TAssetStore, -} - -#[async_trait] -impl AssetProcessor - for ConcreteAssetProcessor -{ - async fn execute_instruction(&mut self, instruction: &Instruction) -> Result<(), DigitalAssetError> { - // TODO: This is thread blocking - self.execute( - instruction.method().to_owned(), - instruction.args().to_vec().into(), - InstructionCaller { - owner_token_id: instruction.from_owner().to_owned(), - }, - // TODO: put in instruction - InstructionId(0), - ) - } -} - -impl ConcreteAssetProcessor { - pub fn new(data_store: TAssetStore, instruction_log: TInstructionLog, asset_definition: AssetDefinition) -> Self { - Self { - _template_factory: TemplateFactory {}, - _instruction_log: instruction_log, - _asset_definition: asset_definition, - _data_store: data_store, - } - } - - pub fn execute( - &mut self, - _method: String, - _args: VecDeque>, - _caller: InstructionCaller, - _id: InstructionId, - ) -> Result<(), DigitalAssetError> { - unimplemented!() - // let instruction = self - // .template_factory - // .create_command(self.template_id, method, args, caller)?; - // let result = instruction.try_execute(&mut self.data_store)?; - // self.instruction_log.store(id, result); - // Ok(()) - } -} - -pub struct TemplateFactory {} - -impl TemplateFactory { - pub fn _create_command( - &self, - template: TemplateId, - method: String, - args: VecDeque>, - caller: InstructionCaller, - ) -> Result { - match template { - TemplateId::_EditableMetadata => _EditableMetadataTemplate::_create_command(method, args, caller), - } - } -} - -pub trait InstructionLog { - fn store(&mut self, id: InstructionId, result: ExecutionResult); -} - -#[derive(Default)] -pub struct MemoryInstructionLog { - log: Vec<(InstructionId, ExecutionResult)>, -} - -impl InstructionLog for MemoryInstructionLog { - fn store(&mut self, id: InstructionId, result: ExecutionResult) { - self.log.push((id, result)) - } -} diff --git a/applications/tari_validator_node/src/dan_layer/services/infrastructure_services/outbound_service.rs b/applications/tari_validator_node/src/dan_layer/services/infrastructure_services/outbound_service.rs deleted file mode 100644 index 7dcc268b63..0000000000 --- a/applications/tari_validator_node/src/dan_layer/services/infrastructure_services/outbound_service.rs +++ /dev/null @@ -1,114 +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 crate::{ - dan_layer::{ - models::{HotStuffMessage, Payload}, - services::infrastructure_services::NodeAddressable, - }, - digital_assets_error::DigitalAssetError, - p2p::proto, -}; -use async_trait::async_trait; - -use crate::dan_layer::models::TariDanPayload; -use std::marker::PhantomData; -use tari_comms::types::CommsPublicKey; -use tari_comms_dht::{domain_message::OutboundDomainMessage, outbound::OutboundMessageRequester}; -use tari_p2p::tari_message::TariMessageType; -use tokio::sync::mpsc::Sender; - -#[async_trait] -pub trait OutboundService { - async fn send( - &mut self, - from: TAddr, - to: TAddr, - message: HotStuffMessage, - ) -> Result<(), DigitalAssetError>; - - async fn broadcast( - &mut self, - from: TAddr, - committee: &[TAddr], - message: HotStuffMessage, - ) -> Result<(), DigitalAssetError>; -} - -pub struct TariCommsOutboundService { - outbound_message_requester: OutboundMessageRequester, - loopback_service: Sender<(CommsPublicKey, HotStuffMessage)>, - // TODO: Remove - phantom: PhantomData, -} - -impl TariCommsOutboundService { - pub fn new( - outbound_message_requester: OutboundMessageRequester, - loopback_service: Sender<(CommsPublicKey, HotStuffMessage)>, - ) -> Self { - Self { - outbound_message_requester, - loopback_service, - phantom: PhantomData, - } - } -} - -#[async_trait] -impl OutboundService for TariCommsOutboundService { - async fn send( - &mut self, - from: CommsPublicKey, - to: CommsPublicKey, - message: HotStuffMessage, - ) -> Result<(), DigitalAssetError> { - // Tari comms does allow sending to itself - if from == to { - self.loopback_service.send((from, message)).await.unwrap(); - return Ok(()); - } - - let inner = proto::dan::HotStuffMessage::from(message); - let tari_message = OutboundDomainMessage::new(TariMessageType::DanConsensusMessage, inner); - - self.outbound_message_requester - .send_direct(to, tari_message) - .await - .unwrap(); - Ok(()) - } - - async fn broadcast( - &mut self, - from: CommsPublicKey, - committee: &[CommsPublicKey], - message: HotStuffMessage, - ) -> Result<(), DigitalAssetError> { - for committee_member in committee { - // TODO: send in parallel - self.send(from.clone(), committee_member.clone(), message.clone()) - .await?; - } - Ok(()) - } -} diff --git a/applications/tari_validator_node/src/dan_layer/storage/mod.rs b/applications/tari_validator_node/src/dan_layer/storage/mod.rs deleted file mode 100644 index 7a7adcbf14..0000000000 --- a/applications/tari_validator_node/src/dan_layer/storage/mod.rs +++ /dev/null @@ -1,30 +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. - -mod error; -pub use error::StorageError; - -mod lmdb; -pub use lmdb::{LmdbAssetBackend, LmdbAssetStore}; - -mod store; -pub use store::{AssetDataStore, AssetStore}; diff --git a/applications/tari_validator_node/src/dan_layer/dan_node.rs b/applications/tari_validator_node/src/dan_node.rs similarity index 84% rename from applications/tari_validator_node/src/dan_layer/dan_node.rs rename to applications/tari_validator_node/src/dan_node.rs index f34ad1bc8d..e54e4405ea 100644 --- a/applications/tari_validator_node/src/dan_layer/dan_node.rs +++ b/applications/tari_validator_node/src/dan_node.rs @@ -1,45 +1,34 @@ -// Copyright 2021. The Tari Project +// 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: +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: // -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. // -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. +// 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. +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{AssetDefinition, Committee}, + grpc::services::base_node_client::GrpcBaseNodeClient, + p2p::{ + create_validator_node_rpc_service, services::{ - infrastructure_services::{TariCommsInboundConnectionService, TariCommsOutboundService}, - ConcreteAssetProcessor, - ConcreteCommitteeManager, - GrpcBaseNodeClient, - LoggingEventsPublisher, - MemoryInstructionLog, - MempoolService, - MempoolServiceHandle, - NodeIdentitySigningService, - TariDanPayloadProcessor, - TariDanPayloadProvider, + inbound_connection_service::TariCommsInboundConnectionService, + outbound_connection_service::TariCommsOutboundService, }, - storage::{AssetDataStore, LmdbAssetStore}, - workers::ConsensusWorker, }, - p2p::create_validator_node_rpc_service, ExitCodes, }; use log::*; @@ -64,6 +53,29 @@ use tari_comms::{ }; use tari_comms_dht::{store_forward::SafConfig, DbConnectionUrl, Dht, DhtConfig}; use tari_crypto::tari_utilities::hex::Hex; +use tari_dan_core::{ + models::{AssetDefinition, Committee}, + services::{ + ConcreteAssetProcessor, + ConcreteCommitteeManager, + LoggingEventsPublisher, + MemoryInstructionLog, + MempoolService, + MempoolServiceHandle, + NodeIdentitySigningService, + TariDanPayloadProcessor, + TariDanPayloadProvider, + }, + storage::{ + sqlite::SqliteStorageService, + AssetDataStore, + BackendAdapter, + DbFactory, + LmdbAssetStore, + SqliteDbFactory, + }, + workers::ConsensusWorker, +}; use tari_p2p::{ comms_connector::{pubsub_connector, SubscriptionFactory}, initialization::{spawn_comms_using_transport, P2pConfig, P2pInitializer}, @@ -119,6 +131,7 @@ impl DanNode { if asset_definitions.is_empty() { warn!(target: LOG_TARGET, "No assets to process. Exiting"); } + let db_factory = SqliteDbFactory::new(&self.config); for asset in asset_definitions { // TODO: spawn into multiple processes. This requires some routing as well. self.start_asset_worker( @@ -129,6 +142,7 @@ impl DanNode { subscription_factory.clone(), shutdown.clone(), dan_config, + db_factory.clone(), ) .await?; } @@ -155,7 +169,11 @@ impl DanNode { Ok(result) } - async fn start_asset_worker( + async fn start_asset_worker< + TMempoolService: MempoolService + Clone, + TBackendAdapter: BackendAdapter + Send + Sync, + TDbFactory: DbFactory + Clone + Send + Sync, + >( &self, asset_definition: AssetDefinition, node_identity: NodeIdentity, @@ -164,6 +182,7 @@ impl DanNode { subscription_factory: SubscriptionFactory, shutdown: ShutdownSignal, config: &ValidatorNodeConfig, + db_factory: TDbFactory, ) -> Result<(), ExitCodes> { let timeout = Duration::from_secs(asset_definition.phase_timeout); // TODO: read from base layer get asset definition @@ -197,7 +216,7 @@ impl DanNode { .map_err(|err| ExitCodes::DatabaseError(err.to_string()))?; let data_store = AssetDataStore::new(backend); let instruction_log = MemoryInstructionLog::default(); - let asset_processor = ConcreteAssetProcessor::new(data_store, instruction_log, asset_definition.clone()); + let asset_processor = ConcreteAssetProcessor::new(instruction_log, asset_definition.clone()); let payload_processor = TariDanPayloadProcessor::new(asset_processor, mempool_service); let mut inbound = TariCommsInboundConnectionService::new(); @@ -213,7 +232,7 @@ impl DanNode { let dht = handles.expect_handle::(); let outbound = TariCommsOutboundService::new(dht.outbound_requester(), loopback); let base_node_client = GrpcBaseNodeClient::new(config.base_node_grpc_address); - + let chain_storage = SqliteStorageService {}; let mut consensus_worker = ConsensusWorker::new( receiver, outbound, @@ -226,6 +245,8 @@ impl DanNode { asset_definition, base_node_client, timeout, + db_factory, + chain_storage, ); consensus_worker .run(shutdown.clone(), None) diff --git a/applications/tari_validator_node/src/grpc/conversions.rs b/applications/tari_validator_node/src/grpc/conversions.rs new file mode 100644 index 0000000000..dbad8bcfb7 --- /dev/null +++ b/applications/tari_validator_node/src/grpc/conversions.rs @@ -0,0 +1,34 @@ +// 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 crate::grpc::validator_node_rpc as rpc; +use tari_crypto::tari_utilities::ByteArray; +use tari_dan_core::models::SidechainMetadata; + +impl From for rpc::SidechainMetadata { + fn from(source: SidechainMetadata) -> Self { + Self { + asset_public_key: source.asset_public_key().as_bytes().to_vec(), + committed_height: source.committed_height().into(), + committed_hash: source.committed_hash().clone().into(), + } + } +} diff --git a/applications/tari_validator_node/src/grpc/mod.rs b/applications/tari_validator_node/src/grpc/mod.rs index ea674747da..de7a0e6019 100644 --- a/applications/tari_validator_node/src/grpc/mod.rs +++ b/applications/tari_validator_node/src/grpc/mod.rs @@ -19,6 +19,8 @@ // 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. +pub(crate) mod conversions; +pub mod services; pub(crate) mod validator_node_grpc_server; pub mod validator_node_rpc { diff --git a/applications/tari_validator_node/src/dan_layer/services/base_node_client.rs b/applications/tari_validator_node/src/grpc/services/base_node_client.rs similarity index 89% rename from applications/tari_validator_node/src/dan_layer/services/base_node_client.rs rename to applications/tari_validator_node/src/grpc/services/base_node_client.rs index cdfdc134b5..124722f2e2 100644 --- a/applications/tari_validator_node/src/dan_layer/services/base_node_client.rs +++ b/applications/tari_validator_node/src/grpc/services/base_node_client.rs @@ -19,28 +19,16 @@ // 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::{ - dan_layer::models::{BaseLayerMetadata, BaseLayerOutput}, - digital_assets_error::DigitalAssetError, - types::PublicKey, -}; use async_trait::async_trait; use std::{convert::TryInto, net::SocketAddr}; use tari_app_grpc::tari_rpc as grpc; use tari_crypto::tari_utilities::ByteArray; - -#[async_trait] -pub trait BaseNodeClient { - async fn get_tip_info(&mut self) -> Result; - - async fn get_current_checkpoint( - &mut self, - height: u64, - asset_public_key: PublicKey, - checkpoint_unique_id: Vec, - ) -> Result, DigitalAssetError>; -} +use tari_dan_core::{ + models::{BaseLayerMetadata, BaseLayerOutput}, + services::BaseNodeClient, + types::PublicKey, + DigitalAssetError, +}; pub struct GrpcBaseNodeClient { endpoint: SocketAddr, diff --git a/applications/tari_validator_node/src/grpc/services/mod.rs b/applications/tari_validator_node/src/grpc/services/mod.rs new file mode 100644 index 0000000000..fb16fd64db --- /dev/null +++ b/applications/tari_validator_node/src/grpc/services/mod.rs @@ -0,0 +1,23 @@ +// 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. + +pub mod base_node_client; 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 ad2f875a64..f9a04bef3b 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 @@ -19,32 +19,47 @@ // 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::{ - dan_layer::{ - models::{Instruction, TokenId}, - services::MempoolService, - }, - grpc::validator_node_rpc as rpc, +use crate::grpc::validator_node_rpc as rpc; +use std::marker::PhantomData; +use tari_crypto::tari_utilities::ByteArray; +use tari_dan_core::{ + models::{Instruction, TemplateId, TokenId}, + services::MempoolService, + storage::{BackendAdapter, ChainStorageService, DbFactory}, types::{ComSig, PublicKey}, }; - -use tari_crypto::tari_utilities::ByteArray; - use tonic::{Request, Response, Status}; -pub struct ValidatorNodeGrpcServer { - mempool_service: TMempoolService, +pub struct ValidatorNodeGrpcServer< + TMempoolService: MempoolService, + TBackendAdapter: BackendAdapter, + TDbFactory: DbFactory, +> { + mempool: TMempoolService, + db_factory: TDbFactory, + // TODO: Can probably remove + pd: PhantomData, } -impl ValidatorNodeGrpcServer { - pub fn new(mempool_service: TMempoolService) -> Self { - Self { mempool_service } +impl> + ValidatorNodeGrpcServer +{ + pub fn new(mempool: TMempoolService, db_factory: TDbFactory) -> Self { + Self { + mempool, + db_factory, + pd: PhantomData, + } } } #[tonic::async_trait] -impl rpc::validator_node_server::ValidatorNode - for ValidatorNodeGrpcServer +impl rpc::validator_node_server::ValidatorNode + for ValidatorNodeGrpcServer +where + TMempoolService: MempoolService + Clone + Sync + Send + 'static, + TBackendAdapter: BackendAdapter + Sync + Send + 'static, + TDbFactory: DbFactory + Sync + Send + 'static, { async fn get_token_data( &self, @@ -63,17 +78,18 @@ impl rpc::valid let instruction = Instruction::new( PublicKey::from_bytes(&request.asset_public_key) .map_err(|_err| Status::invalid_argument("asset_public_key was not a valid public key"))?, + request.template_id.into(), request.method.clone(), request.args.clone(), - TokenId(request.token_id.clone()), - // TODO: put signature in here - ComSig::default() - // create_com_sig_from_bytes(&request.signature) - // .map_err(|err| Status::invalid_argument("signature was not a valid comsig"))?, + /* TokenId(request.token_id.clone()), + * TODO: put signature in here + * ComSig::default() + * create_com_sig_from_bytes(&request.signature) + * .map_err(|err| Status::invalid_argument("signature was not a valid comsig"))?, */ ); - let mut mempool_service = self.mempool_service.clone(); - match mempool_service.submit_instruction(instruction).await { + let mut mempool = self.mempool.clone(); + match mempool.submit_instruction(instruction).await { Ok(_) => { return Ok(Response::new(rpc::ExecuteInstructionResponse { status: "Accepted".to_string(), @@ -86,4 +102,19 @@ impl rpc::valid }, } } + + async fn get_metadata( + &self, + request: Request, + ) -> Result, Status> { + dbg!(&request); + let db = self.db_factory.create(); + todo!() + // let mut tx = db.new_unit_of_work(); + // let metadata = db.metadata.read(&mut tx); + // // .map_err(|e| Status::internal(format!("Could not read metadata from storage:{}", e)))?; + // Ok(Response::new(rpc::GetMetadataResponse { + // sidechains: vec![metadata.into()], + // })) + } } diff --git a/applications/tari_validator_node/src/main.rs b/applications/tari_validator_node/src/main.rs index 54854a3dcf..b7c07b8b92 100644 --- a/applications/tari_validator_node/src/main.rs +++ b/applications/tari_validator_node/src/main.rs @@ -22,17 +22,11 @@ #![allow(clippy::too_many_arguments)] mod cmd_args; -mod dan_layer; -mod digital_assets_error; +mod dan_node; mod grpc; mod p2p; -mod types; - use crate::{ - dan_layer::{ - dan_node::DanNode, - services::{MempoolService, MempoolServiceHandle}, - }, + dan_node::DanNode, grpc::{ validator_node_grpc_server::ValidatorNodeGrpcServer, validator_node_rpc::validator_node_server::ValidatorNodeServer, @@ -46,11 +40,15 @@ use std::{ }; use tari_app_utilities::initialization::init_configuration; use tari_common::{configuration::bootstrap::ApplicationType, exit_codes::ExitCodes, GlobalConfig}; +use tari_dan_core::{ + services::{MempoolService, MempoolServiceHandle}, + storage::{BackendAdapter, ChainStorageService, DbFactory, SqliteDbFactory}, +}; use tari_shutdown::{Shutdown, ShutdownSignal}; use tokio::{runtime, runtime::Runtime, task}; use tonic::transport::Server; -const LOG_TARGET: &str = "validator_node::app"; +const LOG_TARGET: &str = "tari::validator_node::app"; fn main() { if let Err(exit_code) = main_inner() { @@ -83,9 +81,11 @@ async fn run_node(config: GlobalConfig) -> Result<(), ExitCodes> { let shutdown = Shutdown::new(); let mempool_service = MempoolServiceHandle::new(); + // let chain_storage = ChainStorageServiceHandle::new(); + let db_factory = SqliteDbFactory::new(&config); - let grpc_server = ValidatorNodeGrpcServer::new(mempool_service.clone()); - let grpc_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 18080); + let grpc_server = ValidatorNodeGrpcServer::new(mempool_service.clone(), db_factory); + let grpc_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 18144); task::spawn(run_grpc(grpc_server, grpc_addr, shutdown.to_signal())); run_dan_node(shutdown.to_signal(), config, mempool_service).await?; @@ -109,8 +109,12 @@ async fn run_dan_node( node.start(true, shutdown_signal, mempool_service).await } -async fn run_grpc( - grpc_server: ValidatorNodeGrpcServer, +async fn run_grpc< + TMempoolService: MempoolService + Clone + Sync + Send + 'static, + TBackendAdapter: BackendAdapter + Sync + Send + 'static, + TDbFactory: DbFactory + Sync + Send + 'static, +>( + grpc_server: ValidatorNodeGrpcServer, grpc_address: SocketAddr, shutdown_signal: ShutdownSignal, ) -> Result<(), anyhow::Error> { diff --git a/applications/tari_validator_node/src/p2p/mod.rs b/applications/tari_validator_node/src/p2p/mod.rs index 36bb548e34..ebe7216d3c 100644 --- a/applications/tari_validator_node/src/p2p/mod.rs +++ b/applications/tari_validator_node/src/p2p/mod.rs @@ -24,3 +24,4 @@ pub mod proto; mod rpc; pub use rpc::create_validator_node_rpc_service; +pub mod services; diff --git a/applications/tari_validator_node/src/p2p/proto/conversions/dan.rs b/applications/tari_validator_node/src/p2p/proto/conversions/dan.rs index a0cd3fec70..d0930de423 100644 --- a/applications/tari_validator_node/src/p2p/proto/conversions/dan.rs +++ b/applications/tari_validator_node/src/p2p/proto/conversions/dan.rs @@ -20,8 +20,11 @@ // 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::{ - dan_layer::models::{ +use crate::p2p::proto::dan as dan_proto; +use std::convert::{TryFrom, TryInto}; +use tari_crypto::tari_utilities::ByteArray; +use tari_dan_core::{ + models::{ CheckpointData, HotStuffMessage, HotStuffMessageType, @@ -35,11 +38,8 @@ use crate::{ TreeNodeHash, ViewId, }, - p2p::proto::dan as dan_proto, types::{create_com_sig_from_bytes, PublicKey}, }; -use std::convert::{TryFrom, TryInto}; -use tari_crypto::tari_utilities::ByteArray; impl From> for dan_proto::HotStuffMessage { fn from(source: HotStuffMessage) -> Self { @@ -105,11 +105,10 @@ impl From for dan_proto::InstructionSet { impl From<&Instruction> for dan_proto::Instruction { fn from(source: &Instruction) -> Self { Self { - asset_id: Vec::from(source.asset_id().as_bytes()), + asset_public_key: Vec::from(source.asset_id().as_bytes()), + template_id: source.template_id() as u32, method: source.method().to_string(), args: Vec::from(source.args()), - from: Vec::from(source.from_owner().as_bytes()), - signature: vec![], // com_sig_to_bytes(source.signature()), } } } @@ -189,13 +188,11 @@ impl TryFrom for Instruction { fn try_from(value: dan_proto::Instruction) -> Result { Ok(Self::new( - PublicKey::from_bytes(&value.asset_id) + PublicKey::from_bytes(&value.asset_public_key) .map_err(|e| format!("asset_id was not a valid public key: {}", e))?, + value.template_id.into(), value.method, value.args, - TokenId(value.from), - create_com_sig_from_bytes(&value.signature) - .map_err(|e| format!("Could not convert signature bytes to comsig: {}", e))?, )) } } diff --git a/applications/tari_validator_node/src/p2p/rpc/mod.rs b/applications/tari_validator_node/src/p2p/rpc/mod.rs index 155a7ce3b4..51da6a32af 100644 --- a/applications/tari_validator_node/src/p2p/rpc/mod.rs +++ b/applications/tari_validator_node/src/p2p/rpc/mod.rs @@ -22,14 +22,12 @@ mod service_impl; pub use service_impl::ValidatorNodeRpcServiceImpl; - #[cfg(test)] mod tests; - use super::proto::validator_node as proto; -use crate::dan_layer::services::MempoolService; use tari_comms::protocol::rpc::{Request, Response, RpcStatus}; use tari_comms_rpc_macros::tari_rpc; +use tari_dan_core::services::MempoolService; #[tari_rpc(protocol_name = b"t/vn/1", server_struct = ValidatorNodeRpcServer, client_struct = ValidatorNodeRpcClient)] pub trait ValidatorNodeRpcService: Send + Sync + 'static { 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 b8acd566ee..a9e1efa0e5 100644 --- a/applications/tari_validator_node/src/p2p/rpc/service_impl.rs +++ b/applications/tari_validator_node/src/p2p/rpc/service_impl.rs @@ -19,17 +19,14 @@ // 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::{ - dan_layer::{ - models::{Instruction, TokenId}, - services::MempoolService, - }, - p2p::{proto::validator_node as proto, rpc::ValidatorNodeRpcService}, - types::{ComSig, PublicKey}, -}; +use crate::p2p::{proto::validator_node as proto, rpc::ValidatorNodeRpcService}; use tari_comms::protocol::rpc::{Request, Response, RpcStatus}; use tari_crypto::tari_utilities::ByteArray; +use tari_dan_core::{ + models::{Instruction, TokenId}, + services::MempoolService, + types::{ComSig, PublicKey}, +}; pub struct ValidatorNodeRpcServiceImpl { mempool_service: TMempoolService, @@ -60,13 +57,14 @@ impl ValidatorNodeRpcService for Valida let instruction = Instruction::new( PublicKey::from_bytes(&request.asset_public_key) .map_err(|_err| RpcStatus::bad_request("asset_public_key was not a valid public key"))?, + request.template_id.into(), request.method.clone(), request.args.clone(), - TokenId(request.token_id.clone()), - // TODO: put signature in here - ComSig::default() - // create_com_sig_from_bytes(&request.signature) - // .map_err(|err| Status::invalid_argument("signature was not a valid comsig"))?, + /* TokenId(request.token_id.clone()), + * TODO: put signature in here + * ComSig::default() + * create_com_sig_from_bytes(&request.signature) + * .map_err(|err| Status::invalid_argument("signature was not a valid comsig"))?, */ ); let mut mempool_service = self.mempool_service.clone(); diff --git a/applications/tari_validator_node/src/dan_layer/services/infrastructure_services/inbound_connection_service.rs b/applications/tari_validator_node/src/p2p/services/inbound_connection_service.rs similarity index 63% rename from applications/tari_validator_node/src/dan_layer/services/infrastructure_services/inbound_connection_service.rs rename to applications/tari_validator_node/src/p2p/services/inbound_connection_service.rs index 2655f14164..d40655dcc6 100644 --- a/applications/tari_validator_node/src/dan_layer/services/infrastructure_services/inbound_connection_service.rs +++ b/applications/tari_validator_node/src/p2p/services/inbound_connection_service.rs @@ -1,45 +1,39 @@ -// Copyright 2021. The Tari Project +// 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: +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: // -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. // -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. +// 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. +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +use crate::p2p::proto; +use tari_dan_core::models::{HotStuffMessage, Payload, TariDanPayload}; -use crate::dan_layer::models::{HotStuffMessage, Payload, TariDanPayload}; - -use crate::{ - dan_layer::services::infrastructure_services::NodeAddressable, - digital_assets_error::DigitalAssetError, - p2p::proto, -}; use async_trait::async_trait; use futures::{self, pin_mut, Stream, StreamExt}; use std::{convert::TryInto, sync::Arc}; use tari_comms::types::CommsPublicKey; +use tari_dan_core::{ + services::infrastructure_services::{InboundConnectionService, NodeAddressable}, + DigitalAssetError, +}; use tari_p2p::comms_connector::PeerMessage; use tari_shutdown::ShutdownSignal; use tokio::sync::mpsc::{channel, Receiver, Sender}; -#[async_trait] -pub trait InboundConnectionService { - async fn receive_message(&mut self) -> (TAddr, HotStuffMessage); -} - pub struct TariCommsInboundConnectionService { // TODO: remove option receiver: Option>, diff --git a/applications/tari_validator_node/src/p2p/services/mod.rs b/applications/tari_validator_node/src/p2p/services/mod.rs new file mode 100644 index 0000000000..e45af46a40 --- /dev/null +++ b/applications/tari_validator_node/src/p2p/services/mod.rs @@ -0,0 +1,24 @@ +// 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. + +pub mod inbound_connection_service; +pub mod outbound_connection_service; diff --git a/applications/tari_validator_node/src/p2p/services/outbound_connection_service.rs b/applications/tari_validator_node/src/p2p/services/outbound_connection_service.rs new file mode 100644 index 0000000000..68fa32a807 --- /dev/null +++ b/applications/tari_validator_node/src/p2p/services/outbound_connection_service.rs @@ -0,0 +1,93 @@ +// 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 crate::p2p::proto; +use async_trait::async_trait; +use std::marker::PhantomData; +use tari_comms::types::CommsPublicKey; +use tari_comms_dht::{domain_message::OutboundDomainMessage, outbound::OutboundMessageRequester}; +use tari_dan_core::{ + models::{HotStuffMessage, Payload, TariDanPayload}, + services::infrastructure_services::{NodeAddressable, OutboundService}, + DigitalAssetError, +}; +use tari_p2p::tari_message::TariMessageType; +use tokio::sync::mpsc::Sender; + +pub struct TariCommsOutboundService { + outbound_message_requester: OutboundMessageRequester, + loopback_service: Sender<(CommsPublicKey, HotStuffMessage)>, + // TODO: Remove + phantom: PhantomData, +} + +impl TariCommsOutboundService { + pub fn new( + outbound_message_requester: OutboundMessageRequester, + loopback_service: Sender<(CommsPublicKey, HotStuffMessage)>, + ) -> Self { + Self { + outbound_message_requester, + loopback_service, + phantom: PhantomData, + } + } +} + +#[async_trait] +impl OutboundService for TariCommsOutboundService { + async fn send( + &mut self, + from: CommsPublicKey, + to: CommsPublicKey, + message: HotStuffMessage, + ) -> Result<(), DigitalAssetError> { + // Tari comms does allow sending to itself + if from == to { + self.loopback_service.send((from, message)).await.unwrap(); + return Ok(()); + } + + let inner = proto::dan::HotStuffMessage::from(message); + let tari_message = OutboundDomainMessage::new(TariMessageType::DanConsensusMessage, inner); + + self.outbound_message_requester + .send_direct(to, tari_message) + .await + .unwrap(); + Ok(()) + } + + async fn broadcast( + &mut self, + from: CommsPublicKey, + committee: &[CommsPublicKey], + message: HotStuffMessage, + ) -> Result<(), DigitalAssetError> { + for committee_member in committee { + // TODO: send in parallel + self.send(from.clone(), committee_member.clone(), message.clone()) + .await?; + } + Ok(()) + } +} diff --git a/applications/tari_validator_node/src/types.rs b/applications/tari_validator_node/src/types.rs deleted file mode 100644 index 152418c184..0000000000 --- a/applications/tari_validator_node/src/types.rs +++ /dev/null @@ -1,48 +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 tari_crypto::{ - ristretto::{RistrettoPublicKey, RistrettoSecretKey}, - signatures::CommitmentSignature, - tari_utilities::{ByteArray, ByteArrayError}, -}; - -/// Define the explicit Public key implementation for the Tari base layer -pub(crate) type PublicKey = RistrettoPublicKey; - -pub(crate) type ComSig = CommitmentSignature; - -pub fn create_com_sig_from_bytes(_bytes: &[u8]) -> Result { - Ok(ComSig::default()) - // Ok(ComSig::new( - // HomomorphicCommitment::from_bytes(&bytes[0..32])?, - // RistrettoSecretKey::from_bytes(&bytes[33..64])?, - // RistrettoSecretKey::from_bytes(&bytes[64..96])?, - // )) -} - -pub fn com_sig_to_bytes(comsig: &ComSig) -> Vec { - let mut v = Vec::from(comsig.public_nonce().as_bytes()); - v.extend_from_slice(comsig.u().as_bytes()); - v.extend_from_slice(comsig.v().as_bytes()); - v -} diff --git a/applications/test_faucet/Cargo.toml b/applications/test_faucet/Cargo.toml index 978591382e..9d34afdd61 100644 --- a/applications/test_faucet/Cargo.toml +++ b/applications/test_faucet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test_faucet" -version = "0.11.0" +version = "0.12.0" authors = ["The Tari Development Community"] edition = "2018" diff --git a/base_layer/common_types/Cargo.toml b/base_layer/common_types/Cargo.toml index b9ec3b9800..5d470cfff0 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.11.0" +version = "0.12.0" edition = "2018" [dependencies] diff --git a/base_layer/common_types/src/chain_metadata.rs b/base_layer/common_types/src/chain_metadata.rs index f1494aec56..7d31adbc83 100644 --- a/base_layer/common_types/src/chain_metadata.rs +++ b/base_layer/common_types/src/chain_metadata.rs @@ -38,7 +38,7 @@ pub struct ChainMetadata { /// (exclusive). If `pruned_height` is equal to the `height_of_longest_chain` no blocks can be /// provided. Archival nodes wil always have an `pruned_height` of zero. pruned_height: u64, - /// The geometric mean of the proof of work of the longest chain, none if the chain is empty + /// The total accumuated proof of work of the longest chain accumulated_difficulty: u128, } @@ -122,18 +122,15 @@ impl ChainMetadata { } impl Display for ChainMetadata { - fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { let height = self.height_of_longest_chain; let best_block = self.best_block.to_hex(); let accumulated_difficulty = self.accumulated_difficulty; - fmt.write_str(&format!("Height of longest chain : {}\n", height))?; - fmt.write_str(&format!( - "Geometric mean of longest chain : {}\n", - accumulated_difficulty - ))?; - fmt.write_str(&format!("Best block : {}\n", best_block))?; - fmt.write_str(&format!("Pruning horizon : {}\n", self.pruning_horizon))?; - fmt.write_str(&format!("Effective pruned height : {}\n", self.pruned_height))?; + writeln!(f, "Height of longest chain : {}", height)?; + writeln!(f, "Total accumulated difficulty: {}", accumulated_difficulty)?; + writeln!(f, "Best block : {}", best_block)?; + writeln!(f, "Pruning horizon : {}", self.pruning_horizon)?; + writeln!(f, "Effective pruned height : {}", self.pruned_height)?; Ok(()) } } diff --git a/base_layer/core/Cargo.toml b/base_layer/core/Cargo.toml index 0bce4c95ba..5866851520 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.11.0" +version = "0.12.0" edition = "2018" [features] @@ -18,18 +18,18 @@ base_node_proto = [] avx2 = ["tari_crypto/avx2"] [dependencies] -tari_common = { version = "^0.11", path = "../../common" } -tari_common_types = { version = "^0.11", path = "../../base_layer/common_types" } -tari_comms = { version = "^0.11", path = "../../comms" } -tari_comms_dht = { version = "^0.11", path = "../../comms/dht" } -tari_comms_rpc_macros = { version = "^0.11", path = "../../comms/rpc_macros" } +tari_common = { version = "^0.12", path = "../../common" } +tari_common_types = { version = "^0.12", path = "../../base_layer/common_types" } +tari_comms = { version = "^0.12", path = "../../comms" } +tari_comms_dht = { version = "^0.12", path = "../../comms/dht" } +tari_comms_rpc_macros = { version = "^0.12", path = "../../comms/rpc_macros" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } -tari_mmr = { version = "^0.11", path = "../../base_layer/mmr", optional = true, features=["native_bitmap"] } -tari_p2p = { version = "^0.11", path = "../../base_layer/p2p" } -tari_service_framework = { version = "^0.11", path = "../service_framework" } -tari_shutdown = { version = "^0.11", path = "../../infrastructure/shutdown" } -tari_storage = { version = "^0.11", path = "../../infrastructure/storage" } -tari_test_utils = { version = "^0.11", path = "../../infrastructure/test_utils" } +tari_mmr = { version = "^0.12", path = "../../base_layer/mmr", optional = true, features=["native_bitmap"] } +tari_p2p = { version = "^0.12", path = "../../base_layer/p2p" } +tari_service_framework = { version = "^0.12", path = "../service_framework" } +tari_shutdown = { version = "^0.12", path = "../../infrastructure/shutdown" } +tari_storage = { version = "^0.12", path = "../../infrastructure/storage" } +tari_test_utils = { version = "^0.12", path = "../../infrastructure/test_utils" } tari_utilities = "0.3.0" async-trait = "0.1.50" @@ -70,12 +70,12 @@ ttl_cache = "0.5.1" uint = { version = "0.9", default-features = false } [dev-dependencies] -tari_p2p = { version = "^0.11", path = "../../base_layer/p2p", features = ["test-mocks"] } -tari_test_utils = { version = "^0.11", path = "../../infrastructure/test_utils" } +tari_p2p = { version = "^0.12", path = "../../base_layer/p2p", features = ["test-mocks"] } +tari_test_utils = { version = "^0.12", path = "../../infrastructure/test_utils" } config = { version = "0.9.3" } env_logger = "0.7.0" tempfile = "3.1.0" [build-dependencies] -tari_common = { version = "^0.11", path = "../../common", features = ["build"] } +tari_common = { version = "^0.12", path = "../../common", features = ["build"] } diff --git a/base_layer/core/src/base_node/chain_metadata_service/handle.rs b/base_layer/core/src/base_node/chain_metadata_service/handle.rs index cb102c9637..67680b6a67 100644 --- a/base_layer/core/src/base_node/chain_metadata_service/handle.rs +++ b/base_layer/core/src/base_node/chain_metadata_service/handle.rs @@ -30,8 +30,8 @@ use tokio::sync::broadcast; #[derive(Debug, Clone, PartialEq, Eq)] pub struct PeerChainMetadata { - pub node_id: NodeId, - pub chain_metadata: ChainMetadata, + node_id: NodeId, + chain_metadata: ChainMetadata, } impl PeerChainMetadata { @@ -41,6 +41,14 @@ impl PeerChainMetadata { chain_metadata, } } + + pub fn node_id(&self) -> &NodeId { + &self.node_id + } + + pub fn claimed_chain_metadata(&self) -> &ChainMetadata { + &self.chain_metadata + } } impl Display for PeerChainMetadata { diff --git a/base_layer/core/src/base_node/chain_metadata_service/service.rs b/base_layer/core/src/base_node/chain_metadata_service/service.rs index 60b770051d..ad5050a2eb 100644 --- a/base_layer/core/src/base_node/chain_metadata_service/service.rs +++ b/base_layer/core/src/base_node/chain_metadata_service/service.rs @@ -118,7 +118,7 @@ impl ChainMetadataService { use ConnectivityEvent::*; match event { PeerDisconnected(node_id) | PeerBanned(node_id) => { - if let Some(pos) = self.peer_chain_metadata.iter().position(|p| p.node_id == node_id) { + if let Some(pos) = self.peer_chain_metadata.iter().position(|p| *p.node_id() == node_id) { debug!( target: LOG_TARGET, "Removing disconnected/banned peer `{}` from chain metadata list ", node_id @@ -251,7 +251,7 @@ impl ChainMetadataService { if let Some(pos) = self .peer_chain_metadata .iter() - .position(|peer_chainstate| &peer_chainstate.node_id == node_id) + .position(|peer_chainstate| peer_chainstate.node_id() == node_id) { self.peer_chain_metadata.remove(pos); } @@ -284,7 +284,7 @@ impl ChainMetadataService { if let Some(pos) = self .peer_chain_metadata .iter() - .position(|peer_chainstate| &peer_chainstate.node_id == node_id) + .position(|peer_chainstate| peer_chainstate.node_id() == node_id) { self.peer_chain_metadata.remove(pos); } @@ -411,9 +411,9 @@ mod test { service.handle_liveness_event(&sample_event).await.unwrap(); assert_eq!(service.peer_chain_metadata.len(), 1); let metadata = service.peer_chain_metadata.remove(0); - assert_eq!(metadata.node_id, node_id); + assert_eq!(*metadata.node_id(), node_id); assert_eq!( - metadata.chain_metadata.height_of_longest_chain(), + metadata.claimed_chain_metadata().height_of_longest_chain(), proto_chain_metadata.height_of_longest_chain.unwrap() ); } @@ -443,13 +443,13 @@ mod test { assert!(service .peer_chain_metadata .iter() - .any(|p| &p.node_id == nodes[0].node_id())); + .any(|p| p.node_id() == nodes[0].node_id())); service.handle_connectivity_event(ConnectivityEvent::PeerBanned(nodes[0].node_id().clone())); // Check that banned peer was removed assert!(service .peer_chain_metadata .iter() - .all(|p| &p.node_id != nodes[0].node_id())); + .all(|p| p.node_id() != nodes[0].node_id())); } #[tokio::test] diff --git a/base_layer/core/src/base_node/state_machine_service/state_machine.rs b/base_layer/core/src/base_node/state_machine_service/state_machine.rs index 37534b9c4e..ec26f4b318 100644 --- a/base_layer/core/src/base_node/state_machine_service/state_machine.rs +++ b/base_layer/core/src/base_node/state_machine_service/state_machine.rs @@ -138,7 +138,6 @@ impl BaseNodeStateMachine { use self::{BaseNodeState::*, StateEvent::*, SyncStatus::*}; match (state, event) { (Starting(s), Initialized) => Listening(s.into()), - (Listening(s), InitialSync) => HeaderSync(s.into()), (HeaderSync(_), HeadersSynchronized(conn)) => { if self.config.pruning_horizon > 0 { HorizonStateSync(states::HorizonStateSync::with_peer(conn)) @@ -147,6 +146,7 @@ impl BaseNodeStateMachine { } }, (HeaderSync(s), HeaderSyncFailed) => Waiting(s.into()), + (HeaderSync(s), Continue) => Listening(s.into()), (HeaderSync(s), NetworkSilence) => Listening(s.into()), (HorizonStateSync(s), HorizonStateSynchronized) => BlockSync(s.into()), (HorizonStateSync(s), HorizonStateSyncFailure) => Waiting(s.into()), diff --git a/base_layer/core/src/base_node/state_machine_service/states/block_sync.rs b/base_layer/core/src/base_node/state_machine_service/states/block_sync.rs index 16977db92d..96e2a1f2c6 100644 --- a/base_layer/core/src/base_node/state_machine_service/states/block_sync.rs +++ b/base_layer/core/src/base_node/state_machine_service/states/block_sync.rs @@ -77,7 +77,7 @@ impl BlockSync { let local_nci = shared.local_node_interface.clone(); let randomx_vm_cnt = shared.get_randomx_vm_cnt(); let randomx_vm_flags = shared.get_randomx_vm_flags(); - synchronizer.on_progress(move |block, remote_tip_height, sync_peers| { + synchronizer.on_progress(move |block, remote_tip_height, sync_peer| { let local_height = block.height(); local_nci.publish_block_event(BlockEvent::ValidBlockAdded( block.block().clone().into(), @@ -90,7 +90,7 @@ impl BlockSync { state_info: StateInfo::BlockSync(BlockSyncInfo { tip_height: remote_tip_height, local_height, - sync_peers: sync_peers.to_vec(), + sync_peers: vec![sync_peer.clone()], }), randomx_vm_cnt, randomx_vm_flags, diff --git a/base_layer/core/src/base_node/state_machine_service/states/events_and_states.rs b/base_layer/core/src/base_node/state_machine_service/states/events_and_states.rs index 27c8f5c349..080fd9df21 100644 --- a/base_layer/core/src/base_node/state_machine_service/states/events_and_states.rs +++ b/base_layer/core/src/base_node/state_machine_service/states/events_and_states.rs @@ -31,7 +31,7 @@ use crate::base_node::{ Starting, Waiting, }, - sync::SyncPeers, + sync::SyncPeer, }; use randomx_rs::RandomXFlag; use std::fmt::{Display, Error, Formatter}; @@ -54,7 +54,6 @@ pub enum BaseNodeState { #[derive(Debug, Clone, PartialEq)] pub enum StateEvent { Initialized, - InitialSync, HeadersSynchronized(PeerConnection), HeaderSyncFailed, HorizonStateSynchronized, @@ -81,9 +80,9 @@ impl From for StateEvent { #[derive(Debug, Clone, PartialEq)] pub enum SyncStatus { // We are behind the chain tip. - Lagging(ChainMetadata, SyncPeers), + Lagging(ChainMetadata, Vec), // We are behind the pruning horizon. - LaggingBehindHorizon(ChainMetadata, SyncPeers), + LaggingBehindHorizon(ChainMetadata, Vec), UpToDate, } @@ -125,7 +124,6 @@ impl Display for StateEvent { use StateEvent::*; match self { Initialized => f.write_str("Initialized"), - InitialSync => f.write_str("InitialSync"), BlocksSynchronized => f.write_str("Synchronised Blocks"), HeadersSynchronized(conn) => write!(f, "Headers Synchronized from peer `{}`", conn.peer_node_id()), HeaderSyncFailed => f.write_str("Header Synchronization Failed"), @@ -269,7 +267,7 @@ pub struct BlockSyncInfo { } impl BlockSyncInfo { - /// Creates a new blockSyncInfo + /// Creates a new BlockSyncInfo pub fn new(tip_height: u64, local_height: u64, sync_peers: Vec) -> BlockSyncInfo { BlockSyncInfo { tip_height, @@ -282,9 +280,10 @@ impl BlockSyncInfo { format!( "({}) {}/{} ({:.0}%)", self.sync_peers - .first() + .iter() .map(|n| n.short_str()) - .unwrap_or_else(|| "--".to_string()), + .collect::>() + .join(", "), self.local_height, self.tip_height, (self.local_height as f64 / self.tip_height as f64 * 100.0) @@ -294,10 +293,6 @@ impl BlockSyncInfo { impl Display for BlockSyncInfo { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - writeln!(f, "Syncing from the following peers:")?; - for peer in &self.sync_peers { - writeln!(f, "{}", peer)?; - } writeln!(f, "Syncing {}", self.sync_progress_string()) } } diff --git a/base_layer/core/src/base_node/state_machine_service/states/header_sync.rs b/base_layer/core/src/base_node/state_machine_service/states/header_sync.rs index f94af095ae..44fc90b19f 100644 --- a/base_layer/core/src/base_node/state_machine_service/states/header_sync.rs +++ b/base_layer/core/src/base_node/state_machine_service/states/header_sync.rs @@ -24,25 +24,24 @@ use crate::{ base_node::{ comms_interface::BlockEvent, state_machine_service::states::{BlockSyncInfo, Listening, StateEvent, StateInfo, StatusInfo}, - sync::{BlockHeaderSyncError, HeaderSynchronizer, SyncPeers}, + sync::{BlockHeaderSyncError, HeaderSynchronizer, SyncPeer}, BaseNodeStateMachine, }, chain_storage::BlockchainBackend, }; use log::*; use std::time::Instant; -use tari_comms::peer_manager::NodeId; const LOG_TARGET: &str = "c::bn::header_sync"; #[derive(Clone, Debug, Default)] pub struct HeaderSync { - sync_peers: Vec, + sync_peers: Vec, is_synced: bool, } impl HeaderSync { - pub fn new(sync_peers: Vec) -> Self { + pub fn new(sync_peers: Vec) -> Self { Self { sync_peers, is_synced: false, @@ -57,18 +56,12 @@ impl HeaderSync { &mut self, shared: &mut BaseNodeStateMachine, ) -> StateEvent { - let sync_peers = if self.sync_peers.is_empty() { - &shared.config.block_sync_config.sync_peers - } else { - &self.sync_peers - }; - let mut synchronizer = HeaderSynchronizer::new( shared.config.block_sync_config.clone(), shared.db.clone(), shared.consensus_rules.clone(), shared.connectivity.clone(), - sync_peers, + &self.sync_peers, shared.randomx_factory.clone(), ); @@ -76,15 +69,25 @@ impl HeaderSync { let bootstrapped = shared.is_bootstrapped(); let randomx_vm_cnt = shared.get_randomx_vm_cnt(); let randomx_vm_flags = shared.get_randomx_vm_flags(); - synchronizer.on_progress(move |details, sync_peers| { - let details = details.map(|(current_height, remote_tip_height)| BlockSyncInfo { + synchronizer.on_starting(move || { + let _ = status_event_sender.send(StatusInfo { + bootstrapped, + state_info: StateInfo::HeaderSync(None), + randomx_vm_cnt, + randomx_vm_flags, + }); + }); + + let status_event_sender = shared.status_event_sender.clone(); + synchronizer.on_progress(move |current_height, remote_tip_height, sync_peer| { + let details = BlockSyncInfo { tip_height: remote_tip_height, local_height: current_height, - sync_peers: sync_peers.to_vec(), - }); + sync_peers: vec![sync_peer.clone()], + }; let _ = status_event_sender.send(StatusInfo { bootstrapped, - state_info: StateInfo::HeaderSync(details), + state_info: StateInfo::HeaderSync(Some(details)), randomx_vm_cnt, randomx_vm_flags, }); @@ -102,6 +105,10 @@ impl HeaderSync { self.is_synced = true; StateEvent::HeadersSynchronized(sync_peer) }, + Err(err @ BlockHeaderSyncError::SyncFailedAllPeers) => { + warn!(target: LOG_TARGET, "{}. Continuing...", err); + StateEvent::Continue + }, Err(err @ BlockHeaderSyncError::NetworkSilence) => { warn!(target: LOG_TARGET, "{}", err); self.is_synced = true; @@ -120,8 +127,8 @@ impl From for HeaderSync { Default::default() } } -impl From for HeaderSync { - fn from(peers: SyncPeers) -> Self { - Self::new(peers.into_iter().map(|p| p.node_id).collect()) +impl From> for HeaderSync { + fn from(peers: Vec) -> Self { + Self::new(peers) } } diff --git a/base_layer/core/src/base_node/state_machine_service/states/listening.rs b/base_layer/core/src/base_node/state_machine_service/states/listening.rs index 20f25bda01..d1f4c58624 100644 --- a/base_layer/core/src/base_node/state_machine_service/states/listening.rs +++ b/base_layer/core/src/base_node/state_machine_service/states/listening.rs @@ -27,7 +27,6 @@ use crate::{ states::{BlockSync, HeaderSync, StateEvent, StateEvent::FatalError, StateInfo, SyncStatus, Waiting}, BaseNodeStateMachine, }, - sync::SyncPeers, }, chain_storage::BlockchainBackend, }; @@ -53,7 +52,8 @@ pub struct PeerMetadata { impl PeerMetadata { pub fn to_bytes(&self) -> Vec { - let mut buf = Vec::new(); + let size = bincode::serialized_size(self).unwrap(); + let mut buf = Vec::with_capacity(size as usize); bincode::serialize_into(&mut buf, self).unwrap(); // this should not fail buf } @@ -99,22 +99,6 @@ impl Listening { &mut self, shared: &mut BaseNodeStateMachine, ) -> StateEvent { - let local = match shared.db.get_chain_metadata().await { - Ok(m) => m, - Err(e) => { - let msg = format!("Could not get local blockchain metadata. {}", e.to_string()); - return FatalError(msg); - }, - }; - // If we do not have any blocks go straight to initial sync - if !self.is_synced && local.height_of_longest_chain() == 0 { - info!( - target: LOG_TARGET, - "Chain height is at 0, proceeding directly to initial sync" - ); - return StateEvent::InitialSync; - } - info!(target: LOG_TARGET, "Listening for chain metadata updates"); shared.set_state_info(StateInfo::Listening(ListeningInfo::new(self.is_synced))); loop { @@ -129,19 +113,20 @@ impl Listening { } }, Ok(ChainMetadataEvent::PeerChainMetadataReceived(peer_metadata_list)) => { - let mut peer_metadata_list = peer_metadata_list.clone(); + // Convert a &Vec<..> to a Vec<&..> without copying each element + let mut peer_metadata_list = peer_metadata_list.iter().collect::>(); // lets update the peer data from the chain meta data for peer in &peer_metadata_list { let peer_data = PeerMetadata { - metadata: peer.chain_metadata.clone(), + metadata: peer.claimed_chain_metadata().clone(), last_updated: EpochTime::now(), }; // If this fails, its not the end of the world, we just want to keep record of the stats of // the peer let _ = shared .peer_manager - .set_peer_metadata(&peer.node_id, 1, peer_data.to_bytes()) + .set_peer_metadata(peer.node_id(), 1, peer_data.to_bytes()) .await; } @@ -149,7 +134,7 @@ impl Listening { if !configured_sync_peers.is_empty() { // If a _forced_ set of sync peers have been specified, ignore other peers when determining if // we're out of sync - peer_metadata_list.retain(|p| configured_sync_peers.contains(&p.node_id)); + peer_metadata_list.retain(|p| configured_sync_peers.contains(p.node_id())); }; // If ther peer metadata list is empty, there is nothing to do except stay in listening @@ -168,7 +153,7 @@ impl Listening { } // Find the best network metadata and set of sync peers with the best tip. - let best_metadata = match best_metadata(&peer_metadata_list) { + let best_metadata = match best_claimed_metadata(&peer_metadata_list) { Some(m) => m.clone(), None => { debug!( @@ -187,13 +172,13 @@ impl Listening { }, }; - let local_tip_height = local.height_of_longest_chain(); // If we have configured sync peers, they are already filtered at this point let sync_peers = if configured_sync_peers.is_empty() { - select_sync_peers(local_tip_height, &best_metadata, &peer_metadata_list) + select_sync_peers(&local, &best_metadata, &peer_metadata_list) } else { peer_metadata_list }; + let sync_mode = determine_sync_mode( shared.config.blocks_behind_before_considered_lagging, &local, @@ -253,34 +238,43 @@ impl From for Listening { // Finds the set of sync peers that have the best tip on their main chain and have all the data required to update the // local node. -fn select_sync_peers( - local_tip_height: u64, +fn select_sync_peers<'a>( + local_metadata: &ChainMetadata, best_metadata: &ChainMetadata, - peer_metadata_list: &[PeerChainMetadata], -) -> Vec { + peer_metadata_list: &[&'a PeerChainMetadata], +) -> Vec<&'a PeerChainMetadata> { peer_metadata_list .iter() // Check if the peer can provide blocks higher than the local tip height .filter(|peer| { - let peer_horizon_height = peer.chain_metadata.pruned_height(); - local_tip_height >= peer_horizon_height && peer.chain_metadata.best_block() == best_metadata.best_block() + let chain_metadata = peer.claimed_chain_metadata(); + + // If we synced from this peer, do they claim to be able to provide full blocks up until our pruned height? + let our_pruned_height_from_peer = local_metadata.horizon_block(chain_metadata.height_of_longest_chain()); + let their_pruned_height= chain_metadata.pruned_height(); + if our_pruned_height_from_peer < their_pruned_height { + return false; + } + + chain_metadata.best_block() == best_metadata.best_block() }) - .cloned() + // &T is a Copy type + .copied() .collect() } -/// Determine the best metadata from a set of metadata received from the network. -fn best_metadata(metadata_list: &[PeerChainMetadata]) -> Option<&ChainMetadata> { - // TODO: Use heuristics to weed out outliers / dishonest nodes. - metadata_list.iter().fold(None, |best, current| { - if current.chain_metadata.accumulated_difficulty() >= - best.as_ref().map(|cm| cm.accumulated_difficulty()).unwrap_or(0) - { - Some(¤t.chain_metadata) - } else { - best - } - }) +/// Determine the best metadata claimed from a set of metadata received from the network. +fn best_claimed_metadata<'a>(metadata_list: &[&'a PeerChainMetadata]) -> Option<&'a ChainMetadata> { + metadata_list + .iter() + .map(|c| c.claimed_chain_metadata()) + .fold(None, |best, current| { + if current.accumulated_difficulty() >= best.map(|cm| cm.accumulated_difficulty()).unwrap_or(0) { + Some(current) + } else { + best + } + }) } /// Given a local and the network chain state respectively, figure out what synchronisation state we should be in. @@ -288,7 +282,7 @@ fn determine_sync_mode( blocks_behind_before_considered_lagging: u64, local: &ChainMetadata, network: ChainMetadata, - sync_peers: SyncPeers, + sync_peers: Vec<&PeerChainMetadata>, ) -> SyncStatus { use SyncStatus::*; let network_tip_accum_difficulty = network.accumulated_difficulty(); @@ -321,15 +315,12 @@ fn determine_sync_mode( return UpToDate; }; + let sync_peers = sync_peers.into_iter().cloned().collect(); if local_tip_height < network_horizon_block { - debug!( - target: LOG_TARGET, - "Lagging behind horizon ({} sync peer(s))", - sync_peers.len() - ); + debug!(target: LOG_TARGET, "Lagging behind horizon"); LaggingBehindHorizon(network, sync_peers) } else { - debug!(target: LOG_TARGET, "Lagging ({} sync peer(s))", sync_peers.len()); + debug!(target: LOG_TARGET, "Lagging"); Lagging(network, sync_peers) } } else { @@ -360,19 +351,19 @@ mod test { #[test] fn sync_peer_selection() { - let local_tip_height: u64 = 4000; let network_tip_height = 5000; let block_hash1 = vec![0, 1, 2, 3]; let block_hash2 = vec![4, 5, 6, 7]; let accumulated_difficulty1 = 200000; let accumulated_difficulty2 = 100000; - let mut peer_metadata_list = Vec::::new(); - let best_network_metadata = best_metadata(peer_metadata_list.as_slice()); + let mut peer_metadata_list = Vec::new(); + let best_network_metadata = best_claimed_metadata(&peer_metadata_list); assert!(best_network_metadata.is_none()); let best_network_metadata = ChainMetadata::empty(); + let local_metadata = ChainMetadata::new(network_tip_height, Vec::new(), 501, 0, 0); assert_eq!(best_network_metadata, ChainMetadata::new(0, Vec::new(), 0, 0, 0)); - let sync_peers = select_sync_peers(local_tip_height, &best_network_metadata, &peer_metadata_list); + let sync_peers = select_sync_peers(&local_metadata, &best_network_metadata, &peer_metadata_list); assert_eq!(sync_peers.len(), 0); let node_id1 = random_node_id(); @@ -380,10 +371,13 @@ mod test { let node_id3 = random_node_id(); let node_id4 = random_node_id(); let node_id5 = random_node_id(); + // Archival node let peer1 = PeerChainMetadata::new( node_id1.clone(), ChainMetadata::new(network_tip_height, block_hash1.clone(), 0, 0, accumulated_difficulty1), - ); // Archival node + ); + + // Pruning horizon is to short to sync from let peer2 = PeerChainMetadata::new( node_id2, ChainMetadata::new( @@ -393,7 +387,8 @@ mod test { 5000 - 500, accumulated_difficulty1, ), - ); // Pruning horizon is to short to sync from + ); + let peer3 = PeerChainMetadata::new( node_id3.clone(), ChainMetadata::new( @@ -413,7 +408,8 @@ mod test { 5000 - 2880, accumulated_difficulty2, ), - ); // Node running a fork + ); + // Node running a fork let peer5 = PeerChainMetadata::new( node_id5.clone(), ChainMetadata::new( @@ -424,21 +420,21 @@ mod test { accumulated_difficulty1, ), ); - peer_metadata_list.push(peer1); - peer_metadata_list.push(peer2); - peer_metadata_list.push(peer3); - peer_metadata_list.push(peer4); - peer_metadata_list.push(peer5); + peer_metadata_list.push(&peer1); + peer_metadata_list.push(&peer2); + peer_metadata_list.push(&peer3); + peer_metadata_list.push(&peer4); + peer_metadata_list.push(&peer5); - let best_network_metadata = best_metadata(peer_metadata_list.as_slice()).unwrap(); + let best_network_metadata = best_claimed_metadata(peer_metadata_list.as_slice()).unwrap(); assert_eq!(best_network_metadata.height_of_longest_chain(), network_tip_height); assert_eq!(best_network_metadata.best_block(), &block_hash1); assert_eq!(best_network_metadata.accumulated_difficulty(), accumulated_difficulty1); - let sync_peers = select_sync_peers(local_tip_height, best_network_metadata, &peer_metadata_list); + let sync_peers = select_sync_peers(&local_metadata, best_network_metadata, &peer_metadata_list); assert_eq!(sync_peers.len(), 3); - sync_peers.iter().find(|p| p.node_id == node_id1).unwrap(); - sync_peers.iter().find(|p| p.node_id == node_id3).unwrap(); - sync_peers.iter().find(|p| p.node_id == node_id5).unwrap(); + sync_peers.iter().find(|p| *p.node_id() == node_id1).unwrap(); + sync_peers.iter().find(|p| *p.node_id() == node_id3).unwrap(); + sync_peers.iter().find(|p| *p.node_id() == node_id5).unwrap(); } #[test] diff --git a/base_layer/core/src/base_node/sync/block_sync/synchronizer.rs b/base_layer/core/src/base_node/sync/block_sync/synchronizer.rs index d6d83d352a..f858ba901b 100644 --- a/base_layer/core/src/base_node/sync/block_sync/synchronizer.rs +++ b/base_layer/core/src/base_node/sync/block_sync/synchronizer.rs @@ -78,7 +78,7 @@ impl BlockSynchronizer { } pub fn on_progress(&mut self, hook: H) - where H: FnMut(Arc, u64, &[NodeId]) + Send + Sync + 'static { + where H: FnMut(Arc, u64, &NodeId) + Send + Sync + 'static { self.hooks.add_on_progress_block_hook(hook); } @@ -137,6 +137,8 @@ impl BlockSynchronizer { peer: &NodeId, client: &mut rpc::BaseNodeSyncRpcClient, ) -> Result<(), BlockSyncError> { + self.hooks.call_on_starting_hook(); + let tip_header = self.db.fetch_last_header().await?; let local_metadata = self.db.get_chain_metadata().await?; if tip_header.height <= local_metadata.height_of_longest_chain() { @@ -238,8 +240,7 @@ impl BlockSynchronizer { .commit() .await?; - self.hooks - .call_on_progress_block_hooks(block.clone(), tip_height, &[peer.clone()]); + self.hooks.call_on_progress_block_hooks(block.clone(), tip_height, peer); debug!( target: LOG_TARGET, diff --git a/base_layer/core/src/base_node/sync/header_sync/error.rs b/base_layer/core/src/base_node/sync/header_sync/error.rs index 22e99905bd..18e5607416 100644 --- a/base_layer/core/src/base_node/sync/header_sync/error.rs +++ b/base_layer/core/src/base_node/sync/header_sync/error.rs @@ -47,8 +47,11 @@ pub enum BlockHeaderSyncError { FailedToBan(ConnectivityError), #[error("Connectivity Error: {0}")] ConnectivityError(#[from] ConnectivityError), - #[error("Peer could not send a stronger chain than the local chain")] - WeakerChain, + #[error( + "Peer could not provide a stronger chain than the local chain. Claimed was {claimed} but validated was \ + {actual} (local: {local})" + )] + WeakerChain { claimed: u128, actual: u128, local: u128 }, #[error("Node is still not in sync. Sync will be retried with another peer if possible.")] NotInSync, #[error("Unable to locate start hash `{0}`")] @@ -63,7 +66,15 @@ pub enum BlockHeaderSyncError { InvalidProtocolResponse(String), #[error("Headers did not form a chain. Expected {actual} to equal the previous hash {expected}")] ChainLinkBroken { actual: String, expected: String }, - #[error("Block error: {0}")] BlockError(#[from] BlockError), + #[error( + "Peer claimed a stronger chain than they were able to provide. Claimed {claimed}, Actual: {actual:?}, local: \ + {local}" + )] + PeerSentInaccurateChainMetadata { + claimed: u128, + actual: Option, + local: u128, + }, } diff --git a/base_layer/core/src/base_node/sync/header_sync/synchronizer.rs b/base_layer/core/src/base_node/sync/header_sync/synchronizer.rs index 98a079756e..b4dbb77d5b 100644 --- a/base_layer/core/src/base_node/sync/header_sync/synchronizer.rs +++ b/base_layer/core/src/base_node/sync/header_sync/synchronizer.rs @@ -21,7 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use super::{validator::BlockHeaderSyncValidator, BlockHeaderSyncError}; use crate::{ - base_node::sync::{hooks::Hooks, rpc, BlockSyncConfig}, + base_node::sync::{hooks::Hooks, rpc, BlockSyncConfig, SyncPeer}, blocks::{BlockHeader, ChainBlock, ChainHeader}, chain_storage::{async_db::AsyncBlockchainDb, BlockchainBackend}, consensus::ConsensusManager, @@ -32,7 +32,7 @@ use crate::{ }, validation::ValidationError, }; -use futures::{future, StreamExt}; +use futures::{future, stream::FuturesUnordered, StreamExt, TryFutureExt}; use log::*; use std::{ convert::TryFrom, @@ -41,7 +41,7 @@ use std::{ }; use tari_common_types::types::HashOutput; use tari_comms::{ - connectivity::{ConnectivityError, ConnectivityRequester, ConnectivitySelection}, + connectivity::ConnectivityRequester, peer_manager::NodeId, protocol::rpc::{RpcError, RpcHandshakeError}, PeerConnection, @@ -58,7 +58,7 @@ pub struct HeaderSynchronizer<'a, B> { db: AsyncBlockchainDb, header_validator: BlockHeaderSyncValidator, connectivity: ConnectivityRequester, - sync_peers: &'a [NodeId], + sync_peers: &'a [SyncPeer], hooks: Hooks, } @@ -68,7 +68,7 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { db: AsyncBlockchainDb, consensus_rules: ConsensusManager, connectivity: ConnectivityRequester, - sync_peers: &'a [NodeId], + sync_peers: &'a [SyncPeer], randomx_factory: RandomXFactory, ) -> Self { Self { @@ -81,8 +81,13 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { } } + pub fn on_starting(&mut self, hook: H) + where for<'r> H: FnMut() + Send + Sync + 'static { + self.hooks.add_on_starting_hook(hook); + } + pub fn on_progress(&mut self, hook: H) - where H: FnMut(Option<(u64, u64)>, &[NodeId]) + Send + Sync + 'static { + where H: FnMut(u64, u64, &NodeId) + Send + Sync + 'static { self.hooks.add_on_progress_header_hook(hook); } @@ -93,7 +98,8 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { pub async fn synchronize(&mut self) -> Result { debug!(target: LOG_TARGET, "Starting header sync.",); - self.hooks.call_on_progress_header_hooks(None, self.sync_peers); + self.hooks.call_on_starting_hook(); + let sync_peers = self.select_sync_peers().await?; info!( target: LOG_TARGET, @@ -101,13 +107,13 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { sync_peers.len() ); - for peer_conn in sync_peers { + for (sync_peer, peer_conn) in sync_peers { let node_id = peer_conn.peer_node_id().clone(); debug!( target: LOG_TARGET, "Attempting to synchronize headers with `{}`", node_id ); - match self.attempt_sync(peer_conn.clone()).await { + match self.attempt_sync(&sync_peer, peer_conn.clone()).await { Ok(()) => return Ok(peer_conn), // Try another peer Err(err @ BlockHeaderSyncError::NotInSync) => { @@ -126,11 +132,30 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { warn!(target: LOG_TARGET, "Chain split not found for peer {}.", peer); self.ban_peer_long(peer, BanReason::ChainSplitNotFound).await?; }, + Err(ref err @ BlockHeaderSyncError::PeerSentInaccurateChainMetadata { claimed, actual, local }) => { + warn!(target: LOG_TARGET, "{}", err); + self.ban_peer_long(node_id, BanReason::PeerCouldNotProvideStrongerChain { + claimed, + actual: actual.unwrap_or(0), + local, + }) + .await?; + }, + Err(ref err @ BlockHeaderSyncError::WeakerChain { claimed, actual, local }) => { + warn!(target: LOG_TARGET, "{}", err); + self.ban_peer_long(node_id, BanReason::PeerCouldNotProvideStrongerChain { + claimed, + actual, + local, + }) + .await?; + }, Err(err @ BlockHeaderSyncError::InvalidBlockHeight { .. }) => { warn!(target: LOG_TARGET, "{}", err); self.ban_peer_long(node_id, BanReason::GeneralHeaderSyncFailure(err)) .await?; }, + Err(err) => { error!( target: LOG_TARGET, @@ -143,64 +168,22 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { Err(BlockHeaderSyncError::SyncFailedAllPeers) } - async fn wait_until_online(&mut self) -> Result<(), BlockHeaderSyncError> { - const MAX_ONLINE_ATTEMPTS: usize = 5; - let mut attempts = 0; - loop { - match self.connectivity.wait_for_connectivity(Duration::from_secs(10)).await { - Ok(_) => break Ok(()), - Err(ConnectivityError::OnlineWaitTimeout(n)) => { - debug!( - target: LOG_TARGET, - "Still waiting for this node to come online ({} peer(s) connected)", n - ); - // If we have waited a long enough for more node connections and we have some connections, let's try - // and sync - if attempts > MAX_ONLINE_ATTEMPTS && n > 0 { - warn!( - target: LOG_TARGET, - "This node is still not well connected, attempting to sync with {} node(s).", n - ); - break Ok(()); - } - if attempts > MAX_ONLINE_ATTEMPTS && n == 0 { - warn!( - target: LOG_TARGET, - "This node is still not connected to any other nodes. Assuming that this is the only node.", - ); - break Err(BlockHeaderSyncError::NetworkSilence); - } - - attempts += 1; - }, - Err(err) => break Err(err.into()), - } - } - } - - async fn select_sync_peers(&mut self) -> Result, BlockHeaderSyncError> { - if self.sync_peers.is_empty() { - self.wait_until_online().await?; - let sync_peers = self - .connectivity - .select_connections(ConnectivitySelection::all_nodes(vec![])) - .await?; - - debug!( - target: LOG_TARGET, - "Selecting all connected nodes ({})", - sync_peers.len() - ); - - return Ok(sync_peers); - } - - debug!(target: LOG_TARGET, "Dialing {} sync peer(s)", self.sync_peers.len()); - let tasks = self.connectivity.dial_many_peers(self.sync_peers.iter().cloned()); + async fn select_sync_peers(&self) -> Result, BlockHeaderSyncError> { + let tasks = self + .sync_peers + .iter() + .cloned() + .map(|sync_peer| { + debug!(target: LOG_TARGET, "Dialing {} sync peer", sync_peer.node_id()); + self.connectivity + .dial_peer(sync_peer.node_id().clone()) + .and_then(|conn| future::ready(Ok((sync_peer, conn)))) + }) + .collect::>(); let connections = tasks .filter_map(|r| match r { - Ok(conn) => future::ready(Some(conn)), + Ok((sync_peer, conn)) => future::ready(Some((sync_peer, conn))), Err(err) => { debug!(target: LOG_TARGET, "Failed to dial sync peer: {}", err); future::ready(None) @@ -208,7 +191,7 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { }) .collect::>() .await; - debug!( + info!( target: LOG_TARGET, "Successfully dialed {} of {} sync peer(s)", connections.len(), @@ -247,8 +230,11 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { } #[tracing::instrument(skip(self, conn), err)] - async fn attempt_sync(&mut self, mut conn: PeerConnection) -> Result<(), BlockHeaderSyncError> { - let peer = conn.peer_node_id().clone(); + async fn attempt_sync( + &mut self, + sync_peer: &SyncPeer, + mut conn: PeerConnection, + ) -> Result<(), BlockHeaderSyncError> { let mut client = conn.connect_rpc::().await?; let latency = client.get_last_request_latency().await?; debug!( @@ -258,17 +244,30 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { latency.unwrap_or_default().as_millis() ); - let sync_status = self.determine_sync_status(&peer, &mut client).await?; + // Fetch the local tip header at the beginning of the sync process + let local_tip_header = self.db.fetch_tip_header().await?; + let local_total_accumulated_difficulty = local_tip_header.accumulated_data().total_accumulated_difficulty; + let sync_status = self + .determine_sync_status(sync_peer, local_tip_header, &mut client) + .await?; match sync_status { - SyncStatus::InSync => Ok(()), - // We're ahead of this peer, try another peer if possible - SyncStatus::Ahead => Err(BlockHeaderSyncError::NotInSync), + SyncStatus::InSync => Err(BlockHeaderSyncError::PeerSentInaccurateChainMetadata { + claimed: sync_peer.claimed_chain_metadata().accumulated_difficulty(), + actual: None, + local: local_total_accumulated_difficulty, + }), + SyncStatus::WereAhead => Err(BlockHeaderSyncError::PeerSentInaccurateChainMetadata { + claimed: sync_peer.claimed_chain_metadata().accumulated_difficulty(), + actual: None, + local: local_total_accumulated_difficulty, + }), SyncStatus::Lagging(split_info) => { self.hooks.call_on_progress_header_hooks( - Some((split_info.local_tip_header.height(), split_info.remote_tip_height)), - self.sync_peers, + split_info.local_tip_header.height(), + split_info.remote_tip_height, + sync_peer.node_id(), ); - self.synchronize_headers(&peer, &mut client, *split_info).await?; + self.synchronize_headers(sync_peer, &mut client, *split_info).await?; Ok(()) }, } @@ -346,18 +345,19 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { /// returned, the header validator is initialized and the preliminary headers are validated. async fn determine_sync_status( &mut self, - peer: &NodeId, + sync_peer: &SyncPeer, + local_tip_header: ChainHeader, client: &mut rpc::BaseNodeSyncRpcClient, ) -> Result { - // Fetch the local tip header at the beginning of the sync process - let local_tip_header = self.db.fetch_tip_header().await?; - let (resp, block_hashes, steps_back) = self - .find_chain_split(peer, client, NUM_INITIAL_HEADERS_TO_REQUEST) + .find_chain_split(sync_peer.node_id(), client, NUM_INITIAL_HEADERS_TO_REQUEST) .await?; if resp.headers.len() > NUM_INITIAL_HEADERS_TO_REQUEST as usize { - self.ban_peer_long(peer.clone(), BanReason::PeerSentTooManyHeaders(resp.headers.len())) - .await?; + self.ban_peer_long( + sync_peer.node_id().clone(), + BanReason::PeerSentTooManyHeaders(resp.headers.len()), + ) + .await?; return Err(BlockHeaderSyncError::NotInSync); } let proto::FindChainSplitResponse { @@ -370,12 +370,12 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { "Found split {} blocks back, received {} headers from peer `{}`", steps_back, headers.len(), - peer + sync_peer ); if fork_hash_index >= block_hashes.len() as u64 { let _ = self - .ban_peer_long(peer.clone(), BanReason::SplitHashGreaterThanHashes { + .ban_peer_long(sync_peer.node_id().clone(), BanReason::SplitHashGreaterThanHashes { fork_hash_index, num_block_hashes: block_hashes.len(), }) @@ -392,14 +392,14 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { debug!( target: LOG_TARGET, "Peer `{}` has sent no headers but forked_hash_index is {}. The peer is behind our chain.", - peer, + sync_peer, fork_hash_index ); - return Ok(SyncStatus::Ahead); + return Ok(SyncStatus::WereAhead); } - debug!(target: LOG_TARGET, "Already in sync with peer `{}`.", peer); + debug!(target: LOG_TARGET, "Already in sync with peer `{}`.", sync_peer); return Ok(SyncStatus::InSync); } @@ -411,7 +411,7 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { let num_new_headers = headers.len(); // NOTE: We can trust that the header associated with this hash exists because `block_hashes` was supplied by - // this node. usize conversion overflow has already been checked above + // this node. Bounds checking for fork_hash_index has been done above. let chain_split_hash = block_hashes.get(fork_hash_index as usize).unwrap(); self.header_validator.initialize_state(chain_split_hash).await?; @@ -428,20 +428,20 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { debug!( target: LOG_TARGET, - "Peer {} has submitted {} valid header(s)", peer, num_new_headers + "Peer {} has submitted {} valid header(s)", sync_peer, num_new_headers ); // Basic sanity check that the peer sent tip height greater than the split. let split_height = local_tip_header.height().saturating_sub(steps_back); if remote_tip_height < split_height { - self.ban_peer_short(peer.clone(), BanReason::PeerSentInvalidTipHeight { + self.ban_peer_short(sync_peer.node_id().clone(), BanReason::PeerSentInvalidTipHeight { actual: remote_tip_height, expected: split_height, }) .await?; return Err(BlockHeaderSyncError::InvalidProtocolResponse(format!( "Peer {} sent invalid remote tip height", - peer + sync_peer ))); } @@ -472,7 +472,7 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { async fn synchronize_headers( &mut self, - peer: &NodeId, + sync_peer: &SyncPeer, client: &mut rpc::BaseNodeSyncRpcClient, split_info: ChainSplitInfo, ) -> Result<(), BlockHeaderSyncError> { @@ -484,19 +484,26 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { // Find the hash to start syncing the rest of the headers. // The expectation cannot fail because there has been at least one valid header returned (checked in // determine_sync_status) - let (start_header_height, start_header_hash) = self + let (start_header_height, start_header_hash, total_accumulated_difficulty) = self .header_validator .current_valid_chain_tip_header() - .map(|h| (h.height(), h.hash().clone())) + .map(|h| { + ( + h.height(), + h.hash().clone(), + h.accumulated_data().total_accumulated_difficulty, + ) + }) .expect("synchronize_headers: expected there to be a valid tip header but it was None"); // If we already have a stronger chain at this point, switch over to it. // just in case we happen to be exactly NUM_INITIAL_HEADERS_TO_REQUEST headers behind. - let has_better_pow = self.pending_chain_has_higher_pow(&split_info.local_tip_header)?; + let has_better_pow = self.pending_chain_has_higher_pow(&split_info.local_tip_header); if has_better_pow { debug!( target: LOG_TARGET, - "Remote chain from peer {} has higher PoW. Switching", peer + "Remote chain from peer {} has higher PoW. Switching", + sync_peer.node_id() ); self.switch_to_pending_chain(&split_info).await?; has_switched_to_new_chain = true; @@ -507,7 +514,14 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { // headers. debug!(target: LOG_TARGET, "No further headers to download"); if !has_better_pow { - return Err(BlockHeaderSyncError::WeakerChain); + return Err(BlockHeaderSyncError::WeakerChain { + claimed: sync_peer.claimed_chain_metadata().accumulated_difficulty(), + actual: total_accumulated_difficulty, + local: split_info + .local_tip_header + .accumulated_data() + .total_accumulated_difficulty, + }); } return Ok(()); @@ -515,7 +529,9 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { debug!( target: LOG_TARGET, - "Download remaining headers starting from header #{} from peer `{}`", start_header_height, peer + "Download remaining headers starting from header #{} from peer `{}`", + start_header_height, + sync_peer.node_id() ); let request = SyncHeadersRequest { start_hash: start_header_hash, @@ -524,8 +540,13 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { }; let mut header_stream = client.sync_headers(request).await?; - debug!(target: LOG_TARGET, "Reading headers from peer `{}`", peer,); + debug!( + target: LOG_TARGET, + "Reading headers from peer `{}`", + sync_peer.node_id() + ); + let mut last_total_accumulated_difficulty = 0; while let Some(header) = header_stream.next().await { let header = BlockHeader::try_from(header?).map_err(BlockHeaderSyncError::ReceivedInvalidHeader)?; debug!( @@ -548,7 +569,7 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { continue; } let current_height = header.height; - self.header_validator.validate(header)?; + last_total_accumulated_difficulty = self.header_validator.validate(header)?; if has_switched_to_new_chain { // If we've switched to the new chain, we simply commit every COMMIT_EVERY_N_HEADERS headers @@ -559,18 +580,29 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { // The remote chain has not (yet) been accepted. // We check the tip difficulties, switching over to the new chain if a higher accumulated difficulty is // achieved. - if self.pending_chain_has_higher_pow(&split_info.local_tip_header)? { + if self.pending_chain_has_higher_pow(&split_info.local_tip_header) { self.switch_to_pending_chain(&split_info).await?; has_switched_to_new_chain = true; } } self.hooks - .call_on_progress_header_hooks(Some((current_height, split_info.remote_tip_height)), self.sync_peers); + .call_on_progress_header_hooks(current_height, split_info.remote_tip_height, sync_peer.node_id()); } if !has_switched_to_new_chain { - return Err(BlockHeaderSyncError::WeakerChain); + return Err(BlockHeaderSyncError::WeakerChain { + claimed: sync_peer.claimed_chain_metadata().accumulated_difficulty(), + actual: self + .header_validator + .current_valid_chain_tip_header() + .map(|h| h.accumulated_data().total_accumulated_difficulty) + .unwrap_or(0), + local: split_info + .local_tip_header + .accumulated_data() + .total_accumulated_difficulty, + }); } // Commit the last blocks that don't fit into the COMMIT_EVENT_N_HEADERS blocks @@ -578,6 +610,20 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { self.commit_pending_headers().await?; } + let claimed_total_accumulated_diff = sync_peer.claimed_chain_metadata().accumulated_difficulty(); + // This rule is strict: if the peer advertised a higher PoW than they were able to provide (without + // some other external factor like a disconnect etc), we detect the and ban the peer. + if last_total_accumulated_difficulty < claimed_total_accumulated_diff { + return Err(BlockHeaderSyncError::PeerSentInaccurateChainMetadata { + claimed: claimed_total_accumulated_diff, + actual: Some(last_total_accumulated_difficulty), + local: split_info + .local_tip_header + .accumulated_data() + .total_accumulated_difficulty, + }); + } + Ok(()) } @@ -605,19 +651,15 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { Ok(new_tip) } - fn pending_chain_has_higher_pow(&self, current_tip: &ChainHeader) -> Result { + fn pending_chain_has_higher_pow(&self, current_tip: &ChainHeader) -> bool { let chain_headers = self.header_validator.valid_headers(); if chain_headers.is_empty() { - return Ok(false); + return false; } // Check that the remote tip is stronger than the local tip let proposed_tip = chain_headers.last().unwrap(); - match self.header_validator.check_stronger_chain(current_tip, proposed_tip) { - Ok(_) => Ok(true), - Err(BlockHeaderSyncError::WeakerChain) => Ok(false), - Err(err) => Err(err), - } + self.header_validator.compare_chains(current_tip, proposed_tip).is_lt() } async fn switch_to_pending_chain(&mut self, split_info: &ChainSplitInfo) -> Result<(), BlockHeaderSyncError> { @@ -668,6 +710,10 @@ enum BanReason { GeneralHeaderSyncFailure(BlockHeaderSyncError), #[error("Peer did not respond timeously during RPC negotiation")] RpcNegotiationTimedOut, + #[error( + "Peer claimed an accumulated difficulty of {claimed} but validated difficulty was {actual} <= local: {local}" + )] + PeerCouldNotProvideStrongerChain { claimed: u128, actual: u128, local: u128 }, } struct ChainSplitInfo { @@ -681,7 +727,7 @@ enum SyncStatus { /// Local and remote node are in sync InSync, /// Local node is ahead of the remote node - Ahead, + WereAhead, /// Local node is lagging behind remote node Lagging(Box), } diff --git a/base_layer/core/src/base_node/sync/header_sync/validator.rs b/base_layer/core/src/base_node/sync/header_sync/validator.rs index 658630cd6a..622b5bc4cb 100644 --- a/base_layer/core/src/base_node/sync/header_sync/validator.rs +++ b/base_layer/core/src/base_node/sync/header_sync/validator.rs @@ -111,7 +111,7 @@ impl BlockHeaderSyncValidator { self.valid_headers().last() } - pub fn validate(&mut self, header: BlockHeader) -> Result<(), BlockHeaderSyncError> { + pub fn validate(&mut self, header: BlockHeader) -> Result { let state = self.state(); let expected_height = state.current_height + 1; if header.height != expected_height { @@ -163,13 +163,14 @@ impl BlockHeaderSyncValidator { .with_total_kernel_offset(header.total_kernel_offset.clone()) .build()?; - // NOTE: accumulated_data constructed from header + let total_accumulated_difficulty = accumulated_data.total_accumulated_difficulty; + // NOTE: accumulated_data constructed from header so they are guaranteed to correspond let chain_header = ChainHeader::try_construct(header, accumulated_data).unwrap(); state.previous_accum = chain_header.accumulated_data().clone(); state.valid_headers.push(chain_header); - Ok(()) + Ok(total_accumulated_difficulty) } /// Drains and returns all the headers that were validated. @@ -190,11 +191,7 @@ impl BlockHeaderSyncValidator { &self.state().valid_headers } - pub fn check_stronger_chain( - &self, - our_header: &ChainHeader, - their_header: &ChainHeader, - ) -> Result<(), BlockHeaderSyncError> { + pub fn compare_chains(&self, our_header: &ChainHeader, their_header: &ChainHeader) -> Ordering { debug!( target: LOG_TARGET, "Comparing PoW on remote header #{} and local header #{}", @@ -202,14 +199,9 @@ impl BlockHeaderSyncValidator { our_header.height() ); - match self - .consensus_rules + self.consensus_rules .chain_strength_comparer() .compare(our_header, their_header) - { - Ordering::Less => Ok(()), - Ordering::Greater | Ordering::Equal => Err(BlockHeaderSyncError::WeakerChain), - } } fn state_mut(&mut self) -> &mut State { diff --git a/base_layer/core/src/base_node/sync/hooks.rs b/base_layer/core/src/base_node/sync/hooks.rs index debe6a273c..5f3c7e3146 100644 --- a/base_layer/core/src/base_node/sync/hooks.rs +++ b/base_layer/core/src/base_node/sync/hooks.rs @@ -28,38 +28,43 @@ use tari_comms::peer_manager::NodeId; #[derive(Default)] pub(super) struct Hooks { - on_progress_header: Vec, &[NodeId]) + Send + Sync>>, - on_progress_block: Vec, u64, &[NodeId]) + Send + Sync>>, + on_starting: Vec>, + on_progress_header: Vec>, + on_progress_block: Vec, u64, &NodeId) + Send + Sync>>, on_complete: Vec) + Send + Sync>>, on_rewind: Vec>) + Send + Sync>>, } impl Hooks { + pub fn add_on_starting_hook(&mut self, hook: H) + where H: FnMut() + Send + Sync + 'static { + self.on_starting.push(Box::new(hook)); + } + + pub fn call_on_starting_hook(&mut self) { + self.on_starting.iter_mut().for_each(|f| (*f)()); + } + pub fn add_on_progress_header_hook(&mut self, hook: H) - where H: FnMut(Option<(u64, u64)>, &[NodeId]) + Send + Sync + 'static { + where H: FnMut(u64, u64, &NodeId) + Send + Sync + 'static { self.on_progress_header.push(Box::new(hook)); } - pub fn call_on_progress_header_hooks(&mut self, height_vs_remote: Option<(u64, u64)>, sync_peers: &[NodeId]) { + pub fn call_on_progress_header_hooks(&mut self, local_height: u64, remote_height: u64, sync_peer: &NodeId) { self.on_progress_header .iter_mut() - .for_each(|f| (*f)(height_vs_remote, sync_peers)); + .for_each(|f| (*f)(local_height, remote_height, sync_peer)); } pub fn add_on_progress_block_hook(&mut self, hook: H) - where H: FnMut(Arc, u64, &[NodeId]) + Send + Sync + 'static { + where H: FnMut(Arc, u64, &NodeId) + Send + Sync + 'static { self.on_progress_block.push(Box::new(hook)); } - pub fn call_on_progress_block_hooks( - &mut self, - block: Arc, - remote_tip_height: u64, - sync_peers: &[NodeId], - ) { + pub fn call_on_progress_block_hooks(&mut self, block: Arc, remote_tip_height: u64, sync_peer: &NodeId) { self.on_progress_block .iter_mut() - .for_each(|f| (*f)(block.clone(), remote_tip_height, sync_peers)); + .for_each(|f| (*f)(block.clone(), remote_tip_height, sync_peer)); } pub fn add_on_complete_hook(&mut self, hook: H) diff --git a/base_layer/core/src/base_node/sync/mod.rs b/base_layer/core/src/base_node/sync/mod.rs index 9216eadbd7..7c7460fdc7 100644 --- a/base_layer/core/src/base_node/sync/mod.rs +++ b/base_layer/core/src/base_node/sync/mod.rs @@ -42,9 +42,9 @@ mod hooks; pub mod rpc; #[cfg(feature = "base_node")] -mod sync_peers; +mod sync_peer; #[cfg(feature = "base_node")] -pub use sync_peers::{SyncPeer, SyncPeers}; +pub use sync_peer::SyncPeer; #[cfg(feature = "base_node")] mod validators; diff --git a/base_layer/core/src/base_node/sync/rpc/mod.rs b/base_layer/core/src/base_node/sync/rpc/mod.rs index b25d7eb459..3c0d5ea698 100644 --- a/base_layer/core/src/base_node/sync/rpc/mod.rs +++ b/base_layer/core/src/base_node/sync/rpc/mod.rs @@ -28,11 +28,9 @@ mod sync_utxos_task; #[cfg(feature = "base_node")] pub use service::BaseNodeSyncRpcService; -// mod sync_utxos; - // TODO: Tests need to be rewritten -// #[cfg(test)] -// mod tests; +#[cfg(test)] +mod tests; #[cfg(feature = "base_node")] use crate::chain_storage::{async_db::AsyncBlockchainDb, BlockchainBackend}; diff --git a/base_layer/core/src/base_node/sync/rpc/tests.rs b/base_layer/core/src/base_node/sync/rpc/tests.rs index 61adc1aa3c..52fdfd0285 100644 --- a/base_layer/core/src/base_node/sync/rpc/tests.rs +++ b/base_layer/core/src/base_node/sync/rpc/tests.rs @@ -22,81 +22,43 @@ use super::BaseNodeSyncRpcService; use crate::{ - blocks::{Block, BlockBuilder, BlockHeader}, - chain_storage::{BlockchainDatabase, ChainMetadata}, + base_node::BaseNodeSyncService, + chain_storage::BlockchainDatabase, + proto::base_node::SyncBlocksRequest, test_helpers::{ - blockchain::{create_mock_blockchain_database, MockBlockchainBackend}, + blockchain::{create_main_chain, create_new_blockchain, TempDatabase}, create_peer_manager, }, }; -use std::iter; -use tari_comms::protocol::rpc::mock::RpcRequestMock; +use futures::StreamExt; +use tari_comms::protocol::rpc::{mock::RpcRequestMock, RpcStatusCode}; +use tari_test_utils::{streams::convert_mpsc_to_stream, unpack_enum}; use tempfile::{tempdir, TempDir}; -fn setup( - backend: MockBlockchainBackend, -) -> ( - BaseNodeSyncRpcService, - BlockchainDatabase, +fn setup() -> ( + BaseNodeSyncRpcService, + BlockchainDatabase, RpcRequestMock, TempDir, ) { let tmp = tempdir().unwrap(); let peer_manager = create_peer_manager(&tmp); - let request_mock = RpcRequestMock::new(peer_manager.clone()); + let request_mock = RpcRequestMock::new(peer_manager); - let db = create_mock_blockchain_database(backend); + let db = create_new_blockchain(); let service = BaseNodeSyncRpcService::new(db.clone().into()); (service, db, request_mock, tmp) } -fn create_mock_backend() -> MockBlockchainBackend { - let mut backend = MockBlockchainBackend::new(); - // Expectations for BlockchainDatabase::new - backend.expect_is_empty().times(1).returning(|| Ok(false)); - backend - .expect_fetch_chain_metadata() - .times(1) - .returning(|| Ok(ChainMetadata::new(0, Vec::new(), 0, 0, 0))); - backend -} - -fn create_chained_blocks(n: usize) -> Vec { - iter::repeat(()) - .take(n) - .fold(Vec::with_capacity(n), |mut acc, _| match acc.last() { - Some(prev) => { - let header = BlockHeader::from_previous(&prev.header).unwrap(); - let block = BlockBuilder::new(0).with_header(header).build(); - acc.push(block); - acc - }, - None => vec![BlockBuilder::new(0).build()], - }) -} - mod sync_blocks { use super::*; - use crate::{ - base_node::BaseNodeSyncService, - blocks::BlockBuilder, - chain_storage::{ChainMetadata, DbValue}, - proto::base_node::SyncBlocksRequest, - tari_utilities::Hashable, - }; - use futures::StreamExt; - use std::ops::Bound; - use tari_comms::protocol::rpc::RpcStatusCode; - use tari_test_utils::unpack_enum; #[tokio::test] async fn it_returns_not_found_if_unknown_hash() { - let mut backend = create_mock_backend(); - backend.expect_fetch().times(1).returning(|_| Ok(None)); - let (service, _, rpc_request_mock, _tmp) = setup(backend); + let (service, _, rpc_request_mock, _tmp) = setup(); let msg = SyncBlocksRequest { - start_hash: vec![], - end_hash: vec![], + start_hash: vec![0; 32], + end_hash: vec![0; 32], }; let req = rpc_request_mock.request_with_context(Default::default(), msg); let err = service.sync_blocks(req).await.unwrap_err(); @@ -105,31 +67,14 @@ mod sync_blocks { #[tokio::test] async fn it_sends_an_empty_response() { - let mut backend = create_mock_backend(); + let (service, db, rpc_request_mock, _tmp) = setup(); - backend.expect_fetch_chain_metadata().times(1).returning(|| { - Ok(ChainMetadata::new( - 1, - Default::default(), - Default::default(), - Default::default(), - Default::default(), - )) - }); + let (_, chain) = create_main_chain(&db, block_specs!(["A->GB"])); - let mut block = BlockBuilder::new(0).build(); - block.header.height = 1; - // Set both responses to return the same header, the sync rpc handler doesnt care - let header = block.header.clone(); - backend - .expect_fetch() - .times(1) - .returning(move |_| Ok(Some(DbValue::BlockHash(Box::new(header.clone()))))); - - let (service, _, rpc_request_mock, _tmp) = setup(backend); + let block = chain.get("A").unwrap(); let msg = SyncBlocksRequest { - start_hash: block.hash(), - end_hash: block.hash(), + start_hash: block.hash().clone(), + end_hash: block.hash().clone(), }; let req = rpc_request_mock.request_with_context(Default::default(), msg); let mut streaming = service.sync_blocks(req).await.unwrap(); @@ -138,109 +83,27 @@ mod sync_blocks { #[tokio::test] async fn it_streams_blocks_until_end() { - let mut backend = create_mock_backend(); - - let blocks = create_chained_blocks(16); - let first_block = blocks.first().unwrap(); - let first_hash = first_block.hash(); - let last_block = blocks.last().unwrap(); - let last_hash = last_block.hash(); - - let first_header = first_block.header.clone(); - backend - .expect_fetch() - .times(1) - .returning(move |_| Ok(Some(DbValue::BlockHash(Box::new(first_header.clone()))))); - - let metadata = ChainMetadata::new( - 20, - Default::default(), - Default::default(), - Default::default(), - Default::default(), - ); - backend - .expect_fetch_chain_metadata() - .times(1) - .returning({ let metadata =metadata.clone(); move || Ok(metadata.clone())); + let (service, db, rpc_request_mock, _tmp) = setup(); - let last_header = last_block.header.clone(); - backend - .expect_fetch() - .times(1) - .returning(move |_| Ok(Some(DbValue::BlockHash(Box::new(last_header.clone()))))); + let (_, chain) = create_main_chain(&db, block_specs!(["A->GB"], ["B->A"], ["C->B"], ["D->C"], ["E->D"])); - backend - .expect_fetch_chain_metadata() - .times(3) - .returning(move || Ok(metadata.clone())); - - fn expect_fetch_block(backend: &mut MockBlockchainBackend, block: &Block) { - let header = block.header.clone(); - backend - .expect_fetch() - .times(4) - .returning(move |_| Ok(Some(DbValue::BlockHeader(Box::new(header.clone()))))); - - let kernels = block.body.kernels().clone(); - backend - .expect_fetch_kernels_in_block() - .times(4) - .returning(move |_| Ok(kernels.clone())); - - let outputs = block.body.outputs().clone(); - backend - .expect_fetch_outputs_in_block() - .times(4) - .returning(move |_| Ok(outputs.clone())); - - let inputs = block.body.inputs().clone(); - backend - .expect_fetch_inputs_in_block() - .times(4) - .returning(move |_| Ok(inputs.clone())); - } - - // Now expect 4 blocks to be fetched - expect_fetch_block(&mut backend, &first_block); - // expect_fetch_block(&mut backend, &first_block); - // expect_fetch_block(&mut backend, &first_block); - // expect_fetch_block(&mut backend, &first_block); - - let (service, _, rpc_request_mock, _tmp) = setup(backend); + let first_block = chain.get("A").unwrap(); + let last_block = chain.get("E").unwrap(); let msg = SyncBlocksRequest { - start_hash: first_hash, - end_hash: last_hash, + start_hash: first_block.hash().clone(), + end_hash: last_block.hash().clone(), }; let req = rpc_request_mock.request_with_context(Default::default(), msg); - let streaming = service.sync_blocks(req).await.unwrap(); - let _ = streaming.map(Result::unwrap).collect::>().await; - - // assert_eq!(mock.get_call_count("get_blocks").await, 4); - // let (start, end) = mock - // .pop_front_call::<(Bound, Bound)>("get_blocks") - // .await - // .unwrap(); - // unpack_enum!(Bound::Included(start) = start); - // // Exclude block @ start hash - // assert_eq!(start, 1); - // unpack_enum!(Bound::Included(end) = end); - // assert_eq!(end, 4); - // - // let (start, end) = mock - // .pop_front_call::<(Bound, Bound)>("get_blocks") - // .await - // .unwrap(); - // unpack_enum!(Bound::Included(start) = start); - // assert_eq!(start, 5); - // unpack_enum!(Bound::Included(end) = end); - // assert_eq!(end, 8); - // - // let (start, end) = mock.pop_call::<(Bound, Bound)>("get_blocks").await.unwrap(); - // unpack_enum!(Bound::Included(start) = start); - // assert_eq!(start, 13); - // unpack_enum!(Bound::Included(end) = end); - // assert_eq!(end, 15); + let mut streaming = service.sync_blocks(req).await.unwrap().into_inner(); + let blocks = convert_mpsc_to_stream(&mut streaming) + .map(|block| block.unwrap()) + .collect::>() + .await; + + assert_eq!(blocks.len(), 4); + blocks.iter().zip(["B", "C", "D", "E"]).for_each(|(block, name)| { + assert_eq!(*chain.get(name).unwrap().hash(), block.hash); + }); } } diff --git a/base_layer/core/src/base_node/sync/sync_peers.rs b/base_layer/core/src/base_node/sync/sync_peer.rs similarity index 94% rename from base_layer/core/src/base_node/sync/sync_peers.rs rename to base_layer/core/src/base_node/sync/sync_peer.rs index ca5d6dbd3e..dc0f6b9050 100644 --- a/base_layer/core/src/base_node/sync/sync_peers.rs +++ b/base_layer/core/src/base_node/sync/sync_peer.rs @@ -23,5 +23,3 @@ use crate::base_node::chain_metadata_service::PeerChainMetadata; pub type SyncPeer = PeerChainMetadata; -/// Type alias for a collection of PeerChainMetadata -pub type SyncPeers = Vec; diff --git a/base_layer/core/src/chain_storage/blockchain_database.rs b/base_layer/core/src/chain_storage/blockchain_database.rs index 2585a39521..da1d66d6b8 100644 --- a/base_layer/core/src/chain_storage/blockchain_database.rs +++ b/base_layer/core/src/chain_storage/blockchain_database.rs @@ -289,8 +289,8 @@ where B: BlockchainBackend Ok(db.fetch_chain_metadata()?.height_of_longest_chain()) } - /// Return the geometric mean of the proof of work of the longest chain. - /// The proof of work is returned as the geometric mean of all difficulties + /// Return the accumulated proof of work of the longest chain. + /// The proof of work is returned as the product of total difficulties of all PoW algorithms pub fn get_accumulated_difficulty(&self) -> Result { let db = self.db_read_access()?; Ok(db.fetch_chain_metadata()?.accumulated_difficulty()) diff --git a/base_layer/core/src/consensus/emission.rs b/base_layer/core/src/consensus/emission.rs index da76529051..5a3633b10c 100644 --- a/base_layer/core/src/consensus/emission.rs +++ b/base_layer/core/src/consensus/emission.rs @@ -73,6 +73,67 @@ impl EmissionSchedule { EmissionSchedule { initial, decay, tail } } + /// Utility function to calculate the decay parameters that are provided in [EmissionSchedule::new]. This function + /// is provided as a convenience and for the record, but is kept as a separate step. For performance reasons the + /// parameters are 'hard-coded' as a static array rather than a heap allocation. + /// + /// Input : `k`: A string representing a floating point number of (nearly) arbitrary precision, and less than one. + /// + /// Returns: An array of powers of negative two when when applied as a shift right and sum operation is equal to + /// (1-k)*n (to 1/2^64 precision). + /// + /// None - If k is not a valid floating point number less than one. + pub fn decay_params(k: &str) -> Option> { + // Convert string into a vector of digits. e.g. 0.9635 -> [9,6,3,5] + fn frac_vec(n: &str) -> Option> { + if !n.starts_with("0.") { + return None; + } + if !n.chars().skip(2).all(|i| ('0'..='9').contains(&i)) { + return None; + } + let arr = n.chars().skip(2).map(|i| i as u8 - 48).collect::>(); + Some(arr) + } + // Multiply a vector of decimal fractional digits by 2. The bool indicates whether the result was greater than + // one + fn times_two(num: &mut [u8]) -> bool { + let len = num.len(); + let mut carry_last = 0u8; + for i in 0..len { + let index = len - 1 - i; + let carry = if num[index] >= 5 { 1 } else { 0 }; + num[index] = (2 * num[index]) % 10 + carry_last; + carry_last = carry; + } + carry_last > 0 + } + + fn is_zero(v: &[u8]) -> bool { + v.iter().all(|i| *i == 0u8) + } + + let mut next = frac_vec(k)?; + let mut result = Vec::with_capacity(32); + let mut index = 1u8; + let mut exact = true; + while !is_zero(&next) { + let overflow = times_two(&mut next); + if !overflow { + result.push(index); + } + if index >= 63 { + exact = false; + break; + } + index += 1; + } + if exact { + result.push(index - 1); + } + Some(result) + } + /// Return an iterator over the block reward and total supply. This is the most efficient way to iterate through /// the emission curve if you're interested in the supply as well as the reward. /// @@ -260,4 +321,22 @@ mod test { assert_eq!(emission.block_reward(), schedule.block_reward(8)); assert_eq!(emission.supply(), schedule.supply_at_block(8)) } + + #[test] + fn calc_array() { + assert_eq!(EmissionSchedule::decay_params("1.00"), None); + assert_eq!(EmissionSchedule::decay_params("56345"), None); + assert_eq!(EmissionSchedule::decay_params("0.75").unwrap(), vec![2]); + assert_eq!(EmissionSchedule::decay_params("0.25").unwrap(), vec![1, 2]); + assert_eq!(EmissionSchedule::decay_params("0.5").unwrap(), vec![1]); + assert_eq!(EmissionSchedule::decay_params("0.875").unwrap(), vec![3]); + assert_eq!(EmissionSchedule::decay_params("0.125").unwrap(), vec![1, 2, 3]); + assert_eq!(EmissionSchedule::decay_params("0.64732").unwrap(), vec![ + 2, 4, 5, 7, 10, 13, 16, 19, 20, 21, 22, 25, 29, 32, 33, 34, 35, 36, 38, 45, 47, 51, 53, 58, 59, 60, 62, 63 + ]); + assert_eq!(EmissionSchedule::decay_params("0.9999991208182701").unwrap(), vec![ + 21, 22, 23, 25, 26, 37, 38, 39, 41, 45, 49, 50, 51, 52, 55, 57, 59, 60, 63 + ]); + assert_eq!(EmissionSchedule::decay_params("0.0").unwrap(), vec![0]); + } } diff --git a/base_layer/core/src/proof_of_work/randomx_factory.rs b/base_layer/core/src/proof_of_work/randomx_factory.rs index 383bc0417f..79909c679b 100644 --- a/base_layer/core/src/proof_of_work/randomx_factory.rs +++ b/base_layer/core/src/proof_of_work/randomx_factory.rs @@ -15,7 +15,7 @@ pub struct RandomXVMInstance { // The cache and dataset for the VM need to be stored together with it since they are not // mix and match. instance: Arc)>>, - flags: RandomXFlag, + _flags: RandomXFlag, } impl RandomXVMInstance { @@ -48,7 +48,7 @@ impl RandomXVMInstance { Ok(Self { instance: Arc::new(Mutex::new((vm, cache, None))), - flags, + _flags: flags, }) } diff --git a/base_layer/core/src/proof_of_work/target_difficulty.rs b/base_layer/core/src/proof_of_work/target_difficulty.rs index 4727c90b39..ab6582bf51 100644 --- a/base_layer/core/src/proof_of_work/target_difficulty.rs +++ b/base_layer/core/src/proof_of_work/target_difficulty.rs @@ -23,6 +23,7 @@ use crate::proof_of_work::{Difficulty, PowAlgorithm}; /// Immutable struct that is guaranteed to have achieved the target difficulty +#[derive(Debug, Clone, Copy)] pub struct AchievedTargetDifficulty { pow_algo: PowAlgorithm, achieved: Difficulty, diff --git a/base_layer/core/src/test_helpers/block_spec.rs b/base_layer/core/src/test_helpers/block_spec.rs index 8df8d615de..c590ca198d 100644 --- a/base_layer/core/src/test_helpers/block_spec.rs +++ b/base_layer/core/src/test_helpers/block_spec.rs @@ -26,7 +26,7 @@ use crate::{ }; pub struct BlockSpecs { - pub specs: Vec, + specs: Vec, } impl BlockSpecs { @@ -139,7 +139,7 @@ macro_rules! block_specs { { let mut specs = Vec::new(); $crate::block_specs!(@ { specs } [$name, $($k: $v),*], $($tail)*); - BlockSpecs::from(specs) + $crate::test_helpers::BlockSpecs::from(specs) } }; ([$name:expr, $($k:ident: $v:expr),* $(,)?] $(,)*) => {{ diff --git a/base_layer/core/src/transactions/transaction_protocol/sender_transaction_protocol_builder.rs b/base_layer/core/src/transactions/transaction_protocol/sender_transaction_protocol_builder.rs index fa2192420f..e5a4f92138 100644 --- a/base_layer/core/src/transactions/transaction_protocol/sender_transaction_protocol_builder.rs +++ b/base_layer/core/src/transactions/transaction_protocol/sender_transaction_protocol_builder.rs @@ -70,10 +70,9 @@ pub const LOG_TARGET: &str = "c::tx::tx_protocol::tx_initializer"; /// SenderTransactionProtocol::new(1); /// ``` /// which returns an instance of this builder. Once all the sender's information has been added via the builder -/// methods, you can call `build()` which will return a +/// methods, you can call `build()` which will return a [SenderTransactionProtocol] #[derive(Debug, Clone)] pub struct SenderTransactionProtocolBuilder { - consensus_constants: ConsensusConstants, num_recipients: usize, amounts: FixedSet, lock_height: Option, @@ -116,7 +115,6 @@ impl SenderTransactionProtocolBuilder { pub fn new(num_recipients: usize, consensus_constants: ConsensusConstants) -> Self { Self { fee: Fee::new(*consensus_constants.transaction_weight()), - consensus_constants, num_recipients, amounts: FixedSet::new(num_recipients), lock_height: None, diff --git a/base_layer/core/tests/node_state_machine.rs b/base_layer/core/tests/node_state_machine.rs index a126a3c145..9543519197 100644 --- a/base_layer/core/tests/node_state_machine.rs +++ b/base_layer/core/tests/node_state_machine.rs @@ -29,7 +29,6 @@ use std::time::Duration; use tari_common::configuration::Network; use tari_core::{ base_node::{ - chain_metadata_service::PeerChainMetadata, comms_interface::Broadcast, service::BaseNodeServiceConfig, state_machine_service::{ @@ -126,10 +125,7 @@ async fn test_listening_lagging() { .expect("Alice did not emit `StateEvent::FallenBehind` within 10 seconds") .unwrap(); - match next_event { - StateEvent::InitialSync => {}, - _ => panic!(), - } + assert!(matches!(next_event, StateEvent::FallenBehind(_))); } #[tokio::test] @@ -161,19 +157,16 @@ async fn test_event_channel() { task::spawn(state_machine.run()); - let PeerChainMetadata { - node_id, - chain_metadata, - } = random_peer_metadata(10, 5_000); - mock.publish_chain_metadata(&node_id, &chain_metadata) - .await - .expect("Could not publish metadata"); + let peer_chain_metadata = random_peer_metadata(10, 5_000); + mock.publish_chain_metadata( + peer_chain_metadata.node_id(), + peer_chain_metadata.claimed_chain_metadata(), + ) + .await + .expect("Could not publish metadata"); let event = state_change_event_subscriber.recv().await; assert_eq!(*event.unwrap(), StateEvent::Initialized); let event = state_change_event_subscriber.recv().await; let event = event.unwrap(); - match event.as_ref() { - StateEvent::InitialSync => (), - _ => panic!("Unexpected state was found:{:?}", event), - } + assert!(matches!(*event, StateEvent::FallenBehind(_))); } diff --git a/base_layer/key_manager/Cargo.toml b/base_layer/key_manager/Cargo.toml index a514a085bb..6a02245766 100644 --- a/base_layer/key_manager/Cargo.toml +++ b/base_layer/key_manager/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet key management" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "0.11.0" +version = "0.12.0" edition = "2018" [dependencies] diff --git a/base_layer/mmr/Cargo.toml b/base_layer/mmr/Cargo.toml index 6f353b40d6..7e23f38337 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.11.0" +version = "0.12.0" edition = "2018" [features] @@ -24,7 +24,7 @@ criterion = { version="0.2", optional = true } [dev-dependencies] rand="0.8.0" blake2 = "0.9.0" -tari_infra_derive= { path = "../../infrastructure/derive", version = "^0.11" } +tari_infra_derive= { path = "../../infrastructure/derive", version = "^0.12" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } serde_json = "1.0" bincode = "1.1" diff --git a/base_layer/p2p/Cargo.toml b/base_layer/p2p/Cargo.toml index 985a7c4aa6..e0059c090d 100644 --- a/base_layer/p2p/Cargo.toml +++ b/base_layer/p2p/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_p2p" -version = "0.11.0" +version = "0.12.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.11", path = "../../comms" } -tari_comms_dht = { version = "^0.11", path = "../../comms/dht" } -tari_common = { version = "^0.11", path = "../../common" } +tari_comms = { version = "^0.12", path = "../../comms" } +tari_comms_dht = { version = "^0.12", path = "../../comms/dht" } +tari_common = { version = "^0.12", path = "../../common" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } -tari_service_framework = { version = "^0.11", path = "../service_framework" } -tari_shutdown = { version = "^0.11", path = "../../infrastructure/shutdown" } -tari_storage = { version = "^0.11", path = "../../infrastructure/storage" } +tari_service_framework = { version = "^0.12", path = "../service_framework" } +tari_shutdown = { version = "^0.12", path = "../../infrastructure/shutdown" } +tari_storage = { version = "^0.12", path = "../../infrastructure/storage" } tari_utilities = "^0.3" anyhow = "1.0.32" @@ -41,7 +41,7 @@ tower-service = { version = "0.3.0-alpha.2" } trust-dns-client = { version = "0.21.0-alpha.2", features = ["dns-over-rustls"] } [dev-dependencies] -tari_test_utils = { version = "^0.11", path = "../../infrastructure/test_utils" } +tari_test_utils = { version = "^0.12", path = "../../infrastructure/test_utils" } clap = "2.33.0" env_logger = "0.6.2" @@ -56,7 +56,7 @@ features = ["console_appender", "file_appender", "file", "yaml_format"] default-features = false [build-dependencies] -tari_common = { version = "^0.11", path = "../../common", features = ["build"] } +tari_common = { version = "^0.12", path = "../../common", features = ["build"] } [features] test-mocks = [] diff --git a/base_layer/p2p/src/comms_connector/pubsub.rs b/base_layer/p2p/src/comms_connector/pubsub.rs index 198eee63f2..f8841bd4c3 100644 --- a/base_layer/p2p/src/comms_connector/pubsub.rs +++ b/base_layer/p2p/src/comms_connector/pubsub.rs @@ -179,37 +179,37 @@ mod test { #[derive(Debug, Clone)] struct Dummy { a: u32, - b: String, + _b: String, } let messages = vec![ TopicPayload::new("Topic1", Dummy { a: 1u32, - b: "one".to_string(), + _b: "one".to_string(), }), TopicPayload::new("Topic2", Dummy { a: 2u32, - b: "two".to_string(), + _b: "two".to_string(), }), TopicPayload::new("Topic1", Dummy { a: 3u32, - b: "three".to_string(), + _b: "three".to_string(), }), TopicPayload::new("Topic2", Dummy { a: 4u32, - b: "four".to_string(), + _b: "four".to_string(), }), TopicPayload::new("Topic1", Dummy { a: 5u32, - b: "five".to_string(), + _b: "five".to_string(), }), TopicPayload::new("Topic2", Dummy { a: 6u32, - b: "size".to_string(), + _b: "size".to_string(), }), TopicPayload::new("Topic1", Dummy { a: 7u32, - b: "seven".to_string(), + _b: "seven".to_string(), }), ]; @@ -231,15 +231,15 @@ mod test { let messages2 = vec![ TopicPayload::new("Topic1", Dummy { a: 11u32, - b: "one one".to_string(), + _b: "one one".to_string(), }), TopicPayload::new("Topic2", Dummy { a: 22u32, - b: "two two".to_string(), + _b: "two two".to_string(), }), TopicPayload::new("Topic1", Dummy { a: 33u32, - b: "three three".to_string(), + _b: "three three".to_string(), }), ]; diff --git a/base_layer/p2p/src/dns/client.rs b/base_layer/p2p/src/dns/client.rs index 78093186ef..8a875e9429 100644 --- a/base_layer/p2p/src/dns/client.rs +++ b/base_layer/p2p/src/dns/client.rs @@ -106,7 +106,7 @@ impl DnsClient { #[derive(Clone)] pub struct Client { inner: C, - shutdown: Arc, + _shutdown: Arc, } impl Client { @@ -121,7 +121,7 @@ impl Client { Ok(Self { inner: client, - shutdown: Arc::new(shutdown), + _shutdown: Arc::new(shutdown), }) } } @@ -135,7 +135,7 @@ impl Client { Ok(Self { inner: client, - shutdown: Arc::new(shutdown), + _shutdown: Arc::new(shutdown), }) } } @@ -165,7 +165,7 @@ mod mock { let client = MockClientHandle::mock(messages); Ok(Self { inner: client, - shutdown: Arc::new(Shutdown::new()), + _shutdown: Arc::new(Shutdown::new()), }) } } diff --git a/base_layer/p2p/src/dns/mock.rs b/base_layer/p2p/src/dns/mock.rs index 9dec5155cb..1cd0c1bbad 100644 --- a/base_layer/p2p/src/dns/mock.rs +++ b/base_layer/p2p/src/dns/mock.rs @@ -34,7 +34,7 @@ use trust_dns_client::{ #[derive(Clone)] pub struct MockClientHandle { messages: Arc>>, - on_send: O, + _on_send: O, } impl MockClientHandle { @@ -44,7 +44,7 @@ impl MockClientHandle { MockClientHandle { messages: Arc::new(messages), - on_send: DefaultOnSend, + _on_send: DefaultOnSend, } } } diff --git a/base_layer/p2p/src/services/liveness/service.rs b/base_layer/p2p/src/services/liveness/service.rs index bc1cd3bbd5..288e681f6f 100644 --- a/base_layer/p2p/src/services/liveness/service.rs +++ b/base_layer/p2p/src/services/liveness/service.rs @@ -263,7 +263,7 @@ where .collect::>(); if selected_peers.is_empty() { - warn!( + info!( target: LOG_TARGET, "Cannot broadcast pings because there are no broadcast peers available" ) diff --git a/base_layer/p2p/src/services/liveness/state.rs b/base_layer/p2p/src/services/liveness/state.rs index 383652a2ab..f61f14a295 100644 --- a/base_layer/p2p/src/services/liveness/state.rs +++ b/base_layer/p2p/src/services/liveness/state.rs @@ -74,7 +74,6 @@ pub struct LivenessState { pongs_received: usize, pings_sent: usize, pongs_sent: usize, - num_active_peers: usize, local_metadata: Metadata, } diff --git a/base_layer/service_framework/Cargo.toml b/base_layer/service_framework/Cargo.toml index 6b593f47bc..5a73667af0 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.11.0" +version = "0.12.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.11", path = "../../infrastructure/shutdown" } +tari_shutdown = { version = "^0.12", path = "../../infrastructure/shutdown" } anyhow = "1.0.32" async-trait = "0.1.50" @@ -21,7 +21,7 @@ tokio = { version = "1.11", features = ["rt"] } tower-service = { version = "0.3.0" } [dev-dependencies] -tari_test_utils = { version = "^0.11", path = "../../infrastructure/test_utils" } +tari_test_utils = { version = "^0.12", path = "../../infrastructure/test_utils" } tokio = { version = "1.11", 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 941a16a10c..730754c08b 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.11.0" +version = "0.12.0" edition = "2018" [dependencies] -tari_comms = { version = "^0.11", path = "../../comms" } +tari_comms = { version = "^0.12", path = "../../comms" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } tari_common = { path = "../../common" } tari_app_grpc = { path = "../../applications/tari_app_grpc" } diff --git a/base_layer/wallet/Cargo.toml b/base_layer/wallet/Cargo.toml index b966debede..c4b582f98e 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.11.0" +version = "0.12.0" edition = "2018" [dependencies] tari_common = { path = "../../common" } -tari_common_types = { version = "^0.11", path = "../../base_layer/common_types" } -tari_comms = { version = "^0.11", path = "../../comms" } -tari_comms_dht = { version = "^0.11", path = "../../comms/dht" } +tari_common_types = { version = "^0.12", path = "../../base_layer/common_types" } +tari_comms = { version = "^0.12", path = "../../comms" } +tari_comms_dht = { version = "^0.12", path = "../../comms/dht" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } -tari_key_manager = { version = "^0.11", path = "../key_manager" } -tari_p2p = { version = "^0.11", path = "../p2p", features = ["auto-update"] } -tari_service_framework = { version = "^0.11", path = "../service_framework" } -tari_shutdown = { version = "^0.11", path = "../../infrastructure/shutdown" } -tari_storage = { version = "^0.11", path = "../../infrastructure/storage" } +tari_key_manager = { version = "^0.12", path = "../key_manager" } +tari_p2p = { version = "^0.12", path = "../p2p", features = ["auto-update"] } +tari_service_framework = { version = "^0.12", path = "../service_framework" } +tari_shutdown = { version = "^0.12", path = "../../infrastructure/shutdown" } +tari_storage = { version = "^0.12", path = "../../infrastructure/storage" } tari_utilities = "0.3.0" aes-gcm = "^0.8" @@ -47,14 +47,14 @@ tower = "0.3.0-alpha.2" [dependencies.tari_core] path = "../../base_layer/core" -version = "^0.11" +version = "^0.12" default-features = false features = ["transactions", "mempool_proto", "base_node_proto", ] [dev-dependencies] -tari_p2p = { version = "^0.11", path = "../p2p", features = ["test-mocks"] } -tari_comms_dht = { version = "^0.11", path = "../../comms/dht", features = ["test-mocks"] } -tari_test_utils = { version = "^0.11", path = "../../infrastructure/test_utils" } +tari_p2p = { version = "^0.12", path = "../p2p", features = ["test-mocks"] } +tari_comms_dht = { version = "^0.12", path = "../../comms/dht", features = ["test-mocks"] } +tari_test_utils = { version = "^0.12", path = "../../infrastructure/test_utils" } env_logger = "0.7.1" prost = "0.8.0" diff --git a/base_layer/wallet/src/base_node_service/config.rs b/base_layer/wallet/src/base_node_service/config.rs index 85ad381c3e..f6ee2637fb 100644 --- a/base_layer/wallet/src/base_node_service/config.rs +++ b/base_layer/wallet/src/base_node_service/config.rs @@ -36,7 +36,7 @@ pub struct BaseNodeServiceConfig { impl Default for BaseNodeServiceConfig { fn default() -> Self { Self { - base_node_monitor_refresh_interval: Duration::from_secs(30), + base_node_monitor_refresh_interval: Duration::from_secs(3), base_node_rpc_pool_size: 10, request_max_age: Duration::from_secs(60), event_channel_size: 250, diff --git a/base_layer/wallet/src/base_node_service/mod.rs b/base_layer/wallet/src/base_node_service/mod.rs index 94ff82aaf6..66d01d679a 100644 --- a/base_layer/wallet/src/base_node_service/mod.rs +++ b/base_layer/wallet/src/base_node_service/mod.rs @@ -82,7 +82,7 @@ where T: WalletBackend + 'static context.spawn_when_ready(move |handles| async move { let wallet_connectivity = handles.expect_handle::(); - let service = BaseNodeService::new( + let result = BaseNodeService::new( config, request_stream, wallet_connectivity, @@ -90,10 +90,13 @@ where T: WalletBackend + 'static handles.get_shutdown_signal(), db, ) - .start(); - futures::pin_mut!(service); - let _ = service.await; - info!(target: LOG_TARGET, "Wallet Base Node Service shutdown"); + .start() + .await; + + info!( + target: LOG_TARGET, + "Wallet Base Node Service shutdown with result {:?}", result + ); }); Ok(()) diff --git a/base_layer/wallet/src/base_node_service/monitor.rs b/base_layer/wallet/src/base_node_service/monitor.rs index ba46b481ef..11003eff8b 100644 --- a/base_layer/wallet/src/base_node_service/monitor.rs +++ b/base_layer/wallet/src/base_node_service/monitor.rs @@ -30,9 +30,11 @@ use crate::{ storage::database::{WalletBackend, WalletDatabase}, }; use chrono::Utc; +use futures::{future, future::Either}; use log::*; use std::{ convert::TryFrom, + future::Future, sync::Arc, time::{Duration, Instant}, }; @@ -109,17 +111,18 @@ where } async fn monitor_node(&mut self) -> Result<(), BaseNodeMonitorError> { + let mut base_node_watch = self.wallet_connectivity.get_current_base_node_watcher(); loop { - let start = Instant::now(); + let timer = Instant::now(); let mut client = self .wallet_connectivity .obtain_base_node_wallet_rpc_client() .await .ok_or(BaseNodeMonitorError::NodeShuttingDown)?; - trace!( + debug!( target: LOG_TARGET, "Obtain RPC client {} ms", - start.elapsed().as_millis() + timer.elapsed().as_millis() ); let base_node_id = match self.wallet_connectivity.get_current_base_node_id() { @@ -127,15 +130,30 @@ where None => continue, }; - let start = Instant::now(); - let tip_info = client.get_tip_info().await?; + let timer = Instant::now(); + let tip_info = match interrupt(base_node_watch.changed(), client.get_tip_info()).await { + Some(tip_info) => tip_info?, + None => { + self.map_state(|_| Default::default()).await; + continue; + }, + }; let chain_metadata = tip_info .metadata .ok_or_else(|| BaseNodeMonitorError::InvalidBaseNodeResponse("Tip info no metadata".to_string())) .and_then(|metadata| { ChainMetadata::try_from(metadata).map_err(BaseNodeMonitorError::InvalidBaseNodeResponse) })?; - let latency = start.elapsed(); + debug!( + target: LOG_TARGET, + "get_tip_info took {} ms", + timer.elapsed().as_millis() + ); + + let latency = match client.get_last_request_latency().await? { + Some(latency) => latency, + None => continue, + }; let is_synced = tip_info.is_synced; debug!( @@ -147,15 +165,15 @@ where latency.as_millis() ); - let start = Instant::now(); + let timer = Instant::now(); self.db.set_chain_metadata(chain_metadata.clone()).await?; trace!( target: LOG_TARGET, "Update metadata in db {} ms", - start.elapsed().as_millis() + timer.elapsed().as_millis() ); - let start = Instant::now(); + let timer = Instant::now(); self.map_state(move |_| BaseNodeState { chain_metadata: Some(chain_metadata), is_synced: Some(is_synced), @@ -163,9 +181,12 @@ where latency: Some(latency), }) .await; - trace!(target: LOG_TARGET, "Publish event {} ms", start.elapsed().as_millis()); + trace!(target: LOG_TARGET, "Publish event {} ms", timer.elapsed().as_millis()); - time::sleep(self.interval).await + let delay = time::sleep(self.interval.saturating_sub(latency)); + if interrupt(base_node_watch.changed(), delay).await.is_none() { + self.map_state(|_| Default::default()).await; + } } // loop only exits on shutdown/error @@ -200,3 +221,16 @@ enum BaseNodeMonitorError { #[error("Wallet storage error: {0}")] WalletStorageError(#[from] WalletStorageError), } + +async fn interrupt(interrupt: F1, fut: F2) -> Option +where + F1: Future, + F2: Future, +{ + tokio::pin!(interrupt); + tokio::pin!(fut); + match future::select(interrupt, fut).await { + Either::Left(_) => None, + Either::Right((v, _)) => Some(v), + } +} diff --git a/base_layer/wallet/src/base_node_service/service.rs b/base_layer/wallet/src/base_node_service/service.rs index 416ba1eab5..c00af91d47 100644 --- a/base_layer/wallet/src/base_node_service/service.rs +++ b/base_layer/wallet/src/base_node_service/service.rs @@ -42,7 +42,7 @@ use tokio::sync::RwLock; const LOG_TARGET: &str = "wallet::base_node_service::service"; /// State determined from Base Node Service Requests -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] pub struct BaseNodeState { pub chain_metadata: Option, pub is_synced: Option, @@ -50,17 +50,6 @@ pub struct BaseNodeState { pub latency: Option, } -impl Default for BaseNodeState { - fn default() -> Self { - Self { - chain_metadata: None, - is_synced: None, - updated: None, - latency: None, - } - } -} - /// The base node service is responsible for handling requests to be sent to the connected base node. pub struct BaseNodeService where T: WalletBackend + 'static @@ -69,7 +58,7 @@ where T: WalletBackend + 'static request_stream: Option>>, wallet_connectivity: WalletConnectivityHandle, event_publisher: BaseNodeEventSender, - shutdown_signal: Option, + shutdown_signal: ShutdownSignal, state: Arc>, db: WalletDatabase, } @@ -90,7 +79,7 @@ where T: WalletBackend + 'static request_stream: Some(request_stream), wallet_connectivity, event_publisher, - shutdown_signal: Some(shutdown_signal), + shutdown_signal, state: Default::default(), db, } @@ -103,33 +92,13 @@ where T: WalletBackend + 'static /// Starts the service. pub async fn start(mut self) -> Result<(), BaseNodeServiceError> { - let shutdown_signal = self - .shutdown_signal - .take() - .expect("Wallet Base Node Service initialized without shutdown signal"); - - let monitor = BaseNodeMonitor::new( - self.config.base_node_monitor_refresh_interval, - self.state.clone(), - self.db.clone(), - self.wallet_connectivity.clone(), - self.event_publisher.clone(), - ); - - tokio::spawn({ - let shutdown_signal = shutdown_signal.clone(); - async move { - let monitor_fut = monitor.run(); - futures::pin_mut!(monitor_fut); - future::select(shutdown_signal, monitor_fut).await; - } - }); + self.spawn_monitor(); let mut request_stream = self .request_stream .take() .expect("Wallet Base Node Service initialized without request_stream") - .take_until(shutdown_signal); + .take_until(self.shutdown_signal.clone()); info!(target: LOG_TARGET, "Wallet Base Node Service started"); while let Some(request_context) = request_stream.next().await { @@ -152,6 +121,23 @@ where T: WalletBackend + 'static Ok(()) } + fn spawn_monitor(&self) { + let monitor = BaseNodeMonitor::new( + self.config.base_node_monitor_refresh_interval, + self.state.clone(), + self.db.clone(), + self.wallet_connectivity.clone(), + self.event_publisher.clone(), + ); + + let shutdown_signal = self.shutdown_signal.clone(); + tokio::spawn(async move { + let monitor_fut = monitor.run(); + futures::pin_mut!(monitor_fut); + future::select(shutdown_signal, monitor_fut).await; + }); + } + /// This handler is called when requests arrive from the various streams async fn handle_request( &mut self, diff --git a/base_layer/wallet/src/connectivity_service/handle.rs b/base_layer/wallet/src/connectivity_service/handle.rs index 77ef2ddab3..25916e51d9 100644 --- a/base_layer/wallet/src/connectivity_service/handle.rs +++ b/base_layer/wallet/src/connectivity_service/handle.rs @@ -59,6 +59,11 @@ impl WalletConnectivityHandle { #[async_trait::async_trait] impl WalletConnectivityInterface for WalletConnectivityHandle { fn set_base_node(&mut self, base_node_peer: Peer) { + if let Some(peer) = self.base_node_watch.borrow().as_ref() { + if peer.public_key == base_node_peer.public_key { + return; + } + } self.base_node_watch.send(Some(base_node_peer)); } diff --git a/base_layer/wallet/src/output_manager_service/mod.rs b/base_layer/wallet/src/output_manager_service/mod.rs index 57110822e6..27430cfaf1 100644 --- a/base_layer/wallet/src/output_manager_service/mod.rs +++ b/base_layer/wallet/src/output_manager_service/mod.rs @@ -29,7 +29,6 @@ use crate::{ service::OutputManagerService, storage::database::{OutputManagerBackend, OutputManagerDatabase}, }, - transaction_service::handle::TransactionServiceHandle, }; use futures::future; use log::*; @@ -114,13 +113,11 @@ where T: OutputManagerBackend + 'static let constants = self.network.create_consensus_constants().pop().unwrap(); let master_secret_key = self.master_secret_key.clone(); context.spawn_when_ready(move |handles| async move { - let transaction_service = handles.expect_handle::(); let base_node_service_handle = handles.expect_handle::(); let connectivity = handles.expect_handle::(); let service = OutputManagerService::new( config, - transaction_service, receiver, OutputManagerDatabase::new(backend), publisher, diff --git a/base_layer/wallet/src/output_manager_service/resources.rs b/base_layer/wallet/src/output_manager_service/resources.rs index d3cc7de414..ed19bf8749 100644 --- a/base_layer/wallet/src/output_manager_service/resources.rs +++ b/base_layer/wallet/src/output_manager_service/resources.rs @@ -20,14 +20,11 @@ // 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::{ - output_manager_service::{ - config::OutputManagerServiceConfig, - handle::OutputManagerEventSender, - storage::database::OutputManagerDatabase, - MasterKeyManager, - }, - transaction_service::handle::TransactionServiceHandle, +use crate::output_manager_service::{ + config::OutputManagerServiceConfig, + handle::OutputManagerEventSender, + storage::database::OutputManagerDatabase, + MasterKeyManager, }; use std::sync::Arc; use tari_core::{consensus::ConsensusConstants, transactions::CryptoFactories}; @@ -38,7 +35,6 @@ use tari_shutdown::ShutdownSignal; pub(crate) struct OutputManagerResources { pub config: OutputManagerServiceConfig, pub db: OutputManagerDatabase, - pub transaction_service: TransactionServiceHandle, pub factories: CryptoFactories, pub event_publisher: OutputManagerEventSender, pub master_key_manager: Arc>, diff --git a/base_layer/wallet/src/output_manager_service/service.rs b/base_layer/wallet/src/output_manager_service/service.rs index d015ef78a8..5bd54ac0ee 100644 --- a/base_layer/wallet/src/output_manager_service/service.rs +++ b/base_layer/wallet/src/output_manager_service/service.rs @@ -36,7 +36,6 @@ use crate::{ tasks::TxoValidationTask, MasterKeyManager, }, - transaction_service::handle::TransactionServiceHandle, types::HashDigest, }; use blake2::Digest; @@ -102,7 +101,6 @@ where #[allow(clippy::too_many_arguments)] pub async fn new( config: OutputManagerServiceConfig, - transaction_service: TransactionServiceHandle, request_stream: reply_channel::Receiver< OutputManagerRequest, Result, @@ -125,7 +123,6 @@ where let resources = OutputManagerResources { config, db, - transaction_service, factories, connectivity, event_publisher, diff --git a/base_layer/wallet/src/transaction_service/error.rs b/base_layer/wallet/src/transaction_service/error.rs index ef8cb153b6..6588624963 100644 --- a/base_layer/wallet/src/transaction_service/error.rs +++ b/base_layer/wallet/src/transaction_service/error.rs @@ -210,6 +210,8 @@ pub enum TransactionStorageError { AeadError(String), #[error("Transaction (TxId: '{0}') is not mined")] TransactionNotMined(TxId), + #[error("Conversion error: `{0}`")] + ByteArrayError(#[from] ByteArrayError), } /// This error type is used to return TransactionServiceErrors from inside a Transaction Service protocol but also diff --git a/base_layer/wallet/src/transaction_service/service.rs b/base_layer/wallet/src/transaction_service/service.rs index 907d1d2260..a41d1ef24b 100644 --- a/base_layer/wallet/src/transaction_service/service.rs +++ b/base_layer/wallet/src/transaction_service/service.rs @@ -1501,9 +1501,9 @@ where &mut self, join_handles: &mut FuturesUnordered>>, ) -> Result<(), TransactionServiceError> { - let inbound_txs = self.db.get_pending_inbound_transactions().await?; - for (tx_id, tx) in inbound_txs { - self.restart_receive_transaction_protocol(tx_id, tx.source_public_key.clone(), join_handles); + let inbound_txs = self.db.get_pending_inbound_transaction_sender_info().await?; + for txn in inbound_txs { + self.restart_receive_transaction_protocol(txn.tx_id, txn.source_public_key, join_handles); } Ok(()) @@ -1648,12 +1648,14 @@ where } trace!(target: LOG_TARGET, "Restarting transaction broadcast protocols"); - self.broadcast_all_completed_transactions(broadcast_join_handles) + self.broadcast_completed_and_broadcast_transactions(broadcast_join_handles) .await .map_err(|resp| { error!( target: LOG_TARGET, - "Error broadcasting all completed transactions: {:?}", resp + "Error broadcasting all valid and not cancelled Completed Transactions with status 'Completed' \ + and 'Broadcast': {:?}", + resp ); resp })?; @@ -1705,22 +1707,21 @@ where Ok(()) } - /// Go through all completed transactions that have not yet been broadcast and broadcast all of them to the base + /// Broadcast all valid and not cancelled completed transactions with status 'Completed' and 'Broadcast' to the base /// node. - async fn broadcast_all_completed_transactions( + async fn broadcast_completed_and_broadcast_transactions( &mut self, join_handles: &mut FuturesUnordered>>, ) -> Result<(), TransactionServiceError> { - trace!(target: LOG_TARGET, "Attempting to Broadcast all Completed Transactions"); - let completed_txs = self.db.get_completed_transactions().await?; - for (_, completed_tx) in completed_txs { - if completed_tx.valid && - (completed_tx.status == TransactionStatus::Completed || - completed_tx.status == TransactionStatus::Broadcast) && - !completed_tx.is_coinbase() - { - self.broadcast_completed_transaction(completed_tx, join_handles).await?; - } + trace!( + target: LOG_TARGET, + "Attempting to Broadcast all valid and not cancelled Completed Transactions with status 'Completed' and \ + 'Broadcast'" + ); + let txn_list = self.db.get_transactions_to_be_broadcast().await?; + for completed_txn in txn_list { + self.broadcast_completed_transaction(completed_txn, join_handles) + .await?; } Ok(()) diff --git a/base_layer/wallet/src/transaction_service/storage/database.rs b/base_layer/wallet/src/transaction_service/storage/database.rs index 631d745e18..2718afc7f5 100644 --- a/base_layer/wallet/src/transaction_service/storage/database.rs +++ b/base_layer/wallet/src/transaction_service/storage/database.rs @@ -22,7 +22,10 @@ use crate::transaction_service::{ error::TransactionStorageError, - storage::models::{CompletedTransaction, InboundTransaction, OutboundTransaction, WalletTransaction}, + storage::{ + models::{CompletedTransaction, InboundTransaction, OutboundTransaction, WalletTransaction}, + sqlite_db::InboundTransactionSenderInfo, + }, }; use aes_gcm::Aes256Gcm; use chrono::Utc; @@ -54,6 +57,8 @@ pub trait TransactionBackend: Send + Sync + Clone { fn fetch_unconfirmed_transactions(&self) -> Result, TransactionStorageError>; + fn get_transactions_to_be_broadcast(&self) -> Result, TransactionStorageError>; + /// Check if a record with the provided key exists in the backend. fn contains(&self, key: &DbKey) -> Result; /// Modify the state the of the backend with a write operation @@ -119,11 +124,14 @@ pub trait TransactionBackend: Send + Sync + Clone { num_confirmations: u64, is_confirmed: bool, ) -> Result<(), TransactionStorageError>; - /// Clears the mined block and height of a transaction fn set_transaction_as_unmined(&self, tx_id: TxId) -> Result<(), TransactionStorageError>; - + /// Mark all transactions as unvalidated fn mark_all_transactions_as_unvalidated(&self) -> Result<(), TransactionStorageError>; + /// Get transaction sender info for all pending inbound transactions + fn get_pending_inbound_transaction_sender_info( + &self, + ) -> Result, TransactionStorageError>; } #[derive(Clone, PartialEq)] @@ -424,6 +432,11 @@ where T: TransactionBackend + 'static self.db.fetch_unconfirmed_transactions() } + /// This method returns all completed transactions that must be broadcast + pub async fn get_transactions_to_be_broadcast(&self) -> Result, TransactionStorageError> { + self.db.get_transactions_to_be_broadcast() + } + pub async fn get_completed_transaction_cancelled_or_not( &self, tx_id: TxId, @@ -786,6 +799,20 @@ where T: TransactionBackend + 'static .map_err(|err| TransactionStorageError::BlockingTaskSpawnError(err.to_string()))??; Ok(()) } + + pub async fn get_pending_inbound_transaction_sender_info( + &self, + ) -> Result, TransactionStorageError> { + let db_clone = self.db.clone(); + + let t = tokio::task::spawn_blocking(move || match db_clone.get_pending_inbound_transaction_sender_info() { + Ok(v) => Ok(v), + Err(e) => log_error(DbKey::PendingInboundTransactions, e), + }) + .await + .map_err(|err| TransactionStorageError::BlockingTaskSpawnError(err.to_string()))??; + Ok(t) + } } impl Display for DbKey { 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 41a1819421..8f89cd89a4 100644 --- a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs +++ b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs @@ -1034,6 +1034,42 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { Ok(result) } + fn get_transactions_to_be_broadcast(&self) -> Result, TransactionStorageError> { + let start = Instant::now(); + let conn = self.database_connection.acquire_lock(); + 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) + .or(completed_transactions::status.eq(TransactionStatus::Broadcast as i32)), + ) + .filter( + completed_transactions::coinbase_block_height + .is_null() + .or(completed_transactions::coinbase_block_height.eq(0)), + ) + .filter(completed_transactions::cancelled.eq(false as i32)) + .order_by(completed_transactions::tx_id) + .load::(&*conn)?; + + let mut result = vec![]; + for mut tx in txs { + self.decrypt_if_necessary(&mut tx)?; + result.push(tx.try_into()?); + } + trace!( + target: LOG_TARGET, + "sqlite profile - get_transactions_to_be_broadcast: lock {} + db_op {} = {} ms", + acquire_lock.as_millis(), + (start.elapsed() - acquire_lock).as_millis(), + start.elapsed().as_millis() + ); + + Ok(result) + } + fn mark_all_transactions_as_unvalidated(&self) -> Result<(), TransactionStorageError> { let start = Instant::now(); let conn = self.database_connection.acquire_lock(); @@ -1080,6 +1116,67 @@ impl TransactionBackend for TransactionServiceSqliteDatabase { ); Ok(()) } + + fn get_pending_inbound_transaction_sender_info( + &self, + ) -> Result, TransactionStorageError> { + let start = Instant::now(); + let conn = self.database_connection.acquire_lock(); + let acquire_lock = start.elapsed(); + let mut sender_info: Vec = vec![]; + match InboundTransactionSenderInfoSql::get_pending_inbound_transaction_sender_info(&(*conn)) { + Ok(info) => { + for item in info { + sender_info.push(InboundTransactionSenderInfo::try_from(item)?); + } + }, + Err(e) => return Err(e), + } + trace!( + target: LOG_TARGET, + "sqlite profile - get_pending_inbound_transaction_sender_info: lock {} + db_op {} = {} ms", + acquire_lock.as_millis(), + (start.elapsed() - acquire_lock).as_millis(), + start.elapsed().as_millis() + ); + Ok(sender_info) + } +} + +#[derive(Debug, PartialEq)] +pub struct InboundTransactionSenderInfo { + pub(crate) tx_id: TxId, + pub(crate) source_public_key: CommsPublicKey, +} + +impl TryFrom for InboundTransactionSenderInfo { + type Error = TransactionStorageError; + + fn try_from(i: InboundTransactionSenderInfoSql) -> Result { + Ok(Self { + tx_id: TxId::from(i.tx_id as u64), + source_public_key: CommsPublicKey::from_bytes(&*i.source_public_key) + .map_err(TransactionStorageError::ByteArrayError)?, + }) + } +} + +#[derive(Clone, Queryable)] +pub struct InboundTransactionSenderInfoSql { + pub tx_id: i64, + pub source_public_key: Vec, +} + +impl InboundTransactionSenderInfoSql { + pub fn get_pending_inbound_transaction_sender_info( + conn: &SqliteConnection, + ) -> Result, TransactionStorageError> { + let query_result = inbound_transactions::table + .select((inbound_transactions::tx_id, inbound_transactions::source_public_key)) + .filter(inbound_transactions::cancelled.eq(false as i32)) + .load::(conn)?; + Ok(query_result) + } } #[derive(Clone, Debug, Queryable, Insertable, PartialEq)] @@ -1760,6 +1857,7 @@ mod test { models::{CompletedTransaction, InboundTransaction, OutboundTransaction}, sqlite_db::{ CompletedTransactionSql, + InboundTransactionSenderInfo, InboundTransactionSql, OutboundTransactionSql, TransactionServiceSqliteDatabase, @@ -2362,4 +2460,90 @@ mod test { assert!(db3.fetch(&DbKey::PendingOutboundTransactions).is_ok()); assert!(db3.fetch(&DbKey::CompletedTransactions).is_ok()); } + + #[test] + fn test_customized_transactional_queries() { + let db_name = format!("{}.sqlite3", string(8).as_str()); + let temp_dir = tempdir().unwrap(); + let db_folder = temp_dir.path().to_str().unwrap().to_string(); + let db_path = format!("{}{}", db_folder, db_name); + + embed_migrations!("./migrations"); + let conn = SqliteConnection::establish(&db_path).unwrap_or_else(|_| panic!("Error connecting to {}", db_path)); + + embedded_migrations::run_with_output(&conn, &mut std::io::stdout()).expect("Migration failed"); + + 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 completed_tx = CompletedTransaction { + tx_id: i, + source_public_key: PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), + destination_public_key: PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), + amount: MicroTari::from(100), + fee: MicroTari::from(100), + transaction: Transaction::new( + vec![], + vec![], + vec![], + PrivateKey::random(&mut OsRng), + PrivateKey::random(&mut OsRng), + ), + status, + message: "Yo!".to_string(), + timestamp: Utc::now().naive_utc(), + cancelled, + direction: TransactionDirection::Unknown, + coinbase_block_height, + send_count: 0, + last_send_timestamp: None, + valid, + confirmations: None, + mined_height: None, + mined_in_block: None, + }; + let completed_tx_sql = CompletedTransactionSql::try_from(completed_tx.clone()).unwrap(); + completed_tx_sql.commit(&conn).unwrap(); + + let inbound_tx = InboundTransaction::from(completed_tx); + let inbound_tx_sql = InboundTransactionSql::try_from(inbound_tx.clone()).unwrap(); + inbound_tx_sql.commit(&conn).unwrap(); + + if !cancelled { + info_list_reference.push(InboundTransactionSenderInfo { + tx_id: inbound_tx.tx_id, + source_public_key: inbound_tx.source_public_key, + }) + } + } + + let connection = WalletDbConnection::new(conn, None); + let db1 = TransactionServiceSqliteDatabase::new(connection, None); + + let txn_list = db1.get_transactions_to_be_broadcast().unwrap(); + assert_eq!(txn_list.len(), 185); + for txn in &txn_list { + assert!(txn.status == TransactionStatus::Completed || txn.status == TransactionStatus::Broadcast); + assert!(txn.valid); + assert!(!txn.cancelled); + assert!(txn.coinbase_block_height == None || txn.coinbase_block_height == Some(0)); + } + + let info_list = db1.get_pending_inbound_transaction_sender_info().unwrap(); + assert_eq!(info_list.len(), 941); + assert_eq!(info_list, info_list_reference); + } } diff --git a/base_layer/wallet/tests/output_manager_service/service.rs b/base_layer/wallet/tests/output_manager_service/service.rs index c0e8bf4dd2..f0dd38cef8 100644 --- a/base_layer/wallet/tests/output_manager_service/service.rs +++ b/base_layer/wallet/tests/output_manager_service/service.rs @@ -59,7 +59,7 @@ use tari_crypto::{ script::TariScript, }; use tari_p2p::Network; -use tari_service_framework::reply_channel; +use tari_service_framework::{reply_channel, reply_channel::SenderService}; use tari_shutdown::Shutdown; use tari_utilities::Hashable; use tari_wallet::{ @@ -156,7 +156,6 @@ async fn setup_output_manager_service( peer_dial_retry_timeout: Duration::from_secs(5), ..Default::default() }, - ts_handle.clone(), oms_request_receiver, OutputManagerDatabase::new(backend), oms_event_publisher.clone(), @@ -223,7 +222,6 @@ pub async fn setup_oms_with_bn_state( peer_dial_retry_timeout: Duration::from_secs(5), ..Default::default() }, - ts_handle.clone(), oms_request_receiver, OutputManagerDatabase::new(backend), oms_event_publisher.clone(), @@ -1395,6 +1393,23 @@ async fn test_txo_validation() { .await .unwrap(); + // This is needed on a fast computer, otherwise the balance have not been updated correctly yet with the next step + let mut event_stream = oms.get_event_stream(); + let delay = sleep(Duration::from_secs(10)); + tokio::pin!(delay); + loop { + tokio::select! { + event = event_stream.recv() => { + if let OutputManagerEvent::TxoValidationSuccess(_) = &*event.unwrap(){ + break; + } + }, + () = &mut delay => { + break; + }, + } + } + let balance = oms.get_balance().await.unwrap(); assert_eq!( balance.available_balance, @@ -1630,9 +1645,6 @@ async fn test_oms_key_manager_discrepancy() { let (_oms_request_sender, oms_request_receiver) = reply_channel::unbounded(); let (oms_event_publisher, _) = broadcast::channel(200); - let (ts_request_sender, _ts_request_receiver) = reply_channel::unbounded(); - let (event_publisher, _) = channel(100); - let ts_handle = TransactionServiceHandle::new(ts_request_sender, event_publisher); let constants = ConsensusConstantsBuilder::new(Network::Weatherwax).build(); let (sender, receiver_bns) = reply_channel::unbounded(); let (event_publisher_bns, _) = broadcast::channel(100); @@ -1651,7 +1663,6 @@ async fn test_oms_key_manager_discrepancy() { let output_manager_service = OutputManagerService::new( OutputManagerServiceConfig::default(), - ts_handle.clone(), oms_request_receiver, db.clone(), oms_event_publisher.clone(), @@ -1670,7 +1681,6 @@ async fn test_oms_key_manager_discrepancy() { let (_oms_request_sender2, oms_request_receiver2) = reply_channel::unbounded(); let output_manager_service2 = OutputManagerService::new( OutputManagerServiceConfig::default(), - ts_handle.clone(), oms_request_receiver2, db.clone(), oms_event_publisher.clone(), @@ -1689,7 +1699,6 @@ async fn test_oms_key_manager_discrepancy() { let master_key2 = CommsSecretKey::random(&mut OsRng); let output_manager_service3 = OutputManagerService::new( OutputManagerServiceConfig::default(), - ts_handle, oms_request_receiver3, db, oms_event_publisher, diff --git a/base_layer/wallet/tests/transaction_service/service.rs b/base_layer/wallet/tests/transaction_service/service.rs index 07cf1bb244..8275aad32d 100644 --- a/base_layer/wallet/tests/transaction_service/service.rs +++ b/base_layer/wallet/tests/transaction_service/service.rs @@ -335,7 +335,6 @@ pub fn setup_transaction_service_no_comms( let output_manager_service = runtime .block_on(OutputManagerService::new( OutputManagerServiceConfig::default(), - ts_handle.clone(), oms_request_receiver, oms_db, oms_event_publisher.clone(), diff --git a/base_layer/wallet_ffi/Cargo.toml b/base_layer/wallet_ffi/Cargo.toml index cad25e184c..104e936afb 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.19.0" +version = "0.20.0" edition = "2018" [dependencies] -tari_comms = { version = "^0.11", path = "../../comms", features = ["c_integration"]} -tari_comms_dht = { version = "^0.11", path = "../../comms/dht", default-features = false } +tari_comms = { version = "^0.12", path = "../../comms", features = ["c_integration"]} +tari_comms_dht = { version = "^0.12", 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.11", path = "../key_manager" } -tari_p2p = { version = "^0.11", path = "../p2p" } -tari_wallet = { version = "^0.11", path = "../wallet", features = ["c_integration"]} -tari_shutdown = { version = "^0.11", path = "../../infrastructure/shutdown" } +tari_key_manager = { version = "^0.12", path = "../key_manager" } +tari_p2p = { version = "^0.12", path = "../p2p" } +tari_wallet = { version = "^0.12", path = "../wallet", features = ["c_integration"]} +tari_shutdown = { version = "^0.12", path = "../../infrastructure/shutdown" } tari_utilities = "^0.3" chrono = { version = "0.4.6", features = ["serde"]} @@ -38,7 +38,7 @@ security-framework = "2.4.2" [dependencies.tari_core] path = "../../base_layer/core" -version = "^0.11" +version = "^0.12" default-features = false features = ["transactions"] @@ -49,6 +49,7 @@ crate-type = ["staticlib","cdylib"] tempfile = "3.1.0" lazy_static = "1.3.0" env_logger = "0.7.1" -tari_key_manager = { version = "^0.11", path = "../key_manager" } -tari_common_types = { version = "^0.11", path = "../../base_layer/common_types"} -tari_test_utils = { version = "^0.11", path = "../../infrastructure/test_utils"} +tari_key_manager = { version = "^0.12", path = "../key_manager" } +tari_common_types = { version = "^0.12", path = "../../base_layer/common_types"} +tari_test_utils = { version = "^0.12", 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 f9d517b567..a65158ae05 100644 --- a/base_layer/wallet_ffi/src/callback_handler.rs +++ b/base_layer/wallet_ffi/src/callback_handler.rs @@ -54,7 +54,10 @@ use tari_comms::types::CommsPublicKey; use tari_comms_dht::event::{DhtEvent, DhtEventReceiver}; use tari_shutdown::ShutdownSignal; use tari_wallet::{ - output_manager_service::handle::{OutputManagerEvent, OutputManagerEventReceiver}, + output_manager_service::{ + handle::{OutputManagerEvent, OutputManagerEventReceiver, OutputManagerHandle}, + service::Balance, + }, transaction_service::{ handle::{TransactionEvent, TransactionEventReceiver}, storage::{ @@ -88,14 +91,17 @@ where TBackend: TransactionBackend + 'static callback_store_and_forward_send_result: unsafe extern "C" fn(u64, bool), callback_transaction_cancellation: unsafe extern "C" fn(*mut CompletedTransaction), callback_txo_validation_complete: unsafe extern "C" fn(u64, u8), + callback_balance_updated: unsafe extern "C" fn(*mut Balance), callback_transaction_validation_complete: unsafe extern "C" fn(u64, u8), callback_saf_messages_received: unsafe extern "C" fn(), db: TransactionDatabase, transaction_service_event_stream: TransactionEventReceiver, output_manager_service_event_stream: OutputManagerEventReceiver, + output_manager_service: OutputManagerHandle, dht_event_stream: DhtEventReceiver, shutdown_signal: Option, comms_public_key: CommsPublicKey, + balance_cache: Balance, } #[allow(clippy::too_many_arguments)] @@ -106,6 +112,7 @@ where TBackend: TransactionBackend + 'static db: TransactionDatabase, transaction_service_event_stream: TransactionEventReceiver, output_manager_service_event_stream: OutputManagerEventReceiver, + output_manager_service: OutputManagerHandle, dht_event_stream: DhtEventReceiver, shutdown_signal: ShutdownSignal, comms_public_key: CommsPublicKey, @@ -119,6 +126,7 @@ where TBackend: TransactionBackend + 'static callback_store_and_forward_send_result: unsafe extern "C" fn(u64, bool), callback_transaction_cancellation: unsafe extern "C" fn(*mut CompletedTransaction), callback_txo_validation_complete: unsafe extern "C" fn(u64, u8), + callback_balance_updated: unsafe extern "C" fn(*mut Balance), callback_transaction_validation_complete: unsafe extern "C" fn(u64, u8), callback_saf_messages_received: unsafe extern "C" fn(), ) -> Self { @@ -162,6 +170,10 @@ where TBackend: TransactionBackend + 'static target: LOG_TARGET, "TxoValidationCompleteCallback -> Assigning Fn: {:?}", callback_txo_validation_complete ); + info!( + target: LOG_TARGET, + "BalanceUpdatedCallback -> Assigning Fn: {:?}", callback_balance_updated + ); info!( target: LOG_TARGET, "TransactionValidationCompleteCallback -> Assigning Fn: {:?}", callback_transaction_validation_complete @@ -182,14 +194,17 @@ where TBackend: TransactionBackend + 'static callback_store_and_forward_send_result, callback_transaction_cancellation, callback_txo_validation_complete, + callback_balance_updated, callback_transaction_validation_complete, callback_saf_messages_received, db, transaction_service_event_stream, output_manager_service_event_stream, + output_manager_service, dht_event_stream, shutdown_signal: Some(shutdown_signal), comms_public_key, + balance_cache: Balance::zero(), } } @@ -210,33 +225,43 @@ where TBackend: TransactionBackend + 'static match (*msg).clone() { TransactionEvent::ReceivedTransaction(tx_id) => { self.receive_transaction_event(tx_id).await; + self.trigger_balance_refresh().await; }, TransactionEvent::ReceivedTransactionReply(tx_id) => { self.receive_transaction_reply_event(tx_id).await; + self.trigger_balance_refresh().await; }, TransactionEvent::ReceivedFinalizedTransaction(tx_id) => { self.receive_finalized_transaction_event(tx_id).await; + self.trigger_balance_refresh().await; }, TransactionEvent::TransactionDirectSendResult(tx_id, result) => { self.receive_direct_send_result(tx_id, result); + self.trigger_balance_refresh().await; }, TransactionEvent::TransactionStoreForwardSendResult(tx_id, result) => { self.receive_store_and_forward_send_result(tx_id, result); + self.trigger_balance_refresh().await; }, - TransactionEvent::TransactionCancelled(tx_id) => { + TransactionEvent::TransactionCancelled(tx_id) => { self.receive_transaction_cancellation(tx_id).await; + self.trigger_balance_refresh().await; }, TransactionEvent::TransactionBroadcast(tx_id) => { self.receive_transaction_broadcast_event(tx_id).await; + self.trigger_balance_refresh().await; }, TransactionEvent::TransactionMined{tx_id, is_valid: _} => { self.receive_transaction_mined_event(tx_id).await; + self.trigger_balance_refresh().await; }, TransactionEvent::TransactionMinedUnconfirmed{tx_id, num_confirmations, is_valid: _} => { self.receive_transaction_mined_unconfirmed_event(tx_id, num_confirmations).await; + self.trigger_balance_refresh().await; }, TransactionEvent::TransactionValidationSuccess(tx_id) => { self.transaction_validation_complete_event(tx_id, CallbackValidationResults::Success); + self.trigger_balance_refresh().await; }, TransactionEvent::TransactionValidationFailure(tx_id) => { self.transaction_validation_complete_event(tx_id, CallbackValidationResults::Failure); @@ -247,6 +272,12 @@ where TBackend: TransactionBackend + 'static TransactionEvent::TransactionValidationDelayed(tx_id) => { self.transaction_validation_complete_event(tx_id, CallbackValidationResults::BaseNodeNotInSync); }, + TransactionEvent::TransactionMinedRequestTimedOut(_tx_id) | + TransactionEvent::TransactionImported(_tx_id) | + TransactionEvent::TransactionCompletedImmediately(_tx_id) + => { + self.trigger_balance_refresh().await; + }, // Only the above variants are mapped to callbacks _ => (), } @@ -261,6 +292,7 @@ where TBackend: TransactionBackend + 'static match (*msg).clone() { OutputManagerEvent::TxoValidationSuccess(request_key) => { self.output_validation_complete_event(request_key, CallbackValidationResults::Success); + self.trigger_balance_refresh().await; }, OutputManagerEvent::TxoValidationFailure(request_key) => { self.output_validation_complete_event(request_key, CallbackValidationResults::Failure); @@ -348,6 +380,32 @@ where TBackend: TransactionBackend + 'static } } + async fn trigger_balance_refresh(&mut self) { + match self.output_manager_service.get_balance().await { + Ok(balance) => { + if balance != self.balance_cache { + self.balance_cache = balance.clone(); + debug!( + target: LOG_TARGET, + "Calling Update Balance callback function: available {}, time locked {:?}, incoming {}, \ + outgoing {}", + balance.available_balance, + balance.time_locked_balance, + balance.pending_incoming_balance, + balance.pending_outgoing_balance + ); + let boxing = Box::into_raw(Box::new(balance)); + unsafe { + (self.callback_balance_updated)(boxing); + } + } + }, + Err(e) => { + error!(target: LOG_TARGET, "Could not obtain balance ({:?})", e); + }, + } + } + fn receive_direct_send_result(&mut self, tx_id: TxId, result: bool) { debug!( target: LOG_TARGET, @@ -517,410 +575,3 @@ where TBackend: TransactionBackend + 'static } } } - -#[cfg(test)] -mod test { - use crate::callback_handler::CallbackHandler; - use chrono::Utc; - use rand::rngs::OsRng; - use std::{ - sync::{Arc, Mutex}, - thread, - time::Duration, - }; - use tari_common_types::{ - transaction::{TransactionDirection, TransactionStatus}, - types::{BlindingFactor, PrivateKey, PublicKey}, - }; - use tari_comms_dht::event::DhtEvent; - use tari_core::transactions::{ - tari_amount::{uT, MicroTari}, - transaction::Transaction, - ReceiverTransactionProtocol, - SenderTransactionProtocol, - }; - use tari_crypto::keys::{PublicKey as PublicKeyTrait, SecretKey}; - use tari_shutdown::Shutdown; - use tari_wallet::{ - output_manager_service::handle::OutputManagerEvent, - test_utils::make_wallet_database_connection, - transaction_service::{ - handle::TransactionEvent, - storage::{ - database::TransactionDatabase, - models::{CompletedTransaction, InboundTransaction, OutboundTransaction}, - sqlite_db::TransactionServiceSqliteDatabase, - }, - }, - }; - use tokio::{runtime::Runtime, sync::broadcast}; - - struct CallbackState { - pub received_tx_callback_called: bool, - pub received_tx_reply_callback_called: bool, - pub received_finalized_tx_callback_called: bool, - pub broadcast_tx_callback_called: bool, - pub mined_tx_callback_called: bool, - pub mined_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, - pub tx_cancellation_callback_called_inbound: bool, - pub tx_cancellation_callback_called_outbound: bool, - pub callback_txo_validation_complete: u32, - pub callback_transaction_validation_complete: u32, - pub saf_messages_received: bool, - } - - impl CallbackState { - fn new() -> Self { - Self { - received_tx_callback_called: false, - received_tx_reply_callback_called: false, - received_finalized_tx_callback_called: false, - broadcast_tx_callback_called: false, - mined_tx_callback_called: false, - mined_tx_unconfirmed_callback_called: 0, - direct_send_callback_called: false, - store_and_forward_send_callback_called: false, - callback_txo_validation_complete: 0, - callback_transaction_validation_complete: 0, - tx_cancellation_callback_called_completed: false, - tx_cancellation_callback_called_inbound: false, - tx_cancellation_callback_called_outbound: false, - saf_messages_received: false, - } - } - } - - lazy_static! { - static ref CALLBACK_STATE: Mutex = Mutex::new(CallbackState::new()); - } - - unsafe extern "C" fn received_tx_callback(tx: *mut InboundTransaction) { - let mut lock = CALLBACK_STATE.lock().unwrap(); - lock.received_tx_callback_called = true; - drop(lock); - Box::from_raw(tx); - } - - unsafe extern "C" fn received_tx_reply_callback(tx: *mut CompletedTransaction) { - let mut lock = CALLBACK_STATE.lock().unwrap(); - lock.received_tx_reply_callback_called = true; - drop(lock); - Box::from_raw(tx); - } - - unsafe extern "C" fn received_tx_finalized_callback(tx: *mut CompletedTransaction) { - let mut lock = CALLBACK_STATE.lock().unwrap(); - lock.received_finalized_tx_callback_called = true; - drop(lock); - Box::from_raw(tx); - } - - unsafe extern "C" fn broadcast_callback(tx: *mut CompletedTransaction) { - let mut lock = CALLBACK_STATE.lock().unwrap(); - lock.broadcast_tx_callback_called = true; - drop(lock); - Box::from_raw(tx); - } - - unsafe extern "C" fn mined_callback(tx: *mut CompletedTransaction) { - let mut lock = CALLBACK_STATE.lock().unwrap(); - lock.mined_tx_callback_called = true; - drop(lock); - Box::from_raw(tx); - } - - unsafe extern "C" fn mined_unconfirmed_callback(tx: *mut CompletedTransaction, confirmations: u64) { - let mut lock = CALLBACK_STATE.lock().unwrap(); - lock.mined_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; - drop(lock); - } - - unsafe extern "C" fn store_and_forward_send_callback(_tx_id: u64, _result: bool) { - let mut lock = CALLBACK_STATE.lock().unwrap(); - lock.store_and_forward_send_callback_called = true; - drop(lock); - } - - unsafe extern "C" fn saf_messages_received_callback() { - let mut lock = CALLBACK_STATE.lock().unwrap(); - lock.saf_messages_received = true; - drop(lock); - } - - unsafe extern "C" fn tx_cancellation_callback(tx: *mut CompletedTransaction) { - let mut lock = CALLBACK_STATE.lock().unwrap(); - match (*tx).tx_id.as_u64() { - 3 => lock.tx_cancellation_callback_called_inbound = true, - 4 => lock.tx_cancellation_callback_called_completed = true, - 5 => lock.tx_cancellation_callback_called_outbound = true, - _ => (), - } - - drop(lock); - Box::from_raw(tx); - } - - unsafe extern "C" fn txo_validation_complete_callback(_tx_id: u64, result: u8) { - let mut lock = CALLBACK_STATE.lock().unwrap(); - - lock.callback_txo_validation_complete += result as u32; - - drop(lock); - } - - unsafe extern "C" fn transaction_validation_complete_callback(_tx_id: u64, result: u8) { - let mut lock = CALLBACK_STATE.lock().unwrap(); - - lock.callback_transaction_validation_complete += result as u32; - - drop(lock); - } - - #[test] - fn test_callback_handler() { - let runtime = Runtime::new().unwrap(); - - let (connection, _tempdir) = make_wallet_database_connection(None); - let db = TransactionDatabase::new(TransactionServiceSqliteDatabase::new(connection, None)); - let rtp = ReceiverTransactionProtocol::new_placeholder(); - let inbound_tx = InboundTransaction::new( - 1.into(), - PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), - 22 * uT, - rtp, - TransactionStatus::Pending, - "1".to_string(), - Utc::now().naive_utc(), - ); - let completed_tx = CompletedTransaction::new( - 2.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::Completed, - "2".to_string(), - Utc::now().naive_utc(), - TransactionDirection::Inbound, - None, - ); - let stp = SenderTransactionProtocol::new_placeholder(); - let outbound_tx = OutboundTransaction::new( - 3.into(), - PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), - 22 * uT, - 23 * uT, - stp, - TransactionStatus::Pending, - "3".to_string(), - Utc::now().naive_utc(), - false, - ); - let inbound_tx_cancelled = InboundTransaction { - tx_id: 4.into(), - ..inbound_tx.clone() - }; - let completed_tx_cancelled = CompletedTransaction { - tx_id: 5.into(), - ..completed_tx.clone() - }; - - runtime - .block_on(db.add_pending_inbound_transaction(1.into(), inbound_tx)) - .unwrap(); - runtime - .block_on(db.insert_completed_transaction(2.into(), completed_tx)) - .unwrap(); - runtime - .block_on(db.add_pending_inbound_transaction(4.into(), inbound_tx_cancelled)) - .unwrap(); - runtime.block_on(db.cancel_pending_transaction(4.into())).unwrap(); - runtime - .block_on(db.insert_completed_transaction(5.into(), completed_tx_cancelled)) - .unwrap(); - runtime.block_on(db.cancel_completed_transaction(5.into())).unwrap(); - runtime - .block_on(db.add_pending_outbound_transaction(3.into(), outbound_tx)) - .unwrap(); - runtime.block_on(db.cancel_pending_transaction(3.into())).unwrap(); - - let (tx_sender, tx_receiver) = broadcast::channel(20); - let (oms_sender, oms_receiver) = broadcast::channel(20); - let (dht_sender, dht_receiver) = broadcast::channel(20); - - let shutdown_signal = Shutdown::new(); - let callback_handler = CallbackHandler::new( - db, - tx_receiver, - oms_receiver, - dht_receiver, - shutdown_signal.to_signal(), - PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), - received_tx_callback, - received_tx_reply_callback, - received_tx_finalized_callback, - broadcast_callback, - mined_callback, - mined_unconfirmed_callback, - direct_send_callback, - store_and_forward_send_callback, - tx_cancellation_callback, - txo_validation_complete_callback, - transaction_validation_complete_callback, - saf_messages_received_callback, - ); - - runtime.spawn(callback_handler.start()); - - tx_sender - .send(Arc::new(TransactionEvent::ReceivedTransaction(1.into()))) - .unwrap(); - tx_sender - .send(Arc::new(TransactionEvent::ReceivedTransactionReply(2.into()))) - .unwrap(); - tx_sender - .send(Arc::new(TransactionEvent::ReceivedFinalizedTransaction(2.into()))) - .unwrap(); - tx_sender - .send(Arc::new(TransactionEvent::TransactionBroadcast(2.into()))) - .unwrap(); - tx_sender - .send(Arc::new(TransactionEvent::TransactionMined { - tx_id: 2.into(), - is_valid: true, - })) - .unwrap(); - - tx_sender - .send(Arc::new(TransactionEvent::TransactionMinedUnconfirmed { - tx_id: 2.into(), - num_confirmations: 22u64, - is_valid: true, - })) - .unwrap(); - - tx_sender - .send(Arc::new(TransactionEvent::TransactionDirectSendResult(2.into(), true))) - .unwrap(); - tx_sender - .send(Arc::new(TransactionEvent::TransactionStoreForwardSendResult( - 2.into(), - true, - ))) - .unwrap(); - tx_sender - .send(Arc::new(TransactionEvent::TransactionCancelled(3.into()))) - .unwrap(); - tx_sender - .send(Arc::new(TransactionEvent::TransactionCancelled(4.into()))) - .unwrap(); - tx_sender - .send(Arc::new(TransactionEvent::TransactionCancelled(5.into()))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationSuccess(1u64))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationSuccess(1u64))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationSuccess(1u64))) - .unwrap(); - - tx_sender - .send(Arc::new(TransactionEvent::TransactionValidationSuccess(1.into()))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationFailure(1u64))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationFailure(1u64))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationFailure(1u64))) - .unwrap(); - - tx_sender - .send(Arc::new(TransactionEvent::TransactionValidationFailure(1.into()))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationAborted(1u64))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationAborted(1u64))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationAborted(1u64))) - .unwrap(); - - tx_sender - .send(Arc::new(TransactionEvent::TransactionValidationAborted(1.into()))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationDelayed(1u64))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationDelayed(1u64))) - .unwrap(); - - oms_sender - .send(Arc::new(OutputManagerEvent::TxoValidationDelayed(1u64))) - .unwrap(); - - tx_sender - .send(Arc::new(TransactionEvent::TransactionValidationDelayed(1.into()))) - .unwrap(); - - dht_sender - .send(Arc::new(DhtEvent::StoreAndForwardMessagesReceived)) - .unwrap(); - - thread::sleep(Duration::from_secs(10)); - - let lock = CALLBACK_STATE.lock().unwrap(); - assert!(lock.received_tx_callback_called); - assert!(lock.received_tx_reply_callback_called); - assert!(lock.received_finalized_tx_callback_called); - assert!(lock.broadcast_tx_callback_called); - assert!(lock.mined_tx_callback_called); - assert_eq!(lock.mined_tx_unconfirmed_callback_called, 22u64); - assert!(lock.direct_send_callback_called); - assert!(lock.store_and_forward_send_callback_called); - assert!(lock.tx_cancellation_callback_called_inbound); - assert!(lock.tx_cancellation_callback_called_completed); - assert!(lock.tx_cancellation_callback_called_outbound); - assert!(lock.saf_messages_received); - assert_eq!(lock.callback_txo_validation_complete, 18); - assert_eq!(lock.callback_transaction_validation_complete, 6); - - drop(lock); - } -} diff --git a/base_layer/wallet_ffi/src/callback_handler_tests.rs b/base_layer/wallet_ffi/src/callback_handler_tests.rs new file mode 100644 index 0000000000..a140a49225 --- /dev/null +++ b/base_layer/wallet_ffi/src/callback_handler_tests.rs @@ -0,0 +1,542 @@ +// Copyright 2019. 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. + +#[cfg(test)] +mod test { + use crate::{callback_handler::CallbackHandler, output_manager_service_mock::MockOutputManagerService}; + use chrono::Utc; + use rand::rngs::OsRng; + use std::{ + sync::{Arc, Mutex}, + thread, + time::Duration, + }; + use tari_common_types::{ + transaction::{TransactionDirection, TransactionStatus}, + types::{BlindingFactor, PrivateKey, PublicKey}, + }; + use tari_comms_dht::event::DhtEvent; + use tari_core::transactions::{ + tari_amount::{uT, MicroTari}, + transaction::Transaction, + ReceiverTransactionProtocol, + SenderTransactionProtocol, + }; + use tari_crypto::keys::{PublicKey as PublicKeyTrait, SecretKey}; + use tari_service_framework::reply_channel; + use tari_shutdown::Shutdown; + use tari_wallet::{ + output_manager_service::{ + handle::{OutputManagerEvent, OutputManagerHandle}, + service::Balance, + }, + test_utils::make_wallet_database_connection, + transaction_service::{ + handle::TransactionEvent, + storage::{ + database::TransactionDatabase, + models::{CompletedTransaction, InboundTransaction, OutboundTransaction}, + sqlite_db::TransactionServiceSqliteDatabase, + }, + }, + }; + use tokio::{runtime::Runtime, sync::broadcast, time::Instant}; + + struct CallbackState { + pub received_tx_callback_called: bool, + pub received_tx_reply_callback_called: bool, + pub received_finalized_tx_callback_called: bool, + pub broadcast_tx_callback_called: bool, + pub mined_tx_callback_called: bool, + pub mined_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, + pub tx_cancellation_callback_called_inbound: bool, + pub tx_cancellation_callback_called_outbound: bool, + pub callback_txo_validation_complete: u32, + pub callback_balance_updated: u32, + pub callback_transaction_validation_complete: u32, + pub saf_messages_received: bool, + } + + impl CallbackState { + fn new() -> Self { + Self { + received_tx_callback_called: false, + received_tx_reply_callback_called: false, + received_finalized_tx_callback_called: false, + broadcast_tx_callback_called: false, + mined_tx_callback_called: false, + mined_tx_unconfirmed_callback_called: 0, + direct_send_callback_called: false, + store_and_forward_send_callback_called: false, + callback_txo_validation_complete: 0, + callback_balance_updated: 0, + callback_transaction_validation_complete: 0, + tx_cancellation_callback_called_completed: false, + tx_cancellation_callback_called_inbound: false, + tx_cancellation_callback_called_outbound: false, + saf_messages_received: false, + } + } + } + + lazy_static! { + static ref CALLBACK_STATE: Mutex = Mutex::new(CallbackState::new()); + } + + unsafe extern "C" fn received_tx_callback(tx: *mut InboundTransaction) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.received_tx_callback_called = true; + drop(lock); + Box::from_raw(tx); + } + + unsafe extern "C" fn received_tx_reply_callback(tx: *mut CompletedTransaction) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.received_tx_reply_callback_called = true; + drop(lock); + Box::from_raw(tx); + } + + unsafe extern "C" fn received_tx_finalized_callback(tx: *mut CompletedTransaction) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.received_finalized_tx_callback_called = true; + drop(lock); + Box::from_raw(tx); + } + + unsafe extern "C" fn broadcast_callback(tx: *mut CompletedTransaction) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.broadcast_tx_callback_called = true; + drop(lock); + Box::from_raw(tx); + } + + unsafe extern "C" fn mined_callback(tx: *mut CompletedTransaction) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.mined_tx_callback_called = true; + drop(lock); + Box::from_raw(tx); + } + + unsafe extern "C" fn mined_unconfirmed_callback(tx: *mut CompletedTransaction, confirmations: u64) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.mined_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; + drop(lock); + } + + unsafe extern "C" fn store_and_forward_send_callback(_tx_id: u64, _result: bool) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.store_and_forward_send_callback_called = true; + drop(lock); + } + + unsafe extern "C" fn saf_messages_received_callback() { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.saf_messages_received = true; + drop(lock); + } + + unsafe extern "C" fn tx_cancellation_callback(tx: *mut CompletedTransaction) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + match (*tx).tx_id { + 3 => lock.tx_cancellation_callback_called_inbound = true, + 4 => lock.tx_cancellation_callback_called_completed = true, + 5 => lock.tx_cancellation_callback_called_outbound = true, + _ => (), + } + drop(lock); + Box::from_raw(tx); + } + + unsafe extern "C" fn txo_validation_complete_callback(_tx_id: u64, result: u8) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.callback_txo_validation_complete += result as u32; + drop(lock); + } + + unsafe extern "C" fn balance_updated_callback(balance: *mut Balance) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.callback_balance_updated += 1; + drop(lock); + Box::from_raw(balance); + } + + unsafe extern "C" fn transaction_validation_complete_callback(_tx_id: u64, result: u8) { + let mut lock = CALLBACK_STATE.lock().unwrap(); + lock.callback_transaction_validation_complete += result as u32; + drop(lock); + } + + #[test] + fn test_callback_handler() { + let runtime = Runtime::new().unwrap(); + + let (connection, _tempdir) = make_wallet_database_connection(None); + let db = TransactionDatabase::new(TransactionServiceSqliteDatabase::new(connection, None)); + + let rtp = ReceiverTransactionProtocol::new_placeholder(); + let inbound_tx = InboundTransaction::new( + 1u64, + PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), + 22 * uT, + rtp, + TransactionStatus::Pending, + "1".to_string(), + Utc::now().naive_utc(), + ); + let completed_tx = CompletedTransaction::new( + 2u64, + 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::Completed, + "2".to_string(), + Utc::now().naive_utc(), + TransactionDirection::Inbound, + None, + ); + let stp = SenderTransactionProtocol::new_placeholder(); + let outbound_tx = OutboundTransaction::new( + 3u64, + PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), + 22 * uT, + 23 * uT, + stp, + TransactionStatus::Pending, + "3".to_string(), + Utc::now().naive_utc(), + false, + ); + let inbound_tx_cancelled = InboundTransaction { + tx_id: 4u64, + ..inbound_tx.clone() + }; + let completed_tx_cancelled = CompletedTransaction { + tx_id: 5u64, + ..completed_tx.clone() + }; + + runtime + .block_on(db.add_pending_inbound_transaction(1u64, inbound_tx.clone())) + .unwrap(); + runtime + .block_on(db.insert_completed_transaction(2u64, completed_tx.clone())) + .unwrap(); + runtime + .block_on(db.add_pending_inbound_transaction(4u64, inbound_tx_cancelled)) + .unwrap(); + runtime.block_on(db.cancel_pending_transaction(4u64)).unwrap(); + runtime + .block_on(db.insert_completed_transaction(5u64, completed_tx_cancelled.clone())) + .unwrap(); + runtime.block_on(db.cancel_completed_transaction(5u64)).unwrap(); + runtime + .block_on(db.add_pending_outbound_transaction(3u64, outbound_tx.clone())) + .unwrap(); + runtime.block_on(db.cancel_pending_transaction(3u64)).unwrap(); + + let (transaction_event_sender, transaction_event_receiver) = broadcast::channel(20); + let (oms_event_sender, oms_event_receiver) = broadcast::channel(20); + let (dht_event_sender, dht_event_receiver) = broadcast::channel(20); + + let (oms_request_sender, oms_request_receiver) = reply_channel::unbounded(); + let mut oms_handle = OutputManagerHandle::new(oms_request_sender, oms_event_sender.clone()); + + let shutdown_signal = Shutdown::new(); + let mut mock_output_manager_service = + MockOutputManagerService::new(oms_request_receiver, shutdown_signal.to_signal()); + let mut balance = Balance { + available_balance: completed_tx.amount + + completed_tx.fee + + completed_tx_cancelled.amount + + completed_tx_cancelled.fee, + time_locked_balance: None, + pending_incoming_balance: inbound_tx.amount, + pending_outgoing_balance: outbound_tx.amount + outbound_tx.fee, + }; + let mut mock_output_manager_service_state = mock_output_manager_service.get_response_state(); + mock_output_manager_service_state.set_balance(balance.clone()); + runtime.spawn(mock_output_manager_service.run()); + assert_eq!(balance, runtime.block_on(oms_handle.get_balance()).unwrap()); + + let callback_handler = CallbackHandler::new( + db, + transaction_event_receiver, + oms_event_receiver, + oms_handle, + dht_event_receiver, + shutdown_signal.to_signal(), + PublicKey::from_secret_key(&PrivateKey::random(&mut OsRng)), + received_tx_callback, + received_tx_reply_callback, + received_tx_finalized_callback, + broadcast_callback, + mined_callback, + mined_unconfirmed_callback, + direct_send_callback, + store_and_forward_send_callback, + tx_cancellation_callback, + txo_validation_complete_callback, + balance_updated_callback, + transaction_validation_complete_callback, + saf_messages_received_callback, + ); + + runtime.spawn(callback_handler.start()); + let mut callback_balance_updated = 0; + + // The balance updated callback is bundled with other callbacks and will only fire if the balance actually + // changed from an initial zero balance. + // Balance updated should be detected with following event, total = 1 times + transaction_event_sender + .send(Arc::new(TransactionEvent::ReceivedTransaction(1u64))) + .unwrap(); + let start = Instant::now(); + while start.elapsed().as_secs() < 10 { + { + let lock = CALLBACK_STATE.lock().unwrap(); + if lock.callback_balance_updated == 1 { + callback_balance_updated = 1; + break; + } + } + thread::sleep(Duration::from_millis(100)); + } + assert_eq!(callback_balance_updated, 1); + + balance.time_locked_balance = Some(completed_tx_cancelled.amount); + mock_output_manager_service_state.set_balance(balance.clone()); + // Balance updated should be detected with following event, total = 2 times + transaction_event_sender + .send(Arc::new(TransactionEvent::ReceivedTransactionReply(2u64))) + .unwrap(); + let start = Instant::now(); + while start.elapsed().as_secs() < 10 { + { + let lock = CALLBACK_STATE.lock().unwrap(); + if lock.callback_balance_updated == 2 { + callback_balance_updated = 2; + break; + } + } + thread::sleep(Duration::from_millis(100)); + } + assert_eq!(callback_balance_updated, 2); + + balance.pending_incoming_balance += inbound_tx.amount; + mock_output_manager_service_state.set_balance(balance.clone()); + // Balance updated should be detected with following event, total = 3 times + transaction_event_sender + .send(Arc::new(TransactionEvent::ReceivedFinalizedTransaction(2u64))) + .unwrap(); + let start = Instant::now(); + while start.elapsed().as_secs() < 10 { + { + let lock = CALLBACK_STATE.lock().unwrap(); + if lock.callback_balance_updated == 3 { + callback_balance_updated = 3; + break; + } + } + thread::sleep(Duration::from_millis(100)); + } + assert_eq!(callback_balance_updated, 3); + + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionBroadcast(2u64))) + .unwrap(); + + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionMined { + tx_id: 2u64, + is_valid: true, + })) + .unwrap(); + + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionMinedUnconfirmed { + tx_id: 2u64, + num_confirmations: 22u64, + is_valid: true, + })) + .unwrap(); + + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionDirectSendResult(2u64, true))) + .unwrap(); + + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionStoreForwardSendResult( + 2u64, true, + ))) + .unwrap(); + + balance.pending_outgoing_balance += outbound_tx.amount; + mock_output_manager_service_state.set_balance(balance.clone()); + // Balance updated should be detected with following event, total = 4 times + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionCancelled(3u64))) + .unwrap(); + let start = Instant::now(); + while start.elapsed().as_secs() < 10 { + { + let lock = CALLBACK_STATE.lock().unwrap(); + if lock.callback_balance_updated == 4 { + callback_balance_updated = 4; + break; + } + } + thread::sleep(Duration::from_millis(100)); + } + assert_eq!(callback_balance_updated, 4); + + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionCancelled(4u64))) + .unwrap(); + + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionCancelled(5u64))) + .unwrap(); + + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationSuccess(1u64))) + .unwrap(); + + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationSuccess(1u64))) + .unwrap(); + + balance.available_balance -= completed_tx_cancelled.amount; + mock_output_manager_service_state.set_balance(balance); + // Balance updated should be detected with following event, total = 5 times + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationSuccess(1u64))) + .unwrap(); + let start = Instant::now(); + while start.elapsed().as_secs() < 10 { + { + let lock = CALLBACK_STATE.lock().unwrap(); + if lock.callback_balance_updated == 5 { + callback_balance_updated = 5; + break; + } + } + thread::sleep(Duration::from_millis(100)); + } + assert_eq!(callback_balance_updated, 5); + + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionValidationSuccess(1u64))) + .unwrap(); + + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationFailure(1u64))) + .unwrap(); + + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationFailure(1u64))) + .unwrap(); + + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationFailure(1u64))) + .unwrap(); + + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionValidationFailure(1u64))) + .unwrap(); + + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationAborted(1u64))) + .unwrap(); + + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationAborted(1u64))) + .unwrap(); + + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationAborted(1u64))) + .unwrap(); + + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionValidationAborted(1u64))) + .unwrap(); + + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationDelayed(1u64))) + .unwrap(); + + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationDelayed(1u64))) + .unwrap(); + + oms_event_sender + .send(Arc::new(OutputManagerEvent::TxoValidationDelayed(1u64))) + .unwrap(); + + transaction_event_sender + .send(Arc::new(TransactionEvent::TransactionValidationDelayed(1u64))) + .unwrap(); + + dht_event_sender + .send(Arc::new(DhtEvent::StoreAndForwardMessagesReceived)) + .unwrap(); + + thread::sleep(Duration::from_secs(10)); + + let lock = CALLBACK_STATE.lock().unwrap(); + assert!(lock.received_tx_callback_called); + assert!(lock.received_tx_reply_callback_called); + assert!(lock.received_finalized_tx_callback_called); + assert!(lock.broadcast_tx_callback_called); + assert!(lock.mined_tx_callback_called); + assert_eq!(lock.mined_tx_unconfirmed_callback_called, 22u64); + assert!(lock.direct_send_callback_called); + assert!(lock.store_and_forward_send_callback_called); + assert!(lock.tx_cancellation_callback_called_inbound); + assert!(lock.tx_cancellation_callback_called_completed); + assert!(lock.tx_cancellation_callback_called_outbound); + assert!(lock.saf_messages_received); + assert_eq!(lock.callback_txo_validation_complete, 18); + assert_eq!(lock.callback_balance_updated, 5); + assert_eq!(lock.callback_transaction_validation_complete, 6); + + drop(lock); + } +} diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index d9839b2d9b..fa15c278e6 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -22,7 +22,7 @@ #![cfg_attr(not(debug_assertions), deny(unused_variables))] #![cfg_attr(not(debug_assertions), deny(unused_imports))] -#![cfg_attr(not(debug_assertions), deny(dead_code))] +#![warn(dead_code)] #![cfg_attr(not(debug_assertions), deny(unused_extern_crates))] #![deny(unused_must_use)] #![deny(unreachable_patterns)] @@ -193,8 +193,12 @@ use tari_wallet::{ }; mod callback_handler; +#[cfg(test)] +mod callback_handler_tests; mod enums; mod error; +#[cfg(test)] +mod output_manager_service_mock; mod tasks; const LOG_TARGET: &str = "wallet_ffi"; @@ -209,6 +213,7 @@ pub struct TariContacts(Vec); pub type TariContact = tari_wallet::contacts_service::storage::database::Contact; pub type TariCompletedTransaction = tari_wallet::transaction_service::storage::models::CompletedTransaction; +pub type TariBalance = tari_wallet::output_manager_service::service::Balance; pub struct TariCompletedTransactions(Vec); @@ -2729,6 +2734,8 @@ unsafe fn init_logging(log_path: *const c_char, num_rolling_log_files: c_uint, s /// `callback_txo_validation_complete` - The callback function pointer matching the function signature. This is called /// when a TXO validation process is completed. The request_key is used to identify which request this /// callback references and the second parameter is a u8 that represent the ClassbackValidationResults enum. +/// `callback_balance_updated` - The callback function pointer matching the function signature. This is called whenever +/// the balance changes. /// `callback_transaction_validation_complete` - The callback function pointer matching the function signature. This is /// called when a Transaction validation process is completed. The request_key is used to identify which request this /// callback references and the second parameter is a u8 that represent the ClassbackValidationResults enum. @@ -2764,6 +2771,7 @@ pub unsafe extern "C" fn wallet_create( callback_store_and_forward_send_result: unsafe extern "C" fn(c_ulonglong, bool), callback_transaction_cancellation: unsafe extern "C" fn(*mut TariCompletedTransaction), callback_txo_validation_complete: unsafe extern "C" fn(u64, u8), + callback_balance_updated: unsafe extern "C" fn(*mut TariBalance), callback_transaction_validation_complete: unsafe extern "C" fn(u64, u8), callback_saf_messages_received: unsafe extern "C" fn(), recovery_in_progress: *mut bool, @@ -2898,6 +2906,7 @@ pub unsafe extern "C" fn wallet_create( TransactionDatabase::new(transaction_backend), w.transaction_service.get_event_stream(), w.output_manager_service.get_event_stream(), + w.output_manager_service.clone(), w.dht_service.subscribe_dht_events(), w.comms.shutdown_signal(), w.comms.node_identity().public_key().clone(), @@ -2911,6 +2920,7 @@ pub unsafe extern "C" fn wallet_create( callback_store_and_forward_send_result, callback_transaction_cancellation, callback_txo_validation_complete, + callback_balance_updated, callback_transaction_validation_complete, callback_saf_messages_received, ); @@ -3225,6 +3235,128 @@ pub unsafe extern "C" fn wallet_remove_contact( } } +/// Gets the available balance from a TariBalance. This is the balance the user can spend. +/// +/// ## Arguments +/// `balance` - The TariBalance pointer +/// `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_ulonglong` - The available balance, 0 if wallet is null +/// +/// # Safety +/// None +#[no_mangle] +pub unsafe extern "C" fn balance_get_available(balance: *mut TariBalance, error_out: *mut c_int) -> c_ulonglong { + let mut error = 0; + ptr::swap(error_out, &mut error as *mut c_int); + if balance.is_null() { + error = LibWalletError::from(InterfaceError::NullError("balance".to_string())).code; + ptr::swap(error_out, &mut error as *mut c_int); + return 0; + } + + c_ulonglong::from((*balance).available_balance) +} + +/// Gets the time locked balance from a TariBalance. This is the balance the user can spend. +/// +/// ## Arguments +/// `balance` - The TariBalance pointer +/// `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_ulonglong` - The time locked balance, 0 if wallet is null +/// +/// # Safety +/// None +#[no_mangle] +pub unsafe extern "C" fn balance_get_time_locked(balance: *mut TariBalance, error_out: *mut c_int) -> c_ulonglong { + let mut error = 0; + ptr::swap(error_out, &mut error as *mut c_int); + if balance.is_null() { + error = LibWalletError::from(InterfaceError::NullError("balance".to_string())).code; + ptr::swap(error_out, &mut error as *mut c_int); + return 0; + } + + let b = if let Some(bal) = (*balance).time_locked_balance { + bal + } else { + MicroTari::from(0) + }; + c_ulonglong::from(b) +} + +/// Gets the pending incoming balance from a TariBalance. This is the balance the user can spend. +/// +/// ## Arguments +/// `balance` - The TariBalance pointer +/// `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_ulonglong` - The pending incoming, 0 if wallet is null +/// +/// # Safety +/// None +#[no_mangle] +pub unsafe extern "C" fn balance_get_pending_incoming(balance: *mut TariBalance, error_out: *mut c_int) -> c_ulonglong { + let mut error = 0; + ptr::swap(error_out, &mut error as *mut c_int); + if balance.is_null() { + error = LibWalletError::from(InterfaceError::NullError("balance".to_string())).code; + ptr::swap(error_out, &mut error as *mut c_int); + return 0; + } + + c_ulonglong::from((*balance).pending_incoming_balance) +} + +/// Gets the pending outgoing balance from a TariBalance. This is the balance the user can spend. +/// +/// ## Arguments +/// `balance` - The TariBalance pointer +/// `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_ulonglong` - The pending outgoing balance, 0 if wallet is null +/// +/// # Safety +/// None +#[no_mangle] +pub unsafe extern "C" fn balance_get_pending_outgoing(balance: *mut TariBalance, error_out: *mut c_int) -> c_ulonglong { + let mut error = 0; + ptr::swap(error_out, &mut error as *mut c_int); + if balance.is_null() { + error = LibWalletError::from(InterfaceError::NullError("balance".to_string())).code; + ptr::swap(error_out, &mut error as *mut c_int); + return 0; + } + + c_ulonglong::from((*balance).pending_outgoing_balance) +} + +/// Frees memory for a TariBalance +/// +/// ## Arguments +/// `balance` - The pointer to a TariBalance +/// +/// ## Returns +/// `()` - Does not return a value, equivalent to void in C +/// +/// # Safety +/// None +#[no_mangle] +pub unsafe extern "C" fn balance_destroy(balance: *mut TariBalance) { + if !balance.is_null() { + Box::from_raw(balance); + } +} + /// Gets the available balance from a TariWallet. This is the balance the user can spend. /// /// ## Arguments @@ -5177,6 +5309,7 @@ mod test { pub store_and_forward_send_callback_called: bool, pub tx_cancellation_callback_called: bool, pub callback_txo_validation_complete: bool, + pub callback_balance_updated: bool, pub callback_transaction_validation_complete: bool, } @@ -5193,6 +5326,7 @@ mod test { store_and_forward_send_callback_called: false, tx_cancellation_callback_called: false, callback_txo_validation_complete: false, + callback_balance_updated: false, callback_transaction_validation_complete: false, } } @@ -5316,6 +5450,10 @@ mod test { // assert!(true); //optimized out by compiler } + unsafe extern "C" fn balance_updated_callback(_balance: *mut TariBalance) { + // assert!(true); //optimized out by compiler + } + unsafe extern "C" fn transaction_validation_complete_callback(_tx_id: c_ulonglong, _result: u8) { // assert!(true); //optimized out by compiler } @@ -5651,6 +5789,7 @@ mod test { store_and_forward_send_callback, tx_cancellation_callback, txo_validation_complete_callback, + balance_updated_callback, transaction_validation_complete_callback, saf_messages_received_callback, recovery_in_progress_ptr, @@ -5689,6 +5828,7 @@ mod test { store_and_forward_send_callback, tx_cancellation_callback, txo_validation_complete_callback, + balance_updated_callback, transaction_validation_complete_callback, saf_messages_received_callback, recovery_in_progress_ptr, @@ -5793,6 +5933,7 @@ mod test { store_and_forward_send_callback, tx_cancellation_callback, txo_validation_complete_callback, + balance_updated_callback, transaction_validation_complete_callback, saf_messages_received_callback, recovery_in_progress_ptr, @@ -5839,6 +5980,7 @@ mod test { store_and_forward_send_callback, tx_cancellation_callback, txo_validation_complete_callback, + balance_updated_callback, transaction_validation_complete_callback, saf_messages_received_callback, recovery_in_progress_ptr, @@ -5868,6 +6010,7 @@ mod test { store_and_forward_send_callback, tx_cancellation_callback, txo_validation_complete_callback, + balance_updated_callback, transaction_validation_complete_callback, saf_messages_received_callback, recovery_in_progress_ptr, @@ -5892,6 +6035,7 @@ mod test { store_and_forward_send_callback, tx_cancellation_callback, txo_validation_complete_callback, + balance_updated_callback, transaction_validation_complete_callback, saf_messages_received_callback, recovery_in_progress_ptr, @@ -5937,6 +6081,7 @@ mod test { store_and_forward_send_callback, tx_cancellation_callback, txo_validation_complete_callback, + balance_updated_callback, transaction_validation_complete_callback, saf_messages_received_callback, recovery_in_progress_ptr, @@ -6011,6 +6156,7 @@ mod test { store_and_forward_send_callback, tx_cancellation_callback, txo_validation_complete_callback, + balance_updated_callback, transaction_validation_complete_callback, saf_messages_received_callback, recovery_in_progress_ptr, @@ -6160,6 +6306,7 @@ mod test { store_and_forward_send_callback, tx_cancellation_callback, txo_validation_complete_callback, + balance_updated_callback, transaction_validation_complete_callback, saf_messages_received_callback, recovery_in_progress_ptr, @@ -6213,6 +6360,7 @@ mod test { store_and_forward_send_callback, tx_cancellation_callback, txo_validation_complete_callback, + balance_updated_callback, transaction_validation_complete_callback, saf_messages_received_callback, recovery_in_progress_ptr, diff --git a/base_layer/wallet_ffi/src/output_manager_service_mock.rs b/base_layer/wallet_ffi/src/output_manager_service_mock.rs new file mode 100644 index 0000000000..c6c9ec0229 --- /dev/null +++ b/base_layer/wallet_ffi/src/output_manager_service_mock.rs @@ -0,0 +1,129 @@ +// Copyright 2019. 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 futures::StreamExt; +use std::sync::{Arc, Mutex}; +use tari_service_framework::reply_channel::Receiver; +use tari_shutdown::ShutdownSignal; +use tari_wallet::output_manager_service::{ + error::OutputManagerError, + handle::{OutputManagerRequest, OutputManagerResponse}, + service::Balance, +}; + +/// This macro unlocks a Mutex or RwLock. If the lock is poisoned (i.e. panic while unlocked) the last value +/// before the panic is used. +macro_rules! acquire_lock { + ($e:expr, $m:ident) => { + match $e.$m() { + Ok(lock) => lock, + Err(poisoned) => { + log::warn!(target: "wallet", "Lock has been POISONED and will be silently recovered"); + poisoned.into_inner() + }, + } + }; + ($e:expr) => { + acquire_lock!($e, lock) + }; + } + +#[derive(Clone, Debug)] +pub struct ResponseState { + balance: Arc>, +} + +impl ResponseState { + pub fn new() -> Self { + Self { + balance: Arc::new(Mutex::new(Balance::zero())), + } + } + + /// Set the mock server balance response + pub fn set_balance(&mut self, balance: Balance) { + let mut lock = acquire_lock!(self.balance); + *lock = balance; + } + + /// Get the mock server balance value + pub fn get_balance(&mut self) -> Balance { + let lock = acquire_lock!(self.balance); + (*lock).clone() + } +} + +pub struct MockOutputManagerService { + request_stream: Option>>, + state: ResponseState, + shutdown_signal: Option, +} + +impl MockOutputManagerService { + pub fn new( + request_stream: Receiver>, + shutdown_signal: ShutdownSignal, + ) -> Self { + Self { + request_stream: Some(request_stream), + state: ResponseState::new(), + shutdown_signal: Some(shutdown_signal), + } + } + + pub async fn run(mut self) -> Result<(), OutputManagerError> { + let shutdown_signal = self + .shutdown_signal + .take() + .expect("Output Manager Service initialized without shutdown signal"); + + let mut request_stream = self + .request_stream + .take() + .expect("Output Manager Service initialized without request_stream") + .take_until(shutdown_signal); + + while let Some(request_context) = request_stream.next().await { + // Incoming requests + let (request, reply_tx) = request_context.split(); + let response = self.handle_request(request); + let _ = reply_tx.send(response); + } + + Ok(()) + } + + fn handle_request(&mut self, request: OutputManagerRequest) -> Result { + match request { + OutputManagerRequest::GetBalance => Ok(OutputManagerResponse::Balance(self.state.get_balance())), + _ => Err(OutputManagerError::InvalidResponseError(format!( + "Request '{}' not defined for MockOutputManagerService!", + request + ))), + } + } + + /// Returns a clone of the response state to enable updating after the service started + pub fn get_response_state(&mut self) -> ResponseState { + self.state.clone() + } +} diff --git a/base_layer/wallet_ffi/wallet.h b/base_layer/wallet_ffi/wallet.h index dc67011396..f0a69519c3 100644 --- a/base_layer/wallet_ffi/wallet.h +++ b/base_layer/wallet_ffi/wallet.h @@ -57,6 +57,8 @@ struct TariContact; struct TariCompletedTransactions; +struct TariBalance; + struct TariCompletedTransaction; struct TariPendingOutboundTransactions; @@ -424,6 +426,8 @@ void comms_config_destroy(struct TariCommsConfig *wc); /// `callback_txo_validation_complete` - The callback function pointer matching the function signature. This is called /// when a TXO validation process is completed. The request_key is used to identify which request this /// callback references and the second parameter is a u8 that represent the CallbackValidationResults enum. +/// `callback_balance_updated` - The callback function pointer matching the function signature. This is called whenever +/// the balance changes. /// `callback_transaction_validation_complete` - The callback function pointer matching the function signature. This is /// called when a Transaction validation process is completed. The request_key is used to identify which request this /// callback references and the second parameter is a u8 that represent the CallbackValidationResults enum. @@ -464,6 +468,7 @@ struct TariWallet *wallet_create(struct TariCommsConfig *config, void (*callback_store_and_forward_send_result)(unsigned long long, bool), void (*callback_transaction_cancellation)(struct TariCompletedTransaction *), void (*callback_txo_validation_complete)(unsigned long long, unsigned char), + void (*callback_balance_updated)(struct TariBalance *), void (*callback_transaction_validation_complete)(unsigned long long, unsigned char), void (*callback_saf_message_received)(), bool *recovery_in_progress, @@ -484,6 +489,18 @@ bool wallet_upsert_contact(struct TariWallet *wallet, struct TariContact *contac // Removes a TariContact form the TariWallet bool wallet_remove_contact(struct TariWallet *wallet, struct TariContact *contact, int *error_out); +// Gets the available balance from a TariBalance +unsigned long long balance_get_available(struct TariBalance *balance, int *error_out); + +// Gets the available balance from a TariBalance +unsigned long long balance_get_time_locked(struct TariBalance *balance, int *error_out); + +// Gets the available balance from a TariBalance +unsigned long long balance_get_pending_incoming(struct TariBalance *balance, int *error_out); + +// Gets the available balance from a TariBalance +unsigned long long balance_get_pending_outgoing(struct TariBalance *balance, int *error_out); + // Gets the available balance from a TariWallet unsigned long long wallet_get_available_balance(struct TariWallet *wallet, int *error_out); @@ -693,6 +710,9 @@ bool wallet_start_recovery(struct TariWallet *wallet, struct TariPublicKey *base // Frees memory for a TariWallet void wallet_destroy(struct TariWallet *wallet); +// Frees memory for a TariBalance +void balance_destroy(struct TariBalance *balance); + // This function will produce a partial backup of the specified wallet database file (full file path must be provided. // This backup will be written to the provided file (full path must include the filename and extension) and will include // the full wallet db but will clear the sensitive Comms Private Key diff --git a/buildtools/create_osx_install_zip.sh b/buildtools/create_osx_install_zip.sh index 2259a2bb0e..ba99ce6cfa 100755 --- a/buildtools/create_osx_install_zip.sh +++ b/buildtools/create_osx_install_zip.sh @@ -1,8 +1,7 @@ #!/bin/bash -# +# todo: update arg handling -if [ $# -eq 0 ] -then +if [ $# -eq 0 ]; then echo echo Please provide archive file name, \'.tar.gz\' will be appended echo @@ -11,23 +10,25 @@ fi rm -f "./$1.tar.gz" >/dev/null tarball_parent=/tmp -tarball_source=tari_stibbons_testnet +tarball_source=tari_testnet tarball_folder=${tarball_parent}/${tarball_source} -if [ -d "${tarball_folder}" ] -then +if [ -d "${tarball_folder}" ]; then rm -f -r "${tarball_folder:?}" fi mkdir "${tarball_folder}" mkdir "${tarball_folder}/config" mkdir "${tarball_folder}/runtime" +mkdir "${tarball_folder}/scripts" -local_dir="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +local_dir="$( + cd "$(dirname "$0")" >/dev/null 2>&1 || exit 1 + pwd -P +)" project_dir="$(dirname "$(greadlink -e "$local_dir")")" app_dir="$(dirname "$(greadlink -e "$project_dir/applications/tari_base_node")")" -if [ ! "${app_dir}" == "${project_dir}/applications" ] -then +if [ ! "${app_dir}" == "${project_dir}/applications" ]; then echo echo Please run this script from '/buildtools' echo @@ -74,18 +75,27 @@ cp -f "${local_dir}/install_xmrig.sh" "${tarball_folder}/runtime/install_xmrig.s cp -f "${local_dir}/get_xmrig_osx.ps1" "${tarball_folder}/runtime/get_xmrig_osx.ps1" # Config -cat "${project_dir}/common/config/presets/*.toml" >"${tarball_folder}/config/config.toml" +cat "${project_dir}"/common/config/presets/*.toml >"${tarball_folder}/config/config.toml" cp -f "${project_dir}/common/xmrig_config/config_example_stagenet.json" "${tarball_folder}/config/xmrig_config_example_stagenet.json" cp -f "${project_dir}/common/xmrig_config/config_example_mainnet.json" "${tarball_folder}/config/xxmrig_config_example_mainnet.json" cp -f "${project_dir}/common/xmrig_config/config_example_mainnet_self_select.json" "${tarball_folder}/config/xmrig_config_example_mainnet_self_select.json" +# Scripts +cp -f "${local_dir}/osx_postinstall.sh" "${tarball_folder}/scripts/postinstall" + echo Files copied to "${tarball_folder}" echo Creating archive... echo -cd "${tarball_parent}" -tar -cvf "${local_dir}/$1.tar.gz" ${tarball_source} -cd "${local_dir}" -echo -echo Created "./$1.tar.gz" in "${local_dir}" -echo +cd "${tarball_parent}" || exit 1 +if [ -z "$2" ]; then + tar -cvf "${local_dir}/$1.tar.gz" ${tarball_source} + cd "${local_dir}" || exit 1 + echo + echo Created "./$1.tar.gz" in "${local_dir}". + echo +else + echo + echo Files copied to "${tarball_folder}". No zip created. + echo +fi diff --git a/buildtools/docker/base_node.Dockerfile b/buildtools/docker/base_node.Dockerfile index a3bcb09b76..e91722a9f9 100644 --- a/buildtools/docker/base_node.Dockerfile +++ b/buildtools/docker/base_node.Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 #FROM rust:1.42.0 as builder -FROM quay.io/tarilabs/rust_tari-build-with-deps:nightly-2021-08-17 as builder +FROM quay.io/tarilabs/rust_tari-build-with-deps:nightly-2021-08-18 as builder # Copy the dependency lists #ADD Cargo.toml ./ diff --git a/buildtools/docker_rig/base_node.Dockerfile b/buildtools/docker_rig/base_node.Dockerfile index ff0c32d812..43d7288b9d 100644 --- a/buildtools/docker_rig/base_node.Dockerfile +++ b/buildtools/docker_rig/base_node.Dockerfile @@ -1,4 +1,4 @@ -FROM quay.io/tarilabs/rust_tari-build-with-deps:nightly-2021-08-17 as builder +FROM quay.io/tarilabs/rust_tari-build-with-deps:nightly-2021-08-18 as builder WORKDIR /tari diff --git a/buildtools/docker_rig/console_wallet.Dockerfile b/buildtools/docker_rig/console_wallet.Dockerfile index 1a45ff9a93..c43b3eb377 100644 --- a/buildtools/docker_rig/console_wallet.Dockerfile +++ b/buildtools/docker_rig/console_wallet.Dockerfile @@ -1,4 +1,4 @@ -FROM quay.io/tarilabs/rust_tari-build-with-deps:nightly-2021-08-17 as builder +FROM quay.io/tarilabs/rust_tari-build-with-deps:nightly-2021-08-18 as builder WORKDIR /tari diff --git a/buildtools/osx_postinstall.sh b/buildtools/osx_postinstall.sh new file mode 100755 index 0000000000..a561984ebe --- /dev/null +++ b/buildtools/osx_postinstall.sh @@ -0,0 +1,12 @@ +#! /bin/bash + +# logs are in /var/log/install.log +whoami +echo "$HOME" +echo "$USER" +mkdir "$HOME"/.tari/ || exit 1 +cp -R /tmp/tari/ "$HOME"/.tari/ || exit 1 +chown -R "$USER":staff "$HOME"/.tari/ || exit 1 +rm -rf "$HOME"/.tari/scripts/ || exit 1 + +exit 0 \ No newline at end of file diff --git a/changelog.md b/changelog.md index dd0816a204..aa5f4d8911 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,53 @@ # Changelog +## [0.12.0](https://github.com/tari-project/tari/compare/v0.11.0...v0.12.0) (2021-10-29) + + +### ⚠ BREAKING CHANGES + +* **wallet_ffi:** add get_balance callback to wallet ffi (#3475) +* apps should not depend on other app configs (#3469) + +### Features + +* add decay_params method ([#3454](https://github.com/tari-project/tari/issues/3454)) ([a027f32](https://github.com/tari-project/tari/commit/a027f32edb2910528f65b500f032b143a487dad2)) +* add sql query to obtain balance ([#3446](https://github.com/tari-project/tari/issues/3446)) ([e23ceec](https://github.com/tari-project/tari/commit/e23ceecfa441f6739412dafc02e1d5fcc95ff9ab)) +* apps should not depend on other app configs ([#3469](https://github.com/tari-project/tari/issues/3469)) ([b33e8b5](https://github.com/tari-project/tari/commit/b33e8b564732a41f4216f38f4c5f92c459a0c623)) +* improve logging for tari_mining_node ([#3449](https://github.com/tari-project/tari/issues/3449)) ([db9eb96](https://github.com/tari-project/tari/commit/db9eb9641836f6bf3e878a3065c08661a4c57254)) +* optimize get transactions query ([#3496](https://github.com/tari-project/tari/issues/3496)) ([e651a60](https://github.com/tari-project/tari/commit/e651a60f0f18289968fd38dcb382b4d804d0cd2f)) +* optimize pending transactions inbound query ([#3500](https://github.com/tari-project/tari/issues/3500)) ([4ea02e7](https://github.com/tari-project/tari/commit/4ea02e7a04d411748f45a8b35b863d2ba2cc3111)) +* revalidate all outputs ([#3471](https://github.com/tari-project/tari/issues/3471)) ([9bd4760](https://github.com/tari-project/tari/commit/9bd476099b18cf3d10a11ec789cd1450c5d5f011)) +* tx weight takes tariscript and output features into account [igor] ([#3411](https://github.com/tari-project/tari/issues/3411)) ([5bef3fd](https://github.com/tari-project/tari/commit/5bef3fdf6c3771620b5286605faeb83f9b2152e7)) +* **wallet_ffi:** add get_balance callback to wallet ffi ([#3475](https://github.com/tari-project/tari/issues/3475)) ([930860d](https://github.com/tari-project/tari/commit/930860dfc0386f9eb8e578501c2c0e0477c4a638)) + + +### Bug Fixes + +* add details to UnknownError ([#3429](https://github.com/tari-project/tari/issues/3429)) ([dddc18f](https://github.com/tari-project/tari/commit/dddc18fb4d24b4b8ff0069594a54eb699d560e56)) +* add display_currency_decimal method ([#3445](https://github.com/tari-project/tari/issues/3445)) ([1f52ffc](https://github.com/tari-project/tari/commit/1f52ffc0836699872e1f8266bd5821d0d9805eba)) +* add sanity checks to prepare_new_block ([#3448](https://github.com/tari-project/tari/issues/3448)) ([76bc1f0](https://github.com/tari-project/tari/commit/76bc1f0177098fdf1e6af5ae44f4972935d5a221)) +* ban peer that advertises higher PoW than able to provide ([#3478](https://github.com/tari-project/tari/issues/3478)) ([c04fca5](https://github.com/tari-project/tari/commit/c04fca5a4c027ae7331b4d1637a7d73c4013ef0f)) +* check SAF message inflight and check stored_at is in past ([#3444](https://github.com/tari-project/tari/issues/3444)) ([fbf8eb8](https://github.com/tari-project/tari/commit/fbf8eb83353392b977b34bf3d1870ca25320414e)) +* correct panic in tracing for comms ([#3499](https://github.com/tari-project/tari/issues/3499)) ([af15fcc](https://github.com/tari-project/tari/commit/af15fcc2bb863cc4d1ba4a4951456c64aba91a1c)) +* **dht:** discard encrypted message with no destination ([#3472](https://github.com/tari-project/tari/issues/3472)) ([6ca3424](https://github.com/tari-project/tari/commit/6ca3424de306235088d598f741dcb7952efc73f8)) +* ensure that accumulated orphan chain data is committed before header validation ([#3462](https://github.com/tari-project/tari/issues/3462)) ([80f7c78](https://github.com/tari-project/tari/commit/80f7c78b296a48eda3d3e69d266396482679f35a)) +* fix config file whitespace issue when auto generated in windows ([#3491](https://github.com/tari-project/tari/issues/3491)) ([996c047](https://github.com/tari-project/tari/commit/996c0476105665bb32a3f2b13417624c808e8e49)) +* fix confusing names in get_balance functions ([#3447](https://github.com/tari-project/tari/issues/3447)) ([6cd9228](https://github.com/tari-project/tari/commit/6cd9228d61a4b827c4062267074d40b1908773a6)) +* fix flakey rust tests ([#3435](https://github.com/tari-project/tari/issues/3435)) ([7384201](https://github.com/tari-project/tari/commit/73842016db9cfa4cc5abaa3984a5ff3d9f90d7cd)) +* fix recovery test reporting message ([#3479](https://github.com/tari-project/tari/issues/3479)) ([335b626](https://github.com/tari-project/tari/commit/335b62604b577ea7ef19b4b9d637993a0732e559)) +* improve responsiveness of wallet base node switching ([#3488](https://github.com/tari-project/tari/issues/3488)) ([762cb9a](https://github.com/tari-project/tari/commit/762cb9abe5a20c798d72636c83e6e844fc5629be)) +* improve test Wallet should display transactions made ([#3501](https://github.com/tari-project/tari/issues/3501)) ([6b3bac8](https://github.com/tari-project/tari/commit/6b3bac8daaddc01cfbf7208b999ae63d4af67ca9)) +* prevent tari_mining_node from being able to start without a valid address for pool mining ([#3440](https://github.com/tari-project/tari/issues/3440)) ([92dee77](https://github.com/tari-project/tari/commit/92dee77feccc79b9c76bfb98d4cba64027ee3799)) +* remove consensus breaking change in transaction input ([#3474](https://github.com/tari-project/tari/issues/3474)) ([d1b3523](https://github.com/tari-project/tari/commit/d1b3523d981b7ff797ee205d4e349b5116bbd06f)) +* remove is_synced check for transaction validation ([#3459](https://github.com/tari-project/tari/issues/3459)) ([53989f4](https://github.com/tari-project/tari/commit/53989f40b0ab03a9a894f3489452f94efae94bc1)) +* remove unbounded vec allocations from base node grpc/p2p messaging ([#3467](https://github.com/tari-project/tari/issues/3467)) ([5d7fb20](https://github.com/tari-project/tari/commit/5d7fb207c9994ea7f0cd6a0d7c05786d8da60792)) +* remove unnecessary wallet dependency ([#3438](https://github.com/tari-project/tari/issues/3438)) ([07c2c69](https://github.com/tari-project/tari/commit/07c2c693c7ee155deafd94171a8a346d7c3706ba)) +* sha256sum isn't available on all *nix platforms ([#3466](https://github.com/tari-project/tari/issues/3466)) ([6f61582](https://github.com/tari-project/tari/commit/6f6158231eac4b4aefec7499d1a1a551a4350911)) +* typo in console wallet ([#3465](https://github.com/tari-project/tari/issues/3465)) ([401aff9](https://github.com/tari-project/tari/commit/401aff9f89f4064dfbe19845730b3530353980b0)) +* u64->i64->u64 conversion; chain split height as u64 ([#3442](https://github.com/tari-project/tari/issues/3442)) ([43b2033](https://github.com/tari-project/tari/commit/43b20334151b2872b0969bf3fd56e7c5c2af62bd)) +* upgrade rustyline dependencies ([#3476](https://github.com/tari-project/tari/issues/3476)) ([a05ac5e](https://github.com/tari-project/tari/commit/a05ac5e1924987d96e217188bea00a809f5cf57f)) +* validate dht header before dedup cache ([#3468](https://github.com/tari-project/tari/issues/3468)) ([81f01d2](https://github.com/tari-project/tari/commit/81f01d228cc425fb859fd07e08dfb34f03e1bd22)) + ## [0.11.0](https://github.com/tari-project/tari/compare/v0.10.1...v0.11.0) (2021-10-08) diff --git a/clients/validator_node_grpc_client/README.md b/clients/validator_node_grpc_client/README.md new file mode 100644 index 0000000000..f009164c64 --- /dev/null +++ b/clients/validator_node_grpc_client/README.md @@ -0,0 +1,19 @@ +# Tari Validator Node GRPC client + +Async GRPC client library for the Tari Validator Node. + +## Usage + +```javascript +const { Client } = require("@tari/validator-node-grpc-client"); +const client = Client.connect("127.0.0.1:18144"); +``` + +## Development + +- `npm install` +- hack hack hack + +## Tests + +- `npm test` diff --git a/clients/validator_node_grpc_client/package-lock.json b/clients/validator_node_grpc_client/package-lock.json new file mode 100644 index 0000000000..f49ce47a34 --- /dev/null +++ b/clients/validator_node_grpc_client/package-lock.json @@ -0,0 +1,3231 @@ +{ + "name": "@tari/validator-node-grpc-client", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/compat-data": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", + "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "dev": true + }, + "@babel/core": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", + "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.15.8", + "@babel/generator": "^7.15.8", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.8", + "@babel/helpers": "^7.15.4", + "@babel/parser": "^7.15.8", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", + "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", + "dev": true, + "requires": { + "@babel/types": "^7.15.6", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", + "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.15.0", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", + "semver": "^6.3.0" + } + }, + "@babel/helper-function-name": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", + "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", + "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", + "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", + "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-module-imports": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", + "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-module-transforms": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", + "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.15.4", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/helper-validator-identifier": "^7.15.7", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", + "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "dev": true + }, + "@babel/helper-replace-supers": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", + "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-simple-access": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", + "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", + "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "dev": true + }, + "@babel/helpers": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", + "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "dev": true, + "requires": { + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", + "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/template": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", + "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/traverse": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", + "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@grpc/grpc-js": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.4.1.tgz", + "integrity": "sha512-/chkA48TdAvATHA7RXJPeHQLdfFhpu51974s8htjO/XTDHA41j5+SkR5Io+lr9XsLmkZD6HxLyRAFGmA9wjO2w==", + "requires": { + "@grpc/proto-loader": "^0.6.4", + "@types/node": ">=12.12.47" + }, + "dependencies": { + "@grpc/proto-loader": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.6.tgz", + "integrity": "sha512-cdMaPZ8AiFz6ua6PUbP+LKbhwJbFXnrQ/mlnKGUyzDUZ3wp7vPLksnmLCBX6SHgSmjX7CbNVNLFYD5GmmjO4GQ==", + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.10.0", + "yargs": "^16.1.1" + } + } + } + }, + "@grpc/proto-loader": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.6.tgz", + "integrity": "sha512-DT14xgw3PSzPxwS13auTEwxhMMOoz33DPUKNtmYK/QYbBSpLXJy78FGGs5yVoxVobEqPm4iW9MOIoz0A3bLTRQ==", + "requires": { + "lodash.camelcase": "^4.3.0", + "protobufjs": "^6.8.6" + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.3.1.tgz", + "integrity": "sha512-RkFNWmv0iui+qsOr/29q9dyfKTTT5DCuP31kUwg7rmOKPT/ozLeGLKJKVIiOfbiKyleUZKIrHwhmiZWVe8IMdw==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.3.1", + "jest-util": "^27.3.1", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.3.1.tgz", + "integrity": "sha512-DMNE90RR5QKx0EA+wqe3/TNEwiRpOkhshKNxtLxd4rt3IZpCt+RSL+FoJsGeblRZmqdK4upHA/mKKGPPRAifhg==", + "dev": true, + "requires": { + "@jest/console": "^27.3.1", + "@jest/reporters": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^27.3.0", + "jest-config": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-resolve-dependencies": "^27.3.1", + "jest-runner": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "jest-watcher": "^27.3.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.3.1.tgz", + "integrity": "sha512-BCKCj4mOVLme6Tanoyc9k0ultp3pnmuyHw73UHRPeeZxirsU/7E3HC4le/VDb/SMzE1JcPnto+XBKFOcoiJzVw==", + "dev": true, + "requires": { + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "jest-mock": "^27.3.0" + } + }, + "@jest/fake-timers": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.3.1.tgz", + "integrity": "sha512-M3ZFgwwlqJtWZ+QkBG5NmC23A9w+A6ZxNsO5nJxJsKYt4yguBd3i8TpjQz5NfCX91nEve1KqD9RA2Q+Q1uWqoA==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.3.1", + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1" + } + }, + "@jest/globals": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.3.1.tgz", + "integrity": "sha512-Q651FWiWQAIFiN+zS51xqhdZ8g9b88nGCobC87argAxA7nMfNQq0Q0i9zTfQYgLa6qFXk2cGANEqfK051CZ8Pg==", + "dev": true, + "requires": { + "@jest/environment": "^27.3.1", + "@jest/types": "^27.2.5", + "expect": "^27.3.1" + } + }, + "@jest/reporters": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.3.1.tgz", + "integrity": "sha512-m2YxPmL9Qn1emFVgZGEiMwDntDxRRQ2D58tiDQlwYTg5GvbFOKseYCcHtn0WsI8CG4vzPglo3nqbOiT8ySBT/w==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + } + }, + "@jest/source-map": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", + "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.3.1.tgz", + "integrity": "sha512-mLn6Thm+w2yl0opM8J/QnPTqrfS4FoXsXF2WIWJb2O/GBSyResL71BRuMYbYRsGt7ELwS5JGcEcGb52BNrumgg==", + "dev": true, + "requires": { + "@jest/console": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.3.1.tgz", + "integrity": "sha512-siySLo07IMEdSjA4fqEnxfIX8lB/lWYsBPwNFtkOvsFQvmBrL3yj3k3uFNZv/JDyApTakRpxbKLJ3CT8UGVCrA==", + "dev": true, + "requires": { + "@jest/test-result": "^27.3.1", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.3.1", + "jest-runtime": "^27.3.1" + } + }, + "@jest/transform": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.3.1.tgz", + "integrity": "sha512-3fSvQ02kuvjOI1C1ssqMVBKJpZf6nwoCiSu00zAKh5nrp3SptNtZy/8s5deayHnqxhjD9CWDJ+yqQwuQ0ZafXQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.2.5", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-util": "^27.3.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } + }, + "@jest/types": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.5.tgz", + "integrity": "sha512-nmuM4VuDtCZcY+eTpw+0nvstwReMsjPoj7ZR80/BbixulhLaiX+fbv8oeLW8WZlJMcsGQsTmMKT/iTZu1Uy/lQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "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": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.0.1.tgz", + "integrity": "sha512-AU7kwFxreVd6OAXcAFlKSmZquiRUU0FvYm44k1Y1QbK7Co4m0aqfGMhjykIeQp/H6rcl+nFmj0zfdUcGVs9Dew==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", + "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", + "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "@types/node": { + "version": "16.11.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz", + "integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==" + }, + "@types/prettier": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "dev": true + }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, + "acorn": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "dev": true + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "babel-jest": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.3.1.tgz", + "integrity": "sha512-SjIF8hh/ir0peae2D6S6ZKRhUy7q/DnpH7k/V6fT4Bgs/LXXUztOpX4G2tCgq8mLo5HA9mN6NmlFMeYtKmIsTQ==", + "dev": true, + "requires": { + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^27.2.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "dependencies": { + "istanbul-lib-instrument": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.0.4.tgz", + "integrity": "sha512-W6jJF9rLGEISGoCyXRqa/JCGQGmmxPO10TMu7izaUTynxvBvTjqzAIIGCK9USBmIbQAaSWD6XJPrM9Pv5INknw==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + } + } + }, + "babel-plugin-jest-hoist": { + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz", + "integrity": "sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz", + "integrity": "sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^27.2.0", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "browserslist": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz", + "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001271", + "electron-to-chromium": "^1.3.878", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001271", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz", + "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "dev": true + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "dev": true + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff-sequences": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", + "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", + "dev": true + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, + "electron-to-chromium": { + "version": "1.3.879", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.879.tgz", + "integrity": "sha512-zJo+D9GwbJvM31IdFmwcGvychhk4KKbKYo2GWlsn+C/dxz2NwmbhGJjWwTfFSF2+eFH7VvfA8MCZ8SOqTrlnpw==", + "dev": true + }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expect": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.3.1.tgz", + "integrity": "sha512-MrNXV2sL9iDRebWPGOGFdPQRl2eDQNu/uhxIMShjjx74T6kC6jFIkmQ6OqXDtevjGUkyB2IT56RzDBqXf/QPCg==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-regex-util": "^27.0.6" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true + }, + "grpc-promise": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/grpc-promise/-/grpc-promise-1.4.0.tgz", + "integrity": "sha512-4BBXHXb5OjjBh7luylu8vFqL6H6aPn/LeqpQaSBeRzO/Xv95wHW/WkU9TJRqaCTMZ5wq9jTSvlJWp0vRJy1pVA==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "import-local": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", + "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", + "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.3.1.tgz", + "integrity": "sha512-U2AX0AgQGd5EzMsiZpYt8HyZ+nSVIh5ujQ9CPp9EQZJMjXIiSZpJNweZl0swatKRoqHWgGKM3zaSwm4Zaz87ng==", + "dev": true, + "requires": { + "@jest/core": "^27.3.1", + "import-local": "^3.0.2", + "jest-cli": "^27.3.1" + }, + "dependencies": { + "jest-cli": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.3.1.tgz", + "integrity": "sha512-WHnCqpfK+6EvT62me6WVs8NhtbjAS4/6vZJnk7/2+oOr50cwAzG4Wxt6RXX0hu6m1169ZGMlhYYUNeKBXCph/Q==", + "dev": true, + "requires": { + "@jest/core": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "jest-config": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + } + } + } + }, + "jest-changed-files": { + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.3.0.tgz", + "integrity": "sha512-9DJs9garMHv4RhylUMZgbdCJ3+jHSkpL9aaVKp13xtXAD80qLTLrqcDZL1PHA9dYA0bCI86Nv2BhkLpLhrBcPg==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "jest-circus": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.3.1.tgz", + "integrity": "sha512-v1dsM9II6gvXokgqq6Yh2jHCpfg7ZqV4jWY66u7npz24JnhP3NHxI0sKT7+ZMQ7IrOWHYAaeEllOySbDbWsiXw==", + "dev": true, + "requires": { + "@jest/environment": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.3.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + } + }, + "jest-config": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.3.1.tgz", + "integrity": "sha512-KY8xOIbIACZ/vdYCKSopL44I0xboxC751IX+DXL2+Wx6DKNycyEfV3rryC3BPm5Uq/BBqDoMrKuqLEUNJmMKKg==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.3.1", + "@jest/types": "^27.2.5", + "babel-jest": "^27.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-circus": "^27.3.1", + "jest-environment-jsdom": "^27.3.1", + "jest-environment-node": "^27.3.1", + "jest-get-type": "^27.3.1", + "jest-jasmine2": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-runner": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "micromatch": "^4.0.4", + "pretty-format": "^27.3.1" + } + }, + "jest-diff": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.3.1.tgz", + "integrity": "sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.0.6", + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" + } + }, + "jest-docblock": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", + "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.3.1.tgz", + "integrity": "sha512-E4SwfzKJWYcvOYCjOxhZcxwL+AY0uFMvdCOwvzgutJiaiodFjkxQQDxHm8FQBeTqDnSmKsQWn7ldMRzTn2zJaQ==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "chalk": "^4.0.0", + "jest-get-type": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1" + } + }, + "jest-environment-jsdom": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.3.1.tgz", + "integrity": "sha512-3MOy8qMzIkQlfb3W1TfrD7uZHj+xx8Olix5vMENkj5djPmRqndMaXtpnaZkxmxM+Qc3lo+yVzJjzuXbCcZjAlg==", + "dev": true, + "requires": { + "@jest/environment": "^27.3.1", + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1", + "jsdom": "^16.6.0" + } + }, + "jest-environment-node": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.3.1.tgz", + "integrity": "sha512-T89F/FgkE8waqrTSA7/ydMkcc52uYPgZZ6q8OaZgyiZkJb5QNNCF6oPZjH9IfPFfcc9uBWh1574N0kY0pSvTXw==", + "dev": true, + "requires": { + "@jest/environment": "^27.3.1", + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1" + } + }, + "jest-get-type": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz", + "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==", + "dev": true + }, + "jest-haste-map": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.3.1.tgz", + "integrity": "sha512-lYfNZIzwPccDJZIyk9Iz5iQMM/MH56NIIcGj7AFU1YyA4ewWFBl8z+YPJuSCRML/ee2cCt2y3W4K3VXPT6Nhzg==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^27.0.6", + "jest-serializer": "^27.0.6", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.3.1.tgz", + "integrity": "sha512-WK11ZUetDQaC09w4/j7o4FZDUIp+4iYWH/Lik34Pv7ukL+DuXFGdnmmi7dT58J2ZYKFB5r13GyE0z3NPeyJmsg==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^27.3.1", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.3.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1", + "throat": "^6.0.1" + } + }, + "jest-leak-detector": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.3.1.tgz", + "integrity": "sha512-78QstU9tXbaHzwlRlKmTpjP9k4Pvre5l0r8Spo4SbFFVy/4Abg9I6ZjHwjg2QyKEAMg020XcjP+UgLZIY50yEg==", + "dev": true, + "requires": { + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" + } + }, + "jest-matcher-utils": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.3.1.tgz", + "integrity": "sha512-hX8N7zXS4k+8bC1Aj0OWpGb7D3gIXxYvPNK1inP5xvE4ztbz3rc4AkI6jGVaerepBnfWB17FL5lWFJT3s7qo8w==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.3.1", + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" + } + }, + "jest-message-util": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.3.1.tgz", + "integrity": "sha512-bh3JEmxsTZ/9rTm0jQrPElbY2+y48Rw2t47uMfByNyUVR+OfPh4anuyKsGqsNkXk/TI4JbLRZx+7p7Hdt6q1yg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.2.5", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "pretty-format": "^27.3.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.3.0.tgz", + "integrity": "sha512-ziZiLk0elZOQjD08bLkegBzv5hCABu/c8Ytx45nJKkysQwGaonvmTxwjLqEA4qGdasq9o2I8/HtdGMNnVsMTGw==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true + }, + "jest-regex-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", + "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", + "dev": true + }, + "jest-resolve": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.3.1.tgz", + "integrity": "sha512-Dfzt25CFSPo3Y3GCbxynRBZzxq9AdyNN+x/v2IqYx6KVT5Z6me2Z/PsSGFSv3cOSUZqJ9pHxilao/I/m9FouLw==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.3.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.3.1.tgz", + "integrity": "sha512-X7iLzY8pCiYOnvYo2YrK3P9oSE8/3N2f4pUZMJ8IUcZnT81vlSonya1KTO9ZfKGuC+svE6FHK/XOb8SsoRUV1A==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "jest-regex-util": "^27.0.6", + "jest-snapshot": "^27.3.1" + } + }, + "jest-runner": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.3.1.tgz", + "integrity": "sha512-r4W6kBn6sPr3TBwQNmqE94mPlYVn7fLBseeJfo4E2uCTmAyDFm2O5DYAQAFP7Q3YfiA/bMwg8TVsciP7k0xOww==", + "dev": true, + "requires": { + "@jest/console": "^27.3.1", + "@jest/environment": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-docblock": "^27.0.6", + "jest-environment-jsdom": "^27.3.1", + "jest-environment-node": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-leak-detector": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + } + }, + "jest-runtime": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.3.1.tgz", + "integrity": "sha512-qtO6VxPbS8umqhEDpjA4pqTkKQ1Hy4ZSi9mDVeE9Za7LKBo2LdW2jmT+Iod3XFaJqINikZQsn2wEi0j9wPRbLg==", + "dev": true, + "requires": { + "@jest/console": "^27.3.1", + "@jest/environment": "^27.3.1", + "@jest/globals": "^27.3.1", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-mock": "^27.3.0", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^16.2.0" + } + }, + "jest-serializer": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", + "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + } + }, + "jest-snapshot": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.3.1.tgz", + "integrity": "sha512-APZyBvSgQgOT0XumwfFu7X3G5elj6TGhCBLbBdn3R1IzYustPGPE38F51dBWMQ8hRXa9je0vAdeVDtqHLvB6lg==", + "dev": true, + "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.3.1", + "graceful-fs": "^4.2.4", + "jest-diff": "^27.3.1", + "jest-get-type": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-util": "^27.3.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.3.1", + "semver": "^7.3.2" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "jest-util": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz", + "integrity": "sha512-8fg+ifEH3GDryLQf/eKZck1DEs2YuVPBCMOaHQxVVLmQwl/CDhWzrvChTX4efLZxGrw+AA0mSXv78cyytBt/uw==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.4", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.3.1.tgz", + "integrity": "sha512-3H0XCHDFLA9uDII67Bwi1Vy7AqwA5HqEEjyy934lgVhtJ3eisw6ShOF1MDmRPspyikef5MyExvIm0/TuLzZ86Q==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.3.1", + "leven": "^3.1.0", + "pretty-format": "^27.3.1" + }, + "dependencies": { + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.3.1.tgz", + "integrity": "sha512-9/xbV6chABsGHWh9yPaAGYVVKurWoP3ZMCv6h+O1v9/+pkOroigs6WzZ0e9gLP/njokUwM7yQhr01LKJVMkaZA==", + "dev": true, + "requires": { + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.3.1", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz", + "integrity": "sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dev": true, + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mime-db": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", + "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "dev": true + }, + "mime-types": { + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", + "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "dev": true, + "requires": { + "mime-db": "1.50.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-releases": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "pretty-format": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz", + "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", + "dev": true + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + } + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "v8-to-istanbul": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", + "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", + "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + } + } +} diff --git a/clients/validator_node_grpc_client/package.json b/clients/validator_node_grpc_client/package.json new file mode 100644 index 0000000000..4e7cd4c147 --- /dev/null +++ b/clients/validator_node_grpc_client/package.json @@ -0,0 +1,20 @@ +{ + "name": "@tari/validator-node-grpc-client", + "version": "0.0.1", + "description": "GRPC client for Tari Base Node", + "main": "./src/index.js", + "scripts": { + "test": "jest" + }, + "author": "Tari development community", + "dependencies": { + "@grpc/grpc-js": "^1.2.3", + "@grpc/proto-loader": "^0.5.5", + "grpc-promise": "^1.4.0" + }, + "devDependencies": { + "jest": "^27.1.1", + "md5": "^2.3.0", + "node-fetch": "^2.6.1" + } +} diff --git a/clients/validator_node_grpc_client/src/index.js b/clients/validator_node_grpc_client/src/index.js new file mode 100644 index 0000000000..636217bf11 --- /dev/null +++ b/clients/validator_node_grpc_client/src/index.js @@ -0,0 +1,49 @@ +const grpc = require("@grpc/grpc-js"); +const protoLoader = require("@grpc/proto-loader"); +const {promisifyAll} = require("grpc-promise"); +const path = require("path"); + +const packageDefinition = protoLoader.loadSync( + path.resolve( + __dirname, + "../../../applications/tari_validator_node/proto/grpc/validator_node.proto" + ), + { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + } +); +const protoDescriptor = grpc.loadPackageDefinition(packageDefinition); +const tariGrpc = protoDescriptor.tari.validator_node.rpc; + +function connect(address) { + const client = new tariGrpc.ValidatorNode( + address, + grpc.credentials.createInsecure() + ); + promisifyAll(client, {metadata: new grpc.Metadata()}); + return client; +} + +function Client(address = "127.0.0.1:18144") { + this.inner = connect(address); + + const methods = [ + "getMetadata", + "getTokenData", + "executeInstruction", + ]; + methods.forEach((method) => { + this[method] = (arg) => this.inner[method]().sendMessage(arg); + }); +} + +Client.connect = (address) => new Client(address); + +module.exports = { + Client, + types: tariGrpc, +}; diff --git a/common/Cargo.toml b/common/Cargo.toml index 58163aea02..df009b172b 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.11.0" +version = "0.12.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.11", path = "../infrastructure/storage"} +tari_storage = { version = "^0.12", path = "../infrastructure/storage"} tracing = "0.1.26" tracing-opentelemetry = "0.15.0" tracing-subscriber = "0.2.20" @@ -42,6 +42,6 @@ thiserror = "1.0.29" fs2 = "0.4.3" [dev-dependencies] -tari_test_utils = { version = "^0.11", path = "../infrastructure/test_utils"} +tari_test_utils = { version = "^0.12", path = "../infrastructure/test_utils"} tempfile = "3.1.0" anyhow = "1.0" diff --git a/common/config/presets/base_node.toml b/common/config/presets/base_node.toml index 421ccaeb44..8acf317547 100644 --- a/common/config/presets/base_node.toml +++ b/common/config/presets/base_node.toml @@ -1,3 +1,17 @@ +######################################################################################################################## +# # +# The Tari Network Configuration File # +# # +######################################################################################################################## + +# This file carries all the configuration options for running Tari-related nodes and infrastructure in one single +# file. As you'll notice, almost all configuraton options are commented out. This is because they are either not +# needed, are for advanced users that know what they want to tweak, or are already set at their default values. If +# things are working fine, then there's no need to change anything here. +# +# Each major section is clearly marked so that you can quickly find the section you're looking for. This first +# section holds configuration options that are common to all sections. + ######################################################################################################################## # # # Base Node Configuration Options # @@ -73,9 +87,6 @@ grpc_enabled = true # The socket to expose for the gRPC base node server. This value is ignored if grpc_enabled is false. # Valid values here are IPv4 and IPv6 TCP sockets, local unix sockets (e.g. "ipc://base-node-gprc.sock.100") grpc_base_node_address = "127.0.0.1:18142" -# The socket to expose for the gRPC wallet server. This value is ignored if grpc_enabled is false. -# Valid values here are IPv4 and IPv6 TCP sockets, local unix sockets (e.g. "ipc://base-node-gprc.sock.100") -grpc_console_wallet_address = "127.0.0.1:18143" # A path to the file that stores your node identity and secret key base_node_identity_file = "config/base_node_id.json" @@ -142,6 +153,7 @@ console_wallet_tor_identity_file = "config/console_wallet_tor.json" # Mempool Configuration Options # # # ######################################################################################################################## + [mempool.weatherwax] # The maximum number of transactions that can be stored in the Unconfirmed Transaction pool. This is the main waiting @@ -364,3 +376,4 @@ console_wallet_tor_identity_file = "config/console_wallet_tor.json" # this parameter should not affect profitabilty in any meaningful way, since the transaction weights are selected to # closely mirror how much block space they take up #weight_tx_skip_count = 20 + diff --git a/common/config/presets/common.toml b/common/config/presets/common.toml index e6b9021034..a689b7ba4d 100644 --- a/common/config/presets/common.toml +++ b/common/config/presets/common.toml @@ -1,8 +1,14 @@ +######################################################################################################################## +# # +# Common Configuration Options # +# # +######################################################################################################################## + [common] # Select the network to connect to. Valid options are: # mainnet - the "real" Tari network (default) # weatherwax - the Tari testnet -network = "weatherwax" +network = "dibbler" # When first logging onto the Tari network, you need to find a few peers to bootstrap the process. In the absence of # any servers, this is a little more challenging than usual. Our best strategy is just to try and connect to the peers @@ -94,4 +100,5 @@ rpc_max_simultaneous_sessions = 10000 # auto_update.dns_hosts = ["updates.taripulse.com"] # Customize the location of the update SHA hashes and maintainer-signed signature. # auto_update.hashes_url = "https://
/hashes.txt" -# auto_update.hashes_sig_url = "https://
/hashes.txt.sig" \ No newline at end of file +# auto_update.hashes_sig_url = "https://
/hashes.txt.sig" + diff --git a/common/config/presets/console_wallet.toml b/common/config/presets/console_wallet.toml index c7bde84b9e..3a2e9e1cb1 100644 --- a/common/config/presets/console_wallet.toml +++ b/common/config/presets/console_wallet.toml @@ -14,6 +14,12 @@ wallet_db_file = "wallet/wallet.dat" console_wallet_db_file = "wallet/console-wallet.dat" +# Enable the gRPC server for the base node. Set this to true if you want to enable third-party wallet software +grpc_enabled = true +# The socket to expose for the gRPC wallet server. This value is ignored if grpc_enabled is false. +# Valid values here are IPv4 and IPv6 TCP sockets, local unix sockets (e.g. "ipc://base-node-gprc.sock.100") +grpc_address = "127.0.0.1:18143" + # Console wallet password # Should you wish to start your console wallet without typing in your password, the following options are available: # 1. Start the console wallet with the --password=secret argument, or @@ -200,3 +206,55 @@ tor_control_auth = "none" # or "password=xxxxxx" # tor_proxy_bypass_addresses = ["/dns4/my-foo-base-node/tcp/9998"] # When using the tor transport and set to true, outbound TCP connections bypass the tor proxy. Defaults to false for better privacy # tor_proxy_bypass_for_outbound_tcp = false; + + + +# Wallet configuration options for dibbler +[wallet.dibbler] +# -------------- Transport configuration -------------- +# Use TCP to connect to the Tari network. This transport can only communicate with TCP/IP addresses, so peers with +# e.g. tor onion addresses will not be contactable. +#transport = "tcp" +# The address and port to listen for peer connections over TCP. +#tcp_listener_address = "/ip4/0.0.0.0/tcp/18188" +# Configures a tor proxy used to connect to onion addresses. All other traffic uses direct TCP connections. +# This setting is optional however, if it is not specified, this node will not be able to connect to nodes that +# only advertise an onion address. +#tcp_tor_socks_address = "/ip4/127.0.0.1/tcp/36050" +#tcp_tor_socks_auth = "none" + +# Configures the node to run over a tor hidden service using the Tor proxy. This transport recognises ip/tcp, +# onion v2, onion v3 and dns addresses. +transport = "tor" +# Address of the tor control server +tor_control_address = "/ip4/127.0.0.1/tcp/9051" +# Authentication to use for the tor control server +tor_control_auth = "none" # or "password=xxxxxx" +# The onion port to use. +#tor_onion_port = 18141 +# The address to which traffic on the node's onion address will be forwarded +# tor_forward_address = "/ip4/127.0.0.1/tcp/0" +# Instead of attemping to get the SOCKS5 address from the tor control port, use this one. The default is to +# use the first address returned by the tor control port (GETINFO /net/listeners/socks). +#tor_socks_address_override= + +# Use a SOCKS5 proxy transport. This transport recognises any addresses supported by the proxy. +#transport = "socks5" +# The address of the SOCKS5 proxy +#socks5_proxy_address = "/ip4/127.0.0.1/tcp/9050" +# The address to which traffic will be forwarded +#socks5_listener_address = "/ip4/127.0.0.1/tcp/18188" +#socks5_auth = "none" # or "username_password=username:xxxxxxx" + +# Optionally bind an additional TCP socket for inbound Tari P2P protocol commms. +# Use cases include: +# - allowing wallets to locally connect to their base node, rather than through tor, when used in conjunction with `tor_proxy_bypass_addresses` +# - multiple P2P addresses, one public over DNS and one private over TOR +# - a "bridge" between TOR and TCP-only nodes +# auxilary_tcp_listener_address = "/ip4/127.0.0.1/tcp/9998" + +# When these addresses are encountered when dialing another peer, the tor proxy is bypassed and the connection is made +# direcly over TCP. /ip4, /ip6, /dns, /dns4 and /dns6 are supported. +# tor_proxy_bypass_addresses = ["/dns4/my-foo-base-node/tcp/9998"] +# When using the tor transport and set to true, outbound TCP connections bypass the tor proxy. Defaults to false for better privacy +# tor_proxy_bypass_for_outbound_tcp = false; diff --git a/common/config/presets/merge_mining_proxy.toml b/common/config/presets/merge_mining_proxy.toml index 7e18d4b2fc..2a9d93a11c 100644 --- a/common/config/presets/merge_mining_proxy.toml +++ b/common/config/presets/merge_mining_proxy.toml @@ -1,3 +1,9 @@ +######################################################################################################################## +# # +# Merge Mining Configuration Options # +# # +######################################################################################################################## + [merge_mining_proxy.weatherwax] # URL to monerod @@ -27,4 +33,5 @@ monerod_password = "" # The merge mining proxy can either wait for the base node to achieve initial sync at startup before it enables mining, # or not. If merge mining starts before the base node has achieved initial sync, those Tari mined blocks will not be # accepted. (Default value = true; will wait for base node initial sync). -#wait_for_initial_sync_at_startup = true \ No newline at end of file +#wait_for_initial_sync_at_startup = true + diff --git a/common/config/presets/mining_node.toml b/common/config/presets/mining_node.toml index 9fabbf2645..87f3f1aa1f 100644 --- a/common/config/presets/mining_node.toml +++ b/common/config/presets/mining_node.toml @@ -1,3 +1,9 @@ +######################################################################################################################## +# # +# Mining Node Configuration Options # +# # +######################################################################################################################## + [mining_node] # Number of mining threads # Default: number of logical CPU cores @@ -25,4 +31,5 @@ # Stratum Mode configuration # mining_pool_address = "miningcore.tari.com:3052" # mining_wallet_address = "YOUR_WALLET_PUBLIC_KEY" -# mining_worker_name = "worker1" \ No newline at end of file +# mining_worker_name = "worker1" + diff --git a/common/config/presets/stratum_transcoder.toml b/common/config/presets/stratum_transcoder.toml index 34950238a8..0ac048a1e2 100644 --- a/common/config/presets/stratum_transcoder.toml +++ b/common/config/presets/stratum_transcoder.toml @@ -1,4 +1,11 @@ +######################################################################################################################## +# # +# Stratum Transcoder Configuration Options # +# # +######################################################################################################################## + [stratum_transcoder] # Address of the tari_stratum_transcoder application -transcoder_host_address = "127.0.0.1:7879" \ No newline at end of file +transcoder_host_address = "127.0.0.1:7879" + diff --git a/common/examples/base_node_init.rs b/common/examples/base_node_init.rs index 359345df2a..22cf594d18 100644 --- a/common/examples/base_node_init.rs +++ b/common/examples/base_node_init.rs @@ -7,7 +7,7 @@ use tari_common::{configuration::bootstrap::ApplicationType, ConfigBootstrap, De struct Arguments { /// Custom application parameters might eb specified as usual #[structopt(long, default_value = "any structopt options allowed")] - my_param: String, + _my_param: String, #[structopt(flatten)] bootstrap: ConfigBootstrap, } diff --git a/common/src/configuration/global.rs b/common/src/configuration/global.rs index e819f30a1b..36e1b42c64 100644 --- a/common/src/configuration/global.rs +++ b/common/src/configuration/global.rs @@ -29,6 +29,7 @@ use crate::{ BaseNodeConfig, Network, ValidatorNodeConfig, + WalletConfig, }, ConfigurationError, }; @@ -80,7 +81,7 @@ pub struct GlobalConfig { pub base_node_identity_file: PathBuf, pub public_address: Multiaddr, pub base_node_config: Option, - pub grpc_console_wallet_address: SocketAddr, + pub wallet_config: Option, pub peer_seeds: Vec, pub dns_seeds: Vec, pub dns_seeds_name_server: SocketAddr, @@ -336,14 +337,27 @@ fn convert_node_config( base_node_config = Some(bn_config); } - let key = "wallet.grpc_address"; - let grpc_console_wallet_address = cfg - .get_str(key) - .map_err(|e| ConfigurationError::new(key, &e.to_string())) - .and_then(|addr| { - addr.parse::() - .map_err(|e| ConfigurationError::new(key, &e.to_string())) - })?; + let mut wallet_config = None; + if application == ApplicationType::ConsoleWallet { + let mut config = WalletConfig::default(); + // GPRC enabled + let key = "wallet.grpc_enabled"; + let grpc_enabled = cfg.get_bool(key).unwrap_or_default(); + + config.grpc_address = if grpc_enabled { + let key = "wallet.grpc_address"; + let addr = cfg.get_str(key).unwrap_or_else(|_| "127.0.0.1:18143".to_string()); + + let grpc_address = addr + .parse::() + .map_err(|e| ConfigurationError::new(key, &e.to_string()))?; + + Some(grpc_address) + } else { + None + }; + wallet_config = Some(config); + } // Peer and DNS seeds let key = "common.peer_seeds"; @@ -743,7 +757,7 @@ fn convert_node_config( base_node_identity_file, public_address, base_node_config, - grpc_console_wallet_address, + wallet_config, peer_seeds, dns_seeds, dns_seeds_name_server, diff --git a/common/src/configuration/mod.rs b/common/src/configuration/mod.rs index c850f05a35..23c98c0460 100644 --- a/common/src/configuration/mod.rs +++ b/common/src/configuration/mod.rs @@ -45,8 +45,10 @@ mod merge_mining_config; pub mod seconds; pub mod utils; mod validator_node_config; +mod wallet_config; pub mod writer; pub use base_node_config::BaseNodeConfig; pub use merge_mining_config::MergeMiningConfig; pub use validator_node_config::ValidatorNodeConfig; +pub use wallet_config::WalletConfig; diff --git a/common/src/configuration/wallet_config.rs b/common/src/configuration/wallet_config.rs new file mode 100644 index 0000000000..7b5ac28cd0 --- /dev/null +++ b/common/src/configuration/wallet_config.rs @@ -0,0 +1,28 @@ +// 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::net::SocketAddr; + +#[derive(Debug, Clone, Default)] +pub struct WalletConfig { + pub grpc_address: Option, +} diff --git a/comms/Cargo.toml b/comms/Cargo.toml index f584650bf3..865a45235b 100644 --- a/comms/Cargo.toml +++ b/comms/Cargo.toml @@ -6,14 +6,14 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.11.0" +version = "0.12.0" edition = "2018" [dependencies] tari_common = { path = "../common" } tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } -tari_storage = { version = "^0.11", path = "../infrastructure/storage" } -tari_shutdown = { version = "^0.11", path = "../infrastructure/shutdown" } +tari_storage = { version = "^0.12", path = "../infrastructure/storage" } +tari_shutdown = { version = "^0.12", path = "../infrastructure/shutdown" } anyhow = "1.0.32" async-trait = "0.1.36" @@ -55,7 +55,7 @@ opentelemetry-jaeger = { version = "0.15", features = ["rt-tokio"] } tower-make = { version = "0.3.0", optional = true } [dev-dependencies] -tari_test_utils = { version = "^0.11", path = "../infrastructure/test_utils" } +tari_test_utils = { version = "^0.12", path = "../infrastructure/test_utils" } tari_comms_rpc_macros = { version = "*", path = "./rpc_macros" } env_logger = "0.7.0" @@ -63,7 +63,7 @@ serde_json = "1.0.39" tempfile = "3.1.0" [build-dependencies] -tari_common = { version = "^0.11", path = "../common", features = ["build"] } +tari_common = { version = "^0.12", path = "../common", features = ["build"] } [features] c_integration = [] diff --git a/comms/dht/Cargo.toml b/comms/dht/Cargo.toml index 44a0ef68ec..092e409393 100644 --- a/comms/dht/Cargo.toml +++ b/comms/dht/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tari_comms_dht" -version = "0.11.0" +version = "0.12.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.11", path = "../", features = ["rpc"] } -tari_comms_rpc_macros = { version = "^0.11", path = "../rpc_macros" } +tari_comms = { version = "^0.12", path = "../", features = ["rpc"] } +tari_comms_rpc_macros = { version = "^0.12", 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.11", path = "../../infrastructure/shutdown" } -tari_storage = { version = "^0.11", path = "../../infrastructure/storage" } +tari_shutdown = { version = "^0.12", path = "../../infrastructure/shutdown" } +tari_storage = { version = "^0.12", path = "../../infrastructure/storage" } anyhow = "1.0.32" bitflags = "1.2.0" @@ -43,7 +43,7 @@ ttl_cache = "0.5.1" pin-project = "0.4" [dev-dependencies] -tari_test_utils = { version = "^0.11", path = "../../infrastructure/test_utils" } +tari_test_utils = { version = "^0.12", path = "../../infrastructure/test_utils" } env_logger = "0.7.0" futures-test = { version = "0.3.5" } @@ -60,7 +60,7 @@ futures-util = "^0.3.1" lazy_static = "1.4.0" [build-dependencies] -tari_common = { version = "^0.11", path = "../../common" } +tari_common = { version = "^0.12", path = "../../common" } [features] test-mocks = [] diff --git a/comms/dht/src/network_discovery/discovering.rs b/comms/dht/src/network_discovery/discovering.rs index e15e96ed8f..93cb55a5c7 100644 --- a/comms/dht/src/network_discovery/discovering.rs +++ b/comms/dht/src/network_discovery/discovering.rs @@ -41,10 +41,8 @@ const LOG_TARGET: &str = "comms::dht::network_discovery"; pub(super) struct Discovering { params: DiscoveryParams, context: NetworkDiscoveryContext, - candidate_peers: Vec, stats: DhtNetworkDiscoveryRoundInfo, neighbourhood_threshold: NodeDistance, - excluded_peers: Vec, } impl Discovering { @@ -52,10 +50,8 @@ impl Discovering { Self { params, context, - candidate_peers: Vec::new(), stats: Default::default(), neighbourhood_threshold: NodeDistance::max_distance(), - excluded_peers: Vec::new(), } } diff --git a/comms/rpc_macros/Cargo.toml b/comms/rpc_macros/Cargo.toml index a6e0373569..c8789f704f 100644 --- a/comms/rpc_macros/Cargo.toml +++ b/comms/rpc_macros/Cargo.toml @@ -6,21 +6,21 @@ repository = "https://github.com/tari-project/tari" homepage = "https://tari.com" readme = "README.md" license = "BSD-3-Clause" -version = "0.11.0" +version = "0.12.0" edition = "2018" [lib] proc-macro = true [dependencies] -tari_comms = { version = "^0.11", path = "../", features = ["rpc"] } +tari_comms = { version = "^0.12", path = "../", features = ["rpc"] } proc-macro2 = "1.0.24" quote = "1.0.7" syn = { version = "1.0.38", features = ["fold"] } [dev-dependencies] -tari_test_utils = { version = "^0.11", path = "../../infrastructure/test_utils" } +tari_test_utils = { version = "^0.12", path = "../../infrastructure/test_utils" } futures = "0.3.5" prost = "0.8.0" diff --git a/comms/src/connection_manager/manager.rs b/comms/src/connection_manager/manager.rs index 84ef26bba1..d218a883a3 100644 --- a/comms/src/connection_manager/manager.rs +++ b/comms/src/connection_manager/manager.rs @@ -350,14 +350,10 @@ where use ConnectionManagerRequest::*; trace!(target: LOG_TARGET, "Connection manager got request: {:?}", request); match request { - DialPeer { - node_id, - reply_tx, - tracing_id: _tracing, - } => { + DialPeer { node_id, reply_tx } => { + let tracing_id = tracing::Span::current().id(); let span = span!(Level::TRACE, "connection_manager::handle_request"); - // This causes a panic for some reason? - // span.follows_from(tracing_id); + span.follows_from(tracing_id); self.dial_peer(node_id, reply_tx).instrument(span).await }, CancelDial(node_id) => { diff --git a/comms/src/connection_manager/peer_connection.rs b/comms/src/connection_manager/peer_connection.rs index 15862a9ff0..37b05b4cd3 100644 --- a/comms/src/connection_manager/peer_connection.rs +++ b/comms/src/connection_manager/peer_connection.rs @@ -60,7 +60,7 @@ use tokio::{ time, }; use tokio_stream::StreamExt; -use tracing::{self, span, Instrument, Level, Span}; +use tracing::{self, span, Instrument, Level}; const LOG_TARGET: &str = "comms::connection_manager::peer_connection"; @@ -116,7 +116,6 @@ pub enum PeerConnectionRequest { OpenSubstream { protocol_id: ProtocolId, reply_tx: oneshot::Sender, PeerConnectionError>>, - tracing_id: Option, }, /// Disconnect all substreams and close the transport connection Disconnect(bool, oneshot::Sender>), @@ -207,7 +206,6 @@ impl PeerConnection { .send(PeerConnectionRequest::OpenSubstream { protocol_id: protocol_id.clone(), reply_tx, - tracing_id: Span::current().id(), }) .await?; reply_rx @@ -394,11 +392,8 @@ impl PeerConnectionActor { async fn handle_request(&mut self, request: PeerConnectionRequest) { use PeerConnectionRequest::*; match request { - OpenSubstream { - protocol_id, - reply_tx, - tracing_id, - } => { + OpenSubstream { protocol_id, reply_tx } => { + let tracing_id = tracing::Span::current().id(); let span = span!(Level::TRACE, "handle_request"); span.follows_from(tracing_id); let result = self.open_negotiated_protocol_stream(protocol_id).instrument(span).await; diff --git a/comms/src/connection_manager/requester.rs b/comms/src/connection_manager/requester.rs index 7525ef9514..455ca7860e 100644 --- a/comms/src/connection_manager/requester.rs +++ b/comms/src/connection_manager/requester.rs @@ -35,7 +35,6 @@ pub enum ConnectionManagerRequest { DialPeer { node_id: NodeId, reply_tx: Option>>, - tracing_id: Option, }, /// Cancels a pending dial if one exists CancelDial(NodeId), @@ -100,11 +99,7 @@ impl ConnectionManagerRequester { reply_tx: Option>>, ) -> Result<(), ConnectionManagerError> { self.sender - .send(ConnectionManagerRequest::DialPeer { - node_id, - reply_tx, - tracing_id: tracing::Span::current().id(), - }) + .send(ConnectionManagerRequest::DialPeer { node_id, reply_tx }) .await .map_err(|_| ConnectionManagerError::SendToActorFailed)?; Ok(()) diff --git a/comms/src/connectivity/manager.rs b/comms/src/connectivity/manager.rs index 644989e9ba..9d045df380 100644 --- a/comms/src/connectivity/manager.rs +++ b/comms/src/connectivity/manager.rs @@ -209,13 +209,9 @@ impl ConnectivityManagerActor { GetConnectivityStatus(reply) => { let _ = reply.send(self.status); }, - DialPeer { - node_id, - reply_tx, - tracing_id, - } => { + DialPeer { node_id, reply_tx } => { + let tracing_id = tracing::Span::current().id(); let span = span!(Level::TRACE, "handle_request"); - // let _e = span.enter(); span.follows_from(tracing_id); async move { match self.pool.get(&node_id) { diff --git a/comms/src/connectivity/requester.rs b/comms/src/connectivity/requester.rs index 9d0b6af1f8..7c30333736 100644 --- a/comms/src/connectivity/requester.rs +++ b/comms/src/connectivity/requester.rs @@ -89,7 +89,6 @@ pub enum ConnectivityRequest { DialPeer { node_id: NodeId, reply_tx: Option>>, - tracing_id: Option, }, GetConnectivityStatus(oneshot::Sender), SelectConnections( @@ -131,7 +130,6 @@ impl ConnectivityRequester { .send(ConnectivityRequest::DialPeer { node_id: peer.clone(), reply_tx: Some(reply_tx), - tracing_id: tracing::Span::current().id(), }) .await .map_err(|_| ConnectivityError::ActorDisconnected)?; @@ -171,7 +169,6 @@ impl ConnectivityRequester { self.sender.send(ConnectivityRequest::DialPeer { node_id: peer, reply_tx: None, - tracing_id: tracing::Span::current().id(), }) })) .await diff --git a/comms/src/multiplexing/yamux.rs b/comms/src/multiplexing/yamux.rs index 54696cecd7..811f485390 100644 --- a/comms/src/multiplexing/yamux.rs +++ b/comms/src/multiplexing/yamux.rs @@ -144,7 +144,7 @@ impl Control { let stream = self.inner.open_stream().await?; Ok(Substream { stream: stream.compat(), - counter_guard, + _counter_guard: counter_guard, }) } @@ -193,7 +193,7 @@ impl Stream for IncomingSubstreams { match futures::ready!(Pin::new(&mut self.inner).poll_recv(cx)) { Some(stream) => Poll::Ready(Some(Substream { stream: stream.compat(), - counter_guard: self.substream_counter.new_guard(), + _counter_guard: self.substream_counter.new_guard(), })), None => Poll::Ready(None), } @@ -209,7 +209,7 @@ impl Drop for IncomingSubstreams { #[derive(Debug)] pub struct Substream { stream: Compat, - counter_guard: AtomicRefCounterGuard, + _counter_guard: AtomicRefCounterGuard, } impl StreamId for Substream { diff --git a/comms/src/noise/socket.rs b/comms/src/noise/socket.rs index 5b4e1a6d20..85bf932b7c 100644 --- a/comms/src/noise/socket.rs +++ b/comms/src/noise/socket.rs @@ -758,11 +758,11 @@ mod test { let (mut a, mut b) = perform_handshake(dialer, listener).await?; - let buf_send = [1; MAX_PAYLOAD_LENGTH + 1]; - a.write_all(&buf_send).await?; + let buf_send = &[1; MAX_PAYLOAD_LENGTH + 1]; + a.write_all(buf_send).await?; a.flush().await?; - let mut buf_receive = [0; MAX_PAYLOAD_LENGTH + 1]; + let mut buf_receive = vec![0; MAX_PAYLOAD_LENGTH + 1]; b.read_exact(&mut buf_receive).await?; assert_eq!(&buf_receive[..], &buf_send[..]); @@ -776,11 +776,11 @@ mod test { let (mut a, mut b) = perform_handshake(dialer, listener).await?; - let buf_send = [1; MAX_PAYLOAD_LENGTH * 2 + 1024]; - a.write_all(&buf_send).await?; + let buf_send = &[1; MAX_PAYLOAD_LENGTH * 2 + 1024]; + a.write_all(buf_send).await?; a.flush().await?; - let mut buf_receive = [0; MAX_PAYLOAD_LENGTH * 2 + 1024]; + let mut buf_receive = vec![0; MAX_PAYLOAD_LENGTH * 2 + 1024]; b.read_exact(&mut buf_receive).await?; assert_eq!(&buf_receive[..], &buf_send[..]); @@ -793,14 +793,14 @@ mod test { let (mut a, mut b) = perform_handshake(dialer, listener).await?; - let buf_send = [1; MAX_PAYLOAD_LENGTH]; - a.write_all(&buf_send).await?; + let buf_send = &[1; MAX_PAYLOAD_LENGTH]; + a.write_all(buf_send).await?; a.flush().await?; a.socket.shutdown().await.unwrap(); drop(a); - let mut buf_receive = [0; MAX_PAYLOAD_LENGTH]; + let mut buf_receive = vec![0; MAX_PAYLOAD_LENGTH]; b.read_exact(&mut buf_receive).await.unwrap(); assert_eq!(&buf_receive[..], &buf_send[..]); diff --git a/comms/src/test_utils/mocks/connection_manager.rs b/comms/src/test_utils/mocks/connection_manager.rs index 415a4b3aa9..e88962f319 100644 --- a/comms/src/test_utils/mocks/connection_manager.rs +++ b/comms/src/test_utils/mocks/connection_manager.rs @@ -130,11 +130,7 @@ impl ConnectionManagerMock { self.state.inc_call_count(); self.state.add_call(format!("{:?}", req)).await; match req { - DialPeer { - node_id, - mut reply_tx, - tracing_id: _, - } => { + DialPeer { node_id, mut reply_tx } => { // Send Ok(conn) if we have an active connection, otherwise Err(DialConnectFailedAllAddresses) let result = self .state diff --git a/comms/src/test_utils/mocks/connectivity_manager.rs b/comms/src/test_utils/mocks/connectivity_manager.rs index d11d99ecaf..da38b24e35 100644 --- a/comms/src/test_utils/mocks/connectivity_manager.rs +++ b/comms/src/test_utils/mocks/connectivity_manager.rs @@ -213,11 +213,7 @@ impl ConnectivityManagerMock { use ConnectivityRequest::*; self.state.add_call(format!("{:?}", req)).await; match req { - DialPeer { - node_id, - reply_tx, - tracing_id: _, - } => { + DialPeer { node_id, reply_tx } => { self.state.add_dialed_peer(node_id.clone()).await; // No reply, no reason to do anything in the mock if reply_tx.is_none() { diff --git a/comms/src/test_utils/mocks/peer_connection.rs b/comms/src/test_utils/mocks/peer_connection.rs index 36198a0485..23240acd53 100644 --- a/comms/src/test_utils/mocks/peer_connection.rs +++ b/comms/src/test_utils/mocks/peer_connection.rs @@ -197,11 +197,7 @@ impl PeerConnectionMock { use PeerConnectionRequest::*; self.state.inc_call_count(); match req { - OpenSubstream { - protocol_id, - reply_tx, - tracing_id: _, - } => match self.state.open_substream().await { + OpenSubstream { protocol_id, reply_tx } => match self.state.open_substream().await { Ok(stream) => { let negotiated_substream = NegotiatedSubstream { protocol: protocol_id, diff --git a/dan_layer/core/Cargo.toml b/dan_layer/core/Cargo.toml new file mode 100644 index 0000000000..7f7b994dae --- /dev/null +++ b/dan_layer/core/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "tari_dan_core" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tari_common = { path = "../../common" } +tari_comms = { path = "../../comms" } +tari_comms_dht = { path = "../../comms/dht" } +tari_comms_rpc_macros = { path = "../../comms/rpc_macros" } +tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", branch = "main" } +tari_mmr = { path = "../../base_layer/mmr" } +tari_p2p = { path = "../../base_layer/p2p" } +tari_service_framework = { path = "../../base_layer/service_framework" } +tari_shutdown = { path = "../../infrastructure/shutdown" } +tari_storage = { path = "../../infrastructure/storage" } +tari_core = {path = "../../base_layer/core"} + +anyhow = "1.0.32" +async-trait = "0.1.50" +blake2 = "0.9.2" +clap = "2.33.3" +digest = "0.9.0" +futures = { version = "^0.3.1" } +log = { version = "0.4.8", features = ["std"] } +lmdb-zero = "0.4.4" +prost = "0.8" +prost-types = "0.8" +serde = "1.0.126" +thiserror = "^1.0.20" +tokio = { version="1.10", features = ["macros", "time"]} +tokio-stream = { version = "0.1.7", features = ["sync"] } +tonic = "0.5.2" + +# saving of patricia tree +patricia_tree = { version = "0.3.0", features = ["binary-format"] } +bytecodec = { version = "0.4.14", features = ["bincode_codec"] } +serde_json = "1.0.64" + +[dev-dependencies] +tari_test_utils = "0.8.1" + +[build-dependencies] +tari_common = { path = "../../common", features = ["build"] } diff --git a/dan_layer/core/src/digital_assets_error.rs b/dan_layer/core/src/digital_assets_error.rs new file mode 100644 index 0000000000..816a90d436 --- /dev/null +++ b/dan_layer/core/src/digital_assets_error.rs @@ -0,0 +1,47 @@ +// 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 crate::storage::StorageError; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum DigitalAssetError { + #[error("Unknown method: {method_name}")] + _UnknownMethod { method_name: String }, + #[error("Missing argument at position {position} (name: {argument_name}")] + _MissingArgument { argument_name: String, position: usize }, + #[error("Invalid sig, TODO: fill in deets")] + InvalidSignature, + #[error("Peer sent an invalid message: {0}")] + InvalidPeerMessage(String), + #[error("Storage error: {0}")] + StorageError(#[from] StorageError), + #[error("Metadata was malformed: {0}")] + MalformedMetadata(String), + #[error("Could not convert between types:{0}")] + ConversionError(String), +} + +impl From for DigitalAssetError { + fn from(err: lmdb_zero::Error) -> Self { + Self::StorageError(err.into()) + } +} diff --git a/applications/tari_validator_node/src/dan_layer/mod.rs b/dan_layer/core/src/lib.rs similarity index 92% rename from applications/tari_validator_node/src/dan_layer/mod.rs rename to dan_layer/core/src/lib.rs index fd15be8183..6e3b71d1e9 100644 --- a/applications/tari_validator_node/src/dan_layer/mod.rs +++ b/dan_layer/core/src/lib.rs @@ -19,12 +19,13 @@ // 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. - -pub mod template_command; -pub mod templates; - -pub mod dan_node; +#![allow(clippy::too_many_arguments)] +mod digital_assets_error; +pub use digital_assets_error::DigitalAssetError; pub mod models; pub mod services; pub mod storage; +pub mod template_command; +pub mod templates; +pub mod types; pub mod workers; diff --git a/applications/tari_validator_node/src/dan_layer/models/asset_definition.rs b/dan_layer/core/src/models/asset_definition.rs similarity index 99% rename from applications/tari_validator_node/src/dan_layer/models/asset_definition.rs rename to dan_layer/core/src/models/asset_definition.rs index bf2af4c0ae..4f6a6f3635 100644 --- a/applications/tari_validator_node/src/dan_layer/models/asset_definition.rs +++ b/dan_layer/core/src/models/asset_definition.rs @@ -19,6 +19,7 @@ // 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::types::PublicKey; use serde::{self, de, Deserialize, Deserializer}; use std::{fmt, marker::PhantomData}; diff --git a/applications/tari_validator_node/src/dan_layer/models/base_layer_metadata.rs b/dan_layer/core/src/models/base_layer_metadata.rs similarity index 100% rename from applications/tari_validator_node/src/dan_layer/models/base_layer_metadata.rs rename to dan_layer/core/src/models/base_layer_metadata.rs diff --git a/applications/tari_validator_node/src/dan_layer/models/base_layer_output.rs b/dan_layer/core/src/models/base_layer_output.rs similarity index 100% rename from applications/tari_validator_node/src/dan_layer/models/base_layer_output.rs rename to dan_layer/core/src/models/base_layer_output.rs diff --git a/applications/tari_validator_node/src/dan_layer/models/block.rs b/dan_layer/core/src/models/block.rs similarity index 97% rename from applications/tari_validator_node/src/dan_layer/models/block.rs rename to dan_layer/core/src/models/block.rs index cbbb693cf8..da034a0911 100644 --- a/applications/tari_validator_node/src/dan_layer/models/block.rs +++ b/dan_layer/core/src/models/block.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 crate::dan_layer::models::Instruction; +use crate::models::Instruction; pub struct Block { instructions: Vec, diff --git a/applications/tari_validator_node/src/dan_layer/models/committee.rs b/dan_layer/core/src/models/committee.rs similarity index 96% rename from applications/tari_validator_node/src/dan_layer/models/committee.rs rename to dan_layer/core/src/models/committee.rs index 7bc482fe05..a02961069c 100644 --- a/applications/tari_validator_node/src/dan_layer/models/committee.rs +++ b/dan_layer/core/src/models/committee.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 crate::dan_layer::{models::ViewId, services::infrastructure_services::NodeAddressable}; +use crate::{models::ViewId, services::infrastructure_services::NodeAddressable}; #[derive(Clone)] pub struct Committee { diff --git a/applications/tari_validator_node/src/dan_layer/models/domain_events/consensus_worker_domain_event.rs b/dan_layer/core/src/models/domain_events/consensus_worker_domain_event.rs similarity index 97% rename from applications/tari_validator_node/src/dan_layer/models/domain_events/consensus_worker_domain_event.rs rename to dan_layer/core/src/models/domain_events/consensus_worker_domain_event.rs index 977fb69dab..e568c85a60 100644 --- a/applications/tari_validator_node/src/dan_layer/models/domain_events/consensus_worker_domain_event.rs +++ b/dan_layer/core/src/models/domain_events/consensus_worker_domain_event.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 crate::dan_layer::models::{ConsensusWorkerState, Event}; +use crate::models::{ConsensusWorkerState, Event}; use std::{fmt, fmt::Formatter}; #[derive(Debug, Clone, PartialEq)] diff --git a/applications/tari_validator_node/src/dan_layer/models/domain_events/mod.rs b/dan_layer/core/src/models/domain_events/mod.rs similarity index 100% rename from applications/tari_validator_node/src/dan_layer/models/domain_events/mod.rs rename to dan_layer/core/src/models/domain_events/mod.rs diff --git a/applications/tari_validator_node/src/dan_layer/models/hot_stuff_message.rs b/dan_layer/core/src/models/hot_stuff_message.rs similarity index 97% rename from applications/tari_validator_node/src/dan_layer/models/hot_stuff_message.rs rename to dan_layer/core/src/models/hot_stuff_message.rs index dff9ccd89c..d5757ad918 100644 --- a/applications/tari_validator_node/src/dan_layer/models/hot_stuff_message.rs +++ b/dan_layer/core/src/models/hot_stuff_message.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 crate::dan_layer::models::{HotStuffMessageType, HotStuffTreeNode, Payload, QuorumCertificate, Signature, ViewId}; +use crate::models::{HotStuffMessageType, HotStuffTreeNode, Payload, QuorumCertificate, Signature, ViewId}; use digest::Digest; use tari_crypto::common::Blake256; diff --git a/applications/tari_validator_node/src/dan_layer/models/hot_stuff_tree_node.rs b/dan_layer/core/src/models/hot_stuff_tree_node.rs similarity index 96% rename from applications/tari_validator_node/src/dan_layer/models/hot_stuff_tree_node.rs rename to dan_layer/core/src/models/hot_stuff_tree_node.rs index a6a47a6be9..115c4fc99a 100644 --- a/applications/tari_validator_node/src/dan_layer/models/hot_stuff_tree_node.rs +++ b/dan_layer/core/src/models/hot_stuff_tree_node.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 crate::dan_layer::models::{Payload, TreeNodeHash}; +use crate::models::{Payload, TreeNodeHash}; use digest::Digest; use tari_crypto::common::Blake256; @@ -64,6 +64,10 @@ impl HotStuffTreeNode { TreeNodeHash(result.to_vec()) } + pub fn hash(&self) -> &TreeNodeHash { + &self.hash + } + pub fn parent(&self) -> &TreeNodeHash { &self.parent } diff --git a/applications/tari_validator_node/src/dan_layer/models/instruction.rs b/dan_layer/core/src/models/instruction.rs similarity index 75% rename from applications/tari_validator_node/src/dan_layer/models/instruction.rs rename to dan_layer/core/src/models/instruction.rs index 3b4c3529ea..7c45b7c0f3 100644 --- a/applications/tari_validator_node/src/dan_layer/models/instruction.rs +++ b/dan_layer/core/src/models/instruction.rs @@ -21,21 +21,20 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::models::TokenId, + models::{TemplateId, TokenId}, types::{com_sig_to_bytes, ComSig, PublicKey}, }; use digest::Digest; use tari_crypto::{common::Blake256, tari_utilities::ByteArray}; -// TODO: fix hash derive -#[allow(clippy::derive_hash_xor_eq)] -#[derive(Clone, Debug, Hash)] +#[derive(Clone, Debug)] pub struct Instruction { asset_id: PublicKey, + template_id: TemplateId, method: String, args: Vec>, - from: TokenId, - signature: ComSig, + // from: TokenId, + // signature: ComSig, hash: Vec, } @@ -46,14 +45,22 @@ impl PartialEq for Instruction { } impl Instruction { - pub fn new(asset_id: PublicKey, method: String, args: Vec>, from: TokenId, _signature: ComSig) -> Self { + pub fn new( + asset_id: PublicKey, + template_id: TemplateId, + method: String, + args: Vec>, + /* from: TokenId, + * _signature: ComSig, */ + ) -> Self { let mut s = Self { asset_id, + template_id, method, args, - from, + // from, // TODO: this is obviously wrong - signature: ComSig::default(), + // signature: ComSig::default(), hash: vec![], }; s.hash = s.calculate_hash(); @@ -64,6 +71,10 @@ impl Instruction { &self.asset_id } + pub fn template_id(&self) -> TemplateId { + self.template_id + } + pub fn method(&self) -> &str { &self.method } @@ -72,16 +83,16 @@ impl Instruction { &self.args } - // TODO: rename to avoid use of from - pub fn from_owner(&self) -> &TokenId { - &self.from - } + // // TODO: rename to avoid use of from + // pub fn from_owner(&self) -> &TokenId { + // &self.from + // } - pub fn _signature(&self) -> &ComSig { - &self.signature - } + // pub fn _signature(&self) -> &ComSig { + // &self.signature + // } - pub fn _hash(&self) -> &[u8] { + pub fn hash(&self) -> &[u8] { &self.hash } @@ -92,9 +103,8 @@ impl Instruction { for a in &self.args { b = b.chain(a); } - b.chain(self.from.as_bytes()) - .chain(com_sig_to_bytes(&self.signature)) - .finalize() - .to_vec() + // b.chain(self.from.as_bytes()) + // .chain(com_sig_to_bytes(&self.signature)) + b.finalize().to_vec() } } diff --git a/applications/tari_validator_node/src/dan_layer/models/instruction_id.rs b/dan_layer/core/src/models/instruction_id.rs similarity index 100% rename from applications/tari_validator_node/src/dan_layer/models/instruction_id.rs rename to dan_layer/core/src/models/instruction_id.rs diff --git a/applications/tari_validator_node/src/dan_layer/models/instruction_set.rs b/dan_layer/core/src/models/instruction_set.rs similarity index 98% rename from applications/tari_validator_node/src/dan_layer/models/instruction_set.rs rename to dan_layer/core/src/models/instruction_set.rs index c1b370cf09..722aa51699 100644 --- a/applications/tari_validator_node/src/dan_layer/models/instruction_set.rs +++ b/dan_layer/core/src/models/instruction_set.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 crate::dan_layer::models::{ConsensusHash, Instruction}; +use crate::models::{ConsensusHash, Instruction}; use std::hash::Hash; use tari_crypto::common::Blake256; use tari_mmr::MerkleMountainRange; diff --git a/applications/tari_validator_node/src/dan_layer/models/mod.rs b/dan_layer/core/src/models/mod.rs similarity index 83% rename from applications/tari_validator_node/src/dan_layer/models/mod.rs rename to dan_layer/core/src/models/mod.rs index e399712cd8..bead61a970 100644 --- a/applications/tari_validator_node/src/dan_layer/models/mod.rs +++ b/dan_layer/core/src/models/mod.rs @@ -33,7 +33,7 @@ mod quorum_certificate; // mod replica_info; mod base_layer_metadata; mod base_layer_output; -mod instruction_id; +mod sidechain_metadata; mod tari_dan_payload; mod view; mod view_id; @@ -43,14 +43,16 @@ pub use committee::Committee; pub use hot_stuff_message::HotStuffMessage; pub use hot_stuff_tree_node::HotStuffTreeNode; pub use instruction::Instruction; -pub use instruction_id::InstructionId; pub use instruction_set::InstructionSet; pub use quorum_certificate::QuorumCertificate; // pub use replica_info::ReplicaInfo; pub use asset_definition::AssetDefinition; pub use base_layer_metadata::BaseLayerMetadata; pub use base_layer_output::BaseLayerOutput; - +use blake2::Digest; +use digest::Update; +pub use sidechain_metadata::SidechainMetadata; +use tari_crypto::common::Blake256; pub use tari_dan_payload::{CheckpointData, TariDanPayload}; pub use view::View; pub use view_id::ViewId; @@ -66,19 +68,31 @@ impl InstructionCaller { } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum TemplateId { - _EditableMetadata, + EditableMetadata = 2, } impl TemplateId { pub fn _parse(s: &str) -> TemplateId { match s { - "EditableMetadata" => TemplateId::_EditableMetadata, + "EditableMetadata" => TemplateId::EditableMetadata, _ => { // TODO: Propagate error instead dbg!("Unrecognised template"); - TemplateId::_EditableMetadata + TemplateId::EditableMetadata + }, + } + } +} + +impl From for TemplateId { + fn from(v: u32) -> Self { + // Must be an easier way than this + match v { + 2 => TemplateId::EditableMetadata, + _ => { + unimplemented!() }, } } @@ -136,38 +150,42 @@ impl TryFrom for HotStuffMessageType { } } -#[derive(Debug, Clone, Hash, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct TreeNodeHash(pub Vec); impl TreeNodeHash { - pub(crate) fn as_bytes(&self) -> &[u8] { + pub fn as_bytes(&self) -> &[u8] { self.0.as_slice() } } +impl From for Vec { + fn from(v: TreeNodeHash) -> Self { + v.0 + } +} pub trait ConsensusHash { fn consensus_hash(&self) -> &[u8]; } -// TODO: Perhaps should be CoW instead of Clone -pub trait Payload: Debug + Clone + Send + Sync + ConsensusHash {} - -impl Payload for &str {} - impl ConsensusHash for &str { fn consensus_hash(&self) -> &[u8] { self.as_bytes() } } -impl Payload for String {} - impl ConsensusHash for String { fn consensus_hash(&self) -> &[u8] { self.as_bytes() } } +// TODO: Perhaps should be CoW instead of Clone +pub trait Payload: Debug + Clone + Send + Sync + ConsensusHash {} + +impl Payload for &str {} +impl Payload for String {} + pub trait Event: Clone + Send + Sync {} #[derive(Debug, Clone, Copy, PartialEq)] @@ -189,3 +207,18 @@ impl Signature { other.clone() } } + +#[derive(Copy, Clone, Debug)] +pub struct ChainHeight(u64); + +impl From for u64 { + fn from(c: ChainHeight) -> Self { + c.0 + } +} + +impl From for ChainHeight { + fn from(v: u64) -> Self { + ChainHeight(v) + } +} diff --git a/applications/tari_validator_node/src/dan_layer/models/quorum_certificate.rs b/dan_layer/core/src/models/quorum_certificate.rs similarity index 96% rename from applications/tari_validator_node/src/dan_layer/models/quorum_certificate.rs rename to dan_layer/core/src/models/quorum_certificate.rs index fc4a1a07ec..a87d950379 100644 --- a/applications/tari_validator_node/src/dan_layer/models/quorum_certificate.rs +++ b/dan_layer/core/src/models/quorum_certificate.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 crate::dan_layer::models::{HotStuffMessageType, HotStuffTreeNode, Payload, Signature, ViewId}; +use crate::models::{HotStuffMessageType, HotStuffTreeNode, Payload, Signature, ViewId}; #[derive(Debug, Clone)] pub struct QuorumCertificate { diff --git a/applications/tari_validator_node/src/dan_layer/models/replica_info.rs b/dan_layer/core/src/models/replica_info.rs similarity index 100% rename from applications/tari_validator_node/src/dan_layer/models/replica_info.rs rename to dan_layer/core/src/models/replica_info.rs diff --git a/dan_layer/core/src/models/sidechain_metadata.rs b/dan_layer/core/src/models/sidechain_metadata.rs new file mode 100644 index 0000000000..8fc38d55db --- /dev/null +++ b/dan_layer/core/src/models/sidechain_metadata.rs @@ -0,0 +1,54 @@ +// 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 crate::{ + models::{ChainHeight, TreeNodeHash}, + types::PublicKey, +}; + +pub struct SidechainMetadata { + asset_public_key: PublicKey, + committed_height: ChainHeight, + committed_hash: TreeNodeHash, +} + +impl SidechainMetadata { + pub fn new(asset_public_key: PublicKey, committed_height: ChainHeight, committed_hash: TreeNodeHash) -> Self { + Self { + asset_public_key, + committed_hash, + committed_height, + } + } + + pub fn asset_public_key(&self) -> &PublicKey { + &self.asset_public_key + } + + pub fn committed_height(&self) -> ChainHeight { + self.committed_height + } + + pub fn committed_hash(&self) -> &TreeNodeHash { + &self.committed_hash + } +} diff --git a/applications/tari_validator_node/src/dan_layer/models/tari_dan_payload.rs b/dan_layer/core/src/models/tari_dan_payload.rs similarity index 93% rename from applications/tari_validator_node/src/dan_layer/models/tari_dan_payload.rs rename to dan_layer/core/src/models/tari_dan_payload.rs index 468a616573..7914b1a8c8 100644 --- a/applications/tari_validator_node/src/dan_layer/models/tari_dan_payload.rs +++ b/dan_layer/core/src/models/tari_dan_payload.rs @@ -20,10 +20,13 @@ // 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::dan_layer::models::{ConsensusHash, Instruction, InstructionSet, Payload}; +use crate::models::{ConsensusHash, Instruction, InstructionSet, Payload}; use digest::Digest; -use std::fmt::Debug; -use tari_crypto::common::Blake256; +use std::{ + fmt::{Debug, Formatter}, + hash::{Hash, Hasher}, +}; +use tari_crypto::{common::Blake256, tari_utilities::ByteArray}; #[derive(Debug, Clone)] pub struct TariDanPayload { diff --git a/applications/tari_validator_node/src/dan_layer/models/view.rs b/dan_layer/core/src/models/view.rs similarity index 97% rename from applications/tari_validator_node/src/dan_layer/models/view.rs rename to dan_layer/core/src/models/view.rs index f5a8e96427..6e9fffaeda 100644 --- a/applications/tari_validator_node/src/dan_layer/models/view.rs +++ b/dan_layer/core/src/models/view.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 crate::dan_layer::models::ViewId; +use crate::models::ViewId; // TODO: Encapsulate #[derive(Clone)] diff --git a/applications/tari_validator_node/src/dan_layer/models/view_id.rs b/dan_layer/core/src/models/view_id.rs similarity index 100% rename from applications/tari_validator_node/src/dan_layer/models/view_id.rs rename to dan_layer/core/src/models/view_id.rs diff --git a/dan_layer/core/src/services/asset_processor.rs b/dan_layer/core/src/services/asset_processor.rs new file mode 100644 index 0000000000..a0564a17fa --- /dev/null +++ b/dan_layer/core/src/services/asset_processor.rs @@ -0,0 +1,124 @@ +// 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 crate::{ + digital_assets_error::DigitalAssetError, + models::{AssetDefinition, Instruction, InstructionCaller, TemplateId}, + storage::{AssetStore, ChainDbUnitOfWork, StateDb, StateDbUnitOfWork, UnitOfWork}, + template_command::{ExecutionResult, TemplateCommand}, + templates::editable_metadata_template::_EditableMetadataTemplate, +}; +use async_trait::async_trait; +use std::{collections::VecDeque, sync::Arc}; +use tokio::sync::RwLock; + +pub trait AssetProcessor { + // purposefully made sync, because instructions should be run in order, and complete before the + // next one starts. There may be a better way to enforce this though... + fn execute_instruction( + &self, + instruction: &Instruction, + db: TUnitOfWork, + ) -> Result<(), DigitalAssetError>; +} + +pub struct ConcreteAssetProcessor { + asset_definition: AssetDefinition, + template_factory: TemplateFactory, + instruction_log: TInstructionLog, +} + +impl AssetProcessor for ConcreteAssetProcessor { + fn execute_instruction( + &self, + instruction: &Instruction, + db: TUnitOfWork, + ) -> Result<(), DigitalAssetError> { + self.execute( + instruction.template_id(), + instruction.method().to_owned(), + instruction.args().to_vec().into(), + // InstructionCaller { + // owner_token_id: instruction.from_owner().to_owned(), + // }, + instruction.hash().into(), + db, + ) + } +} + +impl ConcreteAssetProcessor { + pub fn new(instruction_log: TInstructionLog, asset_definition: AssetDefinition) -> Self { + Self { + template_factory: TemplateFactory {}, + instruction_log, + asset_definition, + } + } + + pub fn execute( + &self, + template_id: TemplateId, + method: String, + args: VecDeque>, + // caller: InstructionCaller, + hash: Vec, + db: TUnitOfWork, + ) -> Result<(), DigitalAssetError> { + todo!() + // let instruction = self.template_factory.create_command(template_id, method, args)?; + // let unit_of_work = state_db.new_unit_of_work(); + // let result = instruction.try_execute(db)?; + // unit_of_work.commit()?; + // self.instruction_log.store(hash, result); + // Ok(()) + } +} + +pub struct TemplateFactory {} + +impl TemplateFactory { + pub fn create_command( + &self, + template: TemplateId, + method: String, + args: VecDeque>, + // caller: InstructionCaller, + ) -> Result<(), DigitalAssetError> { + todo!() + } +} + +pub trait InstructionLog { + fn store(&mut self, hash: Vec, result: ExecutionResult); +} + +#[derive(Default)] +pub struct MemoryInstructionLog { + log: Vec<(Vec, ExecutionResult)>, +} + +impl InstructionLog for MemoryInstructionLog { + fn store(&mut self, hash: Vec, result: ExecutionResult) { + self.log.push((hash, result)) + } +} diff --git a/dan_layer/core/src/services/base_node_client.rs b/dan_layer/core/src/services/base_node_client.rs new file mode 100644 index 0000000000..4dfc3a2803 --- /dev/null +++ b/dan_layer/core/src/services/base_node_client.rs @@ -0,0 +1,42 @@ +// 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 crate::{ + digital_assets_error::DigitalAssetError, + models::{BaseLayerMetadata, BaseLayerOutput}, + types::PublicKey, +}; +use async_trait::async_trait; +use std::{convert::TryInto, net::SocketAddr}; +use tari_crypto::tari_utilities::ByteArray; + +#[async_trait] +pub trait BaseNodeClient { + async fn get_tip_info(&mut self) -> Result; + + async fn get_current_checkpoint( + &mut self, + height: u64, + asset_public_key: PublicKey, + checkpoint_unique_id: Vec, + ) -> Result, DigitalAssetError>; +} diff --git a/applications/tari_validator_node/src/dan_layer/services/committee_manager.rs b/dan_layer/core/src/services/committee_manager.rs similarity index 95% rename from applications/tari_validator_node/src/dan_layer/services/committee_manager.rs rename to dan_layer/core/src/services/committee_manager.rs index 7812f5d18a..f57ecb200a 100644 --- a/applications/tari_validator_node/src/dan_layer/services/committee_manager.rs +++ b/dan_layer/core/src/services/committee_manager.rs @@ -21,11 +21,9 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{BaseLayerOutput, Committee}, - services::infrastructure_services::NodeAddressable, - }, digital_assets_error::DigitalAssetError, + models::{BaseLayerOutput, Committee}, + services::infrastructure_services::NodeAddressable, types::PublicKey, }; diff --git a/applications/tari_validator_node/src/dan_layer/services/events_publisher.rs b/dan_layer/core/src/services/events_publisher.rs similarity index 98% rename from applications/tari_validator_node/src/dan_layer/services/events_publisher.rs rename to dan_layer/core/src/services/events_publisher.rs index ccf8c0fac9..9c95653aa3 100644 --- a/applications/tari_validator_node/src/dan_layer/services/events_publisher.rs +++ b/dan_layer/core/src/services/events_publisher.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 crate::dan_layer::models::Event; +use crate::models::Event; use log::*; use std::{ fmt::{Debug, Display}, diff --git a/applications/tari_validator_node/src/dan_layer/template_command.rs b/dan_layer/core/src/services/infrastructure_services/inbound_connection_service.rs similarity index 70% rename from applications/tari_validator_node/src/dan_layer/template_command.rs rename to dan_layer/core/src/services/infrastructure_services/inbound_connection_service.rs index cae598853c..dd30e4ab69 100644 --- a/applications/tari_validator_node/src/dan_layer/template_command.rs +++ b/dan_layer/core/src/services/infrastructure_services/inbound_connection_service.rs @@ -20,13 +20,18 @@ // 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::{dan_layer::storage::AssetStore, digital_assets_error::DigitalAssetError}; +use crate::models::{HotStuffMessage, Payload, TariDanPayload}; -pub trait TemplateCommand { - fn try_execute(&self, data_store: &mut dyn AssetStore) -> Result; -} +use crate::{digital_assets_error::DigitalAssetError, services::infrastructure_services::NodeAddressable}; +use async_trait::async_trait; +use futures::{self, pin_mut, Stream, StreamExt}; +use std::{convert::TryInto, sync::Arc}; +use tari_comms::types::CommsPublicKey; +use tari_p2p::comms_connector::PeerMessage; +use tari_shutdown::ShutdownSignal; +use tokio::sync::mpsc::{channel, Receiver, Sender}; -pub enum ExecutionResult { - Ok, - // Error, +#[async_trait] +pub trait InboundConnectionService { + async fn receive_message(&mut self) -> (TAddr, HotStuffMessage); } diff --git a/applications/tari_validator_node/src/dan_layer/services/infrastructure_services/mocks/mod.rs b/dan_layer/core/src/services/infrastructure_services/mocks/mod.rs similarity index 97% rename from applications/tari_validator_node/src/dan_layer/services/infrastructure_services/mocks/mod.rs rename to dan_layer/core/src/services/infrastructure_services/mocks/mod.rs index cf1cc33caa..760cc8a13e 100644 --- a/applications/tari_validator_node/src/dan_layer/services/infrastructure_services/mocks/mod.rs +++ b/dan_layer/core/src/services/infrastructure_services/mocks/mod.rs @@ -21,11 +21,9 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::HotStuffMessage, - services::infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, - }, digital_assets_error::DigitalAssetError, + models::HotStuffMessage, + services::infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, }; use async_trait::async_trait; use std::collections::HashMap; diff --git a/applications/tari_validator_node/src/dan_layer/services/infrastructure_services/mod.rs b/dan_layer/core/src/services/infrastructure_services/mod.rs similarity index 90% rename from applications/tari_validator_node/src/dan_layer/services/infrastructure_services/mod.rs rename to dan_layer/core/src/services/infrastructure_services/mod.rs index cfcb8be2cc..638e3dc94c 100644 --- a/applications/tari_validator_node/src/dan_layer/services/infrastructure_services/mod.rs +++ b/dan_layer/core/src/services/infrastructure_services/mod.rs @@ -24,9 +24,9 @@ mod inbound_connection_service; mod node_addressable; mod outbound_service; -pub use inbound_connection_service::{InboundConnectionService, TariCommsInboundConnectionService}; +pub use inbound_connection_service::InboundConnectionService; pub use node_addressable::NodeAddressable; -pub use outbound_service::{OutboundService, TariCommsOutboundService}; +pub use outbound_service::OutboundService; #[cfg(test)] pub mod mocks; diff --git a/applications/tari_validator_node/src/dan_layer/services/infrastructure_services/node_addressable.rs b/dan_layer/core/src/services/infrastructure_services/node_addressable.rs similarity index 100% rename from applications/tari_validator_node/src/dan_layer/services/infrastructure_services/node_addressable.rs rename to dan_layer/core/src/services/infrastructure_services/node_addressable.rs diff --git a/applications/tari_validator_node/src/digital_assets_error.rs b/dan_layer/core/src/services/infrastructure_services/outbound_service.rs similarity index 62% rename from applications/tari_validator_node/src/digital_assets_error.rs rename to dan_layer/core/src/services/infrastructure_services/outbound_service.rs index dda9194dba..861d156b7b 100644 --- a/applications/tari_validator_node/src/digital_assets_error.rs +++ b/dan_layer/core/src/services/infrastructure_services/outbound_service.rs @@ -19,29 +19,34 @@ // 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::dan_layer::storage::StorageError; -use thiserror::Error; -#[derive(Debug, Error)] -pub enum DigitalAssetError { - #[error("Unknown method: {method_name}")] - _UnknownMethod { method_name: String }, - #[error("Missing argument at position {position} (name: {argument_name}")] - _MissingArgument { argument_name: String, position: usize }, - #[error("Invalid sig, TODO: fill in deets")] - InvalidSignature, - #[error("Peer sent an invalid message: {0}")] - InvalidPeerMessage(String), - #[error("Storage error: {0}")] - StorageError(#[from] StorageError), - #[error("Metadata was malformed: {0}")] - MalformedMetadata(String), - #[error("Could not convert between types:{0}")] - ConversionError(String), -} +use crate::{ + digital_assets_error::DigitalAssetError, + models::{HotStuffMessage, Payload}, + services::infrastructure_services::NodeAddressable, +}; +use async_trait::async_trait; + +use crate::models::TariDanPayload; +use std::marker::PhantomData; +use tari_comms::types::CommsPublicKey; +use tari_comms_dht::{domain_message::OutboundDomainMessage, outbound::OutboundMessageRequester}; +use tari_p2p::tari_message::TariMessageType; +use tokio::sync::mpsc::Sender; + +#[async_trait] +pub trait OutboundService { + async fn send( + &mut self, + from: TAddr, + to: TAddr, + message: HotStuffMessage, + ) -> Result<(), DigitalAssetError>; -impl From for DigitalAssetError { - fn from(err: lmdb_zero::Error) -> Self { - Self::StorageError(err.into()) - } + async fn broadcast( + &mut self, + from: TAddr, + committee: &[TAddr], + message: HotStuffMessage, + ) -> Result<(), DigitalAssetError>; } diff --git a/applications/tari_validator_node/src/dan_layer/services/mempool_service.rs b/dan_layer/core/src/services/mempool_service.rs similarity index 97% rename from applications/tari_validator_node/src/dan_layer/services/mempool_service.rs rename to dan_layer/core/src/services/mempool_service.rs index 4f1289a0c1..c453e33661 100644 --- a/applications/tari_validator_node/src/dan_layer/services/mempool_service.rs +++ b/dan_layer/core/src/services/mempool_service.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 crate::{dan_layer::models::Instruction, digital_assets_error::DigitalAssetError}; +use crate::{digital_assets_error::DigitalAssetError, models::Instruction}; use async_trait::async_trait; use std::sync::Arc; use tokio::sync::Mutex; diff --git a/applications/tari_validator_node/src/dan_layer/services/mocks/mod.rs b/dan_layer/core/src/services/mocks/mod.rs similarity index 93% rename from applications/tari_validator_node/src/dan_layer/services/mocks/mod.rs rename to dan_layer/core/src/services/mocks/mod.rs index f1e9d45172..18b6cafdfb 100644 --- a/applications/tari_validator_node/src/dan_layer/services/mocks/mod.rs +++ b/dan_layer/core/src/services/mocks/mod.rs @@ -21,19 +21,17 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{BaseLayerMetadata, BaseLayerOutput, Committee, Event, Instruction, Payload, Signature}, - services::{ - base_node_client::BaseNodeClient, - infrastructure_services::NodeAddressable, - EventsPublisher, - MempoolService, - PayloadProcessor, - PayloadProvider, - SigningService, - }, - }, digital_assets_error::DigitalAssetError, + models::{BaseLayerMetadata, BaseLayerOutput, Committee, Event, Instruction, Payload, Signature}, + services::{ + base_node_client::BaseNodeClient, + infrastructure_services::NodeAddressable, + EventsPublisher, + MempoolService, + PayloadProcessor, + PayloadProvider, + SigningService, + }, types::PublicKey, }; use async_trait::async_trait; diff --git a/applications/tari_validator_node/src/dan_layer/services/mod.rs b/dan_layer/core/src/services/mod.rs similarity index 97% rename from applications/tari_validator_node/src/dan_layer/services/mod.rs rename to dan_layer/core/src/services/mod.rs index 93046c1c5b..a4c3a0b4dc 100644 --- a/applications/tari_validator_node/src/dan_layer/services/mod.rs +++ b/dan_layer/core/src/services/mod.rs @@ -31,7 +31,7 @@ mod payload_provider; mod signing_service; pub use asset_processor::{AssetProcessor, ConcreteAssetProcessor, MemoryInstructionLog}; -pub use base_node_client::{BaseNodeClient, GrpcBaseNodeClient}; +pub use base_node_client::BaseNodeClient; pub use committee_manager::{CommitteeManager, ConcreteCommitteeManager}; pub use events_publisher::{EventsPublisher, LoggingEventsPublisher}; pub use mempool_service::{ConcreteMempoolService, MempoolService, MempoolServiceHandle}; diff --git a/applications/tari_validator_node/src/dan_layer/services/payload_processor.rs b/dan_layer/core/src/services/payload_processor.rs similarity index 68% rename from applications/tari_validator_node/src/dan_layer/services/payload_processor.rs rename to dan_layer/core/src/services/payload_processor.rs index 36a1a21794..b376ec7b5b 100644 --- a/applications/tari_validator_node/src/dan_layer/services/payload_processor.rs +++ b/dan_layer/core/src/services/payload_processor.rs @@ -21,17 +21,22 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{Payload, TariDanPayload}, - services::{AssetProcessor, MempoolService}, - }, digital_assets_error::DigitalAssetError, + models::{Payload, TariDanPayload}, + services::{AssetProcessor, MempoolService}, + storage::{ChainDb, ChainDbUnitOfWork, DbFactory, UnitOfWork}, }; use async_trait::async_trait; +use std::sync::Arc; +use tokio::sync::RwLock; #[async_trait] pub trait PayloadProcessor { - async fn process_payload(&mut self, payload: &TPayload) -> Result<(), DigitalAssetError>; + async fn process_payload( + &self, + payload: &TPayload, + unit_of_work: TUnitOfWork, + ) -> Result<(), DigitalAssetError>; } pub struct TariDanPayloadProcessor @@ -55,18 +60,27 @@ impl } #[async_trait] -impl PayloadProcessor - for TariDanPayloadProcessor +impl + PayloadProcessor for TariDanPayloadProcessor { - async fn process_payload(&mut self, payload: &TariDanPayload) -> Result<(), DigitalAssetError> { + async fn process_payload( + &self, + payload: &TariDanPayload, + unit_of_work: TUnitOfWork, + ) -> Result<(), DigitalAssetError> { + // let mut unit_of_work = db.new_unit_of_work(); for instruction in payload.instructions() { dbg!("Executing instruction"); dbg!(&instruction); // TODO: Should we swallow + log the error instead of propagating it? - self.asset_processor.execute_instruction(instruction).await?; + self.asset_processor + .execute_instruction(instruction, unit_of_work.clone())?; } - self.mempool_service.remove_instructions(payload.instructions()).await?; + // self.mempool_service.remove_instructions(payload.instructions()).await?; + + // TODO: Remove this....Unit of work should actually be committed only at COMMIT stage + // unit_of_work.commit()?; Ok(()) } diff --git a/applications/tari_validator_node/src/dan_layer/services/payload_provider.rs b/dan_layer/core/src/services/payload_provider.rs similarity index 95% rename from applications/tari_validator_node/src/dan_layer/services/payload_provider.rs rename to dan_layer/core/src/services/payload_provider.rs index 2046294133..76415ae7e4 100644 --- a/applications/tari_validator_node/src/dan_layer/services/payload_provider.rs +++ b/dan_layer/core/src/services/payload_provider.rs @@ -21,11 +21,9 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{InstructionSet, Payload, TariDanPayload}, - services::MempoolService, - }, digital_assets_error::DigitalAssetError, + models::{AssetDefinition, InstructionSet, Payload, TariDanPayload}, + services::MempoolService, }; use async_trait::async_trait; diff --git a/applications/tari_validator_node/src/dan_layer/services/signing_service.rs b/dan_layer/core/src/services/signing_service.rs similarity index 96% rename from applications/tari_validator_node/src/dan_layer/services/signing_service.rs rename to dan_layer/core/src/services/signing_service.rs index fbe0e6181e..5af42d1b5f 100644 --- a/applications/tari_validator_node/src/dan_layer/services/signing_service.rs +++ b/dan_layer/core/src/services/signing_service.rs @@ -21,8 +21,9 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{models::Signature, services::infrastructure_services::NodeAddressable}, digital_assets_error::DigitalAssetError, + models::Signature, + services::infrastructure_services::NodeAddressable, }; use tari_comms::{types::CommsPublicKey, NodeIdentity}; diff --git a/dan_layer/core/src/storage/chain_storage_service.rs b/dan_layer/core/src/storage/chain_storage_service.rs new file mode 100644 index 0000000000..b4467c945b --- /dev/null +++ b/dan_layer/core/src/storage/chain_storage_service.rs @@ -0,0 +1,67 @@ +// 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 crate::{ + models::{HotStuffTreeNode, Payload, QuorumCertificate, SidechainMetadata, TariDanPayload}, + storage::{ChainDbUnitOfWork, DbFactory, StorageError, UnitOfWork}, +}; +use async_trait::async_trait; +use std::sync::Arc; +use tokio::sync::RwLock; + +// TODO: perhaps rename to ChainBusinessLogic +// One per asset, per network +#[async_trait] +pub trait ChainStorageService { + async fn get_metadata(&self) -> Result; + async fn save_node( + &self, + node: &HotStuffTreeNode, + db: TUnitOfWork, + ) -> Result<(), StorageError>; +} +// #[derive(Clone)] +// pub struct ChainStorageServiceHandle { +// service: Arc>, +// } +// +// impl ChainStorageServiceHandle { +// pub fn new() -> Self { +// todo!() +// // Self { +// +// // TODO: fix this ordering +// // service: Arc::new(RwLock::new(LmdbChainStorageService {})), +// // } +// } +// } +// +// #[async_trait] +// impl ChainStorageService for ChainStorageServiceHandle { +// async fn get_metadata(&self) -> Result { +// self.service.read().await.get_metadata().await +// } +// +// async fn save_qc(&self, node: &QuorumCertificate, db: ChainDbUnitOfWork) -> Result<(), StorageError> { +// self.service.write().await.save_qc(node, db) +// } +// } diff --git a/applications/tari_validator_node/src/dan_layer/storage/error.rs b/dan_layer/core/src/storage/error.rs similarity index 100% rename from applications/tari_validator_node/src/dan_layer/storage/error.rs rename to dan_layer/core/src/storage/error.rs diff --git a/dan_layer/core/src/storage/lmdb/asset_db.rs b/dan_layer/core/src/storage/lmdb/asset_db.rs new file mode 100644 index 0000000000..d7b79bfe50 --- /dev/null +++ b/dan_layer/core/src/storage/lmdb/asset_db.rs @@ -0,0 +1,24 @@ +// 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. + +/// A database for each asset (per network) +pub struct AssetDb {} diff --git a/applications/tari_validator_node/src/dan_layer/storage/lmdb/helpers.rs b/dan_layer/core/src/storage/lmdb/helpers.rs similarity index 98% rename from applications/tari_validator_node/src/dan_layer/storage/lmdb/helpers.rs rename to dan_layer/core/src/storage/lmdb/helpers.rs index f77888d126..1a0f769343 100644 --- a/applications/tari_validator_node/src/dan_layer/storage/lmdb/helpers.rs +++ b/dan_layer/core/src/storage/lmdb/helpers.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 crate::dan_layer::storage::StorageError; +use crate::storage::StorageError; use lmdb_zero::db; use std::path::Path; use tari_storage::lmdb_store::{LMDBBuilder, LMDBConfig, LMDBStore}; diff --git a/dan_layer/core/src/storage/lmdb/lmdb_asset_backend.rs b/dan_layer/core/src/storage/lmdb/lmdb_asset_backend.rs new file mode 100644 index 0000000000..5d917c3dfb --- /dev/null +++ b/dan_layer/core/src/storage/lmdb/lmdb_asset_backend.rs @@ -0,0 +1,74 @@ +// 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 lmdb_zero as lmdb; +use lmdb_zero::{put, ConstAccessor, LmdbResultExt, ReadTransaction, WriteAccessor, WriteTransaction}; +use std::{fs, fs::File, path::Path, sync::Arc}; + +use tari_common::file_lock; +use tari_storage::lmdb_store::{DatabaseRef, LMDBConfig}; + +use crate::storage::{lmdb::helpers::create_lmdb_store, StorageError}; + +#[derive(Clone)] +pub struct LmdbAssetBackend { + _file_lock: Arc, + env: Arc, + metadata_db: DatabaseRef, +} + +impl LmdbAssetBackend { + pub(crate) fn initialize>(path: P, config: LMDBConfig) -> Result { + fs::create_dir_all(&path)?; + let file_lock = file_lock::try_lock_exclusive(path.as_ref())?; + let store = create_lmdb_store(path, config)?; + + Ok(Self { + _file_lock: Arc::new(file_lock), + env: store.env(), + metadata_db: store.get_handle("metadata").unwrap().db(), + }) + } + + pub fn read_transaction(&self) -> Result, StorageError> { + Ok(ReadTransaction::new(&*self.env)?) + } + + pub fn write_transaction(&self) -> Result, StorageError> { + Ok(WriteTransaction::new(&*self.env)?) + } + + pub fn get_metadata<'a>(&self, access: &'a ConstAccessor<'_>, key: u64) -> Result, StorageError> { + let val = access.get::<_, [u8]>(&*self.metadata_db, &key).to_opt()?; + Ok(val) + } + + pub fn replace_metadata( + &self, + access: &mut WriteAccessor<'_>, + key: u64, + metadata: &[u8], + ) -> Result<(), StorageError> { + access.put(&self.metadata_db, &key, metadata, put::Flags::empty())?; + Ok(()) + } +} diff --git a/applications/tari_validator_node/src/dan_layer/storage/lmdb/mod.rs b/dan_layer/core/src/storage/lmdb/lmdb_asset_store.rs similarity index 69% rename from applications/tari_validator_node/src/dan_layer/storage/lmdb/mod.rs rename to dan_layer/core/src/storage/lmdb/lmdb_asset_store.rs index f779ab3d0b..dc67a68424 100644 --- a/applications/tari_validator_node/src/dan_layer/storage/lmdb/mod.rs +++ b/dan_layer/core/src/storage/lmdb/lmdb_asset_store.rs @@ -1,4 +1,4 @@ -// Copyright 2021, The Tari Project +// 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: @@ -20,36 +20,27 @@ // 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. -#[cfg(test)] -mod test; +use lmdb_zero::ConstAccessor; +use patricia_tree::{node::Node, PatriciaMap}; +use std::path::Path; -mod helpers; +use tari_storage::lmdb_store::LMDBConfig; use crate::{ - dan_layer::{ - models::TokenId, - storage::{error::StorageError, AssetStore}, - }, digital_assets_error::DigitalAssetError, + models::TokenId, + storage::{ + lmdb::{lmdb_asset_backend::LmdbAssetBackend, PATRICIA_MAP_KEY}, + AssetStore, + StorageError, + }, }; use bytecodec::{ bincode_codec::{BincodeDecoder, BincodeEncoder}, DecodeExt, EncodeExt, }; -use helpers::create_lmdb_store; -use lmdb_zero as lmdb; -use lmdb_zero::{put, ConstAccessor, LmdbResultExt, ReadTransaction, WriteAccessor, WriteTransaction}; -use patricia_tree::{ - node::{Node, NodeDecoder, NodeEncoder}, - PatriciaMap, -}; - -use std::{fs, fs::File, path::Path, sync::Arc}; -use tari_common::file_lock; -use tari_storage::lmdb_store::{DatabaseRef, LMDBConfig}; - -const PATRICIA_MAP_KEY: u64 = 1u64; +use patricia_tree::node::{NodeDecoder, NodeEncoder}; pub struct LmdbAssetStore { db: LmdbAssetBackend, @@ -122,51 +113,6 @@ impl Clone for LmdbAssetStore { } } } - -#[derive(Clone)] -pub struct LmdbAssetBackend { - _file_lock: Arc, - env: Arc, - metadata_db: DatabaseRef, -} - -impl LmdbAssetBackend { - pub(self) fn initialize>(path: P, config: LMDBConfig) -> Result { - fs::create_dir_all(&path)?; - let file_lock = file_lock::try_lock_exclusive(path.as_ref())?; - let store = create_lmdb_store(path, config)?; - - Ok(Self { - _file_lock: Arc::new(file_lock), - env: store.env(), - metadata_db: store.get_handle("metadata").unwrap().db(), - }) - } - - pub fn read_transaction(&self) -> Result, StorageError> { - Ok(ReadTransaction::new(&*self.env)?) - } - - pub fn write_transaction(&self) -> Result, StorageError> { - Ok(WriteTransaction::new(&*self.env)?) - } - - pub fn get_metadata<'a>(&self, access: &'a ConstAccessor<'_>, key: u64) -> Result, StorageError> { - let val = access.get::<_, [u8]>(&*self.metadata_db, &key).to_opt()?; - Ok(val) - } - - pub fn replace_metadata( - &self, - access: &mut WriteAccessor<'_>, - key: u64, - metadata: &[u8], - ) -> Result<(), StorageError> { - access.put(&self.metadata_db, &key, metadata, put::Flags::empty())?; - Ok(()) - } -} - fn decode_patricia_nodes(bytes: &[u8]) -> Result, bytecodec::Error> where for<'de> T: serde::Deserialize<'de> { let mut decoder = NodeDecoder::new(BincodeDecoder::new()); diff --git a/dan_layer/core/src/storage/lmdb/mod.rs b/dan_layer/core/src/storage/lmdb/mod.rs new file mode 100644 index 0000000000..431e086c1b --- /dev/null +++ b/dan_layer/core/src/storage/lmdb/mod.rs @@ -0,0 +1,58 @@ +// 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::{fs, fs::File, path::Path, sync::Arc}; + +use crate::{ + digital_assets_error::DigitalAssetError, + models::TokenId, + storage::{error::StorageError, AssetStore}, +}; +use bytecodec::{ + bincode_codec::{BincodeDecoder, BincodeEncoder}, + DecodeExt, + EncodeExt, +}; +use lmdb_zero as lmdb; +use lmdb_zero::{put, ConstAccessor, LmdbResultExt, ReadTransaction, WriteAccessor, WriteTransaction}; +use patricia_tree::{ + node::{Node, NodeDecoder, NodeEncoder}, + PatriciaMap, +}; + +use helpers::create_lmdb_store; +use tari_common::file_lock; +use tari_storage::lmdb_store::{DatabaseRef, LMDBConfig}; + +#[cfg(test)] +mod test; + +mod asset_db; +mod helpers; +mod lmdb_asset_backend; +mod lmdb_asset_store; + +pub use asset_db::AssetDb; +pub use lmdb_asset_backend::LmdbAssetBackend; +pub use lmdb_asset_store::LmdbAssetStore; + +const PATRICIA_MAP_KEY: u64 = 1u64; diff --git a/applications/tari_validator_node/src/dan_layer/storage/lmdb/test.rs b/dan_layer/core/src/storage/lmdb/test.rs similarity index 96% rename from applications/tari_validator_node/src/dan_layer/storage/lmdb/test.rs rename to dan_layer/core/src/storage/lmdb/test.rs index b47b8b0ad8..fb6548cd5e 100644 --- a/applications/tari_validator_node/src/dan_layer/storage/lmdb/test.rs +++ b/dan_layer/core/src/storage/lmdb/test.rs @@ -20,13 +20,15 @@ // 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::dan_layer::{ - models::TokenId, - storage::{AssetStore, LmdbAssetStore}, -}; use std::fs; + use tari_test_utils::paths; +use crate::{ + models::TokenId, + storage::{lmdb::lmdb_asset_store::LmdbAssetStore, AssetStore}, +}; + fn with_store(f: F) { let path = paths::create_temporary_data_path(); let store = LmdbAssetStore::initialize(&path, Default::default()).unwrap(); diff --git a/dan_layer/core/src/storage/mod.rs b/dan_layer/core/src/storage/mod.rs new file mode 100644 index 0000000000..2845c83efc --- /dev/null +++ b/dan_layer/core/src/storage/mod.rs @@ -0,0 +1,220 @@ +// 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 crate::{ + models::{ChainHeight, HotStuffTreeNode, Instruction, SidechainMetadata, TreeNodeHash}, + storage::sqlite::SqliteBackendAdapter, +}; +pub use chain_storage_service::ChainStorageService; +pub use error::StorageError; +pub use lmdb::{LmdbAssetBackend, LmdbAssetStore}; +use std::sync::{Arc, RwLock}; +pub use store::{AssetDataStore, AssetStore}; +use tari_common::GlobalConfig; + +mod chain_storage_service; +mod error; +pub mod lmdb; +mod store; + +// feature sql +pub mod sqlite; + +pub trait DbFactory { + fn create(&self) -> ChainDb; +} + +#[derive(Clone)] +pub struct SqliteDbFactory {} + +impl SqliteDbFactory { + pub fn new(config: &GlobalConfig) -> Self { + Self {} + } + + fn create_adapter(&self) -> SqliteBackendAdapter { + SqliteBackendAdapter {} + } +} + +impl DbFactory for SqliteDbFactory { + fn create(&self) -> ChainDb { + ChainDb { + adapter: self.create_adapter(), + } + } +} + +pub struct ChainDb { + adapter: TBackendAdapter, +} + +impl ChainDb { + pub fn new_unit_of_work(&self) -> ChainDbUnitOfWork { + ChainDbUnitOfWork { + inner: Arc::new(RwLock::new(ChainDbUnitOfWorkInner::new(self.adapter.clone()))), + } + } +} +impl ChainDb { + pub fn is_empty(&self) -> bool { + return true; + } +} + +pub enum UnitOfWorkTracker { + SidechainMetadata, +} + +pub enum NewUnitOfWorkTracker { + Node { + hash: TreeNodeHash, + parent: TreeNodeHash, + }, + Instruction { + instruction: Instruction, + node_hash: TreeNodeHash, + }, +} + +pub trait BackendAdapter: Send + Sync + Clone { + type BackendTransaction; + fn create_transaction(&self) -> Self::BackendTransaction; + fn insert(&self, item: &NewUnitOfWorkTracker, transaction: &Self::BackendTransaction) -> Result<(), StorageError>; + fn commit(&self, transaction: &Self::BackendTransaction) -> Result<(), StorageError>; +} + +pub struct ChainDbUnitOfWorkInner { + backend_adapter: TBackendAdapter, + clean_items: Vec, + dirty_items: Vec, + new_items: Vec, +} + +impl ChainDbUnitOfWorkInner { + pub fn new(backend_adapter: TBackendAdapter) -> Self { + Self { + backend_adapter, + clean_items: vec![], + dirty_items: vec![], + new_items: vec![], + } + } +} + +pub trait UnitOfWork: Clone + Send + Sync { + fn commit(&mut self) -> Result<(), StorageError>; + fn add_node(&mut self, hash: TreeNodeHash, parent: TreeNodeHash) -> Result<(), StorageError>; + fn add_instruction(&mut self, node_hash: TreeNodeHash, instruction: Instruction) -> Result<(), StorageError>; +} + +// Cloneable, Send, Sync wrapper +pub struct ChainDbUnitOfWork { + inner: Arc>>, +} + +impl Clone for ChainDbUnitOfWork { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } +} + +impl UnitOfWork for ChainDbUnitOfWork { + // pub fn register_clean(&mut self, item: UnitOfWorkTracker) { + // self.clean.push(item); + // } + + fn commit(&mut self) -> Result<(), StorageError> { + let mut inner = self.inner.write().unwrap(); + let tx = inner.backend_adapter.create_transaction(); + for item in inner.new_items.iter() { + inner.backend_adapter.insert(item, &tx)?; + } + + inner.backend_adapter.commit(&tx)?; + Ok(()) + } + + fn add_node(&mut self, hash: TreeNodeHash, parent: TreeNodeHash) -> Result<(), StorageError> { + self.inner + .write() + .unwrap() + .new_items + .push(NewUnitOfWorkTracker::Node { hash, parent }); + Ok(()) + } + + fn add_instruction(&mut self, node_hash: TreeNodeHash, instruction: Instruction) -> Result<(), StorageError> { + self.inner + .write() + .unwrap() + .new_items + .push(NewUnitOfWorkTracker::Instruction { node_hash, instruction }); + Ok(()) + } +} + +pub struct StateDb { + unit_of_work: Option, +} + +impl StateDb { + pub fn new_unit_of_work(&mut self) -> &mut StateDbUnitOfWork { + self.unit_of_work = Some(StateDbUnitOfWork { child: None }); + self.unit_of_work.as_mut().unwrap() + // 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() + } + + fn current_unit_of_work_mut(&mut self) -> Option<&mut StateDbUnitOfWork> { + unimplemented!() + // let mut result = self.unit_of_work.as_mut(); + // let mut child = result; + // while let Some(c) = child { + // result = child; + // child = c.child.as_mut(); + // } + // + // return result; + } +} + +pub struct StateDbUnitOfWork { + child: Option>>, +} + +impl StateDbUnitOfWork { + pub fn new_unit_of_work(&mut self) -> &mut StateDbUnitOfWork { + // TODO: better implementation + self + } + + pub fn commit(&mut self) -> Result<(), StorageError> { + Ok(()) + } +} diff --git a/dan_layer/core/src/storage/sqlite/mod.rs b/dan_layer/core/src/storage/sqlite/mod.rs new file mode 100644 index 0000000000..068646b5f1 --- /dev/null +++ b/dan_layer/core/src/storage/sqlite/mod.rs @@ -0,0 +1,72 @@ +// 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 crate::{ + models::{HotStuffTreeNode, QuorumCertificate, SidechainMetadata, TariDanPayload}, + storage::{BackendAdapter, ChainDbUnitOfWork, ChainStorageService, NewUnitOfWorkTracker, StorageError, UnitOfWork}, +}; +use async_trait::async_trait; +use std::sync::Arc; +use tokio::sync::RwLock; + +pub struct SqliteStorageService {} + +#[async_trait] +impl ChainStorageService for SqliteStorageService { + async fn get_metadata(&self) -> Result { + todo!() + } + + async fn save_node( + &self, + node: &HotStuffTreeNode, + db: TUnitOfWork, + ) -> Result<(), StorageError> { + let mut db = db; + for instruction in node.payload().instructions() { + db.add_instruction(node.hash().clone(), instruction.clone())?; + } + db.add_node(node.hash().clone(), node.parent().clone())?; + Ok(()) + } +} + +#[derive(Clone)] +pub struct SqliteBackendAdapter {} + +pub struct SqliteTransaction {} + +impl BackendAdapter for SqliteBackendAdapter { + type BackendTransaction = SqliteTransaction; + + fn create_transaction(&self) -> Self::BackendTransaction { + SqliteTransaction {} + } + + fn insert(&self, item: &NewUnitOfWorkTracker, transaction: &Self::BackendTransaction) -> Result<(), StorageError> { + todo!() + } + + fn commit(&self, transaction: &Self::BackendTransaction) -> Result<(), StorageError> { + todo!() + } +} diff --git a/applications/tari_validator_node/src/dan_layer/storage/store.rs b/dan_layer/core/src/storage/store.rs similarity index 96% rename from applications/tari_validator_node/src/dan_layer/storage/store.rs rename to dan_layer/core/src/storage/store.rs index a8fa9c71f5..d5619f7154 100644 --- a/applications/tari_validator_node/src/dan_layer/storage/store.rs +++ b/dan_layer/core/src/storage/store.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 crate::{dan_layer::models::TokenId, digital_assets_error::DigitalAssetError}; +use crate::{digital_assets_error::DigitalAssetError, models::TokenId}; // const PATRICIA_MAP_KEY: u64 = 1u64; diff --git a/dan_layer/core/src/template_command.rs b/dan_layer/core/src/template_command.rs new file mode 100644 index 0000000000..b6e8a5ee2d --- /dev/null +++ b/dan_layer/core/src/template_command.rs @@ -0,0 +1,37 @@ +// 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 crate::{ + digital_assets_error::DigitalAssetError, + storage::{AssetStore, ChainDbUnitOfWork, StateDbUnitOfWork, UnitOfWork}, +}; +use std::sync::Arc; +use tokio::sync::RwLock; + +pub trait TemplateCommand { + fn try_execute(&self, db: TUnitOfWork) -> Result; +} + +pub enum ExecutionResult { + Ok, + // Error, +} diff --git a/applications/tari_validator_node/src/dan_layer/templates/editable_metadata_template.rs b/dan_layer/core/src/templates/editable_metadata_template.rs similarity index 57% rename from applications/tari_validator_node/src/dan_layer/templates/editable_metadata_template.rs rename to dan_layer/core/src/templates/editable_metadata_template.rs index d79e289933..d8c41cd094 100644 --- a/applications/tari_validator_node/src/dan_layer/templates/editable_metadata_template.rs +++ b/dan_layer/core/src/templates/editable_metadata_template.rs @@ -21,14 +21,13 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{InstructionCaller, TokenId}, - storage::AssetStore, - template_command::{ExecutionResult, TemplateCommand}, - }, digital_assets_error::DigitalAssetError, + models::{InstructionCaller, TokenId}, + storage::{AssetStore, ChainDbUnitOfWork, StateDbUnitOfWork, UnitOfWork}, + template_command::{ExecutionResult, TemplateCommand}, }; -use std::collections::VecDeque; +use std::{collections::VecDeque, sync::Arc}; +use tokio::sync::RwLock; pub struct _EditableMetadataTemplate {} @@ -36,44 +35,47 @@ impl _EditableMetadataTemplate { pub fn _create_command( method: String, mut args: VecDeque>, - caller: InstructionCaller, - ) -> Result { - match method.as_str() { - "update" => { - let token_id = caller._owner_token_id().clone(); - let metadata = args.pop_front().ok_or_else(|| DigitalAssetError::_MissingArgument { - argument_name: "metadata".to_string(), - position: 0, - })?; - // TODO: check for too many args - - Ok(UpdateMetadataCommand::_new(token_id, metadata, caller)) - }, - _ => Err(DigitalAssetError::_UnknownMethod { - method_name: method.clone(), - }), - } + // caller: InstructionCaller, + ) -> Result { + unimplemented!() + // match method.as_str() { + // "update" => { + // unimplemented!() + // // // let token_id = caller._owner_token_id().clone(); + // // let metadata = args.pop_front().ok_or_else(|| DigitalAssetError::_MissingArgument { + // // argument_name: "metadata".to_string(), + // // position: 0, + // // })?; + // // // TODO: check for too many args + // // + // // Ok(UpdateMetadataCommand::_new(token_id, metadata)) + // }, + // _ => Err(DigitalAssetError::_UnknownMethod { + // method_name: method.clone(), + // }), + // } } } pub struct UpdateMetadataCommand { token_id: TokenId, metadata: Vec, - _caller: InstructionCaller, + // _caller: InstructionCaller, } impl UpdateMetadataCommand { - pub fn _new(token_id: TokenId, metadata: Vec, caller: InstructionCaller) -> Self { + pub fn _new(token_id: TokenId, metadata: Vec) -> Self { Self { token_id, metadata, - _caller: caller, + // _caller: caller, } } } impl TemplateCommand for UpdateMetadataCommand { - fn try_execute(&self, data_store: &mut dyn AssetStore) -> Result { - data_store.replace_metadata(&self.token_id, &self.metadata)?; - Ok(ExecutionResult::Ok) + fn try_execute(&self, db: TUnitOfWork) -> Result { + // data_store.replace_metadata(&self.token_id, &self.metadata)?; + unimplemented!() + // Ok(ExecutionResult::Ok) } } diff --git a/applications/tari_validator_node/src/dan_layer/templates/mod.rs b/dan_layer/core/src/templates/mod.rs similarity index 100% rename from applications/tari_validator_node/src/dan_layer/templates/mod.rs rename to dan_layer/core/src/templates/mod.rs diff --git a/dan_layer/core/src/types.rs b/dan_layer/core/src/types.rs new file mode 100644 index 0000000000..6a652bf1f5 --- /dev/null +++ b/dan_layer/core/src/types.rs @@ -0,0 +1,48 @@ +// 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 tari_crypto::{ + ristretto::{RistrettoPublicKey, RistrettoSecretKey}, + signatures::CommitmentSignature, + tari_utilities::{ByteArray, ByteArrayError}, +}; + +/// Define the explicit Public key implementation for the Tari base layer +pub type PublicKey = RistrettoPublicKey; + +pub type ComSig = CommitmentSignature; + +pub fn create_com_sig_from_bytes(_bytes: &[u8]) -> Result { + Ok(ComSig::default()) + // Ok(ComSig::new( + // HomomorphicCommitment::from_bytes(&bytes[0..32])?, + // RistrettoSecretKey::from_bytes(&bytes[33..64])?, + // RistrettoSecretKey::from_bytes(&bytes[64..96])?, + // )) +} + +pub fn com_sig_to_bytes(comsig: &ComSig) -> Vec { + let mut v = Vec::from(comsig.public_nonce().as_bytes()); + v.extend_from_slice(comsig.u().as_bytes()); + v.extend_from_slice(comsig.v().as_bytes()); + v +} diff --git a/applications/tari_validator_node/src/dan_layer/workers/consensus_worker.rs b/dan_layer/core/src/workers/consensus_worker.rs similarity index 90% rename from applications/tari_validator_node/src/dan_layer/workers/consensus_worker.rs rename to dan_layer/core/src/workers/consensus_worker.rs index 10e1926972..3ae93f4110 100644 --- a/applications/tari_validator_node/src/dan_layer/workers/consensus_worker.rs +++ b/dan_layer/core/src/workers/consensus_worker.rs @@ -21,31 +21,30 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{ - domain_events::ConsensusWorkerDomainEvent, - AssetDefinition, - ConsensusWorkerState, - Payload, - QuorumCertificate, - View, - ViewId, - }, - services::{ - infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, - BaseNodeClient, - CommitteeManager, - EventsPublisher, - PayloadProcessor, - PayloadProvider, - SigningService, - }, - workers::{states, states::ConsensusWorkerStateEvent}, - }, digital_assets_error::DigitalAssetError, + models::{ + domain_events::ConsensusWorkerDomainEvent, + AssetDefinition, + ConsensusWorkerState, + Payload, + QuorumCertificate, + View, + ViewId, + }, + services::{ + infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, + BaseNodeClient, + CommitteeManager, + EventsPublisher, + PayloadProcessor, + PayloadProvider, + SigningService, + }, + storage::{BackendAdapter, ChainStorageService, DbFactory}, + workers::{states, states::ConsensusWorkerStateEvent}, }; use log::*; -use std::sync::Arc; +use std::{marker::PhantomData, sync::Arc}; use tari_shutdown::ShutdownSignal; use tokio::time::Duration; @@ -62,6 +61,9 @@ pub struct ConsensusWorker< TPayloadProcessor, TCommitteeManager, TBaseNodeClient, + TBackendAdapter, + TDbFactory, + TChainStorageService, > where TInboundConnectionService: InboundConnectionService, TOutboundService: OutboundService, @@ -73,6 +75,9 @@ pub struct ConsensusWorker< TPayloadProcessor: PayloadProcessor, TCommitteeManager: CommitteeManager, TBaseNodeClient: BaseNodeClient, + TBackendAdapter: BackendAdapter, + TDbFactory: DbFactory, + TChainStorageService: ChainStorageService, { inbound_connections: TInboundConnectionService, outbound_service: TOutboundService, @@ -89,6 +94,9 @@ pub struct ConsensusWorker< payload_processor: TPayloadProcessor, asset_definition: AssetDefinition, base_node_client: TBaseNodeClient, + db_factory: TDbFactory, + chain_storage_service: TChainStorageService, + pd: PhantomData, } impl< @@ -102,6 +110,9 @@ impl< TPayloadProcessor, TCommitteeManager, TBaseNodeClient, + TBackendAdapter, + TDbFactory, + TChainStorageService, > ConsensusWorker< TInboundConnectionService, @@ -114,6 +125,9 @@ impl< TPayloadProcessor, TCommitteeManager, TBaseNodeClient, + TBackendAdapter, + TDbFactory, + TChainStorageService, > where TInboundConnectionService: InboundConnectionService + 'static + Send + Sync, @@ -125,7 +139,12 @@ where TSigningService: SigningService, TPayloadProcessor: PayloadProcessor, TCommitteeManager: CommitteeManager, + TBaseNodeClient: BaseNodeClient, + // TODO: REmove this Send + TBackendAdapter: BackendAdapter + Send + Sync, + TDbFactory: DbFactory + Clone, + TChainStorageService: ChainStorageService, { pub fn new( inbound_connections: TInboundConnectionService, @@ -140,6 +159,8 @@ where asset_definition: AssetDefinition, base_node_client: TBaseNodeClient, timeout: Duration, + db_factory: TDbFactory, + chain_storage_service: TChainStorageService, ) -> Self { let prepare_qc = Arc::new(QuorumCertificate::genesis(payload_provider.create_genesis_payload())); @@ -159,6 +180,9 @@ where payload_processor, asset_definition, base_node_client, + db_factory, + chain_storage_service, + pd: PhantomData, } } @@ -218,12 +242,16 @@ where &mut self.base_node_client, &self.asset_definition, &mut self.committee_manager, + &self.db_factory, + &self.payload_provider, + &self.payload_processor, + &self.chain_storage_service, &self.node_id, ) .await }, Prepare => { - let mut p = states::Prepare::new(self.node_id.clone(), self.locked_qc.clone()); + let mut p = states::Prepare::new(self.node_id.clone(), self.locked_qc.clone(), self.db_factory.clone()); p.next_event( &self.get_current_view()?, self.timeout, diff --git a/applications/tari_validator_node/src/dan_layer/workers/mod.rs b/dan_layer/core/src/workers/mod.rs similarity index 100% rename from applications/tari_validator_node/src/dan_layer/workers/mod.rs rename to dan_layer/core/src/workers/mod.rs diff --git a/applications/tari_validator_node/src/dan_layer/workers/states/commit_state.rs b/dan_layer/core/src/workers/states/commit_state.rs similarity index 96% rename from applications/tari_validator_node/src/dan_layer/workers/states/commit_state.rs rename to dan_layer/core/src/workers/states/commit_state.rs index c2877a4035..2c8ea178ce 100644 --- a/applications/tari_validator_node/src/dan_layer/workers/states/commit_state.rs +++ b/dan_layer/core/src/workers/states/commit_state.rs @@ -21,24 +21,22 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{ - Committee, - HotStuffMessage, - HotStuffMessageType, - HotStuffTreeNode, - Payload, - QuorumCertificate, - View, - ViewId, - }, - services::{ - infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, - SigningService, - }, - workers::states::ConsensusWorkerStateEvent, - }, digital_assets_error::DigitalAssetError, + models::{ + Committee, + HotStuffMessage, + HotStuffMessageType, + HotStuffTreeNode, + Payload, + QuorumCertificate, + View, + ViewId, + }, + services::{ + infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, + SigningService, + }, + workers::states::ConsensusWorkerStateEvent, }; use std::{collections::HashMap, marker::PhantomData, time::Instant}; use tokio::time::{sleep, Duration}; diff --git a/applications/tari_validator_node/src/dan_layer/workers/states/decide_state.rs b/dan_layer/core/src/workers/states/decide_state.rs similarity index 95% rename from applications/tari_validator_node/src/dan_layer/workers/states/decide_state.rs rename to dan_layer/core/src/workers/states/decide_state.rs index e95166064b..0e514169a4 100644 --- a/applications/tari_validator_node/src/dan_layer/workers/states/decide_state.rs +++ b/dan_layer/core/src/workers/states/decide_state.rs @@ -21,24 +21,22 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{ - Committee, - HotStuffMessage, - HotStuffMessageType, - HotStuffTreeNode, - Payload, - QuorumCertificate, - View, - ViewId, - }, - services::{ - infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, - SigningService, - }, - workers::states::ConsensusWorkerStateEvent, - }, digital_assets_error::DigitalAssetError, + models::{ + Committee, + HotStuffMessage, + HotStuffMessageType, + HotStuffTreeNode, + Payload, + QuorumCertificate, + View, + ViewId, + }, + services::{ + infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, + SigningService, + }, + workers::states::ConsensusWorkerStateEvent, }; use std::{collections::HashMap, marker::PhantomData, time::Instant}; use tokio::time::{sleep, Duration}; @@ -252,7 +250,6 @@ where // &signing_service, // ) // .await?; - dbg!("Going to apply txs: ", justify.node().payload()); Ok(Some(ConsensusWorkerStateEvent::Decided)) } else { diff --git a/applications/tari_validator_node/src/dan_layer/workers/states/idle_state.rs b/dan_layer/core/src/workers/states/idle_state.rs similarity index 94% rename from applications/tari_validator_node/src/dan_layer/workers/states/idle_state.rs rename to dan_layer/core/src/workers/states/idle_state.rs index c62ba5017e..a1d7d51cb7 100644 --- a/applications/tari_validator_node/src/dan_layer/workers/states/idle_state.rs +++ b/dan_layer/core/src/workers/states/idle_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 crate::{dan_layer::workers::states::ConsensusWorkerStateEvent, digital_assets_error::DigitalAssetError}; +use crate::{digital_assets_error::DigitalAssetError, workers::states::ConsensusWorkerStateEvent}; use tokio::time::{sleep, Duration}; pub struct IdleState {} diff --git a/applications/tari_validator_node/src/dan_layer/workers/states/mod.rs b/dan_layer/core/src/workers/states/mod.rs similarity index 98% rename from applications/tari_validator_node/src/dan_layer/workers/states/mod.rs rename to dan_layer/core/src/workers/states/mod.rs index a36606ddd1..f42db59d7e 100644 --- a/applications/tari_validator_node/src/dan_layer/workers/states/mod.rs +++ b/dan_layer/core/src/workers/states/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. -use crate::dan_layer::models::ViewId; +use crate::models::ViewId; // #[async_trait] // pub trait State { diff --git a/applications/tari_validator_node/src/dan_layer/workers/states/next_view.rs b/dan_layer/core/src/workers/states/next_view.rs similarity index 92% rename from applications/tari_validator_node/src/dan_layer/workers/states/next_view.rs rename to dan_layer/core/src/workers/states/next_view.rs index 36e06c9179..9ee5cc17aa 100644 --- a/applications/tari_validator_node/src/dan_layer/workers/states/next_view.rs +++ b/dan_layer/core/src/workers/states/next_view.rs @@ -21,12 +21,10 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{Committee, HotStuffMessage, Payload, QuorumCertificate, View}, - services::infrastructure_services::{NodeAddressable, OutboundService}, - workers::states::ConsensusWorkerStateEvent, - }, digital_assets_error::DigitalAssetError, + models::{Committee, HotStuffMessage, Payload, QuorumCertificate, View}, + services::infrastructure_services::{NodeAddressable, OutboundService}, + workers::states::ConsensusWorkerStateEvent, }; use log::*; use tari_shutdown::ShutdownSignal; diff --git a/applications/tari_validator_node/src/dan_layer/workers/states/pre_commit_state.rs b/dan_layer/core/src/workers/states/pre_commit_state.rs similarity index 95% rename from applications/tari_validator_node/src/dan_layer/workers/states/pre_commit_state.rs rename to dan_layer/core/src/workers/states/pre_commit_state.rs index 214239d8a6..dbbfb4c068 100644 --- a/applications/tari_validator_node/src/dan_layer/workers/states/pre_commit_state.rs +++ b/dan_layer/core/src/workers/states/pre_commit_state.rs @@ -21,24 +21,22 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{ - Committee, - HotStuffMessage, - HotStuffMessageType, - HotStuffTreeNode, - Payload, - QuorumCertificate, - View, - ViewId, - }, - services::{ - infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, - SigningService, - }, - workers::states::ConsensusWorkerStateEvent, - }, digital_assets_error::DigitalAssetError, + models::{ + Committee, + HotStuffMessage, + HotStuffMessageType, + HotStuffTreeNode, + Payload, + QuorumCertificate, + View, + ViewId, + }, + services::{ + infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, + SigningService, + }, + workers::states::ConsensusWorkerStateEvent, }; use std::{collections::HashMap, marker::PhantomData, time::Instant}; use tokio::time::{sleep, Duration}; diff --git a/applications/tari_validator_node/src/dan_layer/workers/states/prepare.rs b/dan_layer/core/src/workers/states/prepare.rs similarity index 91% rename from applications/tari_validator_node/src/dan_layer/workers/states/prepare.rs rename to dan_layer/core/src/workers/states/prepare.rs index 6ef88303ac..d7ee3c4154 100644 --- a/applications/tari_validator_node/src/dan_layer/workers/states/prepare.rs +++ b/dan_layer/core/src/workers/states/prepare.rs @@ -21,30 +21,31 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::{ - Committee, - HotStuffMessage, - HotStuffMessageType, - HotStuffTreeNode, - Payload, - QuorumCertificate, - View, - ViewId, - }, - services::{ - infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, - PayloadProvider, - SigningService, - }, - workers::states::ConsensusWorkerStateEvent, - }, digital_assets_error::DigitalAssetError, + models::{ + Committee, + HotStuffMessage, + HotStuffMessageType, + HotStuffTreeNode, + Payload, + QuorumCertificate, + View, + ViewId, + }, + services::{ + infrastructure_services::{InboundConnectionService, NodeAddressable, OutboundService}, + PayloadProvider, + SigningService, + }, + workers::states::ConsensusWorkerStateEvent, }; use log::*; use std::{collections::HashMap, marker::PhantomData, sync::Arc, time::Instant}; -use crate::dan_layer::services::PayloadProcessor; +use crate::{ + services::PayloadProcessor, + storage::{BackendAdapter, DbFactory}, +}; use tokio::time::{sleep, Duration}; const LOG_TARGET: &str = "tari::dan::workers::states::prepare"; @@ -57,6 +58,8 @@ pub struct Prepare< TPayloadProvider, TPayload, TPayloadProcessor, + TBackendAdapter, + TDbFactory, > where TInboundConnectionService: InboundConnectionService + Send, TOutboundService: OutboundService, @@ -65,6 +68,8 @@ pub struct Prepare< TPayload: Payload, TPayloadProvider: PayloadProvider, TPayloadProcessor: PayloadProcessor, + TBackendAdapter: BackendAdapter, + TDbFactory: DbFactory, { node_id: TAddr, locked_qc: Arc>, @@ -76,6 +81,8 @@ pub struct Prepare< phantom_signing: PhantomData, phantom_processor: PhantomData, received_new_view_messages: HashMap>, + db_factory: TDbFactory, + pd: PhantomData, } impl< @@ -86,6 +93,8 @@ impl< TPayloadProvider, TPayload, TPayloadProcessor, + TBackendAdapter, + TDbFactory, > Prepare< TInboundConnectionService, @@ -95,6 +104,8 @@ impl< TPayloadProvider, TPayload, TPayloadProcessor, + TBackendAdapter, + TDbFactory, > where TInboundConnectionService: InboundConnectionService + Send, @@ -104,8 +115,10 @@ where TPayload: Payload, TPayloadProvider: PayloadProvider, TPayloadProcessor: PayloadProcessor, + TBackendAdapter: BackendAdapter + Send + Sync, + TDbFactory: DbFactory + Clone, { - pub fn new(node_id: TAddr, locked_qc: Arc>) -> Self { + pub fn new(node_id: TAddr, locked_qc: Arc>, db_factory: TDbFactory) -> Self { Self { node_id, locked_qc, @@ -115,6 +128,8 @@ where phantom_signing: PhantomData, received_new_view_messages: HashMap::new(), phantom_processor: PhantomData, + db_factory, + pd: PhantomData, } } @@ -253,7 +268,14 @@ where unimplemented!("Node is not safe") } - payload_processor.process_payload(justify.node().payload()).await?; + let db = self.db_factory.create(); + let unit_of_work = db.new_unit_of_work(); + + let res = payload_processor + .process_payload(justify.node().payload(), unit_of_work) + .await?; + + // TODO: Check result equals qc result self.send_vote_to_leader(node, outbound, view_leader, current_view.view_id, signing_service) .await?; @@ -293,7 +315,6 @@ where sleep(Duration::from_secs(3)).await; let payload = payload_provider.create_payload().await?; - dbg!(&payload); Ok(HotStuffTreeNode::from_parent(parent, payload)) } diff --git a/applications/tari_validator_node/src/dan_layer/workers/states/starting.rs b/dan_layer/core/src/workers/states/starting.rs similarity index 68% rename from applications/tari_validator_node/src/dan_layer/workers/states/starting.rs rename to dan_layer/core/src/workers/states/starting.rs index 8551605c0c..a7fa4ce0d7 100644 --- a/applications/tari_validator_node/src/dan_layer/workers/states/starting.rs +++ b/dan_layer/core/src/workers/states/starting.rs @@ -21,12 +21,17 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - dan_layer::{ - models::AssetDefinition, - services::{infrastructure_services::NodeAddressable, BaseNodeClient, CommitteeManager}, - workers::states::ConsensusWorkerStateEvent, - }, digital_assets_error::DigitalAssetError, + models::{AssetDefinition, Payload, QuorumCertificate, TariDanPayload}, + services::{ + infrastructure_services::NodeAddressable, + BaseNodeClient, + CommitteeManager, + PayloadProcessor, + PayloadProvider, + }, + storage::{BackendAdapter, ChainStorageService, DbFactory, UnitOfWork}, + workers::states::ConsensusWorkerStateEvent, }; use log::*; use std::marker::PhantomData; @@ -46,11 +51,24 @@ where TBaseNodeClient: BaseNodeClient } } - pub async fn next_event>( + pub async fn next_event< + TAddr: NodeAddressable, + TCommitteeManager: CommitteeManager, + TPayload: Payload, + TPayloadProvider: PayloadProvider, + TPayloadProcessor: PayloadProcessor, + TBackendAdapter: BackendAdapter, + TDbFactory: DbFactory, + TChainStorageService: ChainStorageService, + >( &self, base_node_client: &mut TBaseNodeClient, asset_definition: &AssetDefinition, committee_manager: &mut TCommitteeManager, + db_factory: &TDbFactory, + payload_provider: &TPayloadProvider, + payload_processor: &TPayloadProcessor, + chain_storage_service: &TChainStorageService, node_id: &TAddr, ) -> Result { info!( @@ -79,6 +97,21 @@ where TBaseNodeClient: BaseNodeClient return Ok(ConsensusWorkerStateEvent::NotPartOfCommittee); } + // read and create the genesis block + let chain_db = db_factory.create(); + if chain_db.is_empty() { + let mut tx = chain_db.new_unit_of_work(); + + let tx2 = tx.clone(); + // let metadata = chain_db.metadata.read(&mut tx); + let payload = payload_provider.create_genesis_payload(); + + payload_processor.process_payload(&payload, tx2).await?; + let genesis_qc = QuorumCertificate::genesis(payload); + chain_storage_service.save_node(genesis_qc.node(), tx.clone()).await?; + tx.commit()?; + } + Ok(ConsensusWorkerStateEvent::Initialized) } } diff --git a/dan_layer/validator_node_sqlite/Cargo.toml b/dan_layer/validator_node_sqlite/Cargo.toml new file mode 100644 index 0000000000..17b27cb3b5 --- /dev/null +++ b/dan_layer/validator_node_sqlite/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "validator_node_sqlite" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +diesel = { version = "1.4.8", features = ["sqlite"] } +dotenv = "0.15.0" \ No newline at end of file diff --git a/dan_layer/validator_node_sqlite/diesel.toml b/dan_layer/validator_node_sqlite/diesel.toml new file mode 100644 index 0000000000..92267c829f --- /dev/null +++ b/dan_layer/validator_node_sqlite/diesel.toml @@ -0,0 +1,5 @@ +# For documentation on how to configure this file, +# see diesel.rs/guides/configuring-diesel-cli + +[print_schema] +file = "src/schema.rs" diff --git a/dan_layer/validator_node_sqlite/migrations/.gitkeep b/dan_layer/validator_node_sqlite/migrations/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dan_layer/validator_node_sqlite/migrations/2021-11-02-185150_create_nodes/down.sql b/dan_layer/validator_node_sqlite/migrations/2021-11-02-185150_create_nodes/down.sql new file mode 100644 index 0000000000..291a97c5ce --- /dev/null +++ b/dan_layer/validator_node_sqlite/migrations/2021-11-02-185150_create_nodes/down.sql @@ -0,0 +1 @@ +-- This file should undo anything in `up.sql` \ No newline at end of file diff --git a/dan_layer/validator_node_sqlite/migrations/2021-11-02-185150_create_nodes/up.sql b/dan_layer/validator_node_sqlite/migrations/2021-11-02-185150_create_nodes/up.sql new file mode 100644 index 0000000000..87d2ce970a --- /dev/null +++ b/dan_layer/validator_node_sqlite/migrations/2021-11-02-185150_create_nodes/up.sql @@ -0,0 +1,15 @@ +-- Your SQL goes here +create table nodes ( + hash blob not null primary key, + parent blob not null +); + +create table instructions ( + id integer primary key autoincrement not null, + hash blob not null, + node_hash blob not null, + asset_id blob not null, + template_id int not null, + method text not null, + args blob not null +); \ No newline at end of file diff --git a/dan_layer/validator_node_sqlite/src/lib.rs b/dan_layer/validator_node_sqlite/src/lib.rs new file mode 100644 index 0000000000..dfed793316 --- /dev/null +++ b/dan_layer/validator_node_sqlite/src/lib.rs @@ -0,0 +1,26 @@ +// 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. + +#[macro_use] +extern crate diesel; + +mod schema; diff --git a/dan_layer/validator_node_sqlite/src/schema.rs b/dan_layer/validator_node_sqlite/src/schema.rs new file mode 100644 index 0000000000..c4c2a4197a --- /dev/null +++ b/dan_layer/validator_node_sqlite/src/schema.rs @@ -0,0 +1,23 @@ +table! { + instructions (id) { + id -> Integer, + hash -> Binary, + node_hash -> Binary, + asset_id -> Binary, + template_id -> Integer, + method -> Text, + args -> Binary, + } +} + +table! { + nodes (hash) { + hash -> Binary, + parent -> Binary, + } +} + +allow_tables_to_appear_in_same_query!( + instructions, + nodes, +); diff --git a/infrastructure/derive/Cargo.toml b/infrastructure/derive/Cargo.toml index f1ca1ed1e5..b6e9a12927 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.11.0" +version = "0.12.0" edition = "2018" [lib] diff --git a/infrastructure/shutdown/Cargo.toml b/infrastructure/shutdown/Cargo.toml index 735baa82d3..71051cc6db 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.11.0" +version = "0.12.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 da9dfc3c95..5c063a69de 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.11.0" +version = "0.12.0" edition = "2018" [dependencies] diff --git a/infrastructure/test_utils/Cargo.toml b/infrastructure/test_utils/Cargo.toml index fe21d3d742..cb58d95390 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.11.0" +version = "0.12.0" authors = ["The Tari Development Community"] edition = "2018" license = "BSD-3-Clause" diff --git a/integration_tests/README.md b/integration_tests/README.md index 00653b4f5d..6a1bc7ba7e 100644 --- a/integration_tests/README.md +++ b/integration_tests/README.md @@ -2,7 +2,7 @@ ## Prerequisites -- Install `Node.js` +- Install `Node.js` (_Currently, LTS version 12.22.X is recommended for wallet FFI compatibility_) - Open terminal in the `tari-project\integration_tests` folder and run ``` @@ -33,10 +33,10 @@ - To run a specific test, add `-- --name ` to the command line: -```shell - # eg: run a specific test + ```shell + # Runs a specific test npm test -- --name "Simple block sync" -``` + ``` - To run tests with specific tags, e.g. `critical`, add `-- --tags @` to the command line. @@ -53,21 +53,28 @@ npm test -- --tags "@critical and not @long-running and not @broken" ``` - # Runs all @critical tests, but not @long-running - - npm test -- --tags "@critical and not @long-running" +- To run the wallet FFI tests, add `--profile ci` to the command line (_take note of the node version requirements_). + ```shell + # Runs a specific FFI test + npm test -- --profile ci --name "My wallet FFI test scenario name" + # Runs a complete set of FFI tests + npm test -- --profile ci --tags "@wallet-ffi" ``` +- Runs all @critical tests, but not @long-running + + ``` + npm test -- --tags "@critical and not @long-running" ``` - See `npm test -- --help` for more options. ## Notes -- In Windows, running the Tari executables in debug mode fails with a stack overflow, thus Windows users must - run in release mode. See command line options in `baseNodeProcess.js`, `mergeMiningProxyProcess.js` - and `walletProcess.js`. +In Windows, running the Tari executables in debug mode fails with a stack overflow, thus Windows users must +run in release mode. See command line options in `baseNodeProcess.js`, `mergeMiningProxyProcess.js` +and `walletProcess.js`. ## Code Contribution diff --git a/integration_tests/features/Reorgs.feature b/integration_tests/features/Reorgs.feature index fa5022cee1..715a00fd11 100644 --- a/integration_tests/features/Reorgs.feature +++ b/integration_tests/features/Reorgs.feature @@ -63,7 +63,7 @@ Feature: Reorgs When I start base node NODE1 Then all nodes are at height 20 - @critical @reorg + @critical @reorg @flaky Scenario: Pruned mode reorg past horizon Given I have a base node NODE1 connected to all seed nodes And I have wallet WALLET1 connected to base node NODE1 diff --git a/integration_tests/features/Sync.feature b/integration_tests/features/Sync.feature index 1fcf031c98..af98f62ff1 100644 --- a/integration_tests/features/Sync.feature +++ b/integration_tests/features/Sync.feature @@ -115,7 +115,6 @@ Feature: Block Sync | 1000 | 50 | | 1001 | 50 | - Scenario: Pruned mode network only Given I have a base node NODE1 connected to all seed nodes Given I have a pruned node PNODE1 connected to node NODE1 with pruning horizon set to 5 diff --git a/integration_tests/features/WalletCli.feature b/integration_tests/features/WalletCli.feature index 4a7b4021fa..bdbd501980 100644 --- a/integration_tests/features/WalletCli.feature +++ b/integration_tests/features/WalletCli.feature @@ -81,7 +81,7 @@ Feature: Wallet CLI # TODO: base node connection. And I wait 30 seconds And I stop wallet SENDER - And I make it rain from wallet SENDER 1 tx / sec 10 sec 8000 uT 100 increment to RECEIVER via command line + 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 And mining node MINE mines 5 blocks diff --git a/integration_tests/features/WalletFFI.feature b/integration_tests/features/WalletFFI.feature index 2310c785a1..6b5ee539d0 100644 --- a/integration_tests/features/WalletFFI.feature +++ b/integration_tests/features/WalletFFI.feature @@ -36,24 +36,23 @@ Feature: Wallet FFI And I have a ffi wallet FFI_WALLET connected to base node BASE1 And I set base node BASE2 for ffi wallet FFI_WALLET And I stop ffi wallet FFI_WALLET - And I stop node BASE1 - And I wait 5 seconds - # Broken step with reason base node is not persisted - # See details on: - # Scenario: As a client I want to receive Tari via my Public Key sent while I am offline when I come back online - # And I restart ffi wallet FFI_WALLET + And I stop node BASE2 And I restart ffi wallet FFI_WALLET connected to base node BASE2 - Then I wait for ffi wallet FFI_WALLET to receive at least 1 SAF message + And I wait 5 seconds + Then I wait for ffi wallet FFI_WALLET to receive EXACTLY 0 SAF message + And I start base node BASE2 + Then I wait for ffi wallet FFI_WALLET to receive AT_LEAST 1 SAF message And I stop ffi wallet FFI_WALLET Scenario: As a client I want to cancel a transaction Given I have a base node BASE And I have wallet SENDER connected to base node BASE + And I have a ffi wallet FFI_WALLET connected to base node BASE And I have mining node MINER connected to base node BASE and wallet SENDER And mining node MINER mines 10 blocks Then I wait for wallet SENDER to have at least 1000000 uT - And I have a ffi wallet FFI_WALLET connected to base node BASE 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 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 @@ -68,53 +67,49 @@ Feature: Wallet FFI Given I have a base node BASE And I have a ffi wallet FFI_WALLET connected to base node BASE And I have wallet WALLET connected to base node BASE - And I wait 5 seconds And I add contact with alias ALIAS and pubkey WALLET to ffi wallet FFI_WALLET Then I have contact with alias ALIAS and pubkey WALLET in ffi wallet FFI_WALLET When I remove contact with alias ALIAS from ffi wallet FFI_WALLET Then I don't have contact with alias ALIAS in ffi wallet FFI_WALLET And I stop ffi wallet FFI_WALLET - # flaky on circle CI - @flaky Scenario: As a client I want to retrieve a list of transactions I have made and received - Given I have a base node BASE - And I have wallet SENDER connected to base node BASE - And I have mining node MINER connected to base node BASE and wallet SENDER + 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_WALLET connected to base node BASE2 + 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 have a ffi wallet FFI_WALLET connected to base node BASE 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 And mining node MINER mines 10 blocks Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT - And I have wallet RECEIVER connected to base node BASE 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 And mining node MINER mines 10 blocks Then I wait for wallet RECEIVER to have at least 1000000 uT And I have 1 received and 1 send transaction in ffi wallet FFI_WALLET And I start TXO validation on ffi wallet FFI_WALLET And I start TX validation on ffi wallet FFI_WALLET - Then I wait for ffi wallet FFI_WALLET to receive 1 mined + Then I wait for ffi wallet FFI_WALLET to receive 2 mined Then I want to view the transaction kernels for completed transactions in ffi wallet FFI_WALLET And I stop ffi wallet FFI_WALLET Scenario: As a client I want to receive Tari via my Public Key sent while I am offline when I come back online - Given I have a base node BASE - And I have wallet SENDER connected to base node BASE - And I have mining node MINER connected to base node BASE and wallet SENDER + 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_WALLET connected to base node BASE1 + 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 have a ffi wallet FFI_WALLET connected to base node BASE And I stop ffi wallet FFI_WALLET - And I wait 10 seconds And I send 2000000 uT without waiting for broadcast from wallet SENDER to wallet FFI_WALLET at fee 20 - And I wait 5 seconds - # Broken step with reason base node is not persisted - # Log: - # [wallet::transaction_service::callback_handler] DEBUG Calling Received Finalized Transaction callback function for TxId: 7595706993517535281 - # [wallet::transaction_service::service] WARN Error broadcasting completed transaction TxId: 7595706993517535281 to mempool: NoBaseNodeKeysProvided - # And I restart ffi wallet FFI_WALLET - And I restart ffi wallet FFI_WALLET connected to base node BASE + And I restart ffi wallet FFI_WALLET connected to base node BASE2 Then I wait for ffi wallet FFI_WALLET to receive 1 transaction Then I wait for ffi wallet FFI_WALLET to receive 1 finalization Then I wait for ffi wallet FFI_WALLET to receive 1 broadcast diff --git a/integration_tests/features/WalletRecovery.feature b/integration_tests/features/WalletRecovery.feature index 515bea426c..d003de4718 100644 --- a/integration_tests/features/WalletRecovery.feature +++ b/integration_tests/features/WalletRecovery.feature @@ -6,6 +6,7 @@ Feature: Wallet Recovery Given I have a seed node NODE And I have 1 base nodes connected to all seed nodes And I have wallet WALLET_A connected to all seed nodes + And I have wallet WALLET_C connected to all seed nodes And I have mining node MINER connected to base node NODE and wallet WALLET_A When mining node MINER mines 10 blocks When I mine 5 blocks on NODE @@ -13,7 +14,6 @@ Feature: Wallet Recovery Then all nodes are at height 15 When I recover wallet WALLET_A into wallet WALLET_B connected to all seed nodes Then wallet WALLET_A and wallet WALLET_B have the same balance - And I have wallet WALLET_C connected to all seed nodes And I send 100000 uT from wallet WALLET_B to wallet WALLET_C at fee 100 When I mine 5 blocks on NODE Then all nodes are at height 20 @@ -47,10 +47,10 @@ Feature: Wallet Recovery Given I have a seed node NODE And I have 1 base nodes connected to all seed nodes And I have wallet WALLET_A connected to all seed nodes + And I have wallet WALLET_B connected to all seed nodes And I have mining node MINER connected to base node NODE and wallet WALLET_A When mining node MINER mines 10 blocks Then all nodes are at height 10 - And I have wallet WALLET_B connected to all seed nodes And I stop wallet WALLET_B # Send 2 one-sided payments to WALLET_B so it can spend them in two cases Then I send a one-sided transaction of 1000000 uT from WALLET_A to WALLET_B at fee 20 diff --git a/integration_tests/features/WalletTransactions.feature b/integration_tests/features/WalletTransactions.feature index 02f51792be..96d7378903 100644 --- a/integration_tests/features/WalletTransactions.feature +++ b/integration_tests/features/WalletTransactions.feature @@ -6,11 +6,12 @@ Feature: Wallet Transactions Given I have a seed node NODE And I have 1 base nodes connected to all seed nodes And I have wallet WALLET_A connected to all seed nodes + And I have wallet WALLET_B connected to all seed nodes + And I have wallet WALLET_C connected to all seed nodes And I have mining node MINER connected to base node NODE and wallet WALLET_A When mining node MINER mines 15 blocks Then all nodes are at height 15 When I wait for wallet WALLET_A to have at least 55000000000 uT - And I have wallet WALLET_B connected to all seed nodes Then I send a one-sided transaction of 1000000 uT from WALLET_A to WALLET_B at fee 100 Then I send a one-sided transaction of 1000000 uT from WALLET_A to WALLET_B at fee 100 When mining node MINER mines 5 blocks @@ -23,7 +24,6 @@ Feature: Wallet Transactions Then all nodes are at height 25 Then I wait for wallet WALLET_B to have at least 1900000 uT # Make a one-sided payment to a new wallet that is big enough to ensure the second recovered output is spent - And I have wallet WALLET_C connected to all seed nodes Then I send a one-sided transaction of 1500000 uT from WALLET_B to WALLET_C at fee 20 Then I wait for wallet WALLET_B to have less than 1000000 uT When mining node MINER mines 5 blocks @@ -34,17 +34,17 @@ Feature: Wallet Transactions Given I have a seed node NODE And I have 1 base nodes connected to all seed nodes And I have wallet WALLET_A connected to all seed nodes + And I have wallet WALLET_B connected to all seed nodes + And I have wallet WALLET_C connected to all seed nodes And I have mining node MINER connected to base node NODE and wallet WALLET_A When mining node MINER mines 5 blocks Then all nodes are at height 5 Then I wait for wallet WALLET_A to have at least 10000000000 uT - Then I have wallet WALLET_B connected to all seed nodes And I send 1000000 uT from wallet WALLET_A to wallet WALLET_B at fee 100 Then mining node MINER mines 5 blocks Then all nodes are at height 10 Then I wait for wallet WALLET_B to have at least 1000000 uT Then I stop wallet WALLET_B - When I have wallet WALLET_C connected to all seed nodes Then I import WALLET_B unspent outputs to WALLET_C Then I wait for wallet WALLET_C to have at least 1000000 uT Then I restart wallet WALLET_C @@ -56,11 +56,12 @@ Feature: Wallet Transactions Given I have a seed node NODE And I have 1 base nodes connected to all seed nodes And I have wallet WALLET_A connected to all seed nodes + And I have wallet WALLET_B connected to all seed nodes + And I have wallet WALLET_C connected to all seed nodes And I have mining node MINER connected to base node NODE and wallet WALLET_A When mining node MINER mines 5 blocks Then all nodes are at height 5 Then I wait for wallet WALLET_A to have at least 10000000000 uT - Then I have wallet WALLET_B connected to all seed nodes And I send 1000000 uT from wallet WALLET_A to wallet WALLET_B at fee 100 Then mining node MINER mines 5 blocks Then all nodes are at height 10 @@ -70,7 +71,6 @@ Feature: Wallet Transactions Then all nodes are at height 15 When I wait for wallet WALLET_B to have at least 50000 uT Then I stop wallet WALLET_B - When I have wallet WALLET_C connected to all seed nodes Then I import WALLET_B spent outputs to WALLET_C Then I wait for wallet WALLET_C to have at least 1000000 uT Then I restart wallet WALLET_C @@ -86,16 +86,16 @@ Feature: Wallet Transactions Given I have a seed node SEED_B And I have a base node B connected to seed SEED_B And I have wallet WB connected to base node B + And I have wallet WALLET_RECEIVE_TX connected to base node B + And I have wallet WALLET_IMPORTED connected to base node B And I have mining node BM connected to base node B and wallet WB And mining node BM mines 4 blocks with min difficulty 1 and max difficulty 50 Then I wait for wallet WB to have at least 1000000 uT - And I have wallet WALLET_RECEIVE_TX connected to base node B And I send 1000000 uT from wallet WB to wallet WALLET_RECEIVE_TX at fee 100 Then mining node BM mines 4 blocks with min difficulty 50 and max difficulty 100 When node B is at height 8 Then I wait for wallet WALLET_RECEIVE_TX to have at least 1000000 uT Then I stop wallet WALLET_RECEIVE_TX - When I have wallet WALLET_IMPORTED connected to base node B Then I import WALLET_RECEIVE_TX unspent outputs to WALLET_IMPORTED Then I wait for wallet WALLET_IMPORTED to have at least 1000000 uT # This triggers a validation of the imported outputs @@ -128,17 +128,17 @@ Feature: Wallet Transactions Given I have a seed node NODE And I have 1 base nodes connected to all seed nodes And I have wallet WALLET_A connected to all seed nodes + And I have wallet WALLET_B connected to all seed nodes + And I have wallet WALLET_C connected to all seed nodes And I have mining node MINER connected to base node NODE and wallet WALLET_A When mining node MINER mines 5 blocks Then all nodes are at height 5 Then I wait for wallet WALLET_A to have at least 10000000000 uT - When I have wallet WALLET_B connected to all seed nodes And I send 1000000 uT from wallet WALLET_A to wallet WALLET_B at fee 100 When mining node MINER mines 6 blocks Then all nodes are at height 11 Then I wait for wallet WALLET_B to have at least 1000000 uT Then I stop wallet WALLET_B - When I have wallet WALLET_C connected to all seed nodes Then I import WALLET_B unspent outputs as faucet outputs to WALLET_C Then I wait for wallet WALLET_C to have at least 1000000 uT And I send 500000 uT from wallet WALLET_C to wallet WALLET_A at fee 100 @@ -150,11 +150,11 @@ Feature: Wallet Transactions Given I have a seed node NODE And I have 1 base nodes connected to all seed nodes And I have wallet WALLET_A connected to all seed nodes + And I have wallet WALLET_B connected to all seed nodes And I have mining node MINER connected to base node NODE and wallet WALLET_A When mining node MINER mines 10 blocks Then all nodes are at height 10 Then I wait for wallet WALLET_A to have at least 10000000000 uT - Then I have wallet WALLET_B connected to all seed nodes And I send 100000 uT from wallet WALLET_A to wallet WALLET_B at fee 100 And I send 100000 uT from wallet WALLET_A to wallet WALLET_B at fee 100 And I send 100000 uT from wallet WALLET_A to wallet WALLET_B at fee 100 @@ -275,6 +275,7 @@ Feature: Wallet Transactions Given I have a seed node NODE And I have 1 base nodes connected to all seed nodes And I have wallet WALLET_A connected to all seed nodes + And I have wallet WALLET_RECV connected to all seed nodes And I have mining node MINER connected to base node NODE and wallet WALLET_A And mining node MINER mines 5 blocks Then all nodes are at height 5 @@ -284,7 +285,6 @@ Feature: Wallet Transactions And mining node MINER mines 5 blocks Then all nodes are at height 10 Then I wait for wallet WALLET_SENDER to have at least 100000000 uT - And I have wallet WALLET_RECV connected to all seed nodes And I stop wallet WALLET_RECV And I send 1000000 uT without waiting for broadcast from wallet WALLET_SENDER to wallet WALLET_RECV at fee 100 When wallet WALLET_SENDER detects last transaction is Pending diff --git a/integration_tests/features/support/ffi_steps.js b/integration_tests/features/support/ffi_steps.js index da58633e7d..dbc2cddbc6 100644 --- a/integration_tests/features/support/ffi_steps.js +++ b/integration_tests/features/support/ffi_steps.js @@ -13,26 +13,21 @@ When( } ); -Then( - "I want to get emoji id of ffi wallet {word}", - { timeout: 20 * 1000 }, - async function (name) { - let wallet = this.getWallet(name); - let emoji_id = wallet.identifyEmoji(); - console.log(emoji_id); - expect(emoji_id.length).to.be.equal( - 22 * 3, // 22 emojis, 3 bytes per one emoji - `Emoji id has wrong length : ${emoji_id}` - ); - } -); +Then("I want to get emoji id of ffi wallet {word}", async function (name) { + let wallet = this.getWallet(name); + let emoji_id = wallet.identifyEmoji(); + console.log(emoji_id); + expect(emoji_id.length).to.be.equal( + 22 * 3, // 22 emojis, 3 bytes per one emoji + `Emoji id has wrong length : ${emoji_id}` + ); +}); When( "I send {int} uT from ffi wallet {word} to wallet {word} at fee {int}", - { timeout: 20 * 1000 }, function (amount, sender, receiver, feePerGram) { - let ffi_wallet = this.getWallet(sender); - let result = ffi_wallet.sendTransaction( + let ffiWallet = this.getWallet(sender); + let result = ffiWallet.sendTransaction( this.getWalletPubkey(receiver), amount, feePerGram, @@ -44,7 +39,6 @@ When( When( "I set passphrase {word} of ffi wallet {word}", - { timeout: 20 * 1000 }, function (passphrase, name) { let wallet = this.getWallet(name); wallet.applyEncryption(passphrase); @@ -84,41 +78,20 @@ Then( } ); -Then( - "ffi wallet {word} has {int} broadcast transaction", - { timeout: 120 * 1000 }, - async function (name, count) { - let wallet = this.getWallet(name); - let broadcast = await wallet.getBroadcastTransactionsCount(); - let retries = 1; - const retries_limit = 24; - while (broadcast != count && retries <= retries_limit) { - await sleep(5000); - broadcast = await wallet.getBroadcastTransactionsCount(); - ++retries; - } - expect(broadcast, "Number of broadcasted messages mismatch").to.be.equal( - count - ); - } -); - When( "I add contact with alias {word} and pubkey {word} to ffi wallet {word}", - { timeout: 20 * 1000 }, - function (alias, wallet_name, ffi_wallet_name) { - let ffi_wallet = this.getWallet(ffi_wallet_name); - ffi_wallet.addContact(alias, this.getWalletPubkey(wallet_name)); + function (alias, walletName, ffiWalletName) { + let ffiWallet = this.getWallet(ffiWalletName); + ffiWallet.addContact(alias, this.getWalletPubkey(walletName)); } ); Then( "I have contact with alias {word} and pubkey {word} in ffi wallet {word}", - { timeout: 20 * 1000 }, - function (alias, wallet_name, ffi_wallet_name) { - let wallet = this.getWalletPubkey(wallet_name); - let ffi_wallet = this.getWallet(ffi_wallet_name); - let contacts = ffi_wallet.getContactList(); + function (alias, walletName, ffiWalletName) { + let wallet = this.getWalletPubkey(walletName); + let ffiWallet = this.getWallet(ffiWalletName); + let contacts = ffiWallet.getContactList(); let length = contacts.getLength(); let found = false; for (let i = 0; i < length; i++) { @@ -138,17 +111,16 @@ Then( When( "I remove contact with alias {word} from ffi wallet {word}", - { timeout: 20 * 1000 }, - function (alias, wallet_name) { - let ffi_wallet = this.getWallet(wallet_name); - let contacts = ffi_wallet.getContactList(); + function (alias, walletName) { + let ffiWallet = this.getWallet(walletName); + let contacts = ffiWallet.getContactList(); let length = contacts.getLength(); for (let i = 0; i < length; i++) { { let contact = contacts.getAt(i); let calias = contact.getAlias(); if (alias === calias) { - ffi_wallet.removeContact(contact); + ffiWallet.removeContact(contact); } contact.destroy(); } @@ -159,10 +131,9 @@ When( Then( "I don't have contact with alias {word} in ffi wallet {word}", - { timeout: 20 * 1000 }, - function (alias, wallet_name) { - let ffi_wallet = this.getWallet(wallet_name); - let contacts = ffi_wallet.getContactList(); + function (alias, walletName) { + let ffiWallet = this.getWallet(walletName); + let contacts = ffiWallet.getContactList(); let length = contacts.getLength(); let found = false; for (let i = 0; i < length; i++) { @@ -182,8 +153,8 @@ Then( When( "I set base node {word} for ffi wallet {word}", - function (node, wallet_name) { - let wallet = this.getWallet(wallet_name); + function (node, walletName) { + let wallet = this.getWallet(walletName); let peer = this.nodes[node].peerAddress().split("::"); wallet.addBaseNodePeer(peer[0], peer[1]); } @@ -191,16 +162,16 @@ When( Then( "I wait for ffi wallet {word} to have {int} pending outbound transaction(s)", - { timeout: 180 * 1000 }, - async function (wallet_name, count) { - let wallet = this.getWallet(wallet_name); + { timeout: 125 * 1000 }, + async function (walletName, count) { + let wallet = this.getWallet(walletName); let broadcast = wallet.getOutboundTransactions(); let length = broadcast.getLength(); broadcast.destroy(); let retries = 1; - const retries_limit = 24; + const retries_limit = 120; while (length != count && retries <= retries_limit) { - await sleep(5000); + await sleep(1000); broadcast = wallet.getOutboundTransactions(); length = broadcast.getLength(); broadcast.destroy(); @@ -212,8 +183,8 @@ Then( Then( "I cancel all outbound transactions on ffi wallet {word} and it will cancel {int} transaction", - async function (wallet_name, count) { - const wallet = this.getWallet(wallet_name); + function (walletName, count) { + const wallet = this.getWallet(walletName); let txs = wallet.getOutboundTransactions(); let cancelled = 0; for (let i = 0; i < txs.getLength(); i++) { @@ -231,36 +202,34 @@ Then( Given( "I have a ffi wallet {word} connected to base node {word}", - { timeout: 20 * 1000 }, async function (walletName, nodeName) { - let ffi_wallet = await this.createAndAddFFIWallet(walletName, null); + let ffiWallet = await this.createAndAddFFIWallet(walletName, null); let peer = this.nodes[nodeName].peerAddress().split("::"); - ffi_wallet.addBaseNodePeer(peer[0], peer[1]); + ffiWallet.addBaseNodePeer(peer[0], peer[1]); } ); Then( "I recover wallet {word} into ffi wallet {word} from seed words on node {word}", - { timeout: 20 * 1000 }, - async function (wallet_name, ffi_wallet_name, node) { - let wallet = this.getWallet(wallet_name); + async function (walletName, ffiWalletName, node) { + let wallet = this.getWallet(walletName); const seed_words_text = wallet.getSeedWords(); - await wallet.stop(); + wallet.stop(); await sleep(1000); - let ffi_wallet = await this.createAndAddFFIWallet( - ffi_wallet_name, + let ffiWallet = await this.createAndAddFFIWallet( + ffiWalletName, seed_words_text ); let peer = this.nodes[node].peerAddress().split("::"); - ffi_wallet.addBaseNodePeer(peer[0], peer[1]); - ffi_wallet.startRecovery(peer[0]); + ffiWallet.addBaseNodePeer(peer[0], peer[1]); + ffiWallet.startRecovery(peer[0]); } ); Then( "Check callbacks for finished inbound tx on ffi wallet {word}", - async function (wallet_name) { - const wallet = this.getWallet(wallet_name); + async function (walletName) { + const wallet = this.getWallet(walletName); expect(wallet.receivedTransaction).to.be.greaterThanOrEqual(1); expect(wallet.transactionBroadcast).to.be.greaterThanOrEqual(1); wallet.clearCallbackCounters(); @@ -269,8 +238,8 @@ Then( Then( "Check callbacks for finished outbound tx on ffi wallet {word}", - async function (wallet_name) { - const wallet = this.getWallet(wallet_name); + async function (walletName) { + const wallet = this.getWallet(walletName); expect(wallet.receivedTransactionReply).to.be.greaterThanOrEqual(1); expect(wallet.transactionBroadcast).to.be.greaterThanOrEqual(1); wallet.clearCallbackCounters(); @@ -279,13 +248,13 @@ Then( Then( "I wait for ffi wallet {word} to receive {int} transaction", - { timeout: 710 * 1000 }, - async function (wallet_name, amount) { - let wallet = this.getWallet(wallet_name); + { timeout: 125 * 1000 }, + async function (walletName, amount) { + let wallet = this.getWallet(walletName); console.log("\n"); console.log( - "Waiting for " + wallet_name + " to receive " + amount + " transaction(s)" + "Waiting for " + walletName + " to receive " + amount + " transaction(s)" ); await waitForIterate( @@ -294,7 +263,7 @@ Then( }, true, 1000, - 700 + 120 ); if (!(wallet.getCounters().received >= amount)) { @@ -308,14 +277,14 @@ Then( Then( "I wait for ffi wallet {word} to receive {int} finalization", - { timeout: 710 * 1000 }, - async function (wallet_name, amount) { - let wallet = this.getWallet(wallet_name); + { timeout: 125 * 1000 }, + async function (walletName, amount) { + let wallet = this.getWallet(walletName); console.log("\n"); console.log( "Waiting for " + - wallet_name + + walletName + " to receive " + amount + " transaction finalization(s)" @@ -327,7 +296,7 @@ Then( }, true, 1000, - 700 + 120 ); if (!(wallet.getCounters().finalized >= amount)) { @@ -341,14 +310,14 @@ Then( Then( "I wait for ffi wallet {word} to receive {int} broadcast", - { timeout: 710 * 1000 }, - async function (wallet_name, amount) { - let wallet = this.getWallet(wallet_name); + { timeout: 125 * 1000 }, + async function (walletName, amount) { + let wallet = this.getWallet(walletName); console.log("\n"); console.log( "Waiting for " + - wallet_name + + walletName + " to receive " + amount + " transaction broadcast(s)" @@ -360,7 +329,7 @@ Then( }, true, 1000, - 700 + 120 ); if (!(wallet.getCounters().broadcast >= amount)) { @@ -374,17 +343,17 @@ Then( Then( "I wait for ffi wallet {word} to receive {int} mined", - { timeout: 710 * 1000 }, - async function (wallet_name, amount) { - let wallet = this.getWallet(wallet_name); + { timeout: 125 * 1000 }, + async function (walletName, amount) { + let wallet = this.getWallet(walletName); console.log("\n"); console.log( "Waiting for " + - wallet_name + + walletName + " to receive " + amount + - " transaction mined" + " transaction(s) mined" ); await waitForIterate( @@ -393,7 +362,7 @@ Then( }, true, 1000, - 700 + 120 ); if (!(wallet.getCounters().mined >= amount)) { @@ -406,16 +375,19 @@ Then( ); Then( - "I wait for ffi wallet {word} to receive at least {int} SAF message", - { timeout: 710 * 1000 }, - async function (wallet_name, amount) { - let wallet = this.getWallet(wallet_name); - - console.log("\n"); + "I wait for ffi wallet {word} to receive {word} {int} SAF message", + { timeout: 125 * 1000 }, + async function (walletName, comparison, amount) { + const atLeast = "AT_LEAST"; + const exactly = "EXACTLY"; + expect(comparison === atLeast || comparison === exactly).to.equal(true); + let wallet = this.getWallet(walletName); console.log( - "Waiting for " + - wallet_name + - " to receive at least " + + "\nWaiting for " + + walletName + + " to receive " + + comparison + + " " + amount + " SAF messages(s)" ); @@ -426,7 +398,7 @@ Then( }, true, 1000, - 700 + 120 ); if (!(wallet.getCounters().saf >= amount)) { @@ -434,19 +406,23 @@ Then( } else { console.log(wallet.getCounters()); } - expect(wallet.getCounters().saf >= amount).to.equal(true); + if (comparison === atLeast) { + expect(wallet.getCounters().saf >= amount).to.equal(true); + } else { + expect(wallet.getCounters().saf === amount).to.equal(true); + } } ); Then( "I wait for ffi wallet {word} to have at least {int} uT", - { timeout: 710 * 1000 }, - async function (wallet_name, amount) { - let wallet = this.getWallet(wallet_name); + { timeout: 125 * 1000 }, + async function (walletName, amount) { + let wallet = this.getWallet(walletName); console.log("\n"); console.log( - "Waiting for " + wallet_name + " balance to be at least " + amount + " uT" + "Waiting for " + walletName + " balance to be at least " + amount + " uT" ); await waitForIterate( @@ -455,7 +431,7 @@ Then( }, true, 1000, - 700 + 120 ); let balance = wallet.getBalance().available; @@ -468,11 +444,54 @@ Then( } ); +Then( + "ffi wallet {word} detects {word} {int} ffi transactions to be Broadcast", + { timeout: 125 * 1000 }, + async function (walletName, comparison, amount) { + // Pending -> Completed -> Broadcast -> Mined Unconfirmed -> Mined Confirmed + const atLeast = "AT_LEAST"; + const exactly = "EXACTLY"; + expect(comparison === atLeast || comparison === exactly).to.equal(true); + const wallet = this.getWallet(walletName); + + console.log("\n"); + console.log( + "Waiting for " + + walletName + + " to have detected " + + comparison + + " " + + amount + + " broadcast transaction(s)" + ); + + await waitForIterate( + () => { + return wallet.getCounters().broadcast >= amount; + }, + true, + 1000, + 120 + ); + + if (!(wallet.getCounters().broadcast >= amount)) { + console.log("Counter not adequate!"); + } else { + console.log(wallet.getCounters()); + } + if (comparison === atLeast) { + expect(wallet.getCounters().broadcast >= amount).to.equal(true); + } else { + expect(wallet.getCounters().broadcast === amount).to.equal(true); + } + } +); + Then( "I wait for recovery of ffi wallet {word} to finish", { timeout: 600 * 1000 }, - function (wallet_name) { - const wallet = this.getWallet(wallet_name); + function (walletName) { + const wallet = this.getWallet(walletName); while (!wallet.recoveryFinished) { sleep(1000).then(); } @@ -494,25 +513,21 @@ When( } ); -Then( - "I want to get public key of ffi wallet {word}", - { timeout: 20 * 1000 }, - function (name) { - let wallet = this.getWallet(name); - let public_key = wallet.identify(); - expect(public_key.length).to.be.equal( - 64, - `Public key has wrong length : ${public_key}` - ); - } -); +Then("I want to get public key of ffi wallet {word}", function (name) { + let wallet = this.getWallet(name); + let public_key = wallet.identify(); + expect(public_key.length).to.be.equal( + 64, + `Public key has wrong length : ${public_key}` + ); +}); Then( "I want to view the transaction kernels for completed transactions in ffi wallet {word}", { timeout: 20 * 1000 }, function (name) { - let ffi_wallet = this.getWallet(name); - let transactions = ffi_wallet.getCompletedTxs(); + let ffiWallet = this.getWallet(name); + let transactions = ffiWallet.getCompletedTxs(); let length = transactions.getLength(); expect(length > 0).to.equal(true); for (let i = 0; i < length; i++) { @@ -531,16 +546,21 @@ Then( } ); -When("I stop ffi wallet {word}", function (walletName) { - let wallet = this.getWallet(walletName); - wallet.stop(); - wallet.resetCounters(); -}); +When( + "I stop ffi wallet {word}", + { timeout: 20 * 1000 }, + async function (walletName) { + let wallet = this.getWallet(walletName); + await wallet.stop(); + wallet.resetCounters(); + } +); Then( "I start TXO validation on ffi wallet {word}", - async function (wallet_name) { - const wallet = this.getWallet(wallet_name); + { timeout: 125 * 1000 }, + async function (walletName) { + const wallet = this.getWallet(walletName); await wallet.startTxoValidation(); while (!wallet.getTxoValidationStatus().txo_validation_complete) { await sleep(1000); @@ -550,8 +570,9 @@ Then( Then( "I start TX validation on ffi wallet {word}", - async function (wallet_name) { - const wallet = this.getWallet(wallet_name); + { timeout: 125 * 1000 }, + async function (walletName) { + const wallet = this.getWallet(walletName); await wallet.startTxValidation(); while (!wallet.getTxValidationStatus().tx_validation_complete) { await sleep(1000); diff --git a/integration_tests/features/support/steps.js b/integration_tests/features/support/steps.js index f6a1286436..e4e1d5e08b 100644 --- a/integration_tests/features/support/steps.js +++ b/integration_tests/features/support/steps.js @@ -15,6 +15,7 @@ const { consoleLogBalance, consoleLogTransactionDetails, withTimeout, + waitForIterate, byteArrayToHex, } = require("../../helpers/util"); const { ConnectivityStatus, PaymentType } = require("../../helpers/types"); @@ -28,11 +29,11 @@ const AUTOUPDATE_HASHES_TXT_SIG_URL = const AUTOUPDATE_HASHES_TXT_BAD_SIG_URL = "https://raw.githubusercontent.com/tari-project/tari/development/meta/hashes.txt.bad.sig"; -Given(/I have a seed node (.*)/, { timeout: 20 * 1000 }, async function (name) { +Given(/I have a seed node (.*)/, { timeout: 30 * 1000 }, async function (name) { return await this.createSeedNode(name); }); -Given("I have {int} seed nodes", { timeout: 20 * 1000 }, async function (n) { +Given("I have {int} seed nodes", { timeout: 30 * 1000 }, async function (n) { const promises = []; for (let i = 0; i < n; i++) { promises.push(this.createSeedNode(`SeedNode${i}`)); @@ -46,7 +47,7 @@ Then(/all transactions must have succeeded/, function () { Given( /I have a base node (.*) connected to all seed nodes/, - { timeout: 20 * 1000 }, + { timeout: 30 * 1000 }, async function (name) { await this.createAndAddNode(name, this.seedAddresses()); } @@ -54,7 +55,7 @@ Given( Given( /I have a base node (.*) connected to seed (.*)/, - { timeout: 20 * 1000 }, + { timeout: 30 * 1000 }, async function (name, seedNode) { await this.createAndAddNode(name, this.seeds[seedNode].peerAddress()); } @@ -62,7 +63,7 @@ Given( Given( /I have a base node (.*) connected to nodes (.*)/, - { timeout: 20 * 1000 }, + { timeout: 30 * 1000 }, async function (name, nodes) { const addresses = []; nodes = nodes.split(","); @@ -75,7 +76,7 @@ Given( Given( /I have a node (.*) with auto update enabled/, - { timeout: 20 * 1000 }, + { timeout: 30 * 1000 }, async function (name) { const node = await this.createNode(name, { common: { @@ -95,7 +96,7 @@ Given( Given( /I have a node (.*) with auto update configured with a bad signature/, - { timeout: 20 * 1000 }, + { timeout: 30 * 1000 }, async function (name) { const node = await this.createNode(name, { common: { @@ -157,7 +158,7 @@ Given( Given( /I have a base node (.*) connected to node (.*)/, - { timeout: 20 * 1000 }, + { timeout: 10 * 1000 }, async function (name, node) { await this.createAndAddNode(name, this.nodes[node].peerAddress()); } @@ -165,7 +166,7 @@ Given( Given( /I have a base node (\S+)$/, - { timeout: 20 * 1000 }, + { timeout: 10 * 1000 }, async function (name) { await this.createAndAddNode(name); } @@ -183,7 +184,7 @@ Given("I have 1 base node", { timeout: 20 * 1000 }, async function () { Given( /I have a SHA3 miner (.*) connected to seed node (.*)/, - { timeout: 40 * 1000 }, + { timeout: 10 * 1000 }, async function (name, seed) { // add the base_node await this.createAndAddNode(name, this.seeds[seed].peerAddress(), this); @@ -207,7 +208,7 @@ Given( Given( /I have a SHA3 miner (.*) connected to node (.*)/, - { timeout: 40 * 1000 }, + { timeout: 10 * 1000 }, async function (name, basenode) { // add the base_node await this.createAndAddNode(name, this.nodes[basenode].peerAddress(), this); @@ -231,7 +232,7 @@ Given( Given( /I have a SHA3 miner (.*) connected to all seed nodes/, - { timeout: 40 * 1000 }, + { timeout: 10 * 1000 }, async function (name) { // add the base_node await this.createAndAddNode(name, this.seedAddresses(), this); @@ -255,7 +256,7 @@ Given( Given( /I connect node (.*) to node (.*)/, - { timeout: 1200 * 1000 }, + { timeout: 40 * 1000 }, async function (nodeNameA, nodeNameB) { console.log( "Connecting (add new peer seed, shut down, then start up)", @@ -283,11 +284,11 @@ Given( Given( /I have a pruned node (.*) connected to node (.*) with pruning horizon set to (.*)/, { timeout: 20 * 1000 }, - async function (name, node, horizon) { - const miner = this.createNode(name, { pruningHorizon: horizon }); - miner.setPeerSeeds([this.nodes[node].peerAddress()]); - await miner.startNew(); - await this.addNode(name, miner); + async function (name, connected_to, horizon) { + const node = this.createNode(name, { pruningHorizon: horizon }); + node.setPeerSeeds([this.nodes[connected_to].peerAddress()]); + await node.startNew(); + await this.addNode(name, node); } ); @@ -316,7 +317,7 @@ Given( Given( "I have {int} base nodes connected to all seed nodes", - { timeout: 190 * 1000 }, + { timeout: 20 * 1000 }, async function (n) { const promises = []; for (let i = 0; i < n; i++) { @@ -332,7 +333,6 @@ Given( Given( /I have stress-test wallet (.*) connected to the seed node (.*) with broadcast monitoring timeout (.*)/, - { timeout: 20 * 1000 }, async function (walletName, seedName, timeout) { const wallet = new WalletProcess( walletName, @@ -370,7 +370,6 @@ Given( Given( /I have (a )?wallet (.*) connected to seed node (.*)/, - { timeout: 20 * 1000 }, async function (a, walletName, seedName) { await this.createAndAddWallet( walletName, @@ -381,7 +380,6 @@ Given( Given( /I have wallet (.*) connected to base node (.*)/, - { timeout: 20 * 1000 }, async function (walletName, nodeName) { await this.createAndAddWallet( walletName, @@ -390,13 +388,9 @@ Given( } ); -Given( - /I have wallet (.*) connected to all seed nodes/, - { timeout: 20 * 1000 }, - async function (name) { - await this.createAndAddWallet(name, this.seedAddresses()); - } -); +Given(/I have wallet (.*) connected to all seed nodes/, async function (name) { + await this.createAndAddWallet(name, this.seedAddresses()); +}); Given( /I have non-default wallet (.*) connected to all seed nodes using (.*)/, @@ -439,7 +433,6 @@ Given( Given( /I recover wallet (.*) into wallet (.*) connected to all seed nodes/, - { timeout: 120 * 1000 }, async function (walletNameA, walletNameB) { const seedWords = this.getWallet(walletNameA).getSeedWords(); console.log( @@ -468,7 +461,6 @@ Given( Given( /I recover wallet (.*) into (\d+) wallets connected to all seed nodes/, - { timeout: 120 * 1000 }, async function (walletNameA, numwallets) { const seedWords = this.getWallet(walletNameA).getSeedWords(); for (let i = 1; i <= numwallets; i++) { @@ -499,7 +491,6 @@ Given( Then( /I wait for (\d+) wallets to have at least (\d+) uT/, - { timeout: 710 * 1000 }, async function (numwallets, amount) { for (let i = 1; i <= numwallets; i++) { const walletClient = await this.getWallet(i.toString()).connectClient(); @@ -526,7 +517,6 @@ Then( Then( /Wallet (.*) and (\d+) wallets have the same balance/, - { timeout: 120 * 1000 }, async function (wallet, numwallets) { const walletClient = await this.getWallet(wallet).connectClient(); let balance = await walletClient.getBalance(); @@ -654,7 +644,6 @@ When( Given( /I have a merge mining proxy (.*) connected to (.*) and (.*) with default config/, - { timeout: 20 * 1000 }, async function (mmProxy, node, wallet) { const baseNode = this.getNode(node); const walletNode = this.getWallet(wallet); @@ -673,7 +662,6 @@ Given( Given( /I have a merge mining proxy (.*) connected to (.*) and (.*) with origin submission disabled/, - { timeout: 20 * 1000 }, async function (mmProxy, node, wallet) { const baseNode = this.getNode(node); const walletNode = this.getWallet(wallet); @@ -692,7 +680,6 @@ Given( Given( /I have a merge mining proxy (.*) connected to (.*) and (.*) with origin submission enabled/, - { timeout: 20 * 1000 }, async function (mmProxy, node, wallet) { const baseNode = this.getNode(node); const walletNode = this.getWallet(wallet); @@ -829,7 +816,7 @@ Then("Proxy response for block header by hash is valid", function () { assert(lastResult.result.status, "OK"); }); -When(/I start base node (.*)/, { timeout: 20 * 1000 }, async function (name) { +When(/I start base node (.*)/, { timeout: 6 * 1000 }, async function (name) { await this.startNode(name); }); @@ -847,29 +834,17 @@ When(/I stop node (.*)/, async function (name) { Then( /node (.*) is at height (\d+)/, - { timeout: 120 * 1000 }, + { timeout: 600 * 1000 }, async function (name, height) { const client = this.getClient(name); - await waitFor(async () => client.getTipHeight(), height, 115 * 1000); - const currentHeight = await client.getTipHeight(); - console.log( - `Node ${name} is at tip: ${currentHeight} (should be`, + const currentHeight = await waitForIterate( + () => client.getTipHeight(), height, - `)` + 1000, + 5 * height // 5 seconds per block ); - expect(currentHeight).to.equal(height); - } -); - -Then( - /node (.*) has a pruned height of (\d+)/, - { timeout: 120 * 1000 }, - async function (name, height) { - const client = this.getClient(name); - await waitFor(async () => client.getPrunedHeight(), height, 115 * 1000); - const currentHeight = await client.getPrunedHeight(); console.log( - `Node ${name} has a pruned height: ${currentHeight} (should be`, + `Node ${name} is at tip: ${currentHeight} (should be`, height, `)` ); @@ -877,9 +852,21 @@ Then( } ); +Then(/node (.*) has a pruned height of (\d+)/, async function (name, height) { + const client = this.getClient(name); + await waitFor(async () => await client.getPrunedHeight(), height, 115 * 1000); + const currentHeight = await client.getPrunedHeight(); + console.log( + `Node ${name} has a pruned height: ${currentHeight} (should be`, + height, + `)` + ); + expect(currentHeight).to.equal(height); +}); + Then( /node (.*) is at the same height as node (.*)/, - { timeout: 130 * 1000 }, + { timeout: 20 * 1000 }, async function (nodeA, nodeB) { var expectedHeight, currentHeight; expectedHeight = parseInt(await this.getClient(nodeB).getTipHeight()); @@ -906,11 +893,16 @@ Then( Then( "all nodes are on the same chain at height {int}", - { timeout: 1200 * 1000 }, + { timeout: 600 * 1000 }, async function (height) { let tipHash = null; await this.forEachClientAsync(async (client, name) => { - await waitFor(async () => client.getTipHeight(), height, 115 * 1000); + await waitForIterate( + () => client.getTipHeight(), + height, + 1000, + 5 * height /* 5 seconds per block */ + ); const currTip = await client.getTipHeader(); console.log( `${client.name} is at tip ${currTip.height} (${currTip.hash.toString( @@ -934,7 +926,7 @@ Then( Then( "all nodes are on the same chain tip", - { timeout: 1200 * 1000 }, + { timeout: 800 * 1000 }, async function () { await waitFor( async () => { @@ -968,13 +960,17 @@ Then( Then( "all nodes are at height {int}", - { timeout: 1200 * 1000 }, + { timeout: 800 * 1000 }, async function (height) { await waitFor( async () => { let result = true; await this.forEachClientAsync(async (client, name) => { - await waitFor(async () => client.getTipHeight(), height, 60 * 1000); + await waitFor( + async () => await client.getTipHeight(), + height, + 5 * height * 1000 /* 5 seconds per block */ + ); const currTip = await client.getTipHeight(); console.log( `Node ${name} is at tip: ${currTip} (should be ${height})` @@ -997,7 +993,7 @@ Then( async function (node) { const client = this.getClient(node); await waitForPredicate( - async () => (await client.initial_sync_achieved()) === true, + async () => await client.initial_sync_achieved(), 20 * 60 * 1000, 1000 ); @@ -1007,21 +1003,17 @@ Then( } ); -Then( - /node (.*) is in state (.*)/, - { timeout: 21 * 60 * 1000 }, - async function (node, state) { - const client = this.getClient(node); - await waitForPredicate( - async () => (await client.get_node_state()) == state, - 20 * 60 * 1000, - 1000 - ); - let result = await this.getClient(node).get_node_state(); - console.log(`Node ${node} is in the current state: ${result}`); - expect(result).to.equal(state); - } -); +Then(/node (.*) is in state (.*)/, async function (node, state) { + const client = this.getClient(node); + await waitForPredicate( + async () => (await client.get_node_state()) == state, + 20 * 60 * 1000, + 1000 + ); + let result = await this.getClient(node).get_node_state(); + console.log(`Node ${node} is in the current state: ${result}`); + expect(result).to.equal(state); +}); Then( /(.*) does not have a new software update/, @@ -1075,7 +1067,7 @@ Then( let currentHeight; for (let i = 1; i <= 12; i++) { await waitFor( - async () => client.getTipHeight(), + async () => await client.getTipHeight(), expectedHeight, 10 * 1000 ); @@ -1207,32 +1199,26 @@ When(/I spend outputs (.*) via (.*)/, async function (inputs, node) { expect(this.lastResult.result).to.equal("ACCEPTED"); }); -Then( - /(.*) has (.*) in (.*) state/, - { timeout: 21 * 60 * 1000 }, - async function (node, txn, pool) { - const client = this.getClient(node); - const sig = this.transactions[txn].body.kernels[0].excess_sig; - this.lastResult = await waitFor( - async () => { - let tx_result = await client.transactionStateResult(sig); - console.log( - `Node ${node} response is: ${tx_result}, should be: ${pool}` - ); - return tx_result === pool; - }, - true, - 20 * 60 * 1000 - ); - expect(this.lastResult).to.equal(true); - } -); +Then(/(.*) has (.*) in (.*) state/, async function (node, txn, pool) { + const client = this.getClient(node); + const sig = this.transactions[txn].body.kernels[0].excess_sig; + this.lastResult = await waitFor( + async () => { + let tx_result = await client.transactionStateResult(sig); + console.log(`Node ${node} response is: ${tx_result}, should be: ${pool}`); + return tx_result === pool; + }, + true, + // TODO: Does it make sense to fix this timeout? + 20 * 60 * 1000 + ); + expect(this.lastResult).to.equal(true); +}); // The number is rounded down. E.g. if 1% can fail out of 17, that is 16.83 have to succeed. // It's means at least 16 have to succeed. Then( /(.*) is in the (.*) of all nodes(, where (\d+)% can fail)?/, - { timeout: 1200 * 1000 }, async function (txn, pool, canFail) { const sig = this.transactions[txn].body.kernels[0].excess_sig; await this.forEachClientAsync( @@ -1291,7 +1277,6 @@ Then( When( /I mine a block on (.*) with coinbase (.*)/, - { timeout: 600 * 1000 }, async function (name, coinbaseName) { const tipHeight = await this.getClient(name).getTipHeight(); let autoTransactionResult = await this.createTransactions( @@ -1308,7 +1293,6 @@ When( When( /I mine (\d+) custom weight blocks on (.*) with weight (\d+)/, - { timeout: -1 }, async function (numBlocks, name, weight) { const tipHeight = await this.getClient(name).getTipHeight(); for (let i = 0; i < numBlocks; i++) { @@ -1334,7 +1318,7 @@ When( When( /mining node (.*) mines (\d+) blocks with min difficulty (\d+) and max difficulty (\d+)/, - { timeout: 600 * 1000 }, + { timeout: 80 * 1000 }, async function (miner, numBlocks, min, max) { const miningNode = this.getMiningNode(miner); await miningNode.init( @@ -1351,7 +1335,7 @@ When( When( /mining node (.*) mines (\d+) blocks?$/, - { timeout: 600 * 1000 }, + { timeout: 20 * 1000 }, async function (miner, numBlocks) { const miningNode = this.getMiningNode(miner); // Don't wait for sync before mining @@ -1370,7 +1354,7 @@ When("I mine {int} block(s)", { timeout: -1 }, async function (numBlocks) { When( /I mine (\d+) blocks on (.*)/, - { timeout: -1 }, + { timeout: 40 * 1000 }, async function (numBlocks, name) { const tipHeight = await this.getClient(name).getTipHeight(); for (let i = 0; i < numBlocks; i++) { @@ -1411,15 +1395,11 @@ When( } ); -// When( -// /I merge mine (.*) blocks via (.*)/, -// { timeout: 600 * 1000 }, -// async function (numBlocks, mmProxy) { -// for (let i = 0; i < numBlocks; i++) { -// await this.mergeMineBlock(mmProxy); -// } -// } -// ); +When(/I merge mine (.*) blocks via (.*)/, async function (numBlocks, mmProxy) { + for (let i = 0; i < numBlocks; i++) { + await this.mergeMineBlock(mmProxy); + } +}); // TODO: This step is still really flaky, rather use the co-mine with mining node step: // Error: 13 INTERNAL: @@ -1427,7 +1407,7 @@ When( // header_hash:55545... in the database' When( /I co-mine (.*) blocks via merge mining proxy (.*) and base node (.*) with wallet (.*)/, - { timeout: 1200 * 1000 }, + { timeout: 20 * 1000 }, async function (numBlocks, mmProxy, node, wallet) { let tipHeight = await this.getClient(node).getTipHeight(); this.lastResult = tipHeight; @@ -1609,7 +1589,7 @@ When("I print the world", function () { Then( /I wait for wallet (.*) to have at least (.*) uT/, - { timeout: 710 * 1000 }, + { timeout: 40 * 1000 }, async function (wallet, amount) { const walletClient = await this.getWallet(wallet).connectClient(); console.log("\n"); @@ -1634,7 +1614,7 @@ Then( Then( /I wait for wallet (.*) to have less than (.*) uT/, - { timeout: 710 * 1000 }, + { timeout: 6 * 1000 }, async function (wallet, amount) { let walletClient = await this.getWallet(wallet).connectClient(); console.log("\n"); @@ -1659,7 +1639,6 @@ Then( Then( /wallet (.*) and wallet (.*) have the same balance/, - { timeout: 65 * 1000 }, async function (walletNameA, walletNameB) { const walletClientA = await this.getWallet(walletNameA).connectClient(); var balanceA = await walletClientA.getBalance(); @@ -1776,7 +1755,7 @@ async function send_tari( When( /I send (.*) uT from wallet (.*) to wallet (.*) at fee (.*)/, - { timeout: 25 * 5 * 1000 }, + { timeout: 60 * 1000 }, async function (tariAmount, source, dest, feePerGram) { const sourceWallet = this.getWallet(source); const sourceClient = await sourceWallet.connectClient(); @@ -1827,7 +1806,7 @@ When( When( /I send(.*) uT without waiting for broadcast from wallet (.*) to wallet (.*) at fee (.*)/, - { timeout: 25 * 5 * 1000 }, + { timeout: 40 * 1000 }, async function (tariAmount, source, dest, feePerGram) { const sourceWallet = this.getWallet(source); const sourceClient = await sourceWallet.connectClient(); @@ -1863,7 +1842,7 @@ When( When( /I multi-send (.*) transactions of (.*) uT from wallet (.*) to wallet (.*) at fee (.*)/, - { timeout: 25 * 5 * 1000 }, + { timeout: 10 * 1000 }, async function (number, tariAmount, source, dest, fee) { console.log("\n"); const sourceClient = await this.getWallet(source).connectClient(); @@ -1965,7 +1944,7 @@ When( When( /I transfer (.*) uT from (.*) to (.*) and (.*) at fee (.*)/, - { timeout: 25 * 5 * 1000 }, + { timeout: 40 * 1000 }, async function (tariAmount, source, dest1, dest2, feePerGram) { const sourceClient = await this.getWallet(source).connectClient(); const destClient1 = await this.getWallet(dest1).connectClient(); @@ -2061,7 +2040,7 @@ When( When( /I transfer (.*) uT to self from wallet (.*) at fee (.*)/, - { timeout: 25 * 5 * 1000 }, + { timeout: 7 * 1000 }, async function (tariAmount, source, feePerGram) { const sourceClient = await this.getWallet(source).connectClient(); const sourceInfo = await sourceClient.identify(); @@ -2143,7 +2122,7 @@ When( When( /I send a one-sided transaction of (.*) uT from (.*) to (.*) at fee (.*)/, - { timeout: 65 * 1000 }, + { timeout: 8 * 1000 }, async function (amount, source, dest, feePerGram) { const sourceWallet = this.getWallet(source); const sourceClient = await sourceWallet.connectClient(); @@ -2496,7 +2475,7 @@ Then( Then( /wallet (.*) detects all transactions are at least Broadcast/, - { timeout: 1200 * 1000 }, + { timeout: 150 * 1000 }, async function (walletName) { // Pending -> Completed -> Broadcast -> Mined Unconfirmed -> Mined Confirmed const wallet = this.getWallet(walletName); @@ -2787,7 +2766,7 @@ Then( Then( /wallet (.*) detects all transactions as Mined_Confirmed/, - { timeout: 6000 * 1000 }, + { timeout: 30 * 1000 }, async function (walletName) { // Pending -> Completed -> Broadcast -> Mined Unconfirmed -> Mined Confirmed const wallet = this.getWallet(walletName); @@ -2834,7 +2813,6 @@ Then( Then( /while mining via node (.*) all transactions in wallet (.*) are found to be Mined_Confirmed/, - { timeout: 1200 * 1000 }, async function (nodeName, walletName) { const wallet = this.getWallet(walletName); const walletClient = await wallet.connectClient(); @@ -2893,7 +2871,7 @@ Then( Then( /while mining via SHA3 miner (.*) all transactions in wallet (.*) are found to be Mined_Confirmed/, - { timeout: 3600 * 1000 }, + { timeout: 30 * 1000 }, async function (miner, walletName) { const wallet = this.getWallet(walletName); const walletClient = await wallet.connectClient(); @@ -2948,7 +2926,7 @@ Then( Then( /all wallets detect all transactions as Mined_Confirmed/, - { timeout: 6000 * 1000 }, + { timeout: 40 * 1000 }, async function () { // Pending -> Completed -> Broadcast -> Mined Unconfirmed -> Mined Confirmed for (const walletName in this.wallets) { @@ -2997,7 +2975,6 @@ Then( When( /I list all (.*) transactions for wallet (.*)/, - { timeout: 20 * 1000 }, async function (transaction_type, walletName) { const wallet = this.getWallet(walletName); const walletClient = await wallet.connectClient(); @@ -3023,7 +3000,6 @@ When( Then( /wallet (.*) has (.*) coinbase transactions/, - { timeout: 20 * 1000 }, async function (walletName, count) { const walletClient = await this.getWallet(walletName).connectClient(); const transactions = await walletClient.getAllCoinbaseTransactions(); @@ -3034,7 +3010,7 @@ Then( Then( /wallet (.*) detects at least (.*) coinbase transactions as Mined_Confirmed/, - { timeout: 605 * 1000 }, + { timeout: 34 * 1000 }, async function (walletName, count) { const walletClient = await this.getWallet(walletName).connectClient(); await waitFor( @@ -3160,7 +3136,6 @@ Then( Then( /all (.*) transactions for wallet (.*) and wallet (.*) have consistent but opposing validity/, - { timeout: 20 * 1000 }, async function (transaction_type, walletNameA, walletNameB) { let walletClientA = await this.getWallet(walletNameA).connectClient(); let walletClientB = await this.getWallet(walletNameB).connectClient(); @@ -3209,7 +3184,6 @@ Then( Then( /all (.*) transactions for wallet (.*) are valid/, - { timeout: 20 * 1000 }, async function (transaction_type, walletName) { let walletClient = await this.getWallet(walletName).connectClient(); var transactions; @@ -3247,7 +3221,7 @@ Then("difficulties are available", function () { When( /I coin split tari in wallet (.*) to produce (.*) UTXOs of (.*) uT each with fee_per_gram (.*) uT/, - { timeout: 4800 * 1000 }, + { timeout: 7 * 1000 }, async function (walletName, splitNum, splitValue, feePerGram) { console.log("\n"); const numberOfSplits = Math.ceil(splitNum / 499); @@ -3318,7 +3292,7 @@ When( When( /I send (.*) transactions of (.*) uT each from wallet (.*) to wallet (.*) at fee_per_gram (.*)/, - { timeout: 43200 * 1000 }, + { timeout: 7 * 1000 }, async function ( numTransactions, amount, @@ -3395,7 +3369,6 @@ When( Given( /I change the password of wallet (.*) to (.*) via command line/, - { timeout: 20 * 1000 }, async function (name, newPassword) { let wallet = this.getWallet(name); await wallet.changePassword("kensentme", newPassword); @@ -3404,7 +3377,6 @@ Given( Then( /the password of wallet (.*) is (not)? ?(.*)/, - { timeout: 20 * 1000 }, async function (name, is_not, password) { let wallet = this.getWallet(name); try { @@ -3419,7 +3391,6 @@ Then( When( /I wait for (.*) to connect to (.*)/, - { timeout: 30 * 1000 }, async function (firstNode, secondNode) { const firstNodeClient = await this.getNodeOrWalletClient(firstNode); const secondNodeClient = await this.getNodeOrWalletClient(secondNode); @@ -3432,21 +3403,16 @@ When( } ); -Then( - /(.*) is connected to (.*)/, - { timeout: 30 * 1000 }, - async function (firstNode, secondNode) { - const firstNodeClient = await this.getNodeOrWalletClient(firstNode); - const secondNodeClient = await this.getNodeOrWalletClient(secondNode); - const secondNodeIdentity = await secondNodeClient.identify(); - let peers = await firstNodeClient.listConnectedPeers(); - assert(peers.some((p) => secondNodeIdentity.public_key === p.public_key)); - } -); +Then(/(.*) is connected to (.*)/, async function (firstNode, secondNode) { + const firstNodeClient = await this.getNodeOrWalletClient(firstNode); + const secondNodeClient = await this.getNodeOrWalletClient(secondNode); + const secondNodeIdentity = await secondNodeClient.identify(); + let peers = await firstNodeClient.listConnectedPeers(); + assert(peers.some((p) => secondNodeIdentity.public_key === p.public_key)); +}); When( /I wait for (.*) to have (.*) connectivity/, - { timeout: 30 * 1000 }, async function (nodeName, expectedStatus) { const node = await this.getNodeOrWalletClient(nodeName); const expected = ConnectivityStatus[expectedStatus.toUpperCase()]; @@ -3463,7 +3429,6 @@ When( When( /I wait for (.*) to have (\d+) node connections/, - { timeout: 30 * 1000 }, async function (nodeName, numConnections) { const node = await this.getNodeOrWalletClient(nodeName); numConnections = +numConnections; @@ -3481,7 +3446,6 @@ When( Given( "I change base node of {word} to {word} via command line", - { timeout: 20 * 1000 }, async function (wallet_name, base_node_name) { let wallet = this.getWallet(wallet_name); let base_node = this.getNode(base_node_name); @@ -3565,7 +3529,7 @@ When( ); Then( - "I make it rain from wallet {word} {int} tx / sec {int} sec {int} uT {int} increment to {word} via command line", + "I make it rain from wallet {word} {int} tx per sec {int} sec {int} uT {int} increment to {word} via command line", { timeout: 300 * 1000 }, async function (sender, freq, duration, amount, amount_inc, receiver) { let wallet = this.getWallet(sender); @@ -3579,7 +3543,6 @@ Then( Then( "I get count of utxos of wallet {word} and it's at least {int} via command line", - { timeout: 180 * 1000 }, async function (name, amount) { let wallet = this.getWallet(name); let output = await wallet_run_command(wallet, `count-utxos`); @@ -3603,7 +3566,6 @@ When( When( "I discover peer {word} on wallet {word} via command line", - { timeout: 180 * 1000 }, async function (node, name) { let wallet = this.getWallet(name); let peer = this.getNode(node).peerAddress().split("::")[0]; @@ -3615,7 +3577,7 @@ When( When( "I run whois {word} on wallet {word} via command line", - { timeout: 60 * 1000 }, + { timeout: 6 * 1000 }, async function (who, name) { await sleep(5000); let wallet = this.getWallet(name); @@ -3629,7 +3591,6 @@ When( When( "I set custom base node of {word} to {word} via command line", - { timeout: 60 * 1000 }, async function (wallet_name, base_node_name) { let wallet = this.getWallet(wallet_name); let base_node = this.getNode(base_node_name); @@ -3646,7 +3607,6 @@ When( When( "I clear custom base node of wallet {word} via command line", - { timeout: 60 * 1000 }, async function (name) { let wallet = this.getWallet(name); let output = await wallet_run_command(wallet, "clear-custom-base-node"); @@ -3659,7 +3619,6 @@ When( When( "I export the utxos of wallet {word} via command line", - { timeout: 60 * 1000 }, async function (name) { let wallet = this.getWallet(name); let output = await wallet_run_command(wallet, "export-utxos"); @@ -3676,7 +3635,6 @@ When( Then( /I wait until base node (.*) has (.*) unconfirmed transactions in its mempool/, - { timeout: 180 * 1000 }, async function (baseNode, numTransactions) { const client = this.getClient(baseNode); await waitFor( @@ -3738,7 +3696,7 @@ Then( When( "I have {int} base nodes with pruning horizon {int} force syncing on node {word}", - { timeout: 190 * 1000 }, + { timeout: 7 * 1000 }, async function (nodes_count, horizon, force_sync_to) { const promises = []; const force_sync_address = this.getNode(force_sync_to).peerAddress(); diff --git a/integration_tests/features/support/world.js b/integration_tests/features/support/world.js index 889ade3b50..b2b6a2cd88 100644 --- a/integration_tests/features/support/world.js +++ b/integration_tests/features/support/world.js @@ -456,26 +456,31 @@ BeforeAll({ timeout: 2400000 }, async function () { }); Before(async function (testCase) { - console.log(`Testing scenario "${testCase.pickle.name}"`); + console.log(`\nTesting scenario: "${testCase.pickle.name}"\n`); }); After(async function (testCase) { console.log("Stopping nodes"); + await stopAndHandleLogs(this.walletsFFI, testCase, this); await stopAndHandleLogs(this.seeds, testCase, this); await stopAndHandleLogs(this.nodes, testCase, this); await stopAndHandleLogs(this.proxies, testCase, this); - await stopAndHandleLogs(this.wallets, testCase, this); - await stopAndHandleLogs(this.walletsFFI, testCase, this); await stopAndHandleLogs(this.miners, testCase, this); await stopAndHandleLogs(this.dan_nodes, testCase, this); + await stopAndHandleLogs(this.wallets, testCase, this); }); async function stopAndHandleLogs(objects, testCase, context) { for (const key in objects) { - if (testCase.result.status === "failed") { - await attachLogs(`${objects[key].baseDir}`, context); + try { + if (testCase.result.status !== "passed") { + await attachLogs(`${objects[key].baseDir}`, context); + } + await objects[key].stop(); + } catch (e) { + console.log(e); + // Continue with others } - await objects[key].stop(); } } diff --git a/integration_tests/helpers/ffi/balance.js b/integration_tests/helpers/ffi/balance.js new file mode 100644 index 0000000000..f7a55481e4 --- /dev/null +++ b/integration_tests/helpers/ffi/balance.js @@ -0,0 +1,43 @@ +const InterfaceFFI = require("./ffiInterface"); + +class Balance { + ptr; + + pointerAssign(ptr) { + if (this.ptr) { + this.destroy(); + this.ptr = ptr; + } else { + this.ptr = ptr; + } + } + + getPtr() { + return this.ptr; + } + + getAvailable() { + return InterfaceFFI.balanceGetAvailable(this.ptr); + } + + getTimeLocked() { + return InterfaceFFI.balanceGetTimeLocked(this.ptr); + } + + getPendingIncoming() { + return InterfaceFFI.balanceGetPendingIncoming(this.ptr); + } + + getPendingOutgoing() { + return InterfaceFFI.balanceGetPendingOutgoing(this.ptr); + } + + destroy() { + if (this.ptr) { + InterfaceFFI.balanceDestroy(this.ptr); + this.ptr = undefined; //prevent double free segfault + } + } +} + +module.exports = Balance; diff --git a/integration_tests/helpers/ffi/ffiInterface.js b/integration_tests/helpers/ffi/ffiInterface.js index 4eb485baef..cae9624528 100644 --- a/integration_tests/helpers/ffi/ffiInterface.js +++ b/integration_tests/helpers/ffi/ffiInterface.js @@ -13,7 +13,7 @@ class InterfaceFFI { static void = ref.types.void; static bool = ref.types.bool; static int = ref.types.int; - static ulonglong = ref.types.ulonglong; + static ulonglong = ref.types.uint64; // Note: 'ref.types.ulonglong' has a memory alignment problem static uchar = ref.types.uchar; static uint = ref.types.uint; static string = ref.types.CString; @@ -285,6 +285,7 @@ class InterfaceFFI { this.ptr, this.ptr, this.ptr, + this.ptr, this.boolPtr, this.intPtr, ], @@ -303,6 +304,10 @@ class InterfaceFFI { ], wallet_upsert_contact: [this.bool, [this.ptr, this.ptr, this.intPtr]], wallet_remove_contact: [this.bool, [this.ptr, this.ptr, this.intPtr]], + balance_get_available: [this.ulonglong, [this.ptr, this.intPtr]], + balance_get_time_locked: [this.ulonglong, [this.ptr, this.intPtr]], + balance_get_pending_incoming: [this.ulonglong, [this.ptr, this.intPtr]], + balance_get_pending_outgoing: [this.ulonglong, [this.ptr, this.intPtr]], wallet_get_available_balance: [this.ulonglong, [this.ptr, this.intPtr]], wallet_get_pending_incoming_balance: [ this.ulonglong, @@ -426,6 +431,7 @@ class InterfaceFFI { [this.ptr, this.ptr, this.ptr, this.intPtr], ], wallet_destroy: [this.void, [this.ptr]], + balance_destroy: [this.void, [this.ptr]], file_partial_backup: [this.void, [this.string, this.string, this.intPtr]], log_debug_message: [this.void, [this.string]], get_emoji_set: [this.ptr, []], @@ -1119,6 +1125,9 @@ class InterfaceFFI { static createCallbackTxoValidationComplete(fn) { return ffi.Callback(this.void, [this.ulonglong, this.uchar], fn); } + static createCallbackBalanceUpdated(fn) { + return ffi.Callback(this.void, [this.ptr], fn); + } static createCallbackTransactionValidationComplete(fn) { return ffi.Callback(this.void, [this.ulonglong, this.uchar], fn); } @@ -1151,6 +1160,7 @@ class InterfaceFFI { callback_store_and_forward_send_result, callback_transaction_cancellation, callback_txo_validation_complete, + callback_balance_updated, callback_transaction_validation_complete, callback_saf_message_received ) { @@ -1174,6 +1184,7 @@ class InterfaceFFI { callback_store_and_forward_send_result, callback_transaction_cancellation, callback_txo_validation_complete, + callback_balance_updated, callback_transaction_validation_complete, callback_saf_message_received, recovery_in_progress, @@ -1236,6 +1247,34 @@ class InterfaceFFI { return result; } + static balanceGetAvailable(ptr) { + let error = this.initError(); + let result = this.fn.balance_get_available(ptr, error); + this.checkErrorResult(error, `balanceGetAvailable`); + return result; + } + + static balanceGetTimeLocked(ptr) { + let error = this.initError(); + let result = this.fn.balance_get_available(ptr, error); + this.checkErrorResult(error, `balanceGetTimeLocked`); + return result; + } + + static balanceGetPendingIncoming(ptr) { + let error = this.initError(); + let result = this.fn.balance_get_pending_incoming(ptr, error); + this.checkErrorResult(error, `balanceGetPendingIncoming`); + return result; + } + + static balanceGetPendingOutgoing(ptr) { + let error = this.initError(); + let result = this.fn.balance_get_pending_outgoing(ptr, error); + this.checkErrorResult(error, `balanceGetPendingOutgoing`); + return result; + } + static walletGetAvailableBalance(ptr) { let error = this.initError(); let result = this.fn.wallet_get_available_balance(ptr, error); @@ -1534,6 +1573,10 @@ class InterfaceFFI { static walletDestroy(ptr) { this.fn.wallet_destroy(ptr); } + + static balanceDestroy(ptr) { + this.fn.balance_destroy(ptr); + } //endregion } module.exports = InterfaceFFI; diff --git a/integration_tests/helpers/ffi/wallet.js b/integration_tests/helpers/ffi/wallet.js index 70856b18f4..dfdf817e9b 100644 --- a/integration_tests/helpers/ffi/wallet.js +++ b/integration_tests/helpers/ffi/wallet.js @@ -7,6 +7,7 @@ const PendingInboundTransactions = require("./pendingInboundTransactions"); const PendingOutboundTransactions = require("./pendingOutboundTransactions"); const Contact = require("./contact"); const Contacts = require("./contacts"); +const Balance = require("./balance"); const utf8 = require("utf8"); @@ -31,6 +32,7 @@ class Wallet { callback_direct_send_result; callback_store_and_forward_send_result; callback_transaction_cancellation; + callback_balance_updated; callback_transaction_validation_complete; callback_saf_message_received; recoveryProgressCallback; @@ -119,6 +121,9 @@ class Wallet { InterfaceFFI.createCallbackTxoValidationComplete( this.onTxoValidationComplete ); + this.callback_balance_updated = InterfaceFFI.createCallbackBalanceUpdated( + this.onBalanceUpdated + ); this.callback_transaction_validation_complete = InterfaceFFI.createCallbackTransactionValidationComplete( this.onTransactionValidationComplete @@ -165,6 +170,7 @@ class Wallet { this.callback_store_and_forward_send_result, this.callback_transaction_cancellation, this.callback_txo_validation_complete, + this.callback_balance_updated, this.callback_transaction_validation_complete, this.callback_saf_message_received ); @@ -261,6 +267,15 @@ class Wallet { this.txo_validation_result = validation_results; }; + onBalanceUpdated = (ptr) => { + let b = new Balance(); + b.pointerAssign(ptr); + console.log( + `${new Date().toISOString()} callbackBalanceUpdated: available = ${b.getAvailable()}, time locked = ${b.getTimeLocked()} pending incoming = ${b.getPendingIncoming()} pending outgoing = ${b.getPendingOutgoing()}` + ); + b.destroy(); + }; + onTransactionValidationComplete = (request_key, validation_results) => { console.log( `${new Date().toISOString()} callbackTransactionValidationComplete(${request_key},${validation_results})` @@ -422,6 +437,7 @@ class Wallet { this.callback_store_and_forward_send_result = this.callback_transaction_cancellation = this.callback_txo_validation_complete = + this.callback_balance_updated = this.callback_transaction_validation_complete = this.callback_saf_message_received = this.recoveryProgressCallback = diff --git a/integration_tests/helpers/ffi/walletFFI.js b/integration_tests/helpers/ffi/walletFFI.js deleted file mode 100644 index e2c032a5fd..0000000000 --- a/integration_tests/helpers/ffi/walletFFI.js +++ /dev/null @@ -1,2041 +0,0 @@ -/** - * This library was AUTO-GENERATED. Do not modify manually! - */ - -const { expect } = require("chai"); -const ffi = require("ffi-napi"); -const ref = require("ref-napi"); -const dateFormat = require("dateformat"); -const { spawn } = require("child_process"); -const fs = require("fs"); - -class WalletFFI { - static byte_vector = ref.types.void; - static byte_vector_ptr = ref.refType(this.byte_vector); - static tari_comms_config = ref.types.void; - static tari_comms_config_ptr = ref.refType(this.tari_comms_config); - static tari_private_key = ref.types.void; - static tari_private_key_ptr = ref.refType(this.tari_private_key); - static tari_wallet = ref.types.void; - static tari_wallet_ptr = ref.refType(this.tari_wallet); - static tari_public_key = ref.types.void; - static tari_public_key_ptr = ref.refType(this.tari_public_key); - static tari_contacts = ref.types.void; - static tari_contacts_ptr = ref.refType(this.tari_contacts); - static tari_contact = ref.types.void; - static tari_contact_ptr = ref.refType(this.tari_contact); - static tari_completed_transactions = ref.types.void; - static tari_completed_transactions_ptr = ref.refType( - this.tari_completed_transactions - ); - static tari_completed_transaction = ref.types.void; - static tari_completed_transaction_ptr = ref.refType( - this.tari_completed_transaction - ); - static tari_pending_outbound_transactions = ref.types.void; - static tari_pending_outbound_transactions_ptr = ref.refType( - this.tari_pending_outbound_transactions - ); - static tari_pending_outbound_transaction = ref.types.void; - static tari_pending_outbound_transaction_ptr = ref.refType( - this.tari_pending_outbound_transaction - ); - static tari_pending_inbound_transactions = ref.types.void; - static tari_pending_inbound_transactions_ptr = ref.refType( - this.tari_pending_inbound_transactions - ); - static tari_pending_inbound_transaction = ref.types.void; - static tari_pending_inbound_transaction_ptr = ref.refType( - this.tari_pending_inbound_transaction - ); - static tari_transport_type = ref.types.void; - static tari_transport_type_ptr = ref.refType(this.tari_transport_type); - static tari_seed_words = ref.types.void; - static tari_seed_words_ptr = ref.refType(this.tari_seed_words); - static emoji_set = ref.types.void; - static emoji_set_ptr = ref.refType(this.emoji_set); - static tari_excess = ref.types.void; - static tari_excess_ptr = ref.refType(this.tari_excess); - static tari_excess_public_nonce = ref.types.void; - static tari_excess_public_nonce_ptr = ref.refType( - this.tari_excess_public_nonce - ); - static tari_excess_signature = ref.types.void; - static tari_excess_signature_ptr = ref.refType(this.tari_excess_signature); - - static #fn; - static error = ref.alloc(ref.types.int); - static recovery_in_progress = ref.alloc(ref.types.bool); - static NULL = ref.NULL; - static #loaded = false; - static #ps = null; - - static checkAsyncRes(resolve, reject, error_name) { - return (err, res) => { - if (err) reject(err); - expect(this.error.deref()).to.equal(0, `Error in ${error_name}`); - resolve(res); - }; - } - - static compile() { - return new Promise((resolve, _reject) => { - const cmd = "cargo"; - const args = [ - "build", - "--release", - "--package", - "tari_wallet_ffi", - "-Z", - "unstable-options", - "--out-dir", - process.cwd() + "/temp/out", - ]; - const baseDir = `./temp/base_nodes/${dateFormat( - new Date(), - "yyyymmddHHMM" - )}/WalletFFI-compile`; - if (!fs.existsSync(baseDir)) { - fs.mkdirSync(baseDir, { recursive: true }); - fs.mkdirSync(baseDir + "/log", { recursive: true }); - } - const ps = spawn(cmd, args, { - cwd: baseDir, - env: { ...process.env }, - }); - ps.on("close", (_code) => { - resolve(ps); - }); - ps.stderr.on("data", (data) => { - console.log("stderr : ", data.toString()); - }); - ps.on("error", (error) => { - console.log("error : ", error.toString()); - }); - expect(ps.error).to.be.an("undefined"); - this.#ps = ps; - }); - } - - static async Init() { - if (this.#loaded) { - return; - } - - this.#loaded = true; - await this.compile(); - const outputProcess = `${process.cwd()}/temp/out/${ - process.platform === "win32" ? "" : "lib" - }tari_wallet_ffi`; - - // Init callbacks - - this.createCallbackReceivedTransaction = (callback) => - ffi.Callback( - "void", - [this.tari_pending_inbound_transaction_ptr], - callback - ); - this.createCallbackReceivedTransactionReply = (callback) => - ffi.Callback("void", [this.tari_completed_transaction_ptr], callback); - this.createCallbackReceivedFinalizedTransaction = (callback) => - ffi.Callback("void", [this.tari_completed_transaction_ptr], callback); - this.createCallbackTransactionBroadcast = (callback) => - ffi.Callback("void", [this.tari_completed_transaction_ptr], callback); - this.createCallbackTransactionMined = (callback) => - ffi.Callback("void", [this.tari_completed_transaction_ptr], callback); - this.createCallbackTransactionMinedUnconfirmed = (callback) => - ffi.Callback( - "void", - [this.tari_completed_transaction_ptr, "uint64"], - callback - ); - this.createCallbackDirectSendResult = (callback) => - ffi.Callback("void", ["uint64", "bool"], callback); - this.createCallbackStoreAndForwardSendResult = (callback) => - ffi.Callback("void", ["uint64", "bool"], callback); - this.createCallbackTransactionCancellation = (callback) => - ffi.Callback("void", [this.tari_completed_transaction_ptr], callback); - this.createCallbackTxoValidationComplete = (callback) => - ffi.Callback("void", ["uint64", "uchar"], callback); - this.createCallbackTransactionValidationComplete = (callback) => - ffi.Callback("void", ["uint64", "uchar"], callback); - this.createCallbackSafMessageReceived = (callback) => - ffi.Callback("void", [], callback); - this.createRecoveryProgressCallback = (callback) => - ffi.Callback("void", ["uchar", "uint64", "uint64"], callback); - // Load the library - this.#fn = ffi.Library(outputProcess, { - transport_memory_create: [this.tari_transport_type_ptr, []], - transport_tcp_create: [this.tari_transport_type_ptr, ["string", "int*"]], - transport_tor_create: [ - this.tari_transport_type_ptr, - ["string", this.byte_vector_ptr, "ushort", "string", "string", "int*"], - ], - transport_memory_get_address: [ - "char*", - [this.tari_transport_type_ptr, "int*"], - ], - transport_type_destroy: ["void", [this.tari_transport_type_ptr]], - string_destroy: ["void", ["string"]], - byte_vector_create: [this.byte_vector_ptr, ["uchar*", "uint", "int*"]], - byte_vector_get_at: ["uchar", [this.byte_vector_ptr, "uint", "int*"]], - byte_vector_get_length: ["uint", [this.byte_vector_ptr, "int*"]], - byte_vector_destroy: ["void", [this.byte_vector_ptr]], - public_key_create: [ - this.tari_public_key_ptr, - [this.byte_vector_ptr, "int*"], - ], - public_key_get_bytes: [ - this.byte_vector_ptr, - [this.tari_public_key_ptr, "int*"], - ], - public_key_from_private_key: [ - this.tari_public_key_ptr, - [this.tari_private_key_ptr, "int*"], - ], - public_key_from_hex: [this.tari_public_key_ptr, ["string", "int*"]], - public_key_destroy: ["void", [this.tari_public_key_ptr]], - public_key_to_emoji_id: ["char*", [this.tari_public_key_ptr, "int*"]], - emoji_id_to_public_key: [this.tari_public_key_ptr, ["string", "int*"]], - private_key_create: [ - this.tari_private_key_ptr, - [this.byte_vector_ptr, "int*"], - ], - private_key_generate: [this.tari_private_key_ptr, []], - private_key_get_bytes: [ - this.byte_vector_ptr, - [this.tari_private_key_ptr, "int*"], - ], - private_key_from_hex: [this.tari_private_key_ptr, ["string", "int*"]], - private_key_destroy: ["void", [this.tari_private_key_ptr]], - seed_words_create: [this.tari_seed_words_ptr, []], - seed_words_get_length: ["uint", [this.tari_seed_words_ptr, "int*"]], - seed_words_get_at: ["char*", [this.tari_seed_words_ptr, "uint", "int*"]], - seed_words_push_word: [ - "uchar", - [this.tari_seed_words_ptr, "string", "int*"], - ], - seed_words_destroy: ["void", [this.tari_seed_words_ptr]], - contact_create: [ - this.tari_contact_ptr, - ["string", this.tari_public_key_ptr, "int*"], - ], - contact_get_alias: ["char*", [this.tari_contact_ptr, "int*"]], - contact_get_public_key: [ - this.tari_public_key_ptr, - [this.tari_contact_ptr, "int*"], - ], - contact_destroy: ["void", [this.tari_contact_ptr]], - contacts_get_length: ["uint", [this.tari_contacts_ptr, "int*"]], - contacts_get_at: [ - this.tari_contact_ptr, - [this.tari_contacts_ptr, "uint", "int*"], - ], - contacts_destroy: ["void", [this.tari_contacts_ptr]], - completed_transaction_get_destination_public_key: [ - this.tari_public_key_ptr, - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_get_source_public_key: [ - this.tari_public_key_ptr, - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_get_amount: [ - "uint64", - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_get_fee: [ - "uint64", - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_get_message: [ - "char*", - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_get_status: [ - "int", - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_get_transaction_id: [ - "uint64", - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_get_timestamp: [ - "uint64", - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_is_valid: [ - "bool", - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_is_outbound: [ - "bool", - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_get_confirmations: [ - "uint64", - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_destroy: [ - "void", - [this.tari_completed_transaction_ptr], - ], - completed_transaction_get_excess: [ - this.tari_excess_ptr, - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_get_public_nonce: [ - this.tari_excess_public_nonce_ptr, - [this.tari_completed_transaction_ptr, "int*"], - ], - completed_transaction_get_signature: [ - this.tari_excess_signature_ptr, - [this.tari_completed_transaction_ptr, "int*"], - ], - excess_destroy: ["void", [this.tari_excess_ptr]], - nonce_destroy: ["void", [this.tari_excess_public_nonce_ptr]], - signature_destroy: ["void", [this.tari_excess_signature_ptr]], - completed_transactions_get_length: [ - "uint", - [this.tari_completed_transactions_ptr, "int*"], - ], - completed_transactions_get_at: [ - this.tari_completed_transaction_ptr, - [this.tari_completed_transactions_ptr, "uint", "int*"], - ], - completed_transactions_destroy: [ - "void", - [this.tari_completed_transactions_ptr], - ], - pending_outbound_transaction_get_transaction_id: [ - "uint64", - [this.tari_pending_outbound_transaction_ptr, "int*"], - ], - pending_outbound_transaction_get_destination_public_key: [ - this.tari_public_key_ptr, - [this.tari_pending_outbound_transaction_ptr, "int*"], - ], - pending_outbound_transaction_get_amount: [ - "uint64", - [this.tari_pending_outbound_transaction_ptr, "int*"], - ], - pending_outbound_transaction_get_fee: [ - "uint64", - [this.tari_pending_outbound_transaction_ptr, "int*"], - ], - pending_outbound_transaction_get_message: [ - "char*", - [this.tari_pending_outbound_transaction_ptr, "int*"], - ], - pending_outbound_transaction_get_timestamp: [ - "uint64", - [this.tari_pending_outbound_transaction_ptr, "int*"], - ], - pending_outbound_transaction_get_status: [ - "int", - [this.tari_pending_outbound_transaction_ptr, "int*"], - ], - pending_outbound_transaction_destroy: [ - "void", - [this.tari_pending_outbound_transaction_ptr], - ], - pending_outbound_transactions_get_length: [ - "uint", - [this.tari_pending_outbound_transactions_ptr, "int*"], - ], - pending_outbound_transactions_get_at: [ - this.tari_pending_outbound_transaction_ptr, - [this.tari_pending_outbound_transactions_ptr, "uint", "int*"], - ], - pending_outbound_transactions_destroy: [ - "void", - [this.tari_pending_outbound_transactions_ptr], - ], - pending_inbound_transaction_get_transaction_id: [ - "uint64", - [this.tari_pending_inbound_transaction_ptr, "int*"], - ], - pending_inbound_transaction_get_source_public_key: [ - this.tari_public_key_ptr, - [this.tari_pending_inbound_transaction_ptr, "int*"], - ], - pending_inbound_transaction_get_message: [ - "char*", - [this.tari_pending_inbound_transaction_ptr, "int*"], - ], - pending_inbound_transaction_get_amount: [ - "uint64", - [this.tari_pending_inbound_transaction_ptr, "int*"], - ], - pending_inbound_transaction_get_timestamp: [ - "uint64", - [this.tari_pending_inbound_transaction_ptr, "int*"], - ], - pending_inbound_transaction_get_status: [ - "int", - [this.tari_pending_inbound_transaction_ptr, "int*"], - ], - pending_inbound_transaction_destroy: [ - "void", - [this.tari_pending_inbound_transaction_ptr], - ], - pending_inbound_transactions_get_length: [ - "uint", - [this.tari_pending_inbound_transactions_ptr, "int*"], - ], - pending_inbound_transactions_get_at: [ - this.tari_pending_inbound_transaction_ptr, - [this.tari_pending_inbound_transactions_ptr, "uint", "int*"], - ], - pending_inbound_transactions_destroy: [ - "void", - [this.tari_pending_inbound_transactions_ptr], - ], - comms_config_create: [ - this.tari_comms_config_ptr, - [ - "string", - this.tari_transport_type_ptr, - "string", - "string", - "uint64", - "uint64", - "string", - "int*", - ], - ], - comms_config_destroy: ["void", [this.tari_comms_config_ptr]], - wallet_create: [ - this.tari_wallet_ptr, - [ - this.tari_comms_config_ptr, - "string", - "uint", - "uint", - "string", - this.tari_seed_words_ptr, - "pointer", - "pointer", - "pointer", - "pointer", - "pointer", - "pointer", - "pointer", - "pointer", - "pointer", - "pointer", - "pointer", - "pointer", - "pointer", - "pointer", - "bool*", - "int*", - ], - ], - wallet_sign_message: ["char*", [this.tari_wallet_ptr, "string", "int*"]], - wallet_verify_message_signature: [ - "bool", - [ - this.tari_wallet_ptr, - this.tari_public_key_ptr, - "string", - "string", - "int*", - ], - ], - wallet_add_base_node_peer: [ - "bool", - [this.tari_wallet_ptr, this.tari_public_key_ptr, "string", "int*"], - ], - wallet_upsert_contact: [ - "bool", - [this.tari_wallet_ptr, this.tari_contact_ptr, "int*"], - ], - wallet_remove_contact: [ - "bool", - [this.tari_wallet_ptr, this.tari_contact_ptr, "int*"], - ], - wallet_get_available_balance: ["uint64", [this.tari_wallet_ptr, "int*"]], - wallet_get_pending_incoming_balance: [ - "uint64", - [this.tari_wallet_ptr, "int*"], - ], - wallet_get_pending_outgoing_balance: [ - "uint64", - [this.tari_wallet_ptr, "int*"], - ], - wallet_get_fee_estimate: [ - "uint64", - [this.tari_wallet_ptr, "uint64", "uint64", "uint64", "uint64", "int*"], - ], - wallet_get_num_confirmations_required: [ - "uint64", - [this.tari_wallet_ptr, "int*"], - ], - wallet_set_num_confirmations_required: [ - "void", - [this.tari_wallet_ptr, "uint64", "int*"], - ], - wallet_send_transaction: [ - "uint64", - [ - this.tari_wallet_ptr, - this.tari_public_key_ptr, - "uint64", - "uint64", - "string", - "int*", - ], - ], - wallet_get_contacts: [ - this.tari_contacts_ptr, - [this.tari_wallet_ptr, "int*"], - ], - wallet_get_completed_transactions: [ - this.tari_completed_transactions_ptr, - [this.tari_wallet_ptr, "int*"], - ], - wallet_get_pending_outbound_transactions: [ - this.tari_pending_outbound_transactions_ptr, - [this.tari_wallet_ptr, "int*"], - ], - wallet_get_public_key: [ - this.tari_public_key_ptr, - [this.tari_wallet_ptr, "int*"], - ], - wallet_get_pending_inbound_transactions: [ - this.tari_pending_inbound_transactions_ptr, - [this.tari_wallet_ptr, "int*"], - ], - wallet_get_cancelled_transactions: [ - this.tari_completed_transactions_ptr, - [this.tari_wallet_ptr, "int*"], - ], - wallet_get_completed_transaction_by_id: [ - this.tari_completed_transaction_ptr, - [this.tari_wallet_ptr, "uint64", "int*"], - ], - wallet_get_pending_outbound_transaction_by_id: [ - this.tari_pending_outbound_transaction_ptr, - [this.tari_wallet_ptr, "uint64", "int*"], - ], - wallet_get_pending_inbound_transaction_by_id: [ - this.tari_pending_inbound_transaction_ptr, - [this.tari_wallet_ptr, "uint64", "int*"], - ], - wallet_get_cancelled_transaction_by_id: [ - this.tari_completed_transaction_ptr, - [this.tari_wallet_ptr, "uint64", "int*"], - ], - wallet_import_utxo: [ - "uint64", - [ - this.tari_wallet_ptr, - "uint64", - this.tari_private_key_ptr, - this.tari_public_key_ptr, - "string", - "int*", - ], - ], - wallet_start_txo_validation: ["uint64", [this.tari_wallet_ptr, "int*"]], - wallet_start_transaction_validation: [ - "uint64", - [this.tari_wallet_ptr, "int*"], - ], - wallet_restart_transaction_broadcast: [ - "bool", - [this.tari_wallet_ptr, "int*"], - ], - wallet_set_low_power_mode: ["void", [this.tari_wallet_ptr, "int*"]], - wallet_set_normal_power_mode: ["void", [this.tari_wallet_ptr, "int*"]], - wallet_cancel_pending_transaction: [ - "bool", - [this.tari_wallet_ptr, "uint64", "int*"], - ], - wallet_coin_split: [ - "uint64", - [ - this.tari_wallet_ptr, - "uint64", - "uint64", - "uint64", - "string", - "uint64", - "int*", - ], - ], - wallet_get_seed_words: [ - this.tari_seed_words_ptr, - [this.tari_wallet_ptr, "int*"], - ], - wallet_apply_encryption: [ - "void", - [this.tari_wallet_ptr, "string", "int*"], - ], - wallet_remove_encryption: ["void", [this.tari_wallet_ptr, "int*"]], - wallet_set_key_value: [ - "bool", - [this.tari_wallet_ptr, "string", "string", "int*"], - ], - wallet_get_value: ["char*", [this.tari_wallet_ptr, "string", "int*"]], - wallet_clear_value: ["bool", [this.tari_wallet_ptr, "string", "int*"]], - wallet_is_recovery_in_progress: ["bool", [this.tari_wallet_ptr, "int*"]], - wallet_start_recovery: [ - "bool", - [this.tari_wallet_ptr, this.tari_public_key_ptr, "pointer", "int*"], - ], - wallet_destroy: ["void", [this.tari_wallet_ptr]], - file_partial_backup: ["void", ["string", "string", "int*"]], - log_debug_message: ["void", ["string"]], - get_emoji_set: [this.emoji_set_ptr, []], - emoji_set_destroy: ["void", [this.emoji_set_ptr]], - emoji_set_get_at: [ - this.byte_vector_ptr, - [this.emoji_set_ptr, "uint", "int*"], - ], - emoji_set_get_length: ["uint", [this.emoji_set_ptr, "int*"]], - }); - } - - static transportMemoryCreate() { - return new Promise((resolve, reject) => - this.#fn.transport_memory_create.async( - this.checkAsyncRes(resolve, reject, "transportMemoryCreate") - ) - ); - } - - static transportTcpCreate(listener_address) { - return new Promise((resolve, reject) => - this.#fn.transport_tcp_create.async( - listener_address, - this.error, - this.checkAsyncRes(resolve, reject, "transportTcpCreate") - ) - ); - } - - static transportTorCreate( - control_server_address, - tor_cookie, - tor_port, - socks_username, - socks_password - ) { - return new Promise((resolve, reject) => - this.#fn.transport_tor_create.async( - control_server_address, - tor_cookie, - tor_port, - socks_username, - socks_password, - this.error, - this.checkAsyncRes(resolve, reject, "transportTorCreate") - ) - ); - } - - static transportMemoryGetAddress(transport) { - return new Promise((resolve, reject) => - this.#fn.transport_memory_get_address.async( - transport, - this.error, - this.checkAsyncRes(resolve, reject, "transportMemoryGetAddress") - ) - ); - } - - static transportTypeDestroy(transport) { - return new Promise((resolve, reject) => - this.#fn.transport_type_destroy.async( - transport, - this.checkAsyncRes(resolve, reject, "transportTypeDestroy") - ) - ); - } - - static stringDestroy(s) { - return new Promise((resolve, reject) => - this.#fn.string_destroy.async( - s, - this.checkAsyncRes(resolve, reject, "stringDestroy") - ) - ); - } - - static byteVectorCreate(byte_array, element_count) { - return new Promise((resolve, reject) => - this.#fn.byte_vector_create.async( - byte_array, - element_count, - this.error, - this.checkAsyncRes(resolve, reject, "byteVectorCreate") - ) - ); - } - - static byteVectorGetAt(ptr, i) { - return new Promise((resolve, reject) => - this.#fn.byte_vector_get_at.async( - ptr, - i, - this.error, - this.checkAsyncRes(resolve, reject, "byteVectorGetAt") - ) - ); - } - - static byteVectorGetLength(vec) { - return new Promise((resolve, reject) => - this.#fn.byte_vector_get_length.async( - vec, - this.error, - this.checkAsyncRes(resolve, reject, "byteVectorGetLength") - ) - ); - } - - static byteVectorDestroy(bytes) { - return new Promise((resolve, reject) => - this.#fn.byte_vector_destroy.async( - bytes, - this.checkAsyncRes(resolve, reject, "byteVectorDestroy") - ) - ); - } - - static publicKeyCreate(bytes) { - return new Promise((resolve, reject) => - this.#fn.public_key_create.async( - bytes, - this.error, - this.checkAsyncRes(resolve, reject, "publicKeyCreate") - ) - ); - } - - static publicKeyGetBytes(public_key) { - return new Promise((resolve, reject) => - this.#fn.public_key_get_bytes.async( - public_key, - this.error, - this.checkAsyncRes(resolve, reject, "publicKeyGetBytes") - ) - ); - } - - static publicKeyFromPrivateKey(secret_key) { - return new Promise((resolve, reject) => - this.#fn.public_key_from_private_key.async( - secret_key, - this.error, - this.checkAsyncRes(resolve, reject, "publicKeyFromPrivateKey") - ) - ); - } - - static publicKeyFromHex(hex) { - return new Promise((resolve, reject) => - this.#fn.public_key_from_hex.async( - hex, - this.error, - this.checkAsyncRes(resolve, reject, "publicKeyFromHex") - ) - ); - } - - static publicKeyDestroy(pk) { - return new Promise((resolve, reject) => - this.#fn.public_key_destroy.async( - pk, - this.checkAsyncRes(resolve, reject, "publicKeyDestroy") - ) - ); - } - - static publicKeyToEmojiId(pk) { - return new Promise((resolve, reject) => - this.#fn.public_key_to_emoji_id.async( - pk, - this.error, - this.checkAsyncRes(resolve, reject, "publicKeyToEmojiId") - ) - ); - } - - static emojiIdToPublicKey(emoji) { - return new Promise((resolve, reject) => - this.#fn.emoji_id_to_public_key.async( - emoji, - this.error, - this.checkAsyncRes(resolve, reject, "emojiIdToPublicKey") - ) - ); - } - - static privateKeyCreate(bytes) { - return new Promise((resolve, reject) => - this.#fn.private_key_create.async( - bytes, - this.error, - this.checkAsyncRes(resolve, reject, "privateKeyCreate") - ) - ); - } - - static privateKeyGenerate() { - return new Promise((resolve, reject) => - this.#fn.private_key_generate.async( - this.checkAsyncRes(resolve, reject, "privateKeyGenerate") - ) - ); - } - - static privateKeyGetBytes(private_key) { - return new Promise((resolve, reject) => - this.#fn.private_key_get_bytes.async( - private_key, - this.error, - this.checkAsyncRes(resolve, reject, "privateKeyGetBytes") - ) - ); - } - - static privateKeyFromHex(hex) { - return new Promise((resolve, reject) => - this.#fn.private_key_from_hex.async( - hex, - this.error, - this.checkAsyncRes(resolve, reject, "privateKeyFromHex") - ) - ); - } - - static privateKeyDestroy(pk) { - return new Promise((resolve, reject) => - this.#fn.private_key_destroy.async( - pk, - this.checkAsyncRes(resolve, reject, "privateKeyDestroy") - ) - ); - } - - static seedWordsCreate() { - return new Promise((resolve, reject) => - this.#fn.seed_words_create.async( - this.checkAsyncRes(resolve, reject, "seedWordsCreate") - ) - ); - } - - static seedWordsGetLength(seed_words) { - return new Promise((resolve, reject) => - this.#fn.seed_words_get_length.async( - seed_words, - this.error, - this.checkAsyncRes(resolve, reject, "seedWordsGetLength") - ) - ); - } - - static seedWordsGetAt(seed_words, position) { - return new Promise((resolve, reject) => - this.#fn.seed_words_get_at.async( - seed_words, - position, - this.error, - this.checkAsyncRes(resolve, reject, "seedWordsGetAt") - ) - ); - } - - static seedWordsPushWord(seed_words, word) { - return new Promise((resolve, reject) => - this.#fn.seed_words_push_word.async( - seed_words, - word, - this.error, - this.checkAsyncRes(resolve, reject, "seedWordsPushWord") - ) - ); - } - - static seedWordsDestroy(seed_words) { - return new Promise((resolve, reject) => - this.#fn.seed_words_destroy.async( - seed_words, - this.checkAsyncRes(resolve, reject, "seedWordsDestroy") - ) - ); - } - - static contactCreate(alias, public_key) { - return new Promise((resolve, reject) => - this.#fn.contact_create.async( - alias, - public_key, - this.error, - this.checkAsyncRes(resolve, reject, "contactCreate") - ) - ); - } - - static contactGetAlias(contact) { - return new Promise((resolve, reject) => - this.#fn.contact_get_alias.async( - contact, - this.error, - this.checkAsyncRes(resolve, reject, "contactGetAlias") - ) - ); - } - - static contactGetPublicKey(contact) { - return new Promise((resolve, reject) => - this.#fn.contact_get_public_key.async( - contact, - this.error, - this.checkAsyncRes(resolve, reject, "contactGetPublicKey") - ) - ); - } - - static contactDestroy(contact) { - return new Promise((resolve, reject) => - this.#fn.contact_destroy.async( - contact, - this.checkAsyncRes(resolve, reject, "contactDestroy") - ) - ); - } - - static contactsGetLength(contacts) { - return new Promise((resolve, reject) => - this.#fn.contacts_get_length.async( - contacts, - this.error, - this.checkAsyncRes(resolve, reject, "contactsGetLength") - ) - ); - } - - static contactsGetAt(contacts, position) { - return new Promise((resolve, reject) => - this.#fn.contacts_get_at.async( - contacts, - position, - this.error, - this.checkAsyncRes(resolve, reject, "contactsGetAt") - ) - ); - } - - static contactsDestroy(contacts) { - return new Promise((resolve, reject) => - this.#fn.contacts_destroy.async( - contacts, - this.checkAsyncRes(resolve, reject, "contactsDestroy") - ) - ); - } - - static completedTransactionGetDestinationPublicKey(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_destination_public_key.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "completedTransactionGetDestinationPublicKey" - ) - ) - ); - } - - static completedTransactionGetSourcePublicKey(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_source_public_key.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "completedTransactionGetSourcePublicKey" - ) - ) - ); - } - - static completedTransactionGetAmount(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_amount.async( - transaction, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionGetAmount") - ) - ); - } - - static completedTransactionGetFee(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_fee.async( - transaction, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionGetFee") - ) - ); - } - - static completedTransactionGetMessage(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_message.async( - transaction, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionGetMessage") - ) - ); - } - - static completedTransactionGetStatus(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_status.async( - transaction, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionGetStatus") - ) - ); - } - - static completedTransactionGetTransactionId(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_transaction_id.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "completedTransactionGetTransactionId" - ) - ) - ); - } - - static completedTransactionGetTimestamp(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_timestamp.async( - transaction, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionGetTimestamp") - ) - ); - } - - static completedTransactionIsValid(tx) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_is_valid.async( - tx, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionIsValid") - ) - ); - } - - static completedTransactionIsOutbound(tx) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_is_outbound.async( - tx, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionIsOutbound") - ) - ); - } - - static completedTransactionGetConfirmations(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_confirmations.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "completedTransactionGetConfirmations" - ) - ) - ); - } - - static completedTransactionDestroy(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_destroy.async( - transaction, - this.checkAsyncRes(resolve, reject, "completedTransactionDestroy") - ) - ); - } - - static completedTransactionGetExcess(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_excess.async( - transaction, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionGetExcess") - ) - ); - } - - static completedTransactionGetPublicNonce(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_public_nonce.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "completedTransactionGetPublicNonce" - ) - ) - ); - } - - static completedTransactionGetSignature(transaction) { - return new Promise((resolve, reject) => - this.#fn.completed_transaction_get_signature.async( - transaction, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionGetSignature") - ) - ); - } - - static excessDestroy(excess) { - return new Promise((resolve, reject) => - this.#fn.excess_destroy.async( - excess, - this.checkAsyncRes(resolve, reject, "excessDestroy") - ) - ); - } - - static nonceDestroy(nonce) { - return new Promise((resolve, reject) => - this.#fn.nonce_destroy.async( - nonce, - this.checkAsyncRes(resolve, reject, "nonceDestroy") - ) - ); - } - - static signatureDestroy(signature) { - return new Promise((resolve, reject) => - this.#fn.signature_destroy.async( - signature, - this.checkAsyncRes(resolve, reject, "signatureDestroy") - ) - ); - } - - static completedTransactionsGetLength(transactions) { - return new Promise((resolve, reject) => - this.#fn.completed_transactions_get_length.async( - transactions, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionsGetLength") - ) - ); - } - - static completedTransactionsGetAt(transactions, position) { - return new Promise((resolve, reject) => - this.#fn.completed_transactions_get_at.async( - transactions, - position, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionsGetAt") - ) - ); - } - - static completedTransactionsDestroy(transactions) { - return new Promise((resolve, reject) => - this.#fn.completed_transactions_destroy.async( - transactions, - this.checkAsyncRes(resolve, reject, "completedTransactionsDestroy") - ) - ); - } - - static pendingOutboundTransactionGetTransactionId(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_outbound_transaction_get_transaction_id.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingOutboundTransactionGetTransactionId" - ) - ) - ); - } - - static pendingOutboundTransactionGetDestinationPublicKey(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_outbound_transaction_get_destination_public_key.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingOutboundTransactionGetDestinationPublicKey" - ) - ) - ); - } - - static pendingOutboundTransactionGetAmount(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_outbound_transaction_get_amount.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingOutboundTransactionGetAmount" - ) - ) - ); - } - - static pendingOutboundTransactionGetFee(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_outbound_transaction_get_fee.async( - transaction, - this.error, - this.checkAsyncRes(resolve, reject, "pendingOutboundTransactionGetFee") - ) - ); - } - - static pendingOutboundTransactionGetMessage(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_outbound_transaction_get_message.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingOutboundTransactionGetMessage" - ) - ) - ); - } - - static pendingOutboundTransactionGetTimestamp(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_outbound_transaction_get_timestamp.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingOutboundTransactionGetTimestamp" - ) - ) - ); - } - - static pendingOutboundTransactionGetStatus(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_outbound_transaction_get_status.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingOutboundTransactionGetStatus" - ) - ) - ); - } - - static pendingOutboundTransactionDestroy(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_outbound_transaction_destroy.async( - transaction, - this.checkAsyncRes(resolve, reject, "pendingOutboundTransactionDestroy") - ) - ); - } - - static pendingOutboundTransactionsGetLength(transactions) { - return new Promise((resolve, reject) => - this.#fn.pending_outbound_transactions_get_length.async( - transactions, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingOutboundTransactionsGetLength" - ) - ) - ); - } - - static pendingOutboundTransactionsGetAt(transactions, position) { - return new Promise((resolve, reject) => - this.#fn.pending_outbound_transactions_get_at.async( - transactions, - position, - this.error, - this.checkAsyncRes(resolve, reject, "pendingOutboundTransactionsGetAt") - ) - ); - } - - static pendingOutboundTransactionsDestroy(transactions) { - return new Promise((resolve, reject) => - this.#fn.pending_outbound_transactions_destroy.async( - transactions, - this.checkAsyncRes( - resolve, - reject, - "pendingOutboundTransactionsDestroy" - ) - ) - ); - } - - static pendingInboundTransactionGetTransactionId(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_inbound_transaction_get_transaction_id.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingInboundTransactionGetTransactionId" - ) - ) - ); - } - - static pendingInboundTransactionGetSourcePublicKey(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_inbound_transaction_get_source_public_key.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingInboundTransactionGetSourcePublicKey" - ) - ) - ); - } - - static pendingInboundTransactionGetMessage(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_inbound_transaction_get_message.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingInboundTransactionGetMessage" - ) - ) - ); - } - - static pendingInboundTransactionGetAmount(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_inbound_transaction_get_amount.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingInboundTransactionGetAmount" - ) - ) - ); - } - - static pendingInboundTransactionGetTimestamp(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_inbound_transaction_get_timestamp.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingInboundTransactionGetTimestamp" - ) - ) - ); - } - - static pendingInboundTransactionGetStatus(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_inbound_transaction_get_status.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingInboundTransactionGetStatus" - ) - ) - ); - } - - static pendingInboundTransactionDestroy(transaction) { - return new Promise((resolve, reject) => - this.#fn.pending_inbound_transaction_destroy.async( - transaction, - this.checkAsyncRes(resolve, reject, "pendingInboundTransactionDestroy") - ) - ); - } - - static pendingInboundTransactionsGetLength(transactions) { - return new Promise((resolve, reject) => - this.#fn.pending_inbound_transactions_get_length.async( - transactions, - this.error, - this.checkAsyncRes( - resolve, - reject, - "pendingInboundTransactionsGetLength" - ) - ) - ); - } - - static pendingInboundTransactionsGetAt(transactions, position) { - return new Promise((resolve, reject) => - this.#fn.pending_inbound_transactions_get_at.async( - transactions, - position, - this.error, - this.checkAsyncRes(resolve, reject, "pendingInboundTransactionsGetAt") - ) - ); - } - - static pendingInboundTransactionsDestroy(transactions) { - return new Promise((resolve, reject) => - this.#fn.pending_inbound_transactions_destroy.async( - transactions, - this.checkAsyncRes(resolve, reject, "pendingInboundTransactionsDestroy") - ) - ); - } - - static commsConfigCreate( - public_address, - transport, - database_name, - datastore_path, - discovery_timeout_in_secs, - saf_message_duration_in_secs, - network - ) { - return new Promise((resolve, reject) => - this.#fn.comms_config_create.async( - public_address, - transport, - database_name, - datastore_path, - discovery_timeout_in_secs, - saf_message_duration_in_secs, - network, - this.error, - this.checkAsyncRes(resolve, reject, "commsConfigCreate") - ) - ); - } - - static commsConfigDestroy(wc) { - return new Promise((resolve, reject) => - this.#fn.comms_config_destroy.async( - wc, - this.checkAsyncRes(resolve, reject, "commsConfigDestroy") - ) - ); - } - - static walletCreate( - config, - log_path, - num_rolling_log_files, - size_per_log_file_bytes, - passphrase, - seed_words, - callback_received_transaction, - callback_received_transaction_reply, - callback_received_finalized_transaction, - callback_transaction_broadcast, - callback_transaction_mined, - callback_transaction_mined_unconfirmed, - callback_direct_send_result, - callback_store_and_forward_send_result, - callback_transaction_cancellation, - callback_txo_validation_complete, - callback_transaction_validation_complete, - callback_saf_message_received - ) { - return new Promise((resolve, reject) => - this.#fn.wallet_create.async( - config, - log_path, - num_rolling_log_files, - size_per_log_file_bytes, - passphrase, - seed_words, - callback_received_transaction, - callback_received_transaction_reply, - callback_received_finalized_transaction, - callback_transaction_broadcast, - callback_transaction_mined, - callback_transaction_mined_unconfirmed, - callback_direct_send_result, - callback_store_and_forward_send_result, - callback_transaction_cancellation, - callback_txo_validation_complete, - callback_transaction_validation_complete, - callback_saf_message_received, - this.recovery_in_progress, - this.error, - this.checkAsyncRes(resolve, reject, "walletCreate") - ) - ); - } - - static walletSignMessage(wallet, msg) { - return new Promise((resolve, reject) => - this.#fn.wallet_sign_message.async( - wallet, - msg, - this.error, - this.checkAsyncRes(resolve, reject, "walletSignMessage") - ) - ); - } - - static walletVerifyMessageSignature(wallet, public_key, hex_sig_nonce, msg) { - return new Promise((resolve, reject) => - this.#fn.wallet_verify_message_signature.async( - wallet, - public_key, - hex_sig_nonce, - msg, - this.error, - this.checkAsyncRes(resolve, reject, "walletVerifyMessageSignature") - ) - ); - } - - static walletAddBaseNodePeer(wallet, public_key, address) { - return new Promise((resolve, reject) => - this.#fn.wallet_add_base_node_peer.async( - wallet, - public_key, - address, - this.error, - this.checkAsyncRes(resolve, reject, "walletAddBaseNodePeer") - ) - ); - } - - static walletUpsertContact(wallet, contact) { - return new Promise((resolve, reject) => - this.#fn.wallet_upsert_contact.async( - wallet, - contact, - this.error, - this.checkAsyncRes(resolve, reject, "walletUpsertContact") - ) - ); - } - - static walletRemoveContact(wallet, contact) { - return new Promise((resolve, reject) => - this.#fn.wallet_remove_contact.async( - wallet, - contact, - this.error, - this.checkAsyncRes(resolve, reject, "walletRemoveContact") - ) - ); - } - - static walletGetAvailableBalance(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_available_balance.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetAvailableBalance") - ) - ); - } - - static walletGetPendingIncomingBalance(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_pending_incoming_balance.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetPendingIncomingBalance") - ) - ); - } - - static walletGetPendingOutgoingBalance(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_pending_outgoing_balance.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetPendingOutgoingBalance") - ) - ); - } - - static walletGetFeeEstimate( - wallet, - amount, - fee_per_gram, - num_kernels, - num_outputs - ) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_fee_estimate.async( - wallet, - amount, - fee_per_gram, - num_kernels, - num_outputs, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetFeeEstimate") - ) - ); - } - - static walletGetNumConfirmationsRequired(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_num_confirmations_required.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetNumConfirmationsRequired") - ) - ); - } - - static walletSetNumConfirmationsRequired(wallet, num) { - return new Promise((resolve, reject) => - this.#fn.wallet_set_num_confirmations_required.async( - wallet, - num, - this.error, - this.checkAsyncRes(resolve, reject, "walletSetNumConfirmationsRequired") - ) - ); - } - - static walletSendTransaction( - wallet, - destination, - amount, - fee_per_gram, - message - ) { - return new Promise((resolve, reject) => - this.#fn.wallet_send_transaction.async( - wallet, - destination, - amount, - fee_per_gram, - message, - this.error, - this.checkAsyncRes(resolve, reject, "walletSendTransaction") - ) - ); - } - - static walletGetContacts(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_contacts.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetContacts") - ) - ); - } - - static walletGetCompletedTransactions(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_completed_transactions.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetCompletedTransactions") - ) - ); - } - - static walletGetPendingOutboundTransactions(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_pending_outbound_transactions.async( - wallet, - this.error, - this.checkAsyncRes( - resolve, - reject, - "walletGetPendingOutboundTransactions" - ) - ) - ); - } - - static walletGetPublicKey(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_public_key.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetPublicKey") - ) - ); - } - - static walletGetPendingInboundTransactions(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_pending_inbound_transactions.async( - wallet, - this.error, - this.checkAsyncRes( - resolve, - reject, - "walletGetPendingInboundTransactions" - ) - ) - ); - } - - static walletGetCancelledTransactions(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_cancelled_transactions.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetCancelledTransactions") - ) - ); - } - - static walletGetCompletedTransactionById(wallet, transaction_id) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_completed_transaction_by_id.async( - wallet, - transaction_id, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetCompletedTransactionById") - ) - ); - } - - static walletGetPendingOutboundTransactionById(wallet, transaction_id) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_pending_outbound_transaction_by_id.async( - wallet, - transaction_id, - this.error, - this.checkAsyncRes( - resolve, - reject, - "walletGetPendingOutboundTransactionById" - ) - ) - ); - } - - static walletGetPendingInboundTransactionById(wallet, transaction_id) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_pending_inbound_transaction_by_id.async( - wallet, - transaction_id, - this.error, - this.checkAsyncRes( - resolve, - reject, - "walletGetPendingInboundTransactionById" - ) - ) - ); - } - - static walletGetCancelledTransactionById(wallet, transaction_id) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_cancelled_transaction_by_id.async( - wallet, - transaction_id, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetCancelledTransactionById") - ) - ); - } - - static walletImportUtxo( - wallet, - amount, - spending_key, - source_public_key, - message - ) { - return new Promise((resolve, reject) => - this.#fn.wallet_import_utxo.async( - wallet, - amount, - spending_key, - source_public_key, - message, - this.error, - this.checkAsyncRes(resolve, reject, "walletImportUtxo") - ) - ); - } - - static walletStartTxoValidation(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_start_txo_validation.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletStartTxoValidation") - ) - ); - } - - static walletStartTransactionValidation(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_start_transaction_validation.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletStartTransactionValidation") - ) - ); - } - - static walletRestartTransactionBroadcast(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_restart_transaction_broadcast.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletRestartTransactionBroadcast") - ) - ); - } - - static walletSetLowPowerMode(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_set_low_power_mode.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletSetLowPowerMode") - ) - ); - } - - static walletSetNormalPowerMode(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_set_normal_power_mode.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletSetNormalPowerMode") - ) - ); - } - - static walletCancelPendingTransaction(wallet, transaction_id) { - return new Promise((resolve, reject) => - this.#fn.wallet_cancel_pending_transaction.async( - wallet, - transaction_id, - this.error, - this.checkAsyncRes(resolve, reject, "walletCancelPendingTransaction") - ) - ); - } - - static walletCoinSplit(wallet, amount, count, fee, msg, lock_height) { - return new Promise((resolve, reject) => - this.#fn.wallet_coin_split.async( - wallet, - amount, - count, - fee, - msg, - lock_height, - this.error, - this.checkAsyncRes(resolve, reject, "walletCoinSplit") - ) - ); - } - - static walletGetSeedWords(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_seed_words.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetSeedWords") - ) - ); - } - - static walletApplyEncryption(wallet, passphrase) { - return new Promise((resolve, reject) => - this.#fn.wallet_apply_encryption.async( - wallet, - passphrase, - this.error, - this.checkAsyncRes(resolve, reject, "walletApplyEncryption") - ) - ); - } - - static walletRemoveEncryption(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_remove_encryption.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletRemoveEncryption") - ) - ); - } - - static walletSetKeyValue(wallet, key, value) { - return new Promise((resolve, reject) => - this.#fn.wallet_set_key_value.async( - wallet, - key, - value, - this.error, - this.checkAsyncRes(resolve, reject, "walletSetKeyValue") - ) - ); - } - - static walletGetValue(wallet, key) { - return new Promise((resolve, reject) => - this.#fn.wallet_get_value.async( - wallet, - key, - this.error, - this.checkAsyncRes(resolve, reject, "walletGetValue") - ) - ); - } - - static walletClearValue(wallet, key) { - return new Promise((resolve, reject) => - this.#fn.wallet_clear_value.async( - wallet, - key, - this.error, - this.checkAsyncRes(resolve, reject, "walletClearValue") - ) - ); - } - - static walletIsRecoveryInProgress(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_is_recovery_in_progress.async( - wallet, - this.error, - this.checkAsyncRes(resolve, reject, "walletIsRecoveryInProgress") - ) - ); - } - - static walletStartRecovery( - wallet, - base_node_public_key, - recovery_progress_callback - ) { - return new Promise((resolve, reject) => - this.#fn.wallet_start_recovery.async( - wallet, - base_node_public_key, - recovery_progress_callback, - this.error, - this.checkAsyncRes(resolve, reject, "walletStartRecovery") - ) - ); - } - - static walletDestroy(wallet) { - return new Promise((resolve, reject) => - this.#fn.wallet_destroy.async( - wallet, - this.checkAsyncRes(resolve, reject, "walletDestroy") - ) - ); - } - - static filePartialBackup(original_file_path, backup_file_path) { - return new Promise((resolve, reject) => - this.#fn.file_partial_backup.async( - original_file_path, - backup_file_path, - this.error, - this.checkAsyncRes(resolve, reject, "filePartialBackup") - ) - ); - } - - static logDebugMessage(msg) { - return new Promise((resolve, reject) => - this.#fn.log_debug_message.async( - msg, - this.checkAsyncRes(resolve, reject, "logDebugMessage") - ) - ); - } - - static getEmojiSet() { - return new Promise((resolve, reject) => - this.#fn.get_emoji_set.async( - this.checkAsyncRes(resolve, reject, "getEmojiSet") - ) - ); - } - - static emojiSetDestroy(emoji_set) { - return new Promise((resolve, reject) => - this.#fn.emoji_set_destroy.async( - emoji_set, - this.checkAsyncRes(resolve, reject, "emojiSetDestroy") - ) - ); - } - - static emojiSetGetAt(emoji_set, position) { - return new Promise((resolve, reject) => - this.#fn.emoji_set_get_at.async( - emoji_set, - position, - this.error, - this.checkAsyncRes(resolve, reject, "emojiSetGetAt") - ) - ); - } - - static emojiSetGetLength(emoji_set) { - return new Promise((resolve, reject) => - this.#fn.emoji_set_get_length.async( - emoji_set, - this.error, - this.checkAsyncRes(resolve, reject, "emojiSetGetLength") - ) - ); - } -} -module.exports = WalletFFI; diff --git a/integration_tests/helpers/util.js b/integration_tests/helpers/util.js index 1fc09915cb..5db4be6491 100644 --- a/integration_tests/helpers/util.js +++ b/integration_tests/helpers/util.js @@ -110,9 +110,9 @@ async function waitFor( async function waitForIterate(testFn, toBe, sleepMs, maxIterations = 500) { let count = 0; - let val = testFn(); - while (!(val === toBe)) { - val = testFn(); + let val = await Promise.resolve(testFn()); + while (val !== toBe) { + val = await Promise.resolve(testFn()); if (count >= maxIterations) { break; } @@ -120,19 +120,21 @@ async function waitForIterate(testFn, toBe, sleepMs, maxIterations = 500) { await sleep(sleepMs); process.stdout.write("."); } + return val; } async function waitForPredicate(predicate, timeOut, sleepMs = 500) { - const now = new Date(); - while (new Date() - now < timeOut) { + let elapsed = 0; + while (elapsed < timeOut) { const val = await predicate(); if (val) { return val; } await sleep(sleepMs); + elapsed += sleepMs; process.stdout.write("."); } - throw new Error(`Predicate was not true after ${timeOut} ms`); + throw new Error(`Predicate was not truthy after ${timeOut} ms`); } function dec2hex(n) { diff --git a/integration_tests/helpers/walletFFIClient.js b/integration_tests/helpers/walletFFIClient.js index 08d509fb9c..68441f390d 100644 --- a/integration_tests/helpers/walletFFIClient.js +++ b/integration_tests/helpers/walletFFIClient.js @@ -4,6 +4,7 @@ const CommsConfig = require("./ffi/commsConfig"); const Wallet = require("./ffi/wallet"); const { getFreePort } = require("./util"); const dateFormat = require("dateformat"); +const { sleep } = require("./util"); class WalletFFIClient { name; @@ -125,7 +126,9 @@ class WalletFFIClient { return this.wallet.getCounters(); } resetCounters() { - this.wallet.clearCallbackCounters(); + if (this.wallet) { + this.wallet.clearCallbackCounters(); + } } sendTransaction(destination, amount, fee_per_gram, message) { @@ -168,18 +171,32 @@ class WalletFFIClient { return this.wallet.cancelPendingTransaction(tx_id); } - stop() { - if (this.wallet) { - this.wallet.destroy(); - } + async stop() { if (this.comms_config) { - this.comms_config.destroy(); + // console.log("walletFFI destroy comms_config ..."); + await this.comms_config.destroy(); + this.comms_config = undefined; + // console.log("walletFFI destroy comms_config ... done!"); + await sleep(100); } if (this.transport) { - this.transport.destroy(); + // console.log("walletFFI destroy transport ..."); + await this.transport.destroy(); + this.transport = undefined; + // console.log("walletFFI destroy transport ... done!"); + await sleep(100); } if (this.seed_words) { - this.seed_words.destroy(); + // console.log("walletFFI destroy seed_words ..."); + await this.seed_words.destroy(); + this.seed_words = undefined; + // console.log("walletFFI destroy seed_words ... done!"); + } + if (this.wallet) { + // console.log("walletFFI destroy wallet ..."); + await this.wallet.destroy(); + this.wallet = undefined; + // console.log("walletFFI destroy wallet ... done!"); } } } diff --git a/integration_tests/package-lock.json b/integration_tests/package-lock.json index 5f4b48cd14..54d92efa38 100644 --- a/integration_tests/package-lock.json +++ b/integration_tests/package-lock.json @@ -1,4276 +1,12 @@ { "name": "integration_tests", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "integration_tests", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "archiver": "^5.3.0", - "axios": "^0.21.4", - "clone-deep": "^4.0.1", - "csv-parser": "^3.0.0", - "dateformat": "^3.0.3", - "glob": "^7.2.0", - "hex64": "^0.4.0", - "jszip": "^3.7.1", - "sha3": "^2.1.3", - "synchronized-promise": "^0.3.1", - "tari_crypto": "^0.9.1", - "utf8": "^3.0.0", - "wallet-grpc-client": "file:../clients/wallet_grpc_client" - }, - "devDependencies": { - "@babel/core": "^7.15.8", - "@babel/eslint-parser": "^7.15.8", - "@babel/eslint-plugin": "^7.14.5", - "@grpc/grpc-js": "^1.3.6", - "@grpc/proto-loader": "^0.5.5", - "blakejs": "^1.1.0", - "chai": "^4.2.0", - "cucumber": "^6.0.5", - "cucumber-html-reporter": "^5.5.0", - "cucumber-pretty": "^6.0.0", - "eslint": "^7.32.0", - "eslint-config-prettier": "^8.3.0", - "eslint-config-standard": "^16.0.2", - "eslint-plugin-import": "^2.24.2", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-prettier": "^3.4.1", - "eslint-plugin-promise": "^4.3.1", - "ffi-napi": "^4.0.3", - "grpc-promise": "^1.4.0", - "husky": "^6.0.0", - "prettier": "^2.4.1", - "ref-napi": "^3.0.3" - } - }, - "../clients/wallet_grpc_client": { - "name": "@tari/wallet-grpc-client", - "version": "0.0.1", - "dependencies": { - "@grpc/grpc-js": "^1.3.6", - "@grpc/proto-loader": "^0.5.5", - "grpc-promise": "^1.4.0" - } - }, - "../clients/wallet_grpc_client/node_modules/@grpc/grpc-js": { - "version": "1.3.6", - "integrity": "sha512-v7+LQFbqZKmd/Tvf5/j1Xlbq6jXL/4d+gUtm2TNX4QiEC3ELWADmGr2dGlUyLl6aKTuYfsN72vAsO5zmavYkEg==", - "dependencies": { - "@types/node": ">=12.12.47" - }, - "engines": { - "node": "^8.13.0 || >=10.10.0" - } - }, - "../clients/wallet_grpc_client/node_modules/@grpc/proto-loader": { - "version": "0.5.6", - "integrity": "sha512-DT14xgw3PSzPxwS13auTEwxhMMOoz33DPUKNtmYK/QYbBSpLXJy78FGGs5yVoxVobEqPm4iW9MOIoz0A3bLTRQ==", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "protobufjs": "^6.8.6" - }, - "engines": { - "node": ">=6" - } - }, - "../clients/wallet_grpc_client/node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - }, - "../clients/wallet_grpc_client/node_modules/@protobufjs/base64": { - "version": "1.1.2", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "../clients/wallet_grpc_client/node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "../clients/wallet_grpc_client/node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" - }, - "../clients/wallet_grpc_client/node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "../clients/wallet_grpc_client/node_modules/@protobufjs/float": { - "version": "1.0.2", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" - }, - "../clients/wallet_grpc_client/node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" - }, - "../clients/wallet_grpc_client/node_modules/@protobufjs/path": { - "version": "1.1.2", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" - }, - "../clients/wallet_grpc_client/node_modules/@protobufjs/pool": { - "version": "1.1.0", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" - }, - "../clients/wallet_grpc_client/node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" - }, - "../clients/wallet_grpc_client/node_modules/@types/long": { - "version": "4.0.1", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, - "../clients/wallet_grpc_client/node_modules/@types/node": { - "version": "16.3.2", - "integrity": "sha512-jJs9ErFLP403I+hMLGnqDRWT0RYKSvArxuBVh2veudHV7ifEC1WAmjJADacZ7mRbA2nWgHtn8xyECMAot0SkAw==" - }, - "../clients/wallet_grpc_client/node_modules/grpc-promise": { - "version": "1.4.0", - "integrity": "sha512-4BBXHXb5OjjBh7luylu8vFqL6H6aPn/LeqpQaSBeRzO/Xv95wHW/WkU9TJRqaCTMZ5wq9jTSvlJWp0vRJy1pVA==" - }, - "../clients/wallet_grpc_client/node_modules/lodash.camelcase": { - "version": "4.3.0", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" - }, - "../clients/wallet_grpc_client/node_modules/long": { - "version": "4.0.0", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "../clients/wallet_grpc_client/node_modules/protobufjs": { - "version": "6.11.2", - "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": ">=13.7.0", - "long": "^4.0.0" - }, - "bin": { - "pbjs": "bin/pbjs", - "pbts": "bin/pbts" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.15.8", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.15.0", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.15.8", - "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.15.8", - "@babel/generator": "^7.15.8", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.8", - "@babel/helpers": "^7.15.4", - "@babel/parser": "^7.15.8", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/eslint-parser": { - "version": "7.15.8", - "integrity": "sha512-fYP7QFngCvgxjUuw8O057SVH5jCXsbFFOoE77CFDcvzwBVgTOkMD/L4mIC5Ud1xf8chK/no2fRbSSn1wvNmKuQ==", - "dev": true, - "dependencies": { - "eslint-scope": "^5.1.1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.11.0", - "eslint": ">=7.5.0" - } - }, - "node_modules/@babel/eslint-plugin": { - "version": "7.14.5", - "integrity": "sha512-nzt/YMnOOIRikvSn2hk9+W2omgJBy6U8TN0R+WTTmqapA+HnZTuviZaketdTE9W7/k/+E/DfZlt1ey1NSE39pg==", - "dev": true, - "dependencies": { - "eslint-rule-composer": "^0.3.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/eslint-parser": ">=7.11.0", - "eslint": ">=7.5.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.15.8", - "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.6", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.15.4", - "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.15.4", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.15.4", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.15.4", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.15.4", - "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.15.4", - "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.15.8", - "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-simple-access": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.15.4", - "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.15.4", - "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", - "dev": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.15.4", - "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.15.4", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.14.5", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.15.4", - "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.14.5", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.15.8", - "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.15.4", - "integrity": "sha512-lWcAqKeB624/twtTc3w6w/2o9RqJPaNBhPGK6DKLSiwuVWC7WFkypWyNg+CpZoyJH0jVzv1uMtXZ/5/lQOLtCg==", - "dev": true, - "dependencies": { - "core-js-pure": "^3.16.0", - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.15.4", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.15.4", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.15.6", - "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.9", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.11.0", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.3.7", - "integrity": "sha512-CKQVuwuSPh40tgOkR7c0ZisxYRiN05PcKPW72mQL5y++qd7CwBRoaJZvU5xfXnCJDFBmS3qZGQ71Frx6Ofo2XA==", - "dev": true, - "dependencies": { - "@types/node": ">=12.12.47" - }, - "engines": { - "node": "^8.13.0 || >=10.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.5.6", - "integrity": "sha512-DT14xgw3PSzPxwS13auTEwxhMMOoz33DPUKNtmYK/QYbBSpLXJy78FGGs5yVoxVobEqPm4iW9MOIoz0A3bLTRQ==", - "dev": true, - "dependencies": { - "lodash.camelcase": "^4.3.0", - "protobufjs": "^6.8.6" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", - "dev": true - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", - "dev": true - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "dev": true - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "dev": true - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", - "dev": true - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "dev": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", - "dev": true - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", - "dev": true - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", - "dev": true - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", - "dev": true - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "node_modules/@types/long": { - "version": "4.0.1", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==", - "dev": true - }, - "node_modules/@types/node": { - "version": "16.10.3", - "integrity": "sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "7.4.1", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", - "dev": true - }, - "node_modules/archiver": { - "version": "5.3.0", - "integrity": "sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==", - "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.0", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.0.0", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/archiver-utils": { - "version": "2.1.0", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "dependencies": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.7", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-includes": { - "version": "3.1.4", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.2.5", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/assertion-error-formatter": { - "version": "3.0.0", - "integrity": "sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==", - "dev": true, - "dependencies": { - "diff": "^4.0.1", - "pad-right": "^0.2.2", - "repeat-string": "^1.6.1" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.1", - "integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==" - }, - "node_modules/axios": { - "version": "0.21.4", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/becke-ch--regex--s0-0-v1--base--pl--lib": { - "version": "1.4.0", - "integrity": "sha1-Qpzuu/pffpNueNc/vcfacWKyDiA=", - "dev": true - }, - "node_modules/bindings": { - "version": "1.5.0", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/buffer": { - "version": "5.7.1", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/blakejs": { - "version": "1.1.1", - "integrity": "sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg==", - "dev": true - }, - "node_modules/bluebird": { - "version": "3.7.2", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.17.3", - "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", - "dev": true, - "dependencies": { - "caniuse-lite": "^1.0.30001264", - "electron-to-chromium": "^1.3.857", - "escalade": "^3.1.1", - "node-releases": "^1.1.77", - "picocolors": "^0.2.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "engines": { - "node": "*" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001265", - "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/chai": { - "version": "4.3.4", - "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/check-error": { - "version": "1.0.2", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/cli-table3": { - "version": "0.5.1", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", - "dev": true, - "dependencies": { - "object-assign": "^4.1.0", - "string-width": "^2.1.1" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "colors": "^1.1.2" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/colors": { - "version": "1.4.0", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/commander": { - "version": "3.0.2", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", - "dev": true - }, - "node_modules/compress-commons": { - "version": "4.1.1", - "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/core-js-pure": { - "version": "3.18.2", - "integrity": "sha512-4hMMLUlZhKJKOWbbGD1/VDUxGPEhEoN/T01k7bx271WiBKCvCfkgPzy0IeRS4PB50p6/N1q/SZL4B/TRsTE5bA==", - "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "node_modules/crc-32": { - "version": "1.2.0", - "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", - "dependencies": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - }, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crc32-stream": { - "version": "4.0.2", - "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csv-parser": { - "version": "3.0.0", - "integrity": "sha512-s6OYSXAK3IdKqYO33y09jhypG/bSDHPuyCme/IdEHfWpLf/jKcpitVFyOC6UemgGk8v7Q5u2XE0vvwmanxhGlQ==", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "csv-parser": "bin/csv-parser" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cucumber": { - "version": "6.0.5", - "integrity": "sha512-x+W9Fwk6TvcapQsYMxwFU5AsQJDOIJVGrPKmH15OC7jzb9/Dk7Hb0ZAyw4WcpaDcUDRc8bi2k2yJejDp5eTRlg==", - "deprecated": "The npm package has moved to @cucumber/cucumber", - "dev": true, - "dependencies": { - "assertion-error-formatter": "^3.0.0", - "bluebird": "^3.4.1", - "cli-table3": "^0.5.1", - "colors": "^1.1.2", - "commander": "^3.0.1", - "cucumber-expressions": "^8.1.0", - "cucumber-tag-expressions": "^2.0.2", - "duration": "^0.2.1", - "escape-string-regexp": "^2.0.0", - "figures": "^3.0.0", - "gherkin": "5.0.0", - "glob": "^7.1.3", - "indent-string": "^4.0.0", - "is-generator": "^1.0.2", - "is-stream": "^2.0.0", - "knuth-shuffle-seeded": "^1.0.6", - "lodash": "^4.17.14", - "mz": "^2.4.0", - "progress": "^2.0.0", - "resolve": "^1.3.3", - "serialize-error": "^4.1.0", - "stack-chain": "^2.0.0", - "stacktrace-js": "^2.0.0", - "string-argv": "^0.3.0", - "title-case": "^2.1.1", - "util-arity": "^1.0.2", - "verror": "^1.9.0" - }, - "bin": { - "cucumber-js": "bin/cucumber-js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cucumber-expressions": { - "version": "8.3.0", - "integrity": "sha512-cP2ya0EiorwXBC7Ll7Cj7NELYbasNv9Ty42L4u7sso9KruWemWG1ZiTq4PMqir3SNDSrbykoqI5wZgMbLEDjLQ==", - "dev": true, - "dependencies": { - "becke-ch--regex--s0-0-v1--base--pl--lib": "^1.4.0", - "xregexp": "^4.2.4" - } - }, - "node_modules/cucumber-html-reporter": { - "version": "5.5.0", - "integrity": "sha512-kF7vIwvTe7we7Wp/5uNZVZk+Ryozb688LpNvCNhou6N0RmLYPqaoV2aiN8GIB94JUBpribtlq6kDkEUHwxBVeQ==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "find": "^0.3.0", - "fs-extra": "^8.1.0", - "js-base64": "^2.3.2", - "jsonfile": "^5.0.0", - "lodash": "^4.17.11", - "node-emoji": "^1.10.0", - "open": "^6.4.0", - "uuid": "^3.3.3" - } - }, - "node_modules/cucumber-pretty": { - "version": "6.0.0", - "integrity": "sha512-ddx/VInPVKFB7N86QujgLivihJhuzexKwExMuFaUjSlEs5zVVqBgaf55f88h97VafXTWX+ZAcxTUwMBS4mYj/g==", - "dev": true, - "dependencies": { - "cli-table3": "^0.5.1", - "colors": "^1.4.0", - "figures": "^3.0.0" - }, - "peerDependencies": { - "cucumber": ">=6.0.0" - } - }, - "node_modules/cucumber-tag-expressions": { - "version": "2.0.3", - "integrity": "sha512-+x5j1IfZrBtbvYHuoUX0rl4nUGxaey6Do9sM0CABmZfDCcWXuuRm1fQeCaklIYQgOFHQ6xOHvDSdkMHHpni6tQ==", - "dev": true - }, - "node_modules/cucumber/node_modules/escape-string-regexp": { - "version": "2.0.0", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/d": { - "version": "1.0.1", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/dateformat": { - "version": "3.0.3", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "engines": { - "node": "*" - } - }, - "node_modules/deasync": { - "version": "0.1.23", - "integrity": "sha512-CGZSokFwidI50GOAmkz/7z3QdMzTQqAiUOzt95PuhKgi6VVztn9D03ZCzzi93uUWlp/v6A9osvNWpIvqHvKjTA==", - "hasInstallScript": true, - "dependencies": { - "bindings": "^1.5.0", - "node-addon-api": "^1.7.1" - }, - "engines": { - "node": ">=0.11.0" - } - }, - "node_modules/deasync/node_modules/node-addon-api": { - "version": "1.7.2", - "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==" - }, - "node_modules/debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-eql": { - "version": "3.0.1", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/define-properties": { - "version": "1.1.3", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/duration": { - "version": "0.2.2", - "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "~0.10.46" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.3.864", - "integrity": "sha512-v4rbad8GO6/yVI92WOeU9Wgxc4NA0n4f6P1FvZTY+jyY7JHEhw3bduYu60v3Q1h81Cg6eo4ApZrFPuycwd5hGw==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/error-stack-parser": { - "version": "2.0.6", - "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", - "dev": true, - "dependencies": { - "stackframe": "^1.1.1" - } - }, - "node_modules/es-abstract": { - "version": "1.19.1", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es5-ext": { - "version": "0.10.53", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dev": true, - "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "7.32.0", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "8.3.0", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-config-standard": { - "version": "16.0.3", - "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peerDependencies": { - "eslint": "^7.12.1", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^4.2.1 || ^5.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.6.2", - "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "pkg-dir": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.24.2", - "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.3", - "array.prototype.flat": "^1.2.4", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.6.2", - "find-up": "^2.0.0", - "has": "^1.0.3", - "is-core-module": "^2.6.0", - "minimatch": "^3.0.4", - "object.values": "^1.1.4", - "pkg-up": "^2.0.0", - "read-pkg-up": "^3.0.0", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.11.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-plugin-node": { - "version": "11.1.0", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, - "dependencies": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "peerDependencies": { - "eslint": ">=5.16.0" - } - }, - "node_modules/eslint-plugin-node/node_modules/eslint-plugin-es": { - "version": "3.0.1", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", - "dev": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" - } - }, - "node_modules/eslint-plugin-node/node_modules/ignore": { - "version": "5.1.8", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "3.4.1", - "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "peerDependencies": { - "eslint": ">=5.0.0", - "prettier": ">=1.13.0" - }, - "peerDependenciesMeta": { - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-promise": { - "version": "4.3.1", - "integrity": "sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-rule-composer": { - "version": "0.3.0", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/@babel/code-frame": { - "version": "7.12.11", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.11.0", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "7.3.1", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/exit-on-epipe": { - "version": "1.0.1", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/ext": { - "version": "1.6.0", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", - "dev": true, - "dependencies": { - "type": "^2.5.0" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.5.0", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==", - "dev": true - }, - "node_modules/extsprintf": { - "version": "1.4.0", - "integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/ffi-napi": { - "version": "4.0.3", - "integrity": "sha512-PMdLCIvDY9mS32RxZ0XGb95sonPRal8aqRhLbeEtWKZTe2A87qRFG9HjOhvG8EX2UmQw5XNRMIOT+1MYlWmdeg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "debug": "^4.1.1", - "get-uv-event-loop-napi-h": "^1.0.5", - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.1", - "ref-napi": "^2.0.1 || ^3.0.2", - "ref-struct-di": "^1.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, - "node_modules/find": { - "version": "0.3.0", - "integrity": "sha512-iSd+O4OEYV/I36Zl8MdYJO0xD82wH528SaCieTVHhclgiYNe9y+yPKSwK+A7/WsmHL1EZ+pYUJBXWTL5qofksw==", - "dev": true, - "dependencies": { - "traverse-chain": "~0.1.0" - } - }, - "node_modules/find-up": { - "version": "2.1.0", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.2", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.14.4", - "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "node_modules/fs-extra": { - "version": "8.1.0", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs-extra/node_modules/jsonfile": { - "version": "4.0.0", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/function-bind": { - "version": "1.1.1", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-func-name": { - "version": "2.0.0", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-from-current-process-h": { - "version": "1.0.2", - "integrity": "sha512-syloC6fsCt62ELLrr1VKBM1ggOpMdetX9hTrdW77UQdcApPHLmf7CI7OKcN1c9kYuNxKcDe4iJ4FY9sX3aw2xw==", - "dev": true - }, - "node_modules/get-uv-event-loop-napi-h": { - "version": "1.0.6", - "integrity": "sha512-t5c9VNR84nRoF+eLiz6wFrEp1SE2Acg0wS+Ysa2zF0eROes+LzOfuTaVHxGy8AbS8rq7FHEJzjnCZo1BupwdJg==", - "dev": true, - "dependencies": { - "get-symbol-from-current-process-h": "^1.0.1" - } - }, - "node_modules/gherkin": { - "version": "5.0.0", - "integrity": "sha1-lt70EZjsOQgli1Ea909lWidk0qE=", - "dev": true, - "bin": { - "gherkin-javascript": "bin/gherkin" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.8", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" - }, - "node_modules/grpc-promise": { - "version": "1.4.0", - "integrity": "sha512-4BBXHXb5OjjBh7luylu8vFqL6H6aPn/LeqpQaSBeRzO/Xv95wHW/WkU9TJRqaCTMZ5wq9jTSvlJWp0vRJy1pVA==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hex64": { - "version": "0.4.0", - "integrity": "sha1-rRB4rIHVfXLeYjKxADvE9vsCh8A=", - "bin": { - "hex64": "bin/hex64" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/husky": { - "version": "6.0.0", - "integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==", - "dev": true, - "bin": { - "husky": "lib/bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "4.0.6", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/immediate": { - "version": "3.0.6", - "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.7.0", - "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-generator": { - "version": "1.0.3", - "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=", - "dev": true - }, - "node_modules/is-glob": { - "version": "4.0.3", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.0.6", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.1", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "1.1.0", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "node_modules/isexe": { - "version": "2.0.0", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/js-base64": { - "version": "2.6.4", - "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.0", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "5.0.0", - "integrity": "sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==", - "dev": true, - "dependencies": { - "universalify": "^0.1.2" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jszip": { - "version": "3.7.1", - "integrity": "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "set-immediate-shim": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.7", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/knuth-shuffle-seeded": { - "version": "1.0.6", - "integrity": "sha1-AfG2VzOqdUDuCNiwF0Fk0iCB5OE=", - "dev": true, - "dependencies": { - "seed-random": "~2.2.0" - } - }, - "node_modules/lazystream": { - "version": "1.0.0", - "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.7", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "2.0.0", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", - "dev": true - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" - }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "node_modules/lodash.union": { - "version": "4.6.0", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" - }, - "node_modules/long": { - "version": "4.0.0", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", - "dev": true - }, - "node_modules/lower-case": { - "version": "1.1.4", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mz": { - "version": "2.7.0", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/next-tick": { - "version": "1.0.0", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", - "dev": true - }, - "node_modules/no-case": { - "version": "2.3.2", - "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", - "dev": true, - "dependencies": { - "lower-case": "^1.1.1" - } - }, - "node_modules/node-addon-api": { - "version": "3.2.1", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true - }, - "node_modules/node-emoji": { - "version": "1.11.0", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", - "dev": true, - "dependencies": { - "lodash": "^4.17.21" - } - }, - "node_modules/node-gyp-build": { - "version": "4.3.0", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", - "dev": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-releases": { - "version": "1.1.77", - "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.11.0", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.5", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/open": { - "version": "6.4.0", - "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", - "dev": true, - "dependencies": { - "is-wsl": "^1.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "1.3.0", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate": { - "version": "2.0.0", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-try": { - "version": "1.0.0", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pad-right": { - "version": "0.2.2", - "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=", - "dev": true, - "dependencies": { - "repeat-string": "^1.5.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "3.0.0", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pathval": { - "version": "1.1.1", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "0.2.1", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "node_modules/pify": { - "version": "3.0.0", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-dir": { - "version": "2.0.0", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "dependencies": { - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-up": { - "version": "2.0.0", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", - "dev": true, - "dependencies": { - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.4.1", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/printj": { - "version": "1.1.2", - "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==", - "bin": { - "printj": "bin/printj.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/progress": { - "version": "2.0.3", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/protobufjs": { - "version": "6.11.2", - "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": ">=13.7.0", - "long": "^4.0.0" - }, - "bin": { - "pbjs": "bin/pbjs", - "pbts": "bin/pbts" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "3.0.0", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", - "dev": true, - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdir-glob": { - "version": "1.1.1", - "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==", - "dependencies": { - "minimatch": "^3.0.4" - } - }, - "node_modules/ref-napi": { - "version": "3.0.3", - "integrity": "sha512-LiMq/XDGcgodTYOMppikEtJelWsKQERbLQsYm0IOOnzhwE9xYZC7x8txNnFC9wJNOkPferQI4vD4ZkC0mDyrOA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "debug": "^4.1.1", - "get-symbol-from-current-process-h": "^1.0.2", - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.1" - }, - "engines": { - "node": ">= 10.0" - } - }, - "node_modules/ref-struct-di": { - "version": "1.1.1", - "integrity": "sha512-2Xyn/0Qgz89VT+++WP0sTosdm9oeowLP23wRJYhG4BFdMUrLj3jhwHZNEytYNYgtPKLNTP3KJX4HEgBvM1/Y2g==", - "dev": true, - "dependencies": { - "debug": "^3.1.0" - } - }, - "node_modules/ref-struct-di/node_modules/debug": { - "version": "3.2.7", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "node_modules/regexpp": { - "version": "3.2.0", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.20.0", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/seed-random": { - "version": "2.2.0", - "integrity": "sha1-KpsZ4lCoFwmSMaW5mk2vgLf77VQ=", - "dev": true - }, - "node_modules/semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-error": { - "version": "4.1.0", - "integrity": "sha512-5j9GgyGsP9vV9Uj1S0lDCvlsd+gc2LEPVK7HHHte7IyPwOD4lVQFeaX143gx3U5AnoCi+wbcb3mvaxVysjpxEw==", - "dev": true, - "dependencies": { - "type-fest": "^0.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/set-immediate-shim": { - "version": "1.0.1", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sha3": { - "version": "2.1.4", - "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", - "dependencies": { - "buffer": "6.0.3" - } - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.10", - "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/stack-chain": { - "version": "2.0.0", - "integrity": "sha512-GGrHXePi305aW7XQweYZZwiRwR7Js3MWoK/EHzzB9ROdc75nCnjSJVi21rdAGxFl+yCx2L2qdfl5y7NO4lTyqg==", - "dev": true - }, - "node_modules/stack-generator": { - "version": "2.0.5", - "integrity": "sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q==", - "dev": true, - "dependencies": { - "stackframe": "^1.1.1" - } - }, - "node_modules/stackframe": { - "version": "1.2.0", - "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==", - "dev": true - }, - "node_modules/stacktrace-gps": { - "version": "3.0.4", - "integrity": "sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg==", - "dev": true, - "dependencies": { - "source-map": "0.5.6", - "stackframe": "^1.1.1" - } - }, - "node_modules/stacktrace-gps/node_modules/source-map": { - "version": "0.5.6", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stacktrace-js": { - "version": "2.0.2", - "integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==", - "dev": true, - "dependencies": { - "error-stack-parser": "^2.0.6", - "stack-generator": "^2.0.5", - "stacktrace-gps": "^3.0.4" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/string-argv": { - "version": "0.3.1", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", - "dev": true, - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "2.1.1", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "3.0.0", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "4.0.0", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/synchronized-promise": { - "version": "0.3.1", - "integrity": "sha512-Iy+JzrERSUrwpOHUDku8HHIddk8V6iLG9bPIzboP2i5RYkn2eSmRB8waSaX7Rc/+DUUsnFsoOHrmniwOp9BOgw==", - "dependencies": { - "deasync": "^0.1.15" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/table": { - "version": "6.7.2", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.3", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/table/node_modules/string-width": { - "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tari_crypto": { - "version": "0.9.1", - "integrity": "sha512-K7LAtwQQKCeTH5CyyO8d/TiPDEePRaJ4e6+hrxpWv6jlkkAiS4m6csBuVqpSjyAlKeP8cQJpUQX2n22akOuZVg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/thenify": { - "version": "3.3.1", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", - "dev": true, - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/title-case": { - "version": "2.1.1", - "integrity": "sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=", - "dev": true, - "dependencies": { - "no-case": "^2.2.0", - "upper-case": "^1.0.3" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/traverse-chain": { - "version": "0.1.0", - "integrity": "sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=", - "dev": true - }, - "node_modules/tsconfig-paths": { - "version": "3.11.0", - "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/type": { - "version": "1.2.0", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.3.1", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/upper-case": { - "version": "1.1.3", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", - "dev": true - }, - "node_modules/uri-js": { - "version": "4.4.1", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/utf8": { - "version": "3.0.0", - "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" - }, - "node_modules/util-arity": { - "version": "1.1.0", - "integrity": "sha1-WdAa8f2z/t4KxOYysKtfbOl8kzA=", - "dev": true - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/uuid": { - "version": "3.4.0", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/wallet-grpc-client": { - "resolved": "../clients/wallet_grpc_client", - "link": true - }, - "node_modules/which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/xregexp": { - "version": "4.4.1", - "integrity": "sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==", - "dev": true, - "dependencies": { - "@babel/runtime-corejs3": "^7.12.1" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/zip-stream": { - "version": "4.1.0", - "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", - "dependencies": { - "archiver-utils": "^2.1.0", - "compress-commons": "^4.1.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - } - }, "dependencies": { "@babel/code-frame": { "version": "7.15.8", + "resolved": false, "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", "dev": true, "requires": { @@ -4279,11 +15,13 @@ }, "@babel/compat-data": { "version": "7.15.0", + "resolved": false, "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", "dev": true }, "@babel/core": { "version": "7.15.8", + "resolved": false, "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", "dev": true, "requires": { @@ -4306,6 +44,7 @@ }, "@babel/eslint-parser": { "version": "7.15.8", + "resolved": false, "integrity": "sha512-fYP7QFngCvgxjUuw8O057SVH5jCXsbFFOoE77CFDcvzwBVgTOkMD/L4mIC5Ud1xf8chK/no2fRbSSn1wvNmKuQ==", "dev": true, "requires": { @@ -4316,6 +55,7 @@ }, "@babel/eslint-plugin": { "version": "7.14.5", + "resolved": false, "integrity": "sha512-nzt/YMnOOIRikvSn2hk9+W2omgJBy6U8TN0R+WTTmqapA+HnZTuviZaketdTE9W7/k/+E/DfZlt1ey1NSE39pg==", "dev": true, "requires": { @@ -4324,6 +64,7 @@ }, "@babel/generator": { "version": "7.15.8", + "resolved": false, "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", "dev": true, "requires": { @@ -4334,6 +75,7 @@ }, "@babel/helper-compilation-targets": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", "dev": true, "requires": { @@ -4345,6 +87,7 @@ }, "@babel/helper-function-name": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", "dev": true, "requires": { @@ -4355,6 +98,7 @@ }, "@babel/helper-get-function-arity": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", "dev": true, "requires": { @@ -4363,6 +107,7 @@ }, "@babel/helper-hoist-variables": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", "dev": true, "requires": { @@ -4371,6 +116,7 @@ }, "@babel/helper-member-expression-to-functions": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", "dev": true, "requires": { @@ -4379,6 +125,7 @@ }, "@babel/helper-module-imports": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", "dev": true, "requires": { @@ -4387,6 +134,7 @@ }, "@babel/helper-module-transforms": { "version": "7.15.8", + "resolved": false, "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", "dev": true, "requires": { @@ -4402,6 +150,7 @@ }, "@babel/helper-optimise-call-expression": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", "dev": true, "requires": { @@ -4410,6 +159,7 @@ }, "@babel/helper-replace-supers": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", "dev": true, "requires": { @@ -4421,6 +171,7 @@ }, "@babel/helper-simple-access": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", "dev": true, "requires": { @@ -4429,6 +180,7 @@ }, "@babel/helper-split-export-declaration": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", "dev": true, "requires": { @@ -4437,16 +189,19 @@ }, "@babel/helper-validator-identifier": { "version": "7.15.7", + "resolved": false, "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "dev": true }, "@babel/helper-validator-option": { "version": "7.14.5", + "resolved": false, "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", "dev": true }, "@babel/helpers": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", "dev": true, "requires": { @@ -4457,6 +212,7 @@ }, "@babel/highlight": { "version": "7.14.5", + "resolved": false, "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "requires": { @@ -4467,20 +223,13 @@ }, "@babel/parser": { "version": "7.15.8", + "resolved": false, "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", "dev": true }, - "@babel/runtime-corejs3": { - "version": "7.15.4", - "integrity": "sha512-lWcAqKeB624/twtTc3w6w/2o9RqJPaNBhPGK6DKLSiwuVWC7WFkypWyNg+CpZoyJH0jVzv1uMtXZ/5/lQOLtCg==", - "dev": true, - "requires": { - "core-js-pure": "^3.16.0", - "regenerator-runtime": "^0.13.4" - } - }, "@babel/template": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", "dev": true, "requires": { @@ -4491,6 +240,7 @@ }, "@babel/traverse": { "version": "7.15.4", + "resolved": false, "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", "dev": true, "requires": { @@ -4507,6 +257,7 @@ }, "@babel/types": { "version": "7.15.6", + "resolved": false, "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", "dev": true, "requires": { @@ -4514,8 +265,137 @@ "to-fast-properties": "^2.0.0" } }, + "@cucumber/create-meta": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@cucumber/create-meta/-/create-meta-5.0.0.tgz", + "integrity": "sha512-Z5kMZkUff00S3/KSnKzB/KOm2UIxMXY1xXmj2dQMlD49lV6v/W8EEvgDMNtQotQNSOQU5bDupmWQpk+o16tXIw==", + "dev": true, + "requires": { + "@cucumber/messages": "^16.0.0" + } + }, + "@cucumber/cucumber": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@cucumber/cucumber/-/cucumber-7.3.1.tgz", + "integrity": "sha512-x1+/AvouZy205ZvfYbeEVat5aBAj4EeLt9TZfD7pO9j+tQ3W6uxSuDB1TKfxAXFU3WYrswor0CXoJBYOIZhzMw==", + "dev": true, + "requires": { + "@cucumber/create-meta": "^5.0.0", + "@cucumber/cucumber-expressions": "^12.1.1", + "@cucumber/gherkin": "^19.0.3", + "@cucumber/gherkin-streams": "^2.0.2", + "@cucumber/html-formatter": "^15.0.2", + "@cucumber/messages": "^16.0.1", + "@cucumber/tag-expressions": "^3.0.1", + "assertion-error-formatter": "^3.0.0", + "bluebird": "^3.7.2", + "capital-case": "^1.0.4", + "cli-table3": "^0.6.0", + "colors": "^1.4.0", + "commander": "^7.0.0", + "create-require": "^1.1.1", + "duration": "^0.2.2", + "durations": "^3.4.2", + "figures": "^3.2.0", + "glob": "^7.1.6", + "indent-string": "^4.0.0", + "is-generator": "^1.0.3", + "is-stream": "^2.0.0", + "knuth-shuffle-seeded": "^1.0.6", + "lodash": "^4.17.21", + "mz": "^2.7.0", + "progress": "^2.0.3", + "resolve": "^1.19.0", + "resolve-pkg": "^2.0.0", + "stack-chain": "^2.0.0", + "stacktrace-js": "^2.0.2", + "string-argv": "^0.3.1", + "tmp": "^0.2.1", + "util-arity": "^1.1.0", + "verror": "^1.10.0" + } + }, + "@cucumber/cucumber-expressions": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/@cucumber/cucumber-expressions/-/cucumber-expressions-12.1.3.tgz", + "integrity": "sha512-LB8MAzE4F/t2KIgsDEz4gZH0xSI4aG0/LmYUPyISPPjUS1pI/yGWWyeX2WsiUQxpSs765WcNIq5Bggt7gGGO3Q==", + "dev": true, + "requires": { + "regexp-match-indices": "1.0.2" + } + }, + "@cucumber/gherkin": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-19.0.3.tgz", + "integrity": "sha512-gWdMm8mfRk3P+VugJWvNALaQV5QnT+5RkqWy3tO+4NsMSQZPo5p4V4vXwriQZ/sZR1Wni5TDRztuRsKLgZ3XHA==", + "dev": true, + "requires": { + "@cucumber/message-streams": "^2.0.0", + "@cucumber/messages": "^16.0.1" + } + }, + "@cucumber/gherkin-streams": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cucumber/gherkin-streams/-/gherkin-streams-2.0.2.tgz", + "integrity": "sha512-cKmXOBz4OwGlrHMBCc4qCC3KzLaqcEZ11nWWskIbv6jyfvlIRuM2OgEF6VLcNVewczifW1p6DrDj0OO+BeXocA==", + "dev": true, + "requires": { + "@cucumber/gherkin": "^19.0.1", + "@cucumber/message-streams": "^2.0.0", + "@cucumber/messages": "^16.0.0", + "commander": "7.2.0", + "source-map-support": "0.5.19" + } + }, + "@cucumber/html-formatter": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/@cucumber/html-formatter/-/html-formatter-15.0.2.tgz", + "integrity": "sha512-j+YGY4ytj78G/v1gZo53D+vuKXlTg/oxNwSCCGvRQo75+AqYDJSkm/vexXJQ5lY1rXAvlbZ9KI6jhg6LDs0YdQ==", + "dev": true, + "requires": { + "@cucumber/messages": "^16.0.1", + "commander": "7.2.0", + "source-map-support": "0.5.19" + } + }, + "@cucumber/message-streams": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@cucumber/message-streams/-/message-streams-2.1.0.tgz", + "integrity": "sha512-Yh3mw3qv6QL9NI/ihkZF8V9MX2GbnR6oktv34kC3uAbrQy9d/b2SZ3HNjG3J9JQqpV4B7Om3SPElJYIeo66TrA==", + "dev": true, + "requires": { + "@cucumber/messages": "^16.0.1" + } + }, + "@cucumber/messages": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-16.0.1.tgz", + "integrity": "sha512-80JcaAfQragFqR1rMhRwiqWL9HcR6Z4LDD2mfF0Lxg/lFkCNvmWa9Jl10NUNfFXYD555NKPzP/8xFo55abw8TQ==", + "dev": true, + "requires": { + "@types/uuid": "8.3.0", + "class-transformer": "0.4.0", + "reflect-metadata": "0.1.13", + "uuid": "8.3.2" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + } + } + }, + "@cucumber/tag-expressions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/tag-expressions/-/tag-expressions-3.0.1.tgz", + "integrity": "sha512-OGCXaJ1BQXmQ5b9pw+JYsBGumK2/LPZiLmbj1o1JFVeSNs2PY8WPQFSyXrskhrHz5Nd/6lYg7lvGMtFHOncC4w==", + "dev": true + }, "@eslint/eslintrc": { "version": "0.4.3", + "resolved": false, "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", "dev": true, "requires": { @@ -4532,6 +412,7 @@ "dependencies": { "globals": { "version": "13.11.0", + "resolved": false, "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", "dev": true, "requires": { @@ -4540,21 +421,40 @@ }, "type-fest": { "version": "0.20.2", + "resolved": false, "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true } } }, "@grpc/grpc-js": { - "version": "1.3.7", - "integrity": "sha512-CKQVuwuSPh40tgOkR7c0ZisxYRiN05PcKPW72mQL5y++qd7CwBRoaJZvU5xfXnCJDFBmS3qZGQ71Frx6Ofo2XA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.4.1.tgz", + "integrity": "sha512-/chkA48TdAvATHA7RXJPeHQLdfFhpu51974s8htjO/XTDHA41j5+SkR5Io+lr9XsLmkZD6HxLyRAFGmA9wjO2w==", "dev": true, "requires": { + "@grpc/proto-loader": "^0.6.4", "@types/node": ">=12.12.47" + }, + "dependencies": { + "@grpc/proto-loader": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.6.tgz", + "integrity": "sha512-cdMaPZ8AiFz6ua6PUbP+LKbhwJbFXnrQ/mlnKGUyzDUZ3wp7vPLksnmLCBX6SHgSmjX7CbNVNLFYD5GmmjO4GQ==", + "dev": true, + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.10.0", + "yargs": "^16.1.1" + } + } } }, "@grpc/proto-loader": { "version": "0.5.6", + "resolved": false, "integrity": "sha512-DT14xgw3PSzPxwS13auTEwxhMMOoz33DPUKNtmYK/QYbBSpLXJy78FGGs5yVoxVobEqPm4iW9MOIoz0A3bLTRQ==", "dev": true, "requires": { @@ -4564,6 +464,7 @@ }, "@humanwhocodes/config-array": { "version": "0.5.0", + "resolved": false, "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", "dev": true, "requires": { @@ -4574,31 +475,37 @@ }, "@humanwhocodes/object-schema": { "version": "1.2.0", + "resolved": false, "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", "dev": true }, "@protobufjs/aspromise": { "version": "1.1.2", + "resolved": false, "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", "dev": true }, "@protobufjs/base64": { "version": "1.1.2", + "resolved": false, "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", "dev": true }, "@protobufjs/codegen": { "version": "2.0.4", + "resolved": false, "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", "dev": true }, "@protobufjs/eventemitter": { "version": "1.1.0", + "resolved": false, "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", "dev": true }, "@protobufjs/fetch": { "version": "1.1.0", + "resolved": false, "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", "dev": true, "requires": { @@ -4608,57 +515,73 @@ }, "@protobufjs/float": { "version": "1.0.2", + "resolved": false, "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", "dev": true }, "@protobufjs/inquire": { "version": "1.1.0", + "resolved": false, "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", "dev": true }, "@protobufjs/path": { "version": "1.1.2", + "resolved": false, "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", "dev": true }, "@protobufjs/pool": { "version": "1.1.0", + "resolved": false, "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", "dev": true }, "@protobufjs/utf8": { "version": "1.1.0", + "resolved": false, "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", "dev": true }, "@types/json5": { "version": "0.0.29", + "resolved": false, "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, "@types/long": { "version": "4.0.1", + "resolved": false, "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==", "dev": true }, "@types/node": { "version": "16.10.3", + "resolved": false, "integrity": "sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==", "dev": true }, + "@types/uuid": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", + "dev": true + }, "acorn": { "version": "7.4.1", + "resolved": false, "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, "acorn-jsx": { "version": "5.3.2", + "resolved": false, "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "ajv": { "version": "6.12.6", + "resolved": false, "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { @@ -4670,29 +593,49 @@ }, "ansi-colors": { "version": "4.1.1", + "resolved": false, "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, "ansi-regex": { "version": "5.0.1", + "resolved": false, "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { "version": "3.2.1", + "resolved": false, "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" } }, + "ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", + "dev": true + }, "any-promise": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", "dev": true }, "archiver": { "version": "5.3.0", + "resolved": false, "integrity": "sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==", "requires": { "archiver-utils": "^2.1.0", @@ -4706,6 +649,7 @@ }, "archiver-utils": { "version": "2.1.0", + "resolved": false, "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", "requires": { "glob": "^7.1.4", @@ -4722,6 +666,7 @@ "dependencies": { "readable-stream": { "version": "2.3.7", + "resolved": false, "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", @@ -4735,6 +680,7 @@ }, "string_decoder": { "version": "1.1.1", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -4744,6 +690,7 @@ }, "argparse": { "version": "1.0.10", + "resolved": false, "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { @@ -4752,6 +699,7 @@ }, "array-includes": { "version": "3.1.4", + "resolved": false, "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "requires": { @@ -4764,6 +712,7 @@ }, "array.prototype.flat": { "version": "1.2.5", + "resolved": false, "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", "dev": true, "requires": { @@ -4774,16 +723,19 @@ }, "assert-plus": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, "assertion-error": { "version": "1.1.0", + "resolved": false, "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, "assertion-error-formatter": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/assertion-error-formatter/-/assertion-error-formatter-3.0.0.tgz", "integrity": "sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==", "dev": true, "requires": { @@ -4794,15 +746,18 @@ }, "astral-regex": { "version": "2.0.0", + "resolved": false, "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, "async": { "version": "3.2.1", + "resolved": false, "integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==" }, "axios": { "version": "0.21.4", + "resolved": false, "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "requires": { "follow-redirects": "^1.14.0" @@ -4810,19 +765,17 @@ }, "balanced-match": { "version": "1.0.2", + "resolved": false, "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base64-js": { "version": "1.5.1", + "resolved": false, "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, - "becke-ch--regex--s0-0-v1--base--pl--lib": { - "version": "1.4.0", - "integrity": "sha1-Qpzuu/pffpNueNc/vcfacWKyDiA=", - "dev": true - }, "bindings": { "version": "1.5.0", + "resolved": false, "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "requires": { "file-uri-to-path": "1.0.0" @@ -4830,6 +783,7 @@ }, "bl": { "version": "4.1.0", + "resolved": false, "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "requires": { "buffer": "^5.5.0", @@ -4839,6 +793,7 @@ "dependencies": { "buffer": { "version": "5.7.1", + "resolved": false, "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "requires": { "base64-js": "^1.3.1", @@ -4849,16 +804,19 @@ }, "blakejs": { "version": "1.1.1", + "resolved": false, "integrity": "sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg==", "dev": true }, "bluebird": { "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, "brace-expansion": { "version": "1.1.11", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", @@ -4867,6 +825,7 @@ }, "browserslist": { "version": "4.17.3", + "resolved": false, "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", "dev": true, "requires": { @@ -4879,6 +838,7 @@ }, "buffer": { "version": "6.0.3", + "resolved": false, "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "requires": { "base64-js": "^1.3.1", @@ -4887,10 +847,18 @@ }, "buffer-crc32": { "version": "0.2.13", + "resolved": false, "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "call-bind": { "version": "1.0.2", + "resolved": false, "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dev": true, "requires": { @@ -4900,16 +868,40 @@ }, "callsites": { "version": "3.1.0", + "resolved": false, "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, "caniuse-lite": { "version": "1.0.30001265", + "resolved": false, "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==", "dev": true }, + "capital-case": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", + "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", + "dev": true, + "requires": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + } + }, "chai": { "version": "4.3.4", + "resolved": false, "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", "dev": true, "requires": { @@ -4923,6 +915,7 @@ }, "chalk": { "version": "2.4.2", + "resolved": false, "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { @@ -4933,21 +926,41 @@ }, "check-error": { "version": "1.0.2", + "resolved": false, "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "dev": true }, + "class-transformer": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", + "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", + "dev": true + }, "cli-table3": { - "version": "0.5.1", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", + "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", "dev": true, "requires": { "colors": "^1.1.2", "object-assign": "^4.1.0", - "string-width": "^2.1.1" + "string-width": "^4.2.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, "clone-deep": { "version": "4.0.1", + "resolved": false, "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "requires": { "is-plain-object": "^2.0.4", @@ -4957,6 +970,7 @@ }, "color-convert": { "version": "1.9.3", + "resolved": false, "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { @@ -4965,21 +979,25 @@ }, "color-name": { "version": "1.1.3", + "resolved": false, "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, "colors": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, "commander": { - "version": "3.0.2", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true }, "compress-commons": { "version": "4.1.1", + "resolved": false, "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", "requires": { "buffer-crc32": "^0.2.13", @@ -4990,27 +1008,26 @@ }, "concat-map": { "version": "0.0.1", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "convert-source-map": { "version": "1.8.0", + "resolved": false, "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "dev": true, "requires": { "safe-buffer": "~5.1.1" } }, - "core-js-pure": { - "version": "3.18.2", - "integrity": "sha512-4hMMLUlZhKJKOWbbGD1/VDUxGPEhEoN/T01k7bx271WiBKCvCfkgPzy0IeRS4PB50p6/N1q/SZL4B/TRsTE5bA==", - "dev": true - }, "core-util-is": { "version": "1.0.2", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "crc-32": { "version": "1.2.0", + "resolved": false, "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", "requires": { "exit-on-epipe": "~1.0.1", @@ -5019,14 +1036,22 @@ }, "crc32-stream": { "version": "4.0.2", + "resolved": false, "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", "requires": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" } }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "cross-spawn": { "version": "7.0.3", + "resolved": false, "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { @@ -5037,63 +1062,26 @@ }, "csv-parser": { "version": "3.0.0", + "resolved": false, "integrity": "sha512-s6OYSXAK3IdKqYO33y09jhypG/bSDHPuyCme/IdEHfWpLf/jKcpitVFyOC6UemgGk8v7Q5u2XE0vvwmanxhGlQ==", "requires": { "minimist": "^1.2.0" } }, "cucumber": { - "version": "6.0.5", - "integrity": "sha512-x+W9Fwk6TvcapQsYMxwFU5AsQJDOIJVGrPKmH15OC7jzb9/Dk7Hb0ZAyw4WcpaDcUDRc8bi2k2yJejDp5eTRlg==", - "dev": true, - "requires": { - "assertion-error-formatter": "^3.0.0", - "bluebird": "^3.4.1", - "cli-table3": "^0.5.1", - "colors": "^1.1.2", - "commander": "^3.0.1", - "cucumber-expressions": "^8.1.0", - "cucumber-tag-expressions": "^2.0.2", - "duration": "^0.2.1", - "escape-string-regexp": "^2.0.0", - "figures": "^3.0.0", - "gherkin": "5.0.0", - "glob": "^7.1.3", - "indent-string": "^4.0.0", - "is-generator": "^1.0.2", - "is-stream": "^2.0.0", - "knuth-shuffle-seeded": "^1.0.6", - "lodash": "^4.17.14", - "mz": "^2.4.0", - "progress": "^2.0.0", - "resolve": "^1.3.3", - "serialize-error": "^4.1.0", - "stack-chain": "^2.0.0", - "stacktrace-js": "^2.0.0", - "string-argv": "^0.3.0", - "title-case": "^2.1.1", - "util-arity": "^1.0.2", - "verror": "^1.9.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "cucumber-expressions": { - "version": "8.3.0", - "integrity": "sha512-cP2ya0EiorwXBC7Ll7Cj7NELYbasNv9Ty42L4u7sso9KruWemWG1ZiTq4PMqir3SNDSrbykoqI5wZgMbLEDjLQ==", + "version": "7.0.0-rc.0", + "resolved": "https://registry.npmjs.org/cucumber/-/cucumber-7.0.0-rc.0.tgz", + "integrity": "sha512-I8qgAStiDj7l7k14QtBFZrt6B22epU55TdL8L4R52+NF+nx4bvixPCia8pxzQkuEKmLU6r6dAwMPru+laSOiLg==", "dev": true, "requires": { - "becke-ch--regex--s0-0-v1--base--pl--lib": "^1.4.0", - "xregexp": "^4.2.4" + "@cucumber/cucumber": "^7.0.0-rc.0", + "marked": "^1.1.1", + "marked-terminal": "^4.1.0" } }, "cucumber-html-reporter": { "version": "5.5.0", + "resolved": false, "integrity": "sha512-kF7vIwvTe7we7Wp/5uNZVZk+Ryozb688LpNvCNhou6N0RmLYPqaoV2aiN8GIB94JUBpribtlq6kDkEUHwxBVeQ==", "dev": true, "requires": { @@ -5109,22 +1097,63 @@ } }, "cucumber-pretty": { - "version": "6.0.0", - "integrity": "sha512-ddx/VInPVKFB7N86QujgLivihJhuzexKwExMuFaUjSlEs5zVVqBgaf55f88h97VafXTWX+ZAcxTUwMBS4mYj/g==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/cucumber-pretty/-/cucumber-pretty-1.5.2.tgz", + "integrity": "sha512-mZLqD+L2Q5DrfbUvAVBsYRFjU+W8dWXWCb6MniJq9XCeozvIsSR3oC1hGX5YLe3seXpJf/blVSVwAREL5HWW0w==", "dev": true, "requires": { "cli-table3": "^0.5.1", - "colors": "^1.4.0", + "colors": "^1.3.3", "figures": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, - "cucumber-tag-expressions": { - "version": "2.0.3", - "integrity": "sha512-+x5j1IfZrBtbvYHuoUX0rl4nUGxaey6Do9sM0CABmZfDCcWXuuRm1fQeCaklIYQgOFHQ6xOHvDSdkMHHpni6tQ==", - "dev": true - }, "d": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", "dev": true, "requires": { @@ -5134,10 +1163,12 @@ }, "dateformat": { "version": "3.0.3", + "resolved": false, "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" }, "deasync": { "version": "0.1.23", + "resolved": false, "integrity": "sha512-CGZSokFwidI50GOAmkz/7z3QdMzTQqAiUOzt95PuhKgi6VVztn9D03ZCzzi93uUWlp/v6A9osvNWpIvqHvKjTA==", "requires": { "bindings": "^1.5.0", @@ -5146,12 +1177,14 @@ "dependencies": { "node-addon-api": { "version": "1.7.2", + "resolved": false, "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==" } } }, "debug": { "version": "4.3.2", + "resolved": false, "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { @@ -5160,6 +1193,7 @@ }, "deep-eql": { "version": "3.0.1", + "resolved": false, "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { @@ -5168,11 +1202,13 @@ }, "deep-is": { "version": "0.1.4", + "resolved": false, "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, "define-properties": { "version": "1.1.3", + "resolved": false, "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { @@ -5181,11 +1217,13 @@ }, "diff": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, "doctrine": { "version": "3.0.0", + "resolved": false, "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { @@ -5194,6 +1232,7 @@ }, "duration": { "version": "0.2.2", + "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", "dev": true, "requires": { @@ -5201,18 +1240,27 @@ "es5-ext": "~0.10.46" } }, + "durations": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/durations/-/durations-3.4.2.tgz", + "integrity": "sha512-V/lf7y33dGaypZZetVI1eu7BmvkbC4dItq12OElLRpKuaU5JxQstV2zHwLv8P7cNbQ+KL1WD80zMCTx5dNC4dg==", + "dev": true + }, "electron-to-chromium": { "version": "1.3.864", + "resolved": false, "integrity": "sha512-v4rbad8GO6/yVI92WOeU9Wgxc4NA0n4f6P1FvZTY+jyY7JHEhw3bduYu60v3Q1h81Cg6eo4ApZrFPuycwd5hGw==", "dev": true }, "emoji-regex": { "version": "8.0.0", + "resolved": false, "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "end-of-stream": { "version": "1.4.4", + "resolved": false, "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "requires": { "once": "^1.4.0" @@ -5220,22 +1268,16 @@ }, "enquirer": { "version": "2.3.6", + "resolved": false, "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "dev": true, "requires": { "ansi-colors": "^4.1.1" } }, - "error-ex": { - "version": "1.3.2", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, "error-stack-parser": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", "dev": true, "requires": { @@ -5244,6 +1286,7 @@ }, "es-abstract": { "version": "1.19.1", + "resolved": false, "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", "dev": true, "requires": { @@ -5271,6 +1314,7 @@ }, "es-to-primitive": { "version": "1.2.1", + "resolved": false, "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "requires": { @@ -5281,6 +1325,7 @@ }, "es5-ext": { "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", "dev": true, "requires": { @@ -5291,6 +1336,7 @@ }, "es6-iterator": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", "dev": true, "requires": { @@ -5301,6 +1347,7 @@ }, "es6-symbol": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", "dev": true, "requires": { @@ -5310,16 +1357,19 @@ }, "escalade": { "version": "3.1.1", + "resolved": false, "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true }, "escape-string-regexp": { "version": "1.0.5", + "resolved": false, "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, "eslint": { "version": "7.32.0", + "resolved": false, "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", "dev": true, "requires": { @@ -5367,6 +1417,7 @@ "dependencies": { "@babel/code-frame": { "version": "7.12.11", + "resolved": false, "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { @@ -5375,6 +1426,7 @@ }, "ansi-styles": { "version": "4.3.0", + "resolved": false, "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { @@ -5383,6 +1435,7 @@ }, "chalk": { "version": "4.1.2", + "resolved": false, "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { @@ -5392,6 +1445,7 @@ }, "color-convert": { "version": "2.0.1", + "resolved": false, "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { @@ -5400,16 +1454,19 @@ }, "color-name": { "version": "1.1.4", + "resolved": false, "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "escape-string-regexp": { "version": "4.0.0", + "resolved": false, "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, "globals": { "version": "13.11.0", + "resolved": false, "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", "dev": true, "requires": { @@ -5418,11 +1475,13 @@ }, "has-flag": { "version": "4.0.0", + "resolved": false, "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "semver": { "version": "7.3.5", + "resolved": false, "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { @@ -5431,6 +1490,7 @@ }, "supports-color": { "version": "7.2.0", + "resolved": false, "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { @@ -5439,6 +1499,7 @@ }, "type-fest": { "version": "0.20.2", + "resolved": false, "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true } @@ -5446,18 +1507,19 @@ }, "eslint-config-prettier": { "version": "8.3.0", + "resolved": false, "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true, - "requires": {} + "dev": true }, "eslint-config-standard": { "version": "16.0.3", + "resolved": false, "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-node": { "version": "0.3.6", + "resolved": false, "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dev": true, "requires": { @@ -5467,6 +1529,7 @@ "dependencies": { "debug": { "version": "3.2.7", + "resolved": false, "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { @@ -5476,16 +1539,19 @@ } }, "eslint-module-utils": { - "version": "2.6.2", - "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", + "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", "dev": true, "requires": { "debug": "^3.2.7", + "find-up": "^2.1.0", "pkg-dir": "^2.0.0" }, "dependencies": { "debug": { "version": "3.2.7", + "resolved": false, "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { @@ -5495,29 +1561,29 @@ } }, "eslint-plugin-import": { - "version": "2.24.2", - "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", + "version": "2.25.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.2.tgz", + "integrity": "sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==", "dev": true, "requires": { - "array-includes": "^3.1.3", - "array.prototype.flat": "^1.2.4", + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.6.2", - "find-up": "^2.0.0", + "eslint-module-utils": "^2.7.0", "has": "^1.0.3", - "is-core-module": "^2.6.0", + "is-core-module": "^2.7.0", + "is-glob": "^4.0.3", "minimatch": "^3.0.4", - "object.values": "^1.1.4", - "pkg-up": "^2.0.0", - "read-pkg-up": "^3.0.0", + "object.values": "^1.1.5", "resolve": "^1.20.0", "tsconfig-paths": "^3.11.0" }, "dependencies": { "debug": { "version": "2.6.9", + "resolved": false, "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { @@ -5526,6 +1592,7 @@ }, "doctrine": { "version": "2.1.0", + "resolved": false, "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { @@ -5534,6 +1601,7 @@ }, "ms": { "version": "2.0.0", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } @@ -5541,6 +1609,7 @@ }, "eslint-plugin-node": { "version": "11.1.0", + "resolved": false, "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", "dev": true, "requires": { @@ -5554,6 +1623,7 @@ "dependencies": { "eslint-plugin-es": { "version": "3.0.1", + "resolved": false, "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", "dev": true, "requires": { @@ -5563,6 +1633,7 @@ }, "ignore": { "version": "5.1.8", + "resolved": false, "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "dev": true } @@ -5570,6 +1641,7 @@ }, "eslint-plugin-prettier": { "version": "3.4.1", + "resolved": false, "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", "dev": true, "requires": { @@ -5578,16 +1650,19 @@ }, "eslint-plugin-promise": { "version": "4.3.1", + "resolved": false, "integrity": "sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==", "dev": true }, "eslint-rule-composer": { "version": "0.3.0", + "resolved": false, "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", "dev": true }, "eslint-scope": { "version": "5.1.1", + "resolved": false, "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { @@ -5597,6 +1672,7 @@ }, "eslint-utils": { "version": "2.1.0", + "resolved": false, "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, "requires": { @@ -5605,6 +1681,7 @@ "dependencies": { "eslint-visitor-keys": { "version": "1.3.0", + "resolved": false, "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true } @@ -5612,11 +1689,13 @@ }, "eslint-visitor-keys": { "version": "2.1.0", + "resolved": false, "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true }, "espree": { "version": "7.3.1", + "resolved": false, "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, "requires": { @@ -5627,6 +1706,7 @@ "dependencies": { "eslint-visitor-keys": { "version": "1.3.0", + "resolved": false, "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true } @@ -5634,11 +1714,13 @@ }, "esprima": { "version": "4.0.1", + "resolved": false, "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "esquery": { "version": "1.4.0", + "resolved": false, "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { @@ -5647,6 +1729,7 @@ "dependencies": { "estraverse": { "version": "5.2.0", + "resolved": false, "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "dev": true } @@ -5654,6 +1737,7 @@ }, "esrecurse": { "version": "4.3.0", + "resolved": false, "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "requires": { @@ -5662,6 +1746,7 @@ "dependencies": { "estraverse": { "version": "5.2.0", + "resolved": false, "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "dev": true } @@ -5669,20 +1754,24 @@ }, "estraverse": { "version": "4.3.0", + "resolved": false, "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { "version": "2.0.3", + "resolved": false, "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "exit-on-epipe": { "version": "1.0.1", + "resolved": false, "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" }, "ext": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", "dev": true, "requires": { @@ -5691,6 +1780,7 @@ "dependencies": { "type": { "version": "2.5.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==", "dev": true } @@ -5698,31 +1788,37 @@ }, "extsprintf": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz", "integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=", "dev": true }, "fast-deep-equal": { "version": "3.1.3", + "resolved": false, "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, "fast-diff": { "version": "1.2.0", + "resolved": false, "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, "fast-json-stable-stringify": { "version": "2.1.0", + "resolved": false, "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, "fast-levenshtein": { "version": "2.0.6", + "resolved": false, "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, "ffi-napi": { "version": "4.0.3", + "resolved": false, "integrity": "sha512-PMdLCIvDY9mS32RxZ0XGb95sonPRal8aqRhLbeEtWKZTe2A87qRFG9HjOhvG8EX2UmQw5XNRMIOT+1MYlWmdeg==", "dev": true, "requires": { @@ -5736,6 +1832,7 @@ }, "figures": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, "requires": { @@ -5744,6 +1841,7 @@ }, "file-entry-cache": { "version": "6.0.1", + "resolved": false, "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { @@ -5752,10 +1850,12 @@ }, "file-uri-to-path": { "version": "1.0.0", + "resolved": false, "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" }, "find": { "version": "0.3.0", + "resolved": false, "integrity": "sha512-iSd+O4OEYV/I36Zl8MdYJO0xD82wH528SaCieTVHhclgiYNe9y+yPKSwK+A7/WsmHL1EZ+pYUJBXWTL5qofksw==", "dev": true, "requires": { @@ -5764,6 +1864,7 @@ }, "find-up": { "version": "2.1.0", + "resolved": false, "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { @@ -5772,6 +1873,7 @@ }, "flat-cache": { "version": "3.0.4", + "resolved": false, "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { @@ -5781,19 +1883,23 @@ }, "flatted": { "version": "3.2.2", + "resolved": false, "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, "follow-redirects": { "version": "1.14.4", + "resolved": false, "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==" }, "fs-constants": { "version": "1.0.0", + "resolved": false, "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "fs-extra": { "version": "8.1.0", + "resolved": false, "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { @@ -5804,6 +1910,7 @@ "dependencies": { "jsonfile": { "version": "4.0.0", + "resolved": false, "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { @@ -5814,30 +1921,42 @@ }, "fs.realpath": { "version": "1.0.0", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "function-bind": { "version": "1.1.1", + "resolved": false, "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "functional-red-black-tree": { "version": "1.0.1", + "resolved": false, "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, "gensync": { "version": "1.0.0-beta.2", + "resolved": false, "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "get-func-name": { "version": "2.0.0", + "resolved": false, "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, "get-intrinsic": { "version": "1.1.1", + "resolved": false, "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "dev": true, "requires": { @@ -5848,6 +1967,7 @@ }, "get-symbol-description": { "version": "1.0.0", + "resolved": false, "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dev": true, "requires": { @@ -5857,24 +1977,22 @@ }, "get-symbol-from-current-process-h": { "version": "1.0.2", + "resolved": false, "integrity": "sha512-syloC6fsCt62ELLrr1VKBM1ggOpMdetX9hTrdW77UQdcApPHLmf7CI7OKcN1c9kYuNxKcDe4iJ4FY9sX3aw2xw==", "dev": true }, "get-uv-event-loop-napi-h": { "version": "1.0.6", + "resolved": false, "integrity": "sha512-t5c9VNR84nRoF+eLiz6wFrEp1SE2Acg0wS+Ysa2zF0eROes+LzOfuTaVHxGy8AbS8rq7FHEJzjnCZo1BupwdJg==", "dev": true, "requires": { "get-symbol-from-current-process-h": "^1.0.1" } }, - "gherkin": { - "version": "5.0.0", - "integrity": "sha1-lt70EZjsOQgli1Ea909lWidk0qE=", - "dev": true - }, "glob": { "version": "7.2.0", + "resolved": false, "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "requires": { "fs.realpath": "^1.0.0", @@ -5887,6 +2005,7 @@ }, "glob-parent": { "version": "5.1.2", + "resolved": false, "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { @@ -5895,20 +2014,24 @@ }, "globals": { "version": "11.12.0", + "resolved": false, "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "graceful-fs": { "version": "4.2.8", + "resolved": false, "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" }, "grpc-promise": { "version": "1.4.0", + "resolved": false, "integrity": "sha512-4BBXHXb5OjjBh7luylu8vFqL6H6aPn/LeqpQaSBeRzO/Xv95wHW/WkU9TJRqaCTMZ5wq9jTSvlJWp0vRJy1pVA==", "dev": true }, "has": { "version": "1.0.3", + "resolved": false, "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { @@ -5917,21 +2040,25 @@ }, "has-bigints": { "version": "1.0.1", + "resolved": false, "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", "dev": true }, "has-flag": { "version": "3.0.0", + "resolved": false, "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "has-symbols": { "version": "1.0.2", + "resolved": false, "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, "has-tostringtag": { "version": "1.0.0", + "resolved": false, "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dev": true, "requires": { @@ -5940,33 +2067,34 @@ }, "hex64": { "version": "0.4.0", + "resolved": false, "integrity": "sha1-rRB4rIHVfXLeYjKxADvE9vsCh8A=" }, - "hosted-git-info": { - "version": "2.8.9", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, "husky": { "version": "6.0.0", + "resolved": false, "integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==", "dev": true }, "ieee754": { "version": "1.2.1", + "resolved": false, "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { "version": "4.0.6", + "resolved": false, "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "immediate": { "version": "3.0.6", + "resolved": false, "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" }, "import-fresh": { "version": "3.3.0", + "resolved": false, "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { @@ -5976,16 +2104,19 @@ }, "imurmurhash": { "version": "0.1.4", + "resolved": false, "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "indent-string": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, "inflight": { "version": "1.0.6", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { "once": "^1.3.0", @@ -5994,10 +2125,12 @@ }, "inherits": { "version": "2.0.4", + "resolved": false, "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "internal-slot": { "version": "1.0.3", + "resolved": false, "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "dev": true, "requires": { @@ -6006,13 +2139,9 @@ "side-channel": "^1.0.4" } }, - "is-arrayish": { - "version": "0.2.1", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, "is-bigint": { "version": "1.0.4", + "resolved": false, "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, "requires": { @@ -6021,6 +2150,7 @@ }, "is-boolean-object": { "version": "1.1.2", + "resolved": false, "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, "requires": { @@ -6030,11 +2160,13 @@ }, "is-callable": { "version": "1.2.4", + "resolved": false, "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true }, "is-core-module": { "version": "2.7.0", + "resolved": false, "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", "dev": true, "requires": { @@ -6043,6 +2175,7 @@ }, "is-date-object": { "version": "1.0.5", + "resolved": false, "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, "requires": { @@ -6051,21 +2184,25 @@ }, "is-extglob": { "version": "2.1.1", + "resolved": false, "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, "is-fullwidth-code-point": { - "version": "2.0.0", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "is-generator": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz", "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=", "dev": true }, "is-glob": { "version": "4.0.3", + "resolved": false, "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { @@ -6074,11 +2211,13 @@ }, "is-negative-zero": { "version": "2.0.1", + "resolved": false, "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", "dev": true }, "is-number-object": { "version": "1.0.6", + "resolved": false, "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", "dev": true, "requires": { @@ -6087,6 +2226,7 @@ }, "is-plain-object": { "version": "2.0.4", + "resolved": false, "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "requires": { "isobject": "^3.0.1" @@ -6094,6 +2234,7 @@ }, "is-regex": { "version": "1.1.4", + "resolved": false, "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "requires": { @@ -6103,16 +2244,19 @@ }, "is-shared-array-buffer": { "version": "1.0.1", + "resolved": false, "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", "dev": true }, "is-stream": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, "is-string": { "version": "1.0.7", + "resolved": false, "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, "requires": { @@ -6121,6 +2265,7 @@ }, "is-symbol": { "version": "1.0.4", + "resolved": false, "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "requires": { @@ -6129,6 +2274,7 @@ }, "is-weakref": { "version": "1.0.1", + "resolved": false, "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", "dev": true, "requires": { @@ -6137,34 +2283,41 @@ }, "is-wsl": { "version": "1.1.0", + "resolved": false, "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", "dev": true }, "isarray": { "version": "1.0.0", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", + "resolved": false, "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "isobject": { "version": "3.0.1", + "resolved": false, "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, "js-base64": { "version": "2.6.4", + "resolved": false, "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", "dev": true }, "js-tokens": { "version": "4.0.0", + "resolved": false, "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "js-yaml": { "version": "3.14.1", + "resolved": false, "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { @@ -6174,26 +2327,25 @@ }, "jsesc": { "version": "2.5.2", + "resolved": false, "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, - "json-parse-better-errors": { - "version": "1.0.2", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", + "resolved": false, "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", + "resolved": false, "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, "json5": { "version": "2.2.0", + "resolved": false, "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "requires": { @@ -6202,6 +2354,7 @@ }, "jsonfile": { "version": "5.0.0", + "resolved": false, "integrity": "sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==", "dev": true, "requires": { @@ -6211,6 +2364,7 @@ }, "jszip": { "version": "3.7.1", + "resolved": false, "integrity": "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==", "requires": { "lie": "~3.3.0", @@ -6221,6 +2375,7 @@ "dependencies": { "readable-stream": { "version": "2.3.7", + "resolved": false, "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", @@ -6234,6 +2389,7 @@ }, "string_decoder": { "version": "1.1.1", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -6243,10 +2399,12 @@ }, "kind-of": { "version": "6.0.3", + "resolved": false, "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, "knuth-shuffle-seeded": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz", "integrity": "sha1-AfG2VzOqdUDuCNiwF0Fk0iCB5OE=", "dev": true, "requires": { @@ -6255,6 +2413,7 @@ }, "lazystream": { "version": "1.0.0", + "resolved": false, "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", "requires": { "readable-stream": "^2.0.5" @@ -6262,6 +2421,7 @@ "dependencies": { "readable-stream": { "version": "2.3.7", + "resolved": false, "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", @@ -6275,6 +2435,7 @@ }, "string_decoder": { "version": "1.1.1", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -6284,6 +2445,7 @@ }, "levn": { "version": "0.4.1", + "resolved": false, "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "requires": { @@ -6293,24 +2455,15 @@ }, "lie": { "version": "3.3.0", + "resolved": false, "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "requires": { "immediate": "~3.0.5" } }, - "load-json-file": { - "version": "4.0.0", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, "locate-path": { "version": "2.0.0", + "resolved": false, "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { @@ -6320,69 +2473,157 @@ }, "lodash": { "version": "4.17.21", + "resolved": false, "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "lodash.camelcase": { "version": "4.3.0", + "resolved": false, "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", "dev": true }, "lodash.clonedeep": { "version": "4.5.0", + "resolved": false, "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "dev": true }, "lodash.defaults": { "version": "4.2.0", + "resolved": false, "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" }, "lodash.difference": { "version": "4.5.0", + "resolved": false, "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" }, "lodash.flatten": { "version": "4.4.0", + "resolved": false, "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" }, "lodash.isplainobject": { "version": "4.0.6", + "resolved": false, "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" }, "lodash.merge": { "version": "4.6.2", + "resolved": false, "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "lodash.truncate": { "version": "4.4.2", + "resolved": false, "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, "lodash.union": { "version": "4.6.0", + "resolved": false, "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" }, "long": { "version": "4.0.0", + "resolved": false, "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", "dev": true }, "lower-case": { - "version": "1.1.4", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", - "dev": true + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } }, "lru-cache": { "version": "6.0.0", + "resolved": false, "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" } }, + "marked": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz", + "integrity": "sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==", + "dev": true + }, + "marked-terminal": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.2.0.tgz", + "integrity": "sha512-DQfNRV9svZf0Dm9Cf5x5xaVJ1+XjxQW6XjFJ5HFkVyK52SDpj5PCBzS5X5r2w9nHr3mlB0T5201UMLue9fmhUw==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.1", + "cardinal": "^2.1.1", + "chalk": "^4.1.0", + "cli-table3": "^0.6.0", + "node-emoji": "^1.10.0", + "supports-hyperlinks": "^2.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "minimatch": { "version": "3.0.4", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" @@ -6390,15 +2631,18 @@ }, "minimist": { "version": "1.2.5", + "resolved": false, "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "ms": { "version": "2.1.2", + "resolved": false, "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "mz": { "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "dev": true, "requires": { @@ -6409,29 +2653,35 @@ }, "natural-compare": { "version": "1.4.0", + "resolved": false, "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, "next-tick": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, "no-case": { - "version": "2.3.2", - "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, "requires": { - "lower-case": "^1.1.1" + "lower-case": "^2.0.2", + "tslib": "^2.0.3" } }, "node-addon-api": { "version": "3.2.1", + "resolved": false, "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true }, "node-emoji": { "version": "1.11.0", + "resolved": false, "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", "dev": true, "requires": { @@ -6440,53 +2690,47 @@ }, "node-gyp-build": { "version": "4.3.0", + "resolved": false, "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", "dev": true }, "node-releases": { "version": "1.1.77", + "resolved": false, "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==", "dev": true }, - "normalize-package-data": { - "version": "2.5.0", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "normalize-path": { "version": "3.0.0", + "resolved": false, "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, + "nvm": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/nvm/-/nvm-0.0.4.tgz", + "integrity": "sha1-OKF46dMbKDUIyS0VydqGHRqSELw=" + }, "object-assign": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, "object-inspect": { "version": "1.11.0", + "resolved": false, "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", "dev": true }, "object-keys": { "version": "1.1.1", + "resolved": false, "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, "object.assign": { "version": "4.1.2", + "resolved": false, "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dev": true, "requires": { @@ -6498,6 +2742,7 @@ }, "object.values": { "version": "1.1.5", + "resolved": false, "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "requires": { @@ -6508,6 +2753,7 @@ }, "once": { "version": "1.4.0", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" @@ -6515,6 +2761,7 @@ }, "open": { "version": "6.4.0", + "resolved": false, "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", "dev": true, "requires": { @@ -6523,6 +2770,7 @@ }, "optionator": { "version": "0.9.1", + "resolved": false, "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "requires": { @@ -6536,6 +2784,7 @@ }, "p-limit": { "version": "1.3.0", + "resolved": false, "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { @@ -6544,6 +2793,7 @@ }, "p-locate": { "version": "2.0.0", + "resolved": false, "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { @@ -6552,11 +2802,13 @@ }, "p-try": { "version": "1.0.0", + "resolved": false, "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, "pad-right": { "version": "0.2.2", + "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=", "dev": true, "requires": { @@ -6565,95 +2817,77 @@ }, "pako": { "version": "1.0.11", + "resolved": false, "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "parent-module": { "version": "1.0.1", + "resolved": false, "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "requires": { "callsites": "^3.0.0" } }, - "parse-json": { - "version": "4.0.0", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, "path-exists": { "version": "3.0.0", + "resolved": false, "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, "path-is-absolute": { "version": "1.0.1", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-key": { "version": "3.1.1", + "resolved": false, "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "path-parse": { "version": "1.0.7", + "resolved": false, "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "path-type": { - "version": "3.0.0", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, "pathval": { "version": "1.1.1", + "resolved": false, "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true }, "picocolors": { "version": "0.2.1", + "resolved": false, "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true }, - "pify": { - "version": "3.0.0", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, "pkg-dir": { "version": "2.0.0", + "resolved": false, "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { "find-up": "^2.1.0" } }, - "pkg-up": { - "version": "2.0.0", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, "prelude-ls": { "version": "1.2.1", + "resolved": false, "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, "prettier": { "version": "2.4.1", + "resolved": false, "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", "dev": true }, "prettier-linter-helpers": { "version": "1.0.0", + "resolved": false, "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "requires": { @@ -6662,19 +2896,23 @@ }, "printj": { "version": "1.1.2", + "resolved": false, "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==" }, "process-nextick-args": { "version": "2.0.1", + "resolved": false, "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "progress": { "version": "2.0.3", + "resolved": false, "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "protobufjs": { "version": "6.11.2", + "resolved": false, "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", "dev": true, "requires": { @@ -6695,30 +2933,13 @@ }, "punycode": { "version": "2.1.1", + "resolved": false, "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "read-pkg": { - "version": "3.0.0", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "3.0.0", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - } - }, "readable-stream": { "version": "3.6.0", + "resolved": false, "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", @@ -6728,13 +2949,24 @@ }, "readdir-glob": { "version": "1.1.1", + "resolved": false, "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==", "requires": { "minimatch": "^3.0.4" } }, + "redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", + "dev": true, + "requires": { + "esprima": "~4.0.0" + } + }, "ref-napi": { "version": "3.0.3", + "resolved": false, "integrity": "sha512-LiMq/XDGcgodTYOMppikEtJelWsKQERbLQsYm0IOOnzhwE9xYZC7x8txNnFC9wJNOkPferQI4vD4ZkC0mDyrOA==", "dev": true, "requires": { @@ -6746,6 +2978,7 @@ }, "ref-struct-di": { "version": "1.1.1", + "resolved": false, "integrity": "sha512-2Xyn/0Qgz89VT+++WP0sTosdm9oeowLP23wRJYhG4BFdMUrLj3jhwHZNEytYNYgtPKLNTP3KJX4HEgBvM1/Y2g==", "dev": true, "requires": { @@ -6754,6 +2987,7 @@ "dependencies": { "debug": { "version": "3.2.7", + "resolved": false, "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { @@ -6762,28 +2996,54 @@ } } }, - "regenerator-runtime": { - "version": "0.13.9", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regexp-match-indices": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz", + "integrity": "sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ==", + "dev": true, + "requires": { + "regexp-tree": "^0.1.11" + } + }, + "regexp-tree": { + "version": "0.1.24", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz", + "integrity": "sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==", "dev": true }, "regexpp": { "version": "3.2.0", + "resolved": false, "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "repeat-string": { "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, "require-from-string": { "version": "2.0.2", + "resolved": false, "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, "resolve": { "version": "1.20.0", + "resolved": false, "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { @@ -6793,11 +3053,30 @@ }, "resolve-from": { "version": "4.0.0", + "resolved": false, "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "resolve-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-2.0.0.tgz", + "integrity": "sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, "rimraf": { "version": "3.0.2", + "resolved": false, "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { @@ -6806,32 +3085,29 @@ }, "safe-buffer": { "version": "5.1.2", + "resolved": false, "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "seed-random": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/seed-random/-/seed-random-2.2.0.tgz", "integrity": "sha1-KpsZ4lCoFwmSMaW5mk2vgLf77VQ=", "dev": true }, "semver": { "version": "6.3.0", + "resolved": false, "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, - "serialize-error": { - "version": "4.1.0", - "integrity": "sha512-5j9GgyGsP9vV9Uj1S0lDCvlsd+gc2LEPVK7HHHte7IyPwOD4lVQFeaX143gx3U5AnoCi+wbcb3mvaxVysjpxEw==", - "dev": true, - "requires": { - "type-fest": "^0.3.0" - } - }, "set-immediate-shim": { "version": "1.0.1", + "resolved": false, "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" }, "sha3": { "version": "2.1.4", + "resolved": false, "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", "requires": { "buffer": "6.0.3" @@ -6839,6 +3115,7 @@ }, "shallow-clone": { "version": "3.0.1", + "resolved": false, "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "requires": { "kind-of": "^6.0.2" @@ -6846,6 +3123,7 @@ }, "shebang-command": { "version": "2.0.0", + "resolved": false, "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { @@ -6854,11 +3132,13 @@ }, "shebang-regex": { "version": "3.0.0", + "resolved": false, "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "side-channel": { "version": "1.0.4", + "resolved": false, "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, "requires": { @@ -6869,6 +3149,7 @@ }, "slice-ansi": { "version": "4.0.0", + "resolved": false, "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { @@ -6879,6 +3160,7 @@ "dependencies": { "ansi-styles": { "version": "4.3.0", + "resolved": false, "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { @@ -6887,6 +3169,7 @@ }, "color-convert": { "version": "2.0.1", + "resolved": false, "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { @@ -6895,61 +3178,51 @@ }, "color-name": { "version": "1.1.4", + "resolved": false, "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true } } }, "source-map": { "version": "0.5.7", + "resolved": false, "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, - "spdx-correct": { - "version": "3.1.1", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "dev": true, "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, - "spdx-license-ids": { - "version": "3.0.10", - "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==", - "dev": true - }, "sprintf-js": { "version": "1.0.3", + "resolved": false, "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, "stack-chain": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-2.0.0.tgz", "integrity": "sha512-GGrHXePi305aW7XQweYZZwiRwR7Js3MWoK/EHzzB9ROdc75nCnjSJVi21rdAGxFl+yCx2L2qdfl5y7NO4lTyqg==", "dev": true }, "stack-generator": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.5.tgz", "integrity": "sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q==", "dev": true, "requires": { @@ -6958,11 +3231,13 @@ }, "stackframe": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==", "dev": true }, "stacktrace-gps": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz", "integrity": "sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg==", "dev": true, "requires": { @@ -6972,6 +3247,7 @@ "dependencies": { "source-map": { "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", "dev": true } @@ -6979,6 +3255,7 @@ }, "stacktrace-js": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz", "integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==", "dev": true, "requires": { @@ -6987,50 +3264,26 @@ "stacktrace-gps": "^3.0.4" } }, - "string_decoder": { - "version": "1.3.0", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, "string-argv": { "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", "dev": true }, "string-width": { - "version": "2.1.1", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, "string.prototype.trimend": { "version": "1.0.4", + "resolved": false, "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "dev": true, "requires": { @@ -7040,6 +3293,7 @@ }, "string.prototype.trimstart": { "version": "1.0.4", + "resolved": false, "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", "dev": true, "requires": { @@ -7047,8 +3301,24 @@ "define-properties": "^1.1.3" } }, + "string_decoder": { + "version": "1.3.0", + "resolved": false, + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": false, + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, "strip-ansi": { "version": "6.0.1", + "resolved": false, "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { @@ -7057,24 +3327,55 @@ }, "strip-bom": { "version": "3.0.0", + "resolved": false, "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, "strip-json-comments": { "version": "3.1.1", + "resolved": false, "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "supports-color": { "version": "5.5.0", + "resolved": false, "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" } }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "synchronized-promise": { "version": "0.3.1", + "resolved": false, "integrity": "sha512-Iy+JzrERSUrwpOHUDku8HHIddk8V6iLG9bPIzboP2i5RYkn2eSmRB8waSaX7Rc/+DUUsnFsoOHrmniwOp9BOgw==", "requires": { "deasync": "^0.1.15" @@ -7082,6 +3383,7 @@ }, "table": { "version": "6.7.2", + "resolved": false, "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", "dev": true, "requires": { @@ -7095,6 +3397,7 @@ "dependencies": { "ajv": { "version": "8.6.3", + "resolved": false, "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", "dev": true, "requires": { @@ -7104,30 +3407,17 @@ "uri-js": "^4.2.2" } }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, "json-schema-traverse": { "version": "1.0.0", + "resolved": false, "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true - }, - "string-width": { - "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } } } }, "tar-stream": { "version": "2.2.0", + "resolved": false, "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "requires": { "bl": "^4.0.3", @@ -7139,15 +3429,18 @@ }, "tari_crypto": { "version": "0.9.1", + "resolved": false, "integrity": "sha512-K7LAtwQQKCeTH5CyyO8d/TiPDEePRaJ4e6+hrxpWv6jlkkAiS4m6csBuVqpSjyAlKeP8cQJpUQX2n22akOuZVg==" }, "text-table": { "version": "0.2.0", + "resolved": false, "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, "thenify": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "dev": true, "requires": { @@ -7156,33 +3449,37 @@ }, "thenify-all": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", "dev": true, "requires": { "thenify": ">= 3.1.0 < 4" } }, - "title-case": { - "version": "2.1.1", - "integrity": "sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=", + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", "dev": true, "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.0.3" + "rimraf": "^3.0.0" } }, "to-fast-properties": { "version": "2.0.0", + "resolved": false, "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, "traverse-chain": { "version": "0.1.0", + "resolved": false, "integrity": "sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=", "dev": true }, "tsconfig-paths": { "version": "3.11.0", + "resolved": false, "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", "dev": true, "requires": { @@ -7194,6 +3491,7 @@ "dependencies": { "json5": { "version": "1.0.1", + "resolved": false, "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "dev": true, "requires": { @@ -7202,13 +3500,21 @@ } } }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, "type": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", "dev": true }, "type-check": { "version": "0.4.0", + "resolved": false, "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "requires": { @@ -7217,16 +3523,19 @@ }, "type-detect": { "version": "4.0.8", + "resolved": false, "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, "type-fest": { - "version": "0.3.1", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true }, "unbox-primitive": { "version": "1.0.1", + "resolved": false, "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", "dev": true, "requires": { @@ -7238,16 +3547,22 @@ }, "universalify": { "version": "0.1.2", + "resolved": false, "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, - "upper-case": { - "version": "1.1.3", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", - "dev": true + "upper-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", + "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } }, "uri-js": { "version": "4.4.1", + "resolved": false, "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "requires": { @@ -7256,38 +3571,35 @@ }, "utf8": { "version": "3.0.0", + "resolved": false, "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" }, "util-arity": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/util-arity/-/util-arity-1.1.0.tgz", "integrity": "sha1-WdAa8f2z/t4KxOYysKtfbOl8kzA=", "dev": true }, "util-deprecate": { "version": "1.0.2", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { "version": "3.4.0", + "resolved": false, "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, "v8-compile-cache": { "version": "2.3.0", + "resolved": false, "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "validate-npm-package-license": { - "version": "3.0.4", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "verror": { "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { @@ -7306,86 +3618,68 @@ "dependencies": { "@grpc/grpc-js": { "version": "1.3.6", - "integrity": "sha512-v7+LQFbqZKmd/Tvf5/j1Xlbq6jXL/4d+gUtm2TNX4QiEC3ELWADmGr2dGlUyLl6aKTuYfsN72vAsO5zmavYkEg==", "requires": { "@types/node": ">=12.12.47" } }, "@grpc/proto-loader": { "version": "0.5.6", - "integrity": "sha512-DT14xgw3PSzPxwS13auTEwxhMMOoz33DPUKNtmYK/QYbBSpLXJy78FGGs5yVoxVobEqPm4iW9MOIoz0A3bLTRQ==", "requires": { "lodash.camelcase": "^4.3.0", "protobufjs": "^6.8.6" } }, "@protobufjs/aspromise": { - "version": "1.1.2", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + "version": "1.1.2" }, "@protobufjs/base64": { - "version": "1.1.2", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + "version": "1.1.2" }, "@protobufjs/codegen": { - "version": "2.0.4", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + "version": "2.0.4" }, "@protobufjs/eventemitter": { - "version": "1.1.0", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + "version": "1.1.0" }, "@protobufjs/fetch": { "version": "1.1.0", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", "requires": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "@protobufjs/float": { - "version": "1.0.2", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + "version": "1.0.2" }, "@protobufjs/inquire": { - "version": "1.1.0", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + "version": "1.1.0" }, "@protobufjs/path": { - "version": "1.1.2", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + "version": "1.1.2" }, "@protobufjs/pool": { - "version": "1.1.0", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + "version": "1.1.0" }, "@protobufjs/utf8": { - "version": "1.1.0", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + "version": "1.1.0" }, "@types/long": { - "version": "4.0.1", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + "version": "4.0.1" }, "@types/node": { - "version": "16.3.2", - "integrity": "sha512-jJs9ErFLP403I+hMLGnqDRWT0RYKSvArxuBVh2veudHV7ifEC1WAmjJADacZ7mRbA2nWgHtn8xyECMAot0SkAw==" + "version": "16.3.2" }, "grpc-promise": { - "version": "1.4.0", - "integrity": "sha512-4BBXHXb5OjjBh7luylu8vFqL6H6aPn/LeqpQaSBeRzO/Xv95wHW/WkU9TJRqaCTMZ5wq9jTSvlJWp0vRJy1pVA==" + "version": "1.4.0" }, "lodash.camelcase": { - "version": "4.3.0", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + "version": "4.3.0" }, "long": { - "version": "4.0.0", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + "version": "4.0.0" }, "protobufjs": { "version": "6.11.2", - "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -7406,6 +3700,7 @@ }, "which": { "version": "2.0.2", + "resolved": false, "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { @@ -7414,6 +3709,7 @@ }, "which-boxed-primitive": { "version": "1.0.2", + "resolved": false, "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, "requires": { @@ -7426,28 +3722,88 @@ }, "word-wrap": { "version": "1.2.3", + "resolved": false, "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, "wrappy": { "version": "1.0.2", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "xregexp": { - "version": "4.4.1", - "integrity": "sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==", - "dev": true, - "requires": { - "@babel/runtime-corejs3": "^7.12.1" - } + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true }, "yallist": { "version": "4.0.0", + "resolved": false, "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + }, "zip-stream": { "version": "4.1.0", + "resolved": false, "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", "requires": { "archiver-utils": "^2.1.0", diff --git a/integration_tests/package.json b/integration_tests/package.json index 89cb1f8f08..8dc86e6d29 100644 --- a/integration_tests/package.json +++ b/integration_tests/package.json @@ -17,17 +17,17 @@ "@babel/core": "^7.15.8", "@babel/eslint-parser": "^7.15.8", "@babel/eslint-plugin": "^7.14.5", - "@grpc/grpc-js": "^1.3.6", + "@grpc/grpc-js": "^1.4.1", "@grpc/proto-loader": "^0.5.5", "blakejs": "^1.1.0", "chai": "^4.2.0", - "cucumber": "^6.0.5", + "cucumber": "^7.0.0-rc.0", "cucumber-html-reporter": "^5.5.0", - "cucumber-pretty": "^6.0.0", + "cucumber-pretty": "^1.5.2", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-config-standard": "^16.0.2", - "eslint-plugin-import": "^2.24.2", + "eslint-plugin-import": "^2.25.2", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.4.1", "eslint-plugin-promise": "^4.3.1", @@ -46,6 +46,7 @@ "glob": "^7.2.0", "hex64": "^0.4.0", "jszip": "^3.7.1", + "nvm": "^0.0.4", "sha3": "^2.1.3", "synchronized-promise": "^0.3.1", "tari_crypto": "^0.9.1", diff --git a/package-lock.json b/package-lock.json index 0b0c5d3492..7ee14dcd9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,4 +1,4 @@ { "lockfileVersion": 1, - "version": "0.11.0" + "version": "0.12.0" } diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 63dc7f53b2..0000000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly-2021-08-18 diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000000..0d2a95711f --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,5 @@ +# Please update all references in the codebase! +# and increment this number: +# Hours spent updating the Rust Toolchain = 1 +[toolchain] +channel = "nightly-2021-09-18"