diff --git a/.github/scripts/fixtures.sh b/.github/scripts/fixtures.sh new file mode 100755 index 0000000000..e0d8bda3d3 --- /dev/null +++ b/.github/scripts/fixtures.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +export LC_ALL=C + +# setup_var +ownerauthaddr="mwsZw8nF7pKxWH8eoKL9tPxTpaFkz7QeLU" +ownerauthpriv="cRiRQ9cHmy5evDqNDdEV8f6zfbK6epi9Fpz4CRZsmLEmkwy54dWz" +# operatorauthaddr="mswsMVsyGMj1FzDMbbxw2QW3KvQAv2FKiy" +operatorauthpriv="cPGEaz8AGiM71NGMRybbCqFNRcuUhg3uGvyY4TFE1BZC26EW2PkC" +alice="0x9b8a4af42140d8a4c153a822f02571a1dd037e89" +# bob="0x6C34CBb9219d8cAa428835D2073E8ec88BA0a110" +privkey_alice="af990cc3ba17e776f7f57fcc59942a82846d75833fa17d2ba59ce6858d886e23" +privkey_bob="17b8cb134958b3d8422b6c43b0732fcdb8c713b524df2d45de12f0c7e214ba35" +contract_counter="0x60c0604052600760808190526621b7bab73a32b960c91b60a090815261002891600091906100ab565b50600060025534801561003a57600080fd5b50600180546001600160a01b031916331790556040517ff15da729ec5b36e9bda8b3f71979cdac5d0f3169f8590778ac0cd82cc5cc1d4a9061009e906020808252600e908201526d2432b63637961021b7bab73a32b960911b604082015260600190565b60405180910390a161017f565b8280546100b790610144565b90600052602060002090601f0160209004810192826100d9576000855561011f565b82601f106100f257805160ff191683800117855561011f565b8280016001018555821561011f579182015b8281111561011f578251825591602001919060010190610104565b5061012b92915061012f565b5090565b5b8082111561012b5760008155600101610130565b60028104600182168061015857607f821691505b6020821081141561017957634e487b7160e01b600052602260045260246000fd5b50919050565b6103e68061018e6000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c80638da5cb5b116100665780638da5cb5b146100f4578063a87d942c1461011f578063c8a4ac9c14610127578063d14e62b81461013a578063ee82ac5e1461014d5761009e565b806306fdde03146100a3578063119fbbd4146100c15780631a93d1c3146100cb578063672d5d3b146100db5780638361ff9c146100e1575b600080fd5b6100ab61015f565b6040516100b891906102d5565b60405180910390f35b6100c96101ed565b005b455b6040519081526020016100b8565b436100cd565b6100cd6100ef36600461029c565b610207565b600154610107906001600160a01b031681565b6040516001600160a01b0390911681526020016100b8565b6002546100cd565b6100cd6101353660046102b4565b61026d565b6100c961014836600461029c565b610280565b6100cd61015b36600461029c565b4090565b6000805461016c9061035f565b80601f01602080910402602001604051908101604052809291908181526020018280546101989061035f565b80156101e55780601f106101ba576101008083540402835291602001916101e5565b820191906000526020600020905b8154815290600101906020018083116101c857829003601f168201915b505050505081565b6001600260008282546102009190610328565b9091555050565b6000600a8211156102695760405162461bcd60e51b815260206004820152602260248201527f56616c7565206d757374206e6f742062652067726561746572207468616e2031604482015261181760f11b606482015260840160405180910390fd5b5090565b60006102798284610340565b9392505050565b6001546001600160a01b0316331461029757600080fd5b600255565b6000602082840312156102ad578081fd5b5035919050565b600080604083850312156102c6578081fd5b50508035926020909101359150565b6000602080835283518082850152825b81811015610301578581018301518582016040015282016102e5565b818111156103125783604083870101525b50601f01601f1916929092016040019392505050565b6000821982111561033b5761033b61039a565b500190565b600081600019048311821515161561035a5761035a61039a565b500290565b60028104600182168061037357607f821691505b6020821081141561039457634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220698216ef3f0a0eede3cc4f13017b1d1699d56b3aa4aa8491a3f47fc2d37ac22164736f6c63430008020033" +contract_countercaller="0x608060405234801561001057600080fd5b5060405161025c38038061025c83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610082565b600060208284031215610065578081fd5b81516001600160a01b038116811461007b578182fd5b9392505050565b6101cb806100916000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806360598c0114610046578063a87d942c14610050578063c3da42b81461006b575b600080fd5b61004e610096565b005b6100586100f1565b6040519081526020015b60405180910390f35b60005461007e906001600160a01b031681565b6040516001600160a01b039091168152602001610062565b6000805460408051630467eef560e21b815290516001600160a01b039092169263119fbbd49260048084019382900301818387803b1580156100d757600080fd5b505af11580156100eb573d6000803e3d6000fd5b50505050565b60008060009054906101000a90046001600160a01b03166001600160a01b031663a87d942c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561014057600080fd5b505afa158015610154573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610178919061017d565b905090565b60006020828403121561018e578081fd5b505191905056fea2646970667358221220220b50dea2907d54fd36279d0583e05fe9868a78b29df0e8d111fabac5ef1d9564736f6c63430008020033" + +# foundation members +./build/src/defi-cli -regtest importprivkey $ownerauthpriv owner true +./build/src/defi-cli -regtest importprivkey $operatorauthpriv operator true + +# push fixtures +./build/src/defi-cli -regtest importprivkey $privkey_alice +./build/src/defi-cli -regtest importprivkey $privkey_bob +./build/src/defi-cli -regtest generatetoaddress 100 $ownerauthaddr + +./build/src/defi-cli -regtest utxostoaccount '{"'"$ownerauthaddr"'":"5000@DFI"}' +./build/src/defi-cli -regtest generatetoaddress 1 $ownerauthaddr + +./build/src/defi-cli -regtest setgov '{"ATTRIBUTES":{"v0/params/feature/evm":"true"}}' +./build/src/defi-cli -regtest generatetoaddress 1 $ownerauthaddr + +./build/src/defi-cli -regtest transferdomain 1 '{"'"$ownerauthaddr"'":["2000@DFI"]}' '{"'"$alice"'":["2000@DFI"]}' +./build/src/defi-cli -regtest generatetoaddress 1 $ownerauthaddr + +curl http://localhost:19551 \ + -H 'content-type:application/json' \ + --data-binary \ + '{ + "jsonrpc":"2.0", + "id":"fixture", + "method":"eth_sendTransaction", + "params":[{ + "data":"'"$contract_counter"'", + "value":"0x00", + "gas":"0x7a120", + "gasPrice": "0x22ecb25c00" + }] + }' +./build/src/defi-cli -regtest generatetoaddress 1 $ownerauthaddr +# contract address +# 0x966aaec51a95a737d086d21f015a6991dd5559ae + +curl http://localhost:19551 \ + -H 'content-type:application/json' \ + --data-binary \ + '{ + "jsonrpc":"2.0", + "id":"fixture", + "method":"eth_sendTransaction", + "params":[{ + "data":"'"$contract_countercaller"'", + "value":"0x00", + "gas":"0x7a120", + "gasPrice": "0x22ecb25c00" + }] + }' +./build/src/defi-cli -regtest generatetoaddress 1 $ownerauthaddr +# contract address +# 0x007138e9d5bdb3f0b7f3abf2d46ad4f9184ef99d diff --git a/.github/workflows/build-dev.yaml b/.github/workflows/build-dev.yaml index 354b3f7eff..f3928e7784 100644 --- a/.github/workflows/build-dev.yaml +++ b/.github/workflows/build-dev.yaml @@ -25,7 +25,7 @@ jobs: run: GIT_VERSION=1 ./make.sh ci-export-vars - name: Build and package - run: GIT_VERSION=1 DOCKERFILE="x86_64-pc-linux-gnu-clang" TARGET="x86_64-pc-linux-gnu" ./make.sh docker-release + run: GIT_VERSION=1 TARGET="x86_64-pc-linux-gnu" ./make.sh docker-release - name: Publish artifact - x86_64-pc-linux-gnu uses: actions/upload-artifact@v3 diff --git a/.github/workflows/build-release.yaml b/.github/workflows/build-release.yaml index 1977418353..5efa639682 100644 --- a/.github/workflows/build-release.yaml +++ b/.github/workflows/build-release.yaml @@ -8,6 +8,7 @@ on: env: BUILD_VERSION: latest # Computed DOCKER_HUB_USER: defi + MAKE_DEBUG: 0 jobs: linux-x64: @@ -21,7 +22,7 @@ jobs: run: GIT_VERSION=1 ./make.sh ci-export-vars - name: Build and package - run: GIT_VERSION=1 DOCKERFILE="x86_64-pc-linux-gnu-clang" TARGET="x86_64-pc-linux-gnu" ./make.sh docker-release + run: GIT_VERSION=1 TARGET="x86_64-pc-linux-gnu" ./make.sh docker-release - name: Publish artifacts uses: actions/upload-artifact@v3 diff --git a/.github/workflows/build-staging.yaml b/.github/workflows/build-staging.yaml index 7ecf928b4d..254bb8da85 100644 --- a/.github/workflows/build-staging.yaml +++ b/.github/workflows/build-staging.yaml @@ -2,6 +2,11 @@ name: Build - Staging on: workflow_dispatch: + release: + types: [created] + +env: + MAKE_DEBUG: 0 jobs: linux-x64: @@ -15,7 +20,7 @@ jobs: run: GIT_VERSION=1 ./make.sh ci-export-vars - name: Build and package - run: GIT_VERSION=1 DOCKERFILE="x86_64-pc-linux-gnu-clang" TARGET="x86_64-pc-linux-gnu" ./make.sh docker-release + run: GIT_VERSION=1 TARGET="x86_64-pc-linux-gnu" ./make.sh docker-release - name: Publish artifacts uses: actions/upload-artifact@v3 diff --git a/.github/workflows/tests-evm-rpc.yaml b/.github/workflows/tests-evm-rpc.yaml new file mode 100644 index 0000000000..8c2fdbb304 --- /dev/null +++ b/.github/workflows/tests-evm-rpc.yaml @@ -0,0 +1,71 @@ +name: Tests - EVM + +on: + workflow_dispatch: + pull_request: + branches: + - feature/evm + push: + branches: + - feature/evm + tags: + - evm + +env: + NODE_URL: "http://127.0.0.1:19551/" + +jobs: + build-binaries: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + run: sudo ./make.sh pkg-install-deps && sudo ./make.sh pkg-install-llvm + + - name: Build binaries + run: TARGET="x86_64-pc-linux-gnu" ./make.sh build + + - name: Upload binaries + uses: actions/upload-artifact@v3 + with: + name: defibins + path: | + build/src/defid + build/src/defi-cli + .github/scripts/fixtures.sh + + node-rpc-tests: + runs-on: ubuntu-latest + needs: build-binaries + steps: + - name: Download binaries + uses: actions/download-artifact@v3 + with: + name: defibins + + - name: Chores + run: | + chmod uog+x build/src/defid build/src/defi-cli .github/scripts/fixtures.sh + + - name: Run defid node + run: | + ./build/src/defid -regtest -daemon -debug=rpc -printtoconsole -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0 -masternode_operator=mswsMVsyGMj1FzDMbbxw2QW3KvQAv2FKiy -masternode_owner=mwsZw8nF7pKxWH8eoKL9tPxTpaFkz7QeLU -dummypos=0 -subsidytest=1 -txnotokens=0 -txindex=1 -amkheight=0 -bayfrontheight=1 -clarkequayheight=3 -dakotaheight=4 -dakotacrescentheight=5 -eunosheight=6 -eunospayaheight=7 -fortcanningheight=8 -fortcanningmuseumheight=9 -fortcanninghillheight=10 -fortcanningroadheight=11 -fortcanningcrunchheight=12 -fortcanningspringheight=13 -fortcanninggreatworldheight=14 -fortcanningepilogueheight=15 -grandcentralheight=16 -nextnetworkupgradeheight=17 + + - name: Push fixtures + run: | + sleep 5 + ./.github/scripts/fixtures.sh + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: '^1.17.0' + + - name: Set up go eth test suites library + uses: actions/checkout@v3 + with: + repository: 'DeFiCh/go-ethlibs' + + - name: Run EVM RPC tests + run: go test -v ./node/rpc_meta_test.go diff --git a/.github/workflows/tests-rust.yml b/.github/workflows/tests-rust.yml new file mode 100644 index 0000000000..621e4e30ed --- /dev/null +++ b/.github/workflows/tests-rust.yml @@ -0,0 +1,71 @@ +name: Tests - Rust + +on: + push: + paths: [ lib/** ] + + pull_request: + paths: [ lib/** ] + +jobs: + lint_cargo_fmt: + name: Lint (cargo fmt) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + + - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af + with: + profile: minimal + toolchain: stable + default: true + override: true + components: rustfmt, clippy + + - run: | + cd lib + cargo fmt --all -- --check + + lint_cargo_clippy: + name: Lint (cargo clippy) + runs-on: ubuntu-latest + steps: + - uses: arduino/setup-protoc@64c0c85d18e984422218383b81c52f8b077404d3 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + + - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af + with: + profile: minimal + toolchain: stable + default: true + override: true + components: rustfmt, clippy + + - run: | + cd lib + cargo clippy + + test_cargo: + name: Test (cargo) + runs-on: ubuntu-latest + steps: + - uses: arduino/setup-protoc@64c0c85d18e984422218383b81c52f8b077404d3 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + + - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af + with: + profile: minimal + toolchain: stable + default: true + override: true + components: rustfmt, clippy + + - run: | + cd lib + cargo test --no-fail-fast diff --git a/.gitignore b/.gitignore index 08b61ae038..a3a8374190 100644 --- a/.gitignore +++ b/.gitignore @@ -145,4 +145,4 @@ contrib/devtools/split-debug.sh # Rust local artifacts /lib/target -*.bin \ No newline at end of file +*.bin diff --git a/configure.ac b/configure.ac index c28fb4f70b..85018516d3 100644 --- a/configure.ac +++ b/configure.ac @@ -101,6 +101,12 @@ if test -z "$DOXYGEN"; then fi AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"]) +dnl Rust toolchain checks +AC_PATH_PROG([RUSTC], [rustc], [no]) +AS_IF([test "$RUSTC" = "no"], [AC_MSG_ERROR([Rust toolchain with rustc is required])]) +AC_PATH_PROG([CARGO], [cargo], [no]) +AS_IF([test "$CARGO" = "no"], [AC_MSG_ERROR([Rust toolchain with cargo is required])]) + AC_ARG_VAR(PYTHONPATH, Augments the default search path for python module files) AC_ARG_ENABLE([wallet], @@ -247,6 +253,7 @@ if test "x$enable_debug" = xyes; then if test "x$CXXFLAGS_overridden" = xno; then CXXFLAGS="" fi + AC_SUBST(ENABLE_DEBUG,[1]) # Disable all optimizations AX_CHECK_COMPILE_FLAG([-O0], [[DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -O0"]],,[[$CXXFLAG_WERROR]]) @@ -1316,8 +1323,11 @@ if test x$build_defi_wallet$build_defi_cli$build_defi_tx$build_defid$use_bench$u fi AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) +AM_CONDITIONAL([TARGET_NOT_DARWIN], [test x$TARGET_OS != xdarwin]) AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) +AM_CONDITIONAL([BUILD_NOT_DARWIN], [test x$BUILD_OS != xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) +AM_CONDITIONAL([TARGET_NOT_WINDOWS], [test x$TARGET_OS != xwindows]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([ENABLE_FUZZ],[test x$enable_fuzz = xyes]) @@ -1396,7 +1406,22 @@ AC_SUBST(HAVE_O_CLOEXEC) AC_SUBST(HAVE_BUILTIN_PREFETCH) AC_SUBST(HAVE_MM_PREFETCH) AC_SUBST(HAVE_STRONG_GETAUXVAL) -AC_CONFIG_FILES([Makefile src/Makefile test/config.ini]) +AC_SUBST(PROTOC) +AC_SUBST(PROTOC_INCLUDE_DIR) + +dnl If the host and build triplets are the same, we don't +dnl keep this empty +if test x$host = x$build; then + RUST_TARGET= +else + RUST_TARGET=`TARGET="$host" $ac_abs_confdir/make.sh get_rust_target` + if test x$RUST_TARGET = x; then + AC_MSG_ERROR("unsupported host target") + fi +fi +AC_SUBST(RUST_TARGET) + +AC_CONFIG_FILES([Makefile src/Makefile lib/Makefile test/config.ini]) AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh]) AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])]) AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py]) @@ -1482,4 +1507,7 @@ echo " CXX = $CXX" echo " CXXFLAGS = $DEBUG_CXXFLAGS $HARDENED_CXXFLAGS $WARN_CXXFLAGS $NOWARN_CXXFLAGS $ERROR_CXXFLAGS $GPROF_CXXFLAGS $CXXFLAGS" echo " LDFLAGS = $PTHREAD_CFLAGS $HARDENED_LDFLAGS $GPROF_LDFLAGS $LDFLAGS" echo " ARFLAGS = $ARFLAGS" +echo " CARGO = $CARGO" +echo " ENABLE_DEBUG = $ENABLE_DEBUG" +echo " RUST_TARGET = $RUST_TARGET" echo diff --git a/contrib/dockerfiles/aarch64-apple-darwin.dockerfile b/contrib/dockerfiles/aarch64-apple-darwin.dockerfile deleted file mode 100644 index 95eec30664..0000000000 --- a/contrib/dockerfiles/aarch64-apple-darwin.dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -ARG TARGET=aarch64-apple-darwin - -# ----------- -FROM --platform=linux/amd64 ubuntu:latest as builder -ARG TARGET -LABEL org.defichain.name="defichain-builder" -LABEL org.defichain.arch=${TARGET} - -WORKDIR /work -COPY ./make.sh . - -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_update_base -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps_osx_tools - -COPY . . -RUN ./make.sh clean-depends && ./make.sh build-deps -RUN ./make.sh clean-conf && ./make.sh build-conf -RUN ./make.sh build-make - -RUN mkdir /app && cd build/${TARGET} && \ - make -s prefix=/ DESTDIR=/app install - -# NOTE: These are not runnable images. So we do not add into a scratch base image. diff --git a/contrib/dockerfiles/aarch64-linux-gnu.dockerfile b/contrib/dockerfiles/aarch64-linux-gnu.dockerfile index 1578241026..61703e0507 100644 --- a/contrib/dockerfiles/aarch64-linux-gnu.dockerfile +++ b/contrib/dockerfiles/aarch64-linux-gnu.dockerfile @@ -9,16 +9,18 @@ LABEL org.defichain.arch=${TARGET} WORKDIR /work COPY ./make.sh . -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_update_base -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps_arm64 +# Temporary workaround until https://github.com/DeFiCh/ain/pull/1946 lands +# with specific ci-* methods +ENV PATH=/root/.cargo/bin:$PATH +RUN ./make.sh ci-setup-deps +RUN ./make.sh ci-setup-deps-target COPY . . RUN ./make.sh clean-depends && ./make.sh build-deps RUN ./make.sh clean-conf && ./make.sh build-conf RUN ./make.sh build-make -RUN mkdir /app && cd build/${TARGET} && \ +RUN mkdir /app && cd build/ && \ make -s prefix=/ DESTDIR=/app install # ----------- diff --git a/contrib/dockerfiles/arm-linux-gnueabihf.dockerfile b/contrib/dockerfiles/arm-linux-gnueabihf.dockerfile index 353d75bdec..cab571ec86 100644 --- a/contrib/dockerfiles/arm-linux-gnueabihf.dockerfile +++ b/contrib/dockerfiles/arm-linux-gnueabihf.dockerfile @@ -9,16 +9,18 @@ LABEL org.defichain.arch=${TARGET} WORKDIR /work COPY ./make.sh . -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_update_base -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps_armhf +# Temporary workaround until https://github.com/DeFiCh/ain/pull/1946 lands +# with specific ci-* methods +ENV PATH=/root/.cargo/bin:$PATH +RUN ./make.sh ci-setup-deps +RUN ./make.sh ci-setup-deps-target COPY . . RUN ./make.sh clean-depends && ./make.sh build-deps RUN ./make.sh clean-conf && ./make.sh build-conf RUN ./make.sh build-make -RUN mkdir /app && cd build/${TARGET} && \ +RUN mkdir /app && cd build/ && \ make -s prefix=/ DESTDIR=/app install # ----------- diff --git a/contrib/dockerfiles/noarch.dockerfile b/contrib/dockerfiles/noarch.dockerfile new file mode 100644 index 0000000000..a9a50960a6 --- /dev/null +++ b/contrib/dockerfiles/noarch.dockerfile @@ -0,0 +1,30 @@ +# This is required to be passed in for compilation. +# This is the dockerfile to use for adding support to new arch or or arch +# without end docker images, like darwin x84_64 and darwin aarch64 platforms +ARG TARGET=unknown + +# ----------- +FROM --platform=linux/amd64 ubuntu:latest as builder +ARG TARGET +LABEL org.defichain.name="defichain-builder" +LABEL org.defichain.arch=${TARGET} + +WORKDIR /work +COPY ./make.sh . + +# Temporary workaround until https://github.com/DeFiCh/ain/pull/1946 lands +# with specific ci-* methods +ENV PATH=/root/.cargo/bin:$PATH +RUN ./make.sh ci-setup-deps +RUN ./make.sh ci-setup-deps-target + +COPY . . +RUN ./make.sh clean-depends && ./make.sh build-deps +RUN ./make.sh clean-conf && ./make.sh build-conf +RUN ./make.sh build-make + +RUN mkdir /app && cd build/ && \ + make -s prefix=/ DESTDIR=/app install + +# NOTE: These may or may not be runnable binaries on the platform. +# So we do not add into a scratch base image. Extract and use as needed. diff --git a/contrib/dockerfiles/x86_64-apple-darwin.dockerfile b/contrib/dockerfiles/x86_64-apple-darwin.dockerfile deleted file mode 100644 index 965642ae45..0000000000 --- a/contrib/dockerfiles/x86_64-apple-darwin.dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -ARG TARGET=x86_64-apple-darwin - -# ----------- -FROM --platform=linux/amd64 ubuntu:latest as builder -ARG TARGET -LABEL org.defichain.name="defichain-builder" -LABEL org.defichain.arch=${TARGET} - -WORKDIR /work -COPY ./make.sh . - -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_update_base -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps_osx_tools - -COPY . . -RUN ./make.sh clean-depends && ./make.sh build-deps -RUN ./make.sh clean-conf && ./make.sh build-conf -RUN ./make.sh build-make - -RUN mkdir /app && cd build/${TARGET} && \ - make -s prefix=/ DESTDIR=/app install - -# NOTE: These are not runnable images. So we do not add into a scratch base image. diff --git a/contrib/dockerfiles/x86_64-pc-linux-gnu-clang.dockerfile b/contrib/dockerfiles/x86_64-pc-linux-gnu-clang.dockerfile deleted file mode 100644 index 087858fd1d..0000000000 --- a/contrib/dockerfiles/x86_64-pc-linux-gnu-clang.dockerfile +++ /dev/null @@ -1,53 +0,0 @@ -ARG TARGET=x86_64-pc-linux-gnu - -# ----------- -FROM --platform=linux/amd64 debian:10 as builder -ARG TARGET -ARG CLANG_VERSION=15 -LABEL org.defichain.name="defichain-builder" -LABEL org.defichain.arch=${TARGET} - -WORKDIR /work -COPY ./make.sh . - -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_update_base -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_llvm - -COPY . . -RUN ./make.sh clean-depends && \ - export MAKE_DEPS_ARGS="\ - x86_64_linux_CC=clang-${CLANG_VERSION} \ - x86_64_linux_CXX=clang++-${CLANG_VERSION}" && \ - ./make.sh build-deps -RUN export MAKE_CONF_ARGS="\ - CC=clang-${CLANG_VERSION} \ - CXX=clang++-${CLANG_VERSION}" && \ - ./make.sh clean-conf && ./make.sh build-conf -RUN ./make.sh build-make - -RUN mkdir /app && cd build/${TARGET} && \ - make -s prefix=/ DESTDIR=/app install - -# ----------- -### Actual image that contains defi binaries -FROM --platform=linux/amd64 debian:10 -ARG TARGET -ENV PATH=/app/bin:$PATH -LABEL org.defichain.name="defichain" -LABEL org.defichain.arch=${TARGET} - -WORKDIR /app -COPY --from=builder /app/. ./ - -RUN useradd --create-home defi && \ - mkdir -p /data && \ - chown defi:defi /data && \ - ln -s /data /home/defi/.defi - -VOLUME ["/data"] - -USER defi:defi -CMD [ "/app/bin/defid" ] - -EXPOSE 8554 8550 8551 18554 18550 18551 19554 19550 19551 20554 20550 20551 \ No newline at end of file diff --git a/contrib/dockerfiles/x86_64-pc-linux-gnu.dockerfile b/contrib/dockerfiles/x86_64-pc-linux-gnu.dockerfile index 19096c4eab..24a2abf8b3 100644 --- a/contrib/dockerfiles/x86_64-pc-linux-gnu.dockerfile +++ b/contrib/dockerfiles/x86_64-pc-linux-gnu.dockerfile @@ -9,16 +9,18 @@ LABEL org.defichain.arch=${TARGET} WORKDIR /work COPY ./make.sh . -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_update_base -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps +# Temporary workaround until https://github.com/DeFiCh/ain/pull/1946 lands +# with specific ci-* methods +ENV PATH=/root/.cargo/bin:$PATH +RUN ./make.sh ci-setup-deps +RUN ./make.sh ci-setup-deps-target COPY . . RUN ./make.sh clean-depends && ./make.sh build-deps -RUN export MAKE_CONF_ARGS="CC=gcc CXX=g++" && \ - ./make.sh clean-conf && ./make.sh build-conf +RUN ./make.sh clean-conf && ./make.sh build-conf RUN ./make.sh build-make -RUN mkdir /app && cd build/${TARGET} && \ +RUN mkdir /app && cd build/ && \ make -s prefix=/ DESTDIR=/app install # ----------- diff --git a/contrib/dockerfiles/x86_64-w64-mingw32.dockerfile b/contrib/dockerfiles/x86_64-w64-mingw32.dockerfile deleted file mode 100644 index 35d1f50278..0000000000 --- a/contrib/dockerfiles/x86_64-w64-mingw32.dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -ARG TARGET=x86_64-w64-mingw32 - -# ----------- -FROM --platform=linux/amd64 ubuntu:latest as builder -ARG TARGET -LABEL org.defichain.name="defichain-builder" -LABEL org.defichain.arch=${TARGET} - -WORKDIR /work -COPY ./make.sh . - -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_update_base -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps -RUN export DEBIAN_FRONTEND=noninteractive && ./make.sh pkg_install_deps_mingw_x86_64 - -RUN update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix -RUN update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix - -COPY . . -RUN ./make.sh clean-depends && ./make.sh build-deps -RUN ./make.sh clean-conf && ./make.sh build-conf -RUN ./make.sh build-make - -RUN mkdir /app && cd build/${TARGET} && \ - make -s prefix=/ DESTDIR=/app install - -# NOTE: These are not runnable images. So we do not add into a scratch base image. \ No newline at end of file diff --git a/depends/config.site.in b/depends/config.site.in index 4625308d16..d1cb20a14d 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -78,3 +78,6 @@ fi if test -n "@LDFLAGS@"; then LDFLAGS="@LDFLAGS@ $LDFLAGS" fi + +export PROTOC=${depends_prefix}/bin/protoc +export PROTOC_INCLUDE_DIR=${depends_prefix}/include diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index 7c880bc7c4..018f4b8c31 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -6,8 +6,11 @@ LD64_VERSION=609 OSX_SDK=$(SDK_PATH)/Xcode-$(XCODE_VERSION)-$(XCODE_BUILD_ID)-extracted-SDK-with-libcxx-headers -darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -Wno-unused-command-line-argument -Wno-unused-variable -darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -stdlib=libc++ -Wno-unused-command-line-argument -Wno-unused-variable +SILENCED_WARNINGS=-Wno-unused-command-line-argument -Wno-deprecated-non-prototype -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable +DARWIN_SHAREDCC_FLAGS=-target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) $(SILENCED_WARNINGS) + +darwin_CC=clang $(DARWIN_SHAREDCC_FLAGS) +darwin_CXX=clang++ -stdlib=libc++ $(DARWIN_SHAREDCC_FLAGS) darwin_CFLAGS=-pipe darwin_CXXFLAGS=$(darwin_CFLAGS) diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk index 5ad2b50337..44dfa3d135 100644 --- a/depends/packages/native_cctools.mk +++ b/depends/packages/native_cctools.mk @@ -56,8 +56,8 @@ endef # - Then, just do a move to the right location where autoconf later expects it define $(package)_preprocess_cmds sed -i.old 's/$$MAKE install-libtapi/$$MAKE DESTDIR=\"$$$$INSTALLPREFIX\" install-libtapi/' ./libtapi/install.sh && \ - CC=$($(package)_cc) CXX=$($(package)_cxx) INSTALLPREFIX="$($(package)_extract_dir)" ./libtapi/build.sh && \ - CC=$($(package)_cc) CXX=$($(package)_cxx) INSTALLPREFIX="$($(package)_extract_dir)" ./libtapi/install.sh && \ + CC="$($(package)_cc)" CXX="$($(package)_cxx)" INSTALLPREFIX="$($(package)_extract_dir)" ./libtapi/build.sh && \ + CC="$($(package)_cc)" CXX="$($(package)_cxx)" INSTALLPREFIX="$($(package)_extract_dir)" ./libtapi/install.sh && \ sed -i.old "/define HAVE_PTHREADS/d" $($(package)_build_subdir)/ld64/src/ld/InputFiles.h && \ mv "$($(package)_extract_dir)/$($(package)_extract_dir)/include" $($(package)_extract_dir)/ && \ mv "$($(package)_extract_dir)/$($(package)_extract_dir)/lib" $($(package)_extract_dir)/ diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index ced6602ea0..b2aa878ef8 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,12 +1,9 @@ -packages:=boost libevent +packages := boost libevent protobuf rapidcheck_packages = rapidcheck - -wallet_packages=bdb - -zmq_packages=zeromq - -upnp_packages=miniupnpc +wallet_packages = bdb +zmq_packages = zeromq +upnp_packages = miniupnpc darwin_native_packages = ifneq ($(build_os),darwin) diff --git a/depends/packages/protobuf.mk b/depends/packages/protobuf.mk new file mode 100644 index 0000000000..a439305230 --- /dev/null +++ b/depends/packages/protobuf.mk @@ -0,0 +1,48 @@ +package=protobuf +$(package)_version=22.2 +$(package)_download_path=https://github.com/protocolbuffers/protobuf/releases/download/v22.2/ + +# NOTE: protoc gets invoked on the BUILD OS during compile. So, we don't +# care about HOST OS, unlike all other dependencies. +# That is: protoc is run on the BUILD OS, not targeted to run on the +# HOST OS. + +# TODO: Fill up hashes later +ifeq ($(build_os)-$(build_arch),linux-x86_64) + $(package)_file_name=protoc-$($(package)_version)-linux-x86_64.zip + $(package)_sha256_hash=15f281b36897e0ffbbe3a02f687ff9108c7a0f98bb653fb433e4bd62e698abe7 +endif +ifeq ($(build_os)-$(build_arch),linux-aarch64) + $(package)_file_name=protoc-$($(package)_version)-linux-aarch_64.zip + $(package)_sha256_hash=aa2efbb2d481b7ad3c2428e0aa4dd6d813e4538e6c0a1cd4d921ac998187e07e +endif +ifeq ($(build_os)-$(build_arch),darwin-x86_64) + $(package)_file_name=protoc-$($(package)_version)-osx-x86_64.zip + $(package)_sha256_hash=8bb75680c376190d960ef1d073618c1103960f70dc4fafa7bde872029562aec1 +endif +ifeq ($(build_os)-$(build_arch),darwin-arm) + $(package)_file_name=protoc-$($(package)_version)-osx-aarch_64.zip + $(package)_sha256_hash=a196fd39acd312688b58e81266fd88e9f7799967c5439738c10345a29049261d +endif + +ifeq ($($(package)_file_name),) + $(error Unsupported build platform: $(BUILD)) +endif + +define $(package)_extract_cmds + mkdir -p $$($(package)_extract_dir) && echo "$$($(package)_sha256_hash) $$($(package)_source)" > $$($(package)_extract_dir)/.$$($(package)_file_name).hash && $(build_SHA256SUM) -c $$($(package)_extract_dir)/.$$($(package)_file_name).hash && unzip $$($(package)_source) +endef + +define $(package)_set_vars + $(package)_ROOT="$($(package)_staging_dir)/$(host_prefix)" +endef + +define $(package)_preprocess_cmds + rm -f readme.txt +endef + +define $(package)_build_cmds + mkdir -p $($(package)_ROOT) && \ + mv bin include $($(package)_ROOT)/ +endef + diff --git a/depends/packages/rust.mk b/depends/packages/rust.mk new file mode 100644 index 0000000000..a327f31b5c --- /dev/null +++ b/depends/packages/rust.mk @@ -0,0 +1,60 @@ +package=rust +$(package)_version=1.25.2 +$(package)_download_path=https://github.com/rust-lang/rustup/archive +$(package)_sha256_hash=dc9bb5d3dbac5cea9afa9b9c3c96fcf644a1e7ed6188a6b419dfe3605223b5f3 +$(package)_file_name=$($(package)_version).tar.gz + +# Note we don't support arm that doesn't have hf. So any armv7 or below +# wihtout hard floats, we just ignore it +define $(package)_set_vars + $(package)_ROOT="$($(package)_staging_dir)/$(host_prefix)" + $(package)_RUSTUP_HOME="$($(package)_staging_dir)/$(host_prefix)/.rustup" + $(package)_CARGO_HOME="$($(package)_staging_dir)/$(host_prefix)/" + + ifeq ($(host_os)-$(host_arch),linux-x86_64) + $(package)_target=x86_64-unknown-linux-gnu + endif + ifeq ($(host_os)-$(host_arch),linux-aarch64) + $(package)_target=aarch64-unknown-linux-gnu + endif + ifeq ($(host_os)-$(host_arch),linux-arm) + $(package)_target=armv7-unknown-linux-gnueabihf + endif + ifeq ($(host_os)-$(host_arch),darwin-x86_64) + $(package)_target=x86_64-apple-darwin + endif + ifeq ($(host_os)-$(host_arch),darwin-aarch64) + $(package)_target=aarch64-apple-darwin + endif + ifeq ($(host_os)-$(host_arch),mingw32-x86_64) + $(package)_target=x86_64-pc-windows-gnu + endif +endef + +define $(package)_preprocess_cmds + test "$($(package)_target)" = "" && \ + echo "Unsupported host platform: $(HOST)" && \ + exit 1 || exit 0 +endef + +# This autoinstalls the build os target +define $(package)_build_cmds + RUSTUP_HOME="$($(package)_RUSTUP_HOME)" \ + CARGO_HOME="$($(package)_CARGO_HOME)" \ + ./rustup-init.sh --no-modify-path -y +endef + +# We add the host os target +define $(package)_stage_cmds + RUSTUP_HOME="$($(package)_RUSTUP_HOME)" \ + CARGO_HOME="$($(package)_CARGO_HOME)" \ + $($(package)_CARGO_HOME)/bin/rustup target add \ + $($(package)_target) +endef + +define $(package)_postprocess_cmds + mkdir -p $($(package)_ROOT)/share/cargo && \ + mv $($(package)_ROOT)/env $($(package)_ROOT)/share/cargo/env && \ + perl -pi -e 's#$($(package)_staging_dir)/##' $($(package)_ROOT)/share/cargo/env +endef + diff --git a/doc/build-osx.md b/doc/build-osx.md index 0a31551acf..9415724d0e 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -24,6 +24,11 @@ Then install [Homebrew](https://brew.sh). brew install automake berkeley-db@4 libtool boost miniupnpc openssl pkg-config protobuf python libevent qrencode ``` +Rust toolchain is necessary for the build: +```shell +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + See [dependencies.md](dependencies.md) for a complete overview. If you want to build the disk image with `make deploy` (.dmg / optional), you need RSVG: @@ -103,6 +108,23 @@ You can monitor the download process by looking at the debug.log file: tail -f $HOME/Library/Application\ Support/Bitcoin/debug.log ``` +## Installing the rust toolchain (MacOS M1) +```shell +# default installation +curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y +# custom installation +curl https://sh.rustup.rs -sSf | sh +PATH=$PATH:~/.cargo/bin/cargo +rustup target add aarch64-apple-darwin +``` + +## Installing the protobuf compiler +```shell +brew install protobuf@3.20 +# ensure installation was successful by running +protoc --version +``` + ## Other commands: ```shell ./src/defid -daemon # Starts the defi daemon. diff --git a/doc/build-unix.md b/doc/build-unix.md index fb8ee8e599..45104e1fff 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -77,12 +77,16 @@ Finally, clang (often less resource hungry) can be used instead of gcc, which is Build requirements: - sudo apt-get install build-essential libtool autotools-dev automake pkg-config bsdmainutils python3 curl + sudo apt-get install build-essential libtool autotools-dev automake pkg-config bsdmainutils python3 curl clang-15 Now, you can either build from self-compiled [depends](/depends/README.md) or install the required dependencies: sudo apt-get install libssl-dev libevent-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev +Rust toolchain is necessary for the build: + + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + BerkeleyDB is required for the wallet. Ubuntu and Debian have their own `libdb-dev` and `libdb++-dev` packages, but these will install diff --git a/doc/build-windows.md b/doc/build-windows.md index e1b0a41784..eab075d5bf 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -62,6 +62,7 @@ First, install the general dependencies: sudo apt update sudo apt upgrade sudo apt install build-essential libtool autotools-dev automake pkg-config bsdmainutils curl git + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh A host toolchain (`build-essential`) is necessary because some dependency packages (such as `protobuf`) need to build host utilities that are used in the diff --git a/lib/.cargo/config.toml b/lib/.cargo/config.toml new file mode 100644 index 0000000000..e7ae27d7a9 --- /dev/null +++ b/lib/.cargo/config.toml @@ -0,0 +1,24 @@ +[build] +# We set this so that Makefile based +# builds and ad-hoc cargo invocations all +# result in the consistent compilation +target-dir = "../build/lib/target" + +# We temporarily ignore linkages until +# we fix cpp links +rustflags = [ + "-C", "link-arg=-z", + "-C", "link-arg=undefs", +] + +[target.x86_64-apple-darwin] +rustflags = [ + "-C", "link-arg=-undefined", + "-C", "link-arg=dynamic_lookup", +] + +[target.aarch64-apple-darwin] +rustflags = [ + "-C", "link-arg=-undefined", + "-C", "link-arg=dynamic_lookup", +] diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000000..23b60d3f4c --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1,4 @@ +target +*.cpp +*.h +*.bin diff --git a/lib/Cargo.lock b/lib/Cargo.lock new file mode 100644 index 0000000000..cedfa69a5a --- /dev/null +++ b/lib/Cargo.lock @@ -0,0 +1,7343 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli 0.26.2", +] + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli 0.27.2", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.9", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom 0.2.9", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + +[[package]] +name = "ain-cpp-imports" +version = "0.1.0" +dependencies = [ + "anyhow", + "cxx", + "cxx-build", +] + +[[package]] +name = "ain-evm" +version = "0.1.0" +dependencies = [ + "ain-cpp-imports", + "anyhow", + "bincode", + "ethbloom", + "ethereum", + "ethereum-types", + "evm", + "hash-db 0.16.0", + "hex", + "hex-literal", + "jsonrpsee-core 0.18.2", + "jsonrpsee-http-server", + "jsonrpsee-types 0.18.2", + "keccak-hash", + "lazy_static", + "libsecp256k1", + "log", + "lru 0.10.0", + "once_cell", + "primitive-types", + "rand 0.8.5", + "rlp", + "serde", + "serde_json", + "sha3", + "sp-core", + "statrs", + "tempdir", + "tokio", + "vsdb_core", + "vsdb_trie_db", + "vsdbsled", +] + +[[package]] +name = "ain-grpc" +version = "0.1.0" +dependencies = [ + "ain-cpp-imports", + "ain-evm", + "anyhow", + "async-trait", + "cxx", + "cxx-gen", + "env_logger", + "ethereum", + "ethereum-types", + "heck 0.4.1", + "hex", + "jsonrpsee 0.15.1", + "lazy_static", + "libsecp256k1", + "log", + "num-traits", + "prettyplease 0.2.4", + "primitive-types", + "proc-macro2", + "prost", + "prost-build", + "quote", + "regex", + "rlp", + "rustc-hex", + "serde", + "serde_json", + "syn 2.0.15", + "tokio", + "tonic", + "tonic-build", +] + +[[package]] +name = "ain-rs-exports" +version = "0.1.0" +dependencies = [ + "ain-evm", + "ain-grpc", + "cxx", + "cxx-gen", + "ethereum", + "log", + "primitive-types", + "proc-macro2", + "rlp", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "anymap" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "array-bytes" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "async-channel" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-lock" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-task" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" + +[[package]] +name = "async-trait" +version = "0.1.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "atk" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" +dependencies = [ + "atk-sys", + "bitflags", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.1.0", +] + +[[package]] +name = "atomic-polyfill" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" +dependencies = [ + "critical-section", +] + +[[package]] +name = "atomic-waker" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "auto_impl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "axum" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" +dependencies = [ + "async-trait", + "axum-core", + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa 1.0.6", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line 0.19.0", + "cc", + "cfg-if", + "libc", + "miniz_oxide 0.6.2", + "object 0.30.3", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "bcs" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd3ffe8b19a604421a5d461d4a70346223e535903fbc3067138bddbebddcf77" +dependencies = [ + "serde", + "thiserror", +] + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +dependencies = [ + "serde", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.64.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.109", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +dependencies = [ + "arrayref", + "arrayvec 0.7.2", + "constant_time_eq", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "blocking" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "log", +] + +[[package]] +name = "bounded-collections" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3888522b497857eb606bf51695988dba7096941822c1bcf676e3a929a9ae7a0" +dependencies = [ + "log", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bstr" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" + +[[package]] +name = "bumpslab" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e5816c875b50b9866d759fa24d46159dccab0d7942c0ccbfd700b4f45dd961e" +dependencies = [ + "bumpalo", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "cairo-rs" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" +dependencies = [ + "bitflags", + "cairo-sys-rs", + "glib", + "libc", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +dependencies = [ + "glib-sys", + "libc", + "system-deps 6.1.0", +] + +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-expr" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8790cf1286da485c72cf5fc7aeba308438800036ec67d89425924c4807268c9" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time 0.1.45", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "cocoa" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "constant_time_eq" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-entity" +version = "0.93.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f42ea692c7b450ad18b8c9889661505d51c09ec4380cf1c2d278dbb2da22cae1" +dependencies = [ + "serde", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "critical-section" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset 0.8.0", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossterm" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85525306c4291d1b73ce93c8acf9c339f9b213aef6c1d85c3830cbf1c16325c" +dependencies = [ + "bitflags", + "crossterm_winapi", + "libc", + "mio 0.7.14", + "parking_lot 0.11.2", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17" +dependencies = [ + "bitflags", + "crossterm_winapi", + "libc", + "mio 0.8.6", + "parking_lot 0.12.1", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +dependencies = [ + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.7", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.7", + "subtle", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.7", + "subtle", +] + +[[package]] +name = "cssparser" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa 0.4.8", + "matches", + "phf", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "curve25519-dalek" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b85542f99a2dfa2a1b8e192662741c9859a846b296bef1c92ef9b58b5a216" +dependencies = [ + "byteorder", + "digest 0.8.1", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "cxx" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.15", +] + +[[package]] +name = "cxx-gen" +version = "0.7.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee165c38de64e6761c2f38b7e9beee0721110f8585165987ef9db2a753ee4176" +dependencies = [ + "codespan-reporting", + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "darling" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "darling_macro" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "dioxus" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e24fd50a67f179f801ffe5316357d95c064676661614a38efd8902361dac9ef" +dependencies = [ + "dioxus-core 0.3.3", + "dioxus-core-macro 0.3.0", + "dioxus-hooks", + "dioxus-hot-reload", + "dioxus-html 0.3.1", + "dioxus-rsx 0.0.3", +] + +[[package]] +name = "dioxus-core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50fd75cb8f4752b122e3935eaa65b4c8c5c61dac2a305cb3d4c3422a01e0aee2" +dependencies = [ + "backtrace", + "bumpalo", + "futures-channel", + "futures-util", + "fxhash", + "indexmap", + "log", + "longest-increasing-subsequence", + "once_cell", + "slab", + "smallvec", +] + +[[package]] +name = "dioxus-core" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4d15b0bb9c58d015b2295f240600dd76e427758377569fa33783afc295706a" +dependencies = [ + "bumpalo", + "bumpslab", + "futures-channel", + "futures-util", + "indexmap", + "log", + "longest-increasing-subsequence", + "rustc-hash", + "serde", + "slab", + "smallbox", +] + +[[package]] +name = "dioxus-core-macro" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243fe485d0455d6f3645526970100a403fd037740af105cb5f175d8f4227baa6" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dioxus-core-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8eb3c0de91a0351ed6bb4ea866ce42d461792803b407df35d5a77db8d1e8276" +dependencies = [ + "dioxus-rsx 0.0.2", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dioxus-desktop" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a5e6f6c50cd4aab15d3a3c22c4747852f6c8abbd124a968f0111b119e5fa2" +dependencies = [ + "core-foundation", + "dioxus-core 0.3.3", + "dioxus-html 0.3.1", + "dioxus-interpreter-js", + "dunce", + "futures-channel", + "futures-util", + "infer", + "interprocess", + "log", + "objc", + "objc_id", + "serde", + "serde_json", + "thiserror", + "tokio", + "webbrowser", + "wry", +] + +[[package]] +name = "dioxus-hooks" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1311daf0cd7591ab055ae7dd90860ce69dcfdb11cc09e1deb9c8f208c8ee09a" +dependencies = [ + "dioxus-core 0.3.3", + "futures-channel", + "log", +] + +[[package]] +name = "dioxus-hot-reload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e478ed2d0f70aa51608e8672704e0f35925ddc7ad80a28d255bfe504dd5362bd" +dependencies = [ + "chrono", + "dioxus-core 0.3.3", + "dioxus-html 0.3.1", + "dioxus-rsx 0.0.3", + "execute", + "ignore", + "interprocess", + "notify", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "dioxus-html" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42fe33f30303e9acb0404e9c9aa61535ab50ad9e84f4809543881ee6a2b5abc" +dependencies = [ + "dioxus-core 0.2.1", +] + +[[package]] +name = "dioxus-html" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7682a6615e4e5a460cd3293ce420451abffb719c84c4b54e297b17365f601fb4" +dependencies = [ + "async-trait", + "dioxus-core 0.3.3", + "dioxus-rsx 0.0.3", + "enumset", + "euclid", + "keyboard-types", + "serde", + "serde-value", + "serde_repr", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "dioxus-interpreter-js" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360fdd7b22ac8859492efb2fbfd0e380d2208a442896ea54891424a67f984918" +dependencies = [ + "js-sys", + "sledgehammer_bindgen", + "sledgehammer_utils", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "dioxus-native-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafc8c6a562963ad62b6e831128b8224043aa4a3168d8b1bce611e9e35568ad5" +dependencies = [ + "anymap", + "dioxus-core 0.2.1", + "dioxus-core-macro 0.2.1", + "dioxus-html 0.2.1", + "fxhash", + "smallvec", + "stretch2", +] + +[[package]] +name = "dioxus-native-core-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb92b7b181b37138fb33added88b6e174eb2afc4cd512b6b80b3e8893efd67b" +dependencies = [ + "dioxus-native-core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dioxus-rsx" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42b7fee07fccc5c3fb9b341a0000db47fc4ab0a2a5bf268c71f6f1c9fd3ed598" +dependencies = [ + "dioxus-core 0.3.3", + "internment", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + +[[package]] +name = "dioxus-rsx" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8544632e20f462a64f26502c91e7cf6ae3b30d82956e70543644d2c16b6659d" +dependencies = [ + "dioxus-core 0.3.3", + "internment", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + +[[package]] +name = "dioxus-tui" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678794b6c1379a7e2c4918bc0fb4031673bc31ae9ee0ce48a0b71fa69c1b9a7c" +dependencies = [ + "anyhow", + "anymap", + "crossterm 0.23.2", + "dioxus-core 0.2.1", + "dioxus-html 0.2.1", + "dioxus-native-core", + "dioxus-native-core-macro", + "futures", + "fxhash", + "smallvec", + "stretch2", + "tokio", + "tui", +] + +[[package]] +name = "dioxus-web" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90cda9fc7992af131b4ce468ea4740669fb18983c209f9b95572e5fea82a57e" +dependencies = [ + "anyhow", + "console_error_panic_hook", + "dioxus-core 0.3.3", + "dioxus-html 0.3.1", + "dioxus-interpreter-js", + "futures-channel", + "futures-util", + "gloo-timers", + "js-sys", + "log", + "once_cell", + "rustc-hash", + "serde", + "serde-wasm-bindgen", + "serde_json", + "smallstr", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "dtoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" + +[[package]] +name = "dtoa-short" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde03329ae10e79ede66c9ce4dc930aa8599043b0743008548680f25b91502d6" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "dyn-clonable" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" +dependencies = [ + "dyn-clonable-impl", + "dyn-clone", +] + +[[package]] +name = "dyn-clonable-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dyn-clone" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", + "hex", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "enumset" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e875f1719c16de097dee81ed675e2d9bb63096823ed3f0ca827b7dea3028bbbb" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "environmental" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" + +[[package]] +name = "erased-serde" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2b0c2380453a92ea8b6c8e5f64ecaafccddde8ceab55ff7a8ac1029f894569" +dependencies = [ + "serde", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89fb87a9e103f71b903b80b670200b54cc67a07578f070681f1fffb7396fb7" +dependencies = [ + "bytes", + "ethereum-types", + "hash-db 0.15.2", + "hash256-std-hasher", + "parity-scale-codec", + "rlp", + "scale-info", + "serde", + "sha3", + "triehash", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "euclid" +version = "0.22.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f253bc5c813ca05792837a0ff4b3a580336b224512d48f7eda1d7dd9210787" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "evm" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1099df1dac16f32a136452ad98ee0f1ff42acd3e12ce65bea4462b61d656608a" +dependencies = [ + "auto_impl", + "ethereum", + "evm-core", + "evm-gasometer", + "evm-runtime", + "log", + "primitive-types", + "rlp", + "serde", + "sha3", +] + +[[package]] +name = "evm-core" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1f13264b044cb66f0602180f0bc781c29accb41ff560669a3ec15858d5b606" +dependencies = [ + "primitive-types", + "serde", +] + +[[package]] +name = "evm-gasometer" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d43eadc395bd1a52990787ca1495c26b0248165444912be075c28909a853b8c" +dependencies = [ + "evm-core", + "evm-runtime", + "primitive-types", +] + +[[package]] +name = "evm-runtime" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aa5b32f59ec582a5651978004e5c784920291263b7dcb6de418047438e37f4f" +dependencies = [ + "auto_impl", + "evm-core", + "primitive-types", + "sha3", +] + +[[package]] +name = "execute" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d9a9ea4c04632c16bc5c71a2fcc63d308481f7fc67eb1a1ce6315c44a426ae" +dependencies = [ + "execute-command-macro", + "execute-command-tokens", + "generic-array 0.14.7", +] + +[[package]] +name = "execute-command-macro" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5fbc65a0cf735106743f4c38c9a3671c1e734b5c2c20d21a3c93c696daa3157" +dependencies = [ + "execute-command-macro-impl", +] + +[[package]] +name = "execute-command-macro-impl" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55a9a55d1dab3b07854648d48e366f684aefe2ac78ae28cec3bf65e3cd53d9a3" +dependencies = [ + "execute-command-tokens", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "execute-command-tokens" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba569491c70ec8471e34aa7e9c0b9e82bb5d2464c0398442d17d3c4af814e5a" + +[[package]] +name = "fake" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a44c765350db469b774425ff1c833890b16ceb9612fb5d7c4bbdf4a1b55f876" +dependencies = [ + "rand 0.8.5", + "unidecode", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535" +dependencies = [ + "memoffset 0.8.0", + "rustc_version", +] + +[[package]] +name = "filetime" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "windows-sys 0.48.0", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide 0.7.1", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs4" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef5c93884e5cef757f63446122c2f420713c3e03f85540d09485b9415983b4a" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" +dependencies = [ + "bitflags", + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.1.0", +] + +[[package]] +name = "gdk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps 6.1.0", +] + +[[package]] +name = "gdkx11-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps 6.1.0", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] + +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" + +[[package]] +name = "gio" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-io", + "gio-sys", + "glib", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.1.0", + "winapi", +] + +[[package]] +name = "glib" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.15.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10c6ae9f6fa26f4fb2ac16b528d138d971ead56141de489f8111e259b9df3c4a" +dependencies = [ + "anyhow", + "heck 0.4.1", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "glib-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" +dependencies = [ + "libc", + "system-deps 6.1.0", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "globset" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +dependencies = [ + "aho-corasick 0.7.20", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gobject-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" +dependencies = [ + "glib-sys", + "libc", + "system-deps 6.1.0", +] + +[[package]] +name = "gtk" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" +dependencies = [ + "atk", + "bitflags", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "once_cell", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps 6.1.0", +] + +[[package]] +name = "gtk3-macros" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684c0456c086e8e7e9af73ec5b84e35938df394712054550e81558d21c44ab0d" +dependencies = [ + "anyhow", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "h2" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hash-db" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" + +[[package]] +name = "hash-db" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7d7786361d7425ae2fe4f9e407eb0efaa0840f5212d109cc018c40c35c6ab4" + +[[package]] +name = "hash256-std-hasher" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hash32-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59d2aba832b60be25c1b169146b27c64115470981b128ed84c8db18c1b03c6ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] + +[[package]] +name = "heapless" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "spin 0.9.8", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array 0.14.7", + "hmac 0.8.1", +] + +[[package]] +name = "html5ever" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.6", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa 1.0.6", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +dependencies = [ + "http", + "hyper", + "log", + "rustls 0.20.8", + "rustls-native-certs", + "tokio", + "tokio-rustls 0.23.4", + "webpki-roots", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" +dependencies = [ + "http", + "hyper", + "log", + "rustls 0.21.1", + "rustls-native-certs", + "tokio", + "tokio-rustls 0.24.0", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows 0.48.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +dependencies = [ + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "image" +version = "0.24.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-rational", + "num-traits", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "infer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6c16b11a665b26aeeb9b1d7f954cdeb034be38dd00adab4f2ae921a8fee804" +dependencies = [ + "cfb", +] + +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "internment" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a798d7677f07d6f1e77be484ea8626ddb1566194de399f1206306820c406371" +dependencies = [ + "hashbrown 0.12.3", + "parking_lot 0.12.1", +] + +[[package]] +name = "interprocess" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f2533f3be42fffe3b5e63b71aeca416c1c3bc33e4e27be018521e76b1f38fb" +dependencies = [ + "blocking", + "cfg-if", + "futures-core", + "futures-io", + "intmap", + "libc", + "once_cell", + "rustc_version", + "spinning", + "thiserror", + "to_method", + "winapi", +] + +[[package]] +name = "intmap" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9" + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix 0.37.19", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "javascriptcore-rs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c" +dependencies = [ + "bitflags", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 5.0.0", +] + +[[package]] +name = "jni" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonrpsee" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd0d559d5e679b1ab2f869b486a11182923863b1b3ee8b421763cdd707b783a" +dependencies = [ + "jsonrpsee-core 0.15.1", + "jsonrpsee-http-client 0.15.1", + "jsonrpsee-http-server", + "jsonrpsee-proc-macros", + "jsonrpsee-types 0.15.1", + "tracing", +] + +[[package]] +name = "jsonrpsee" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1822d18e4384a5e79d94dc9e4d1239cfa9fad24e55b44d2efeff5b394c9fece4" +dependencies = [ + "jsonrpsee-core 0.18.2", + "jsonrpsee-http-client 0.18.2", + "jsonrpsee-types 0.18.2", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3dc3e9cf2ba50b7b1d7d76a667619f82846caa39e8e8daa8a4962d74acaddca" +dependencies = [ + "anyhow", + "arrayvec 0.7.2", + "async-trait", + "beef", + "futures-channel", + "futures-util", + "globset", + "http", + "hyper", + "jsonrpsee-types 0.15.1", + "lazy_static", + "parking_lot 0.12.1", + "rand 0.8.5", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "unicase", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c6832a55f662b5a6ecc844db24b8b9c387453f923de863062c60ce33d62b81" +dependencies = [ + "anyhow", + "async-trait", + "beef", + "futures-util", + "hyper", + "jsonrpsee-types 0.18.2", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f7c0e2333ab2115c302eeb4f137c8a4af5ab609762df68bbda8f06496677c9" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls 0.23.2", + "jsonrpsee-core 0.15.1", + "jsonrpsee-types 0.15.1", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1705c65069729e3dccff6fd91ee431d5d31cabcf00ce68a62a2c6435ac713af9" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls 0.24.0", + "jsonrpsee-core 0.18.2", + "jsonrpsee-types 0.18.2", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", +] + +[[package]] +name = "jsonrpsee-http-server" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03802f0373a38c2420c70b5144742d800b509e2937edc4afb116434f07120117" +dependencies = [ + "futures-channel", + "futures-util", + "hyper", + "jsonrpsee-core 0.15.1", + "jsonrpsee-types 0.15.1", + "serde", + "serde_json", + "tokio", + "tracing", + "tracing-futures", +] + +[[package]] +name = "jsonrpsee-proc-macros" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd67957d4280217247588ac86614ead007b301ca2fa9f19c19f880a536f029e3" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e290bba767401b646812f608c099b922d8142603c9e73a50fb192d3ac86f4a0d" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5bf6c75ce2a4217421154adfc65a24d2b46e77286e59bba5d9fa6544ccc8f4" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-hash" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" +dependencies = [ + "primitive-types", + "tiny-keccak", +] + +[[package]] +name = "keccak-hasher" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ea4653859ca2266a86419d3f592d3f22e7a854b482f99180d2498507902048" +dependencies = [ + "hash-db 0.16.0", + "hash256-std-hasher", + "tiny-keccak", +] + +[[package]] +name = "keyboard-types" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7668b7cff6a51fe61cdde64cd27c8a220786f399501b57ebe36f7d8112fd68" +dependencies = [ + "bitflags", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "kqueue" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8fc60ba15bf51257aa9807a48a61013db043fcf3a78cb0d916e8e396dcad98" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587" +dependencies = [ + "bitflags", + "libc", +] + +[[package]] +name = "kuchiki" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ea8e9c6e031377cff82ee3001dc8026cdf431ed4e2e6b51f98ab8c73484a358" +dependencies = [ + "cssparser", + "html5ever", + "matches", + "selectors", +] + +[[package]] +name = "labs-dfeye" +version = "0.1.0" +dependencies = [ + "dioxus", + "dioxus-desktop", + "dioxus-tui", + "dioxus-web", +] + +[[package]] +name = "labs-grpc2" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "env_logger", + "erased-serde", + "fake", + "lazy_static", + "log", + "num-traits", + "prost", + "prost-build", + "rand 0.8.5", + "serde", + "serde_json", + "tonic", + "tonic-build", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "librocksdb-sys" +version = "0.10.0+7.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fe4d5874f5ff2bc616e55e8c6086d478fcda13faf9495768a4aa1c22042d30b" +dependencies = [ + "bindgen", + "bzip2-sys", + "cc", + "glob", + "libc", + "libz-sys", + "zstd-sys", +] + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libz-sys" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "linux-raw-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "longest-increasing-subsequence" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86" + +[[package]] +name = "lru" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" +dependencies = [ + "hashbrown 0.12.3", +] + +[[package]] +name = "lru" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03f1160296536f10c833a82dca22267d5486734230d47bf00bf435885814ba1e" +dependencies = [ + "hashbrown 0.13.2", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "markup5ever" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd" +dependencies = [ + "log", + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "matchit" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" + +[[package]] +name = "matrixmultiply" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memfd" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" +dependencies = [ + "rustix 0.37.19", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memory-db" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808b50db46293432a45e63bc15ea51e0ab4c0a1647b8eb114e31a3e698dd6fbe" +dependencies = [ + "hash-db 0.16.0", +] + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "merlin" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e261cf0f8b3c42ded9f7d2bb59dea03aa52bc8a1cbc7482f9fc3fd1229d3b42" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.5.1", + "zeroize", +] + +[[package]] +name = "metachain-cli" +version = "0.1.0" +dependencies = [ + "ain-grpc", + "ethereum", + "hex", + "jsonrpsee 0.18.2", + "primitive-types", + "serde", + "serde_json", + "structopt", + "tokio", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "mio" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.45.0", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "nalgebra" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d506eb7e08d6329505faa8a3a00a5dcc6de9f76e0c77e4b75763ae3c770831ff" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "rand 0.8.5", + "rand_distr", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "notify" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ea850aa68a06e48fdb069c0ec44d0d64c8dbffa49bf3b6f7f0a901fdea1ba9" +dependencies = [ + "bitflags", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "mio 0.8.6", + "walkdir", + "windows-sys 0.42.0", +] + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec 0.7.2", + "itoa 1.0.6", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "crc32fast", + "hashbrown 0.12.3", + "indexmap", + "memchr", +] + +[[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "ordered-float" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +dependencies = [ + "num-traits", +] + +[[package]] +name = "pango" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" +dependencies = [ + "bitflags", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.1.0", +] + +[[package]] +name = "parity-scale-codec" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ddb756ca205bd108aee3c62c6d3c994e1df84a59b9d6d4a5ea42ee1fd5a9a28" +dependencies = [ + "arrayvec 0.7.2", + "bitvec", + "byte-slice-cast", + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parity-wasm" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" + +[[package]] +name = "parking" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.7", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "windows-sys 0.45.0", +] + +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + +[[package]] +name = "pbkdf2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +dependencies = [ + "crypto-mac 0.11.1", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "petgraph" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_macros", + "phf_shared 0.8.0", + "proc-macro-hack", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "png" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide 0.7.1", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "prettyplease" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ceca8aaf45b5c46ec7ed39fff75f57290368c1846d33d24a122ca81416ab058" +dependencies = [ + "proc-macro2", + "syn 2.0.15", +] + +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease 0.1.25", + "prost", + "prost-types", + "regex", + "syn 1.0.109", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quote" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.9", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.9", + "redox_syscall 0.2.16", + "thiserror", +] + +[[package]] +name = "ref-cast" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43faa91b1c8b36841ee70e97188a869d37ae21759da6846d4be66de5bf7b12c" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "regex" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +dependencies = [ + "aho-corasick 1.0.1", + "memchr", + "regex-syntax 0.7.1", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rocksdb" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "015439787fce1e75d55f279078d33ff14b4af5d93d995e8838ee4631301c8a99" +dependencies = [ + "libc", + "librocksdb-sys", +] + +[[package]] +name = "ruc" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20d7f74d19a4608c0e78c2d742c31c1e864aeeecd003651aa3e64e0a91749276" +dependencies = [ + "once_cell", + "time 0.3.21", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.36.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a38f9520be93aba504e8ca974197f46158de5dcaa9fa04b57c57cd6a679d658" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.7", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +dependencies = [ + "base64 0.21.0", +] + +[[package]] +name = "rustls-webpki" +version = "0.100.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "safe_arch" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfdef77228a4c05dc94211441595746732131ad7f6530c6c18f045da7b7ab937" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53012eae69e5aa5c14671942a5dd47de59d4cdcff8532a6dd0e081faf1119482" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "schnellru" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +dependencies = [ + "ahash 0.8.3", + "cfg-if", + "hashbrown 0.13.2", +] + +[[package]] +name = "schnorrkel" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "curve25519-dalek 2.1.3", + "getrandom 0.1.16", + "merlin", + "rand 0.7.3", + "rand_core 0.5.1", + "sha2 0.8.2", + "subtle", + "zeroize", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scratch" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secp256k1" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +dependencies = [ + "cc", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "selectors" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +dependencies = [ + "bitflags", + "cssparser", + "derive_more", + "fxhash", + "log", + "matches", + "phf", + "phf_codegen", + "precomputed-hash", + "servo_arc", + "smallvec", + "thin-slice", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa 1.0.6", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + +[[package]] +name = "servo_arc" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.6", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "signal-hook" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio 0.7.14", + "mio 0.8.6", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "simba" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0b7840f121a46d63066ee7a99fc81dcabbc6105e437cae43528cea199b5a05f" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "simd-adler32" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "sledgehammer_bindgen" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b56abc5091d1a0671f24490664b5dfb1f6f73e0c7ac4d0ac01856809a45aa916" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sledgehammer_utils" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "095fd5332b21763203248070746b86b98c6167fc620af73d4cb2bc2d7d9cd815" +dependencies = [ + "lru 0.8.1", + "once_cell", + "rustc-hash", + "ux", +] + +[[package]] +name = "smallbox" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4679d6eef28b85020158619fc09769de89e90886c5de7157587d87cb72648faa" + +[[package]] +name = "smallstr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e922794d168678729ffc7e07182721a14219c65814e66e91b839a272fe5ae4f" +dependencies = [ + "smallvec", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "soup2" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0" +dependencies = [ + "bitflags", + "gio", + "glib", + "libc", + "once_cell", + "soup2-sys", +] + +[[package]] +name = "soup2-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" +dependencies = [ + "bitflags", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps 5.0.0", +] + +[[package]] +name = "sp-core" +version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7789372146f8ad40d0b40fad0596cb1db5771187a258eabe19b06f00767fcbd6" +dependencies = [ + "array-bytes", + "bitflags", + "blake2", + "bounded-collections", + "bs58", + "dyn-clonable", + "ed25519-zebra", + "futures", + "hash-db 0.16.0", + "hash256-std-hasher", + "impl-serde", + "lazy_static", + "libsecp256k1", + "log", + "merlin", + "parity-scale-codec", + "parking_lot 0.12.1", + "primitive-types", + "rand 0.8.5", + "regex", + "scale-info", + "schnorrkel", + "secp256k1", + "secrecy", + "serde", + "sp-core-hashing", + "sp-debug-derive", + "sp-externalities", + "sp-runtime-interface", + "sp-std", + "sp-storage", + "ss58-registry", + "substrate-bip39", + "thiserror", + "tiny-bip39", + "zeroize", +] + +[[package]] +name = "sp-core-hashing" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27449abdfbe41b473e625bce8113745e81d65777dd1d5a8462cf24137930dad8" +dependencies = [ + "blake2b_simd", + "byteorder", + "digest 0.10.6", + "sha2 0.10.6", + "sha3", + "sp-std", + "twox-hash", +] + +[[package]] +name = "sp-debug-derive" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62211eed9ef9dac4b9d837c56ccc9f8ee4fc49d9d9b7e6b9daf098fe173389ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp-externalities" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae0f275760689aaefe967943331d458cd99f5169d18364365d4cb584b246d1c" +dependencies = [ + "environmental", + "parity-scale-codec", + "sp-std", + "sp-storage", +] + +[[package]] +name = "sp-runtime-interface" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5d0cd80200bf85b8b064238b2508b69b6146b13adf36066ec5d924825af737" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "primitive-types", + "sp-externalities", + "sp-runtime-interface-proc-macro", + "sp-std", + "sp-storage", + "sp-tracing", + "sp-wasm-interface", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ae5b00aef477127ddb6177b3464ad1e2bdcc12ee913fc5dfc9d065c6cea89b" +dependencies = [ + "Inflector", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp-std" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de8eef39962b5b97478719c493bed2926cf70cb621005bbf68ebe58252ff986" + +[[package]] +name = "sp-storage" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad1f8c52d4700ac7bc42b3375679a6c6fc1fe876f4b40c6efdf36f933ef0291" +dependencies = [ + "impl-serde", + "parity-scale-codec", + "ref-cast", + "serde", + "sp-debug-derive", + "sp-std", +] + +[[package]] +name = "sp-tracing" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00fab60bf3d42255ce3f678903d3a2564662371c75623de4a1ffc7cac46143df" +dependencies = [ + "parity-scale-codec", + "sp-std", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sp-trie" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58401c53c08b6ecad83acd7e14534c8bbcb3fa73e81e26685e0ac70e51b00c56" +dependencies = [ + "ahash 0.8.3", + "hash-db 0.16.0", + "hashbrown 0.13.2", + "lazy_static", + "memory-db", + "nohash-hasher", + "parity-scale-codec", + "parking_lot 0.12.1", + "scale-info", + "schnellru", + "sp-core", + "sp-std", + "thiserror", + "tracing", + "trie-db", + "trie-root", +] + +[[package]] +name = "sp-wasm-interface" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "153b7374179439e2aa783c66ed439bd86920c67bbc95d34c76390561972bc02f" +dependencies = [ + "anyhow", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-std", + "wasmi", + "wasmtime", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spinning" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b" +dependencies = [ + "lock_api", +] + +[[package]] +name = "ss58-registry" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47a8ad42e5fc72d5b1eb104a5546937eaf39843499948bb666d6e93c62423b" +dependencies = [ + "Inflector", + "num-format", + "proc-macro2", + "quote", + "serde", + "serde_json", + "unicode-xid", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "statrs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d08e5e1748192713cc281da8b16924fb46be7b0c2431854eadc785823e5696e" +dependencies = [ + "approx", + "lazy_static", + "nalgebra", + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "stretch2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c8e640c9e28d216546bb5ebfd18e31e84347595743e092291c4047530b29701" +dependencies = [ + "arrayvec 0.7.2", + "hash32", + "hash32-derive", + "heapless", + "num-traits", + "typenum", +] + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot 0.12.1", + "phf_shared 0.10.0", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck 0.3.3", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "substrate-bip39" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c" +dependencies = [ + "hmac 0.11.0", + "pbkdf2 0.8.0", + "schnorrkel", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-deps" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e" +dependencies = [ + "cfg-expr 0.9.1", + "heck 0.3.3", + "pkg-config", + "toml 0.5.11", + "version-compare 0.0.11", +] + +[[package]] +name = "system-deps" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5fa6fb9ee296c0dc2df41a656ca7948546d061958115ddb0bcaae43ad0d17d2" +dependencies = [ + "cfg-expr 0.15.1", + "heck 0.4.1", + "pkg-config", + "toml 0.7.3", + "version-compare 0.1.1", +] + +[[package]] +name = "tao" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac8e6399427c8494f9849b58694754d7cc741293348a6836b6c8d2c5aa82d8e6" +dependencies = [ + "bitflags", + "cairo-rs", + "cc", + "cocoa", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dispatch", + "gdk", + "gdk-pixbuf", + "gdk-sys", + "gdkx11-sys", + "gio", + "glib", + "glib-sys", + "gtk", + "image", + "instant", + "jni 0.20.0", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc", + "once_cell", + "parking_lot 0.12.1", + "paste", + "png", + "raw-window-handle", + "scopeguard", + "serde", + "unicode-segmentation", + "uuid", + "windows 0.39.0", + "windows-implement", + "x11-dl", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "target-lexicon" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" + +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +dependencies = [ + "rand 0.4.6", + "remove_dir_all", +] + +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix 0.37.19", + "windows-sys 0.45.0", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thin-slice" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +dependencies = [ + "itoa 1.0.6", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] + +[[package]] +name = "tiny-bip39" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" +dependencies = [ + "anyhow", + "hmac 0.12.1", + "once_cell", + "pbkdf2 0.11.0", + "rand 0.8.5", + "rustc-hash", + "sha2 0.10.6", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "to_method" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8" + +[[package]] +name = "tokio" +version = "1.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +dependencies = [ + "autocfg", + "bytes", + "libc", + "mio 0.8.6", + "num_cpus", + "parking_lot 0.12.1", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls 0.20.8", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" +dependencies = [ + "rustls 0.21.1", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tonic" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" +dependencies = [ + "async-trait", + "axum", + "base64 0.21.0", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6fdaae4c2c638bb70fe42803a26fbd6fc6ac8c72f5c59f67ecc2a2dcabf4b07" +dependencies = [ + "prettyplease 0.1.25", + "proc-macro2", + "prost-build", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "ansi_term", + "chrono", + "lazy_static", + "matchers", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "trie-db" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "767abe6ffed88a1889671a102c2861ae742726f52e0a5a425b92c9fbfa7e9c85" +dependencies = [ + "hash-db 0.16.0", + "hashbrown 0.13.2", + "log", + "rustc-hex", + "smallvec", +] + +[[package]] +name = "trie-root" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ed310ef5ab98f5fa467900ed906cb9232dd5376597e00fd4cba2a449d06c0b" +dependencies = [ + "hash-db 0.16.0", +] + +[[package]] +name = "triehash" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1631b201eb031b563d2e85ca18ec8092508e262a3196ce9bd10a67ec87b9f5c" +dependencies = [ + "hash-db 0.15.2", + "rlp", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "tui" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ed0a32c88b039b73f1b6c5acbd0554bfa5b6be94467375fd947c4de3a02271" +dependencies = [ + "bitflags", + "cassowary", + "crossterm 0.22.1", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "digest 0.10.6", + "rand 0.8.5", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "unidecode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2" +dependencies = [ + "getrandom 0.2.9", +] + +[[package]] +name = "ux" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb3ff47e36907a6267572c1e398ff32ef78ac5131de8aa272e53846592c207e" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version-compare" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" + +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vsdb" +version = "0.55.0" +source = "git+https://github.com/defich/vsdb.git#54659a979f7215eefe6ca7239c96271d02f94f15" +dependencies = [ + "once_cell", + "parking_lot 0.12.1", + "ruc", + "serde", + "vsdb_core", +] + +[[package]] +name = "vsdb_core" +version = "0.55.6" +source = "git+https://github.com/defich/vsdb.git#54659a979f7215eefe6ca7239c96271d02f94f15" +dependencies = [ + "once_cell", + "parking_lot 0.12.1", + "rand 0.8.5", + "rocksdb", + "ruc", + "serde", + "threadpool", + "vsdbsled", +] + +[[package]] +name = "vsdb_hash_db" +version = "0.6.0" +source = "git+https://github.com/defich/vsdb.git#54659a979f7215eefe6ca7239c96271d02f94f15" +dependencies = [ + "bcs", + "hash-db 0.16.0", + "keccak-hasher", + "ruc", + "serde", + "sp-trie", + "trie-db", + "vsdb", +] + +[[package]] +name = "vsdb_trie_db" +version = "0.7.0" +source = "git+https://github.com/defich/vsdb.git#54659a979f7215eefe6ca7239c96271d02f94f15" +dependencies = [ + "ruc", + "serde", + "sp-trie", + "vsdb", + "vsdb_hash_db", +] + +[[package]] +name = "vsdbsled" +version = "0.34.8" +source = "git+https://github.com/defich/vsdbsled.git#a20d135447652d6d8ca97ce5830267515a7322e6" +dependencies = [ + "crc32fast", + "crossbeam-epoch", + "crossbeam-utils", + "fs4", + "fxhash", + "libc", + "log", + "parking_lot 0.12.1", + "zstd", +] + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.15", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "083abe15c5d88556b77bdf7aef403625be9e327ad37c62c4e4129af740168163" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb" + +[[package]] +name = "wasmi" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c326c93fbf86419608361a2c925a31754cf109da1b8b55737070b4d6669422" +dependencies = [ + "parity-wasm", + "wasmi-validation", + "wasmi_core", +] + +[[package]] +name = "wasmi-validation" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ff416ad1ff0c42e5a926ed5d5fab74c0f098749aa0ad8b2a34b982ce0e867b" +dependencies = [ + "parity-wasm", +] + +[[package]] +name = "wasmi_core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d20cb3c59b788653d99541c646c561c9dd26506f25c0cebfe810659c54c6d7" +dependencies = [ + "downcast-rs", + "libm", + "memory_units", + "num-rational", + "num-traits", +] + +[[package]] +name = "wasmparser" +version = "0.100.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64b20236ab624147dfbb62cf12a19aaf66af0e41b8398838b66e997d07d269d4" +dependencies = [ + "indexmap", + "url", +] + +[[package]] +name = "wasmtime" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a222f5fa1e14b2cefc286f1b68494d7a965f4bf57ec04c59bb62673d639af6" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "indexmap", + "libc", + "log", + "object 0.29.0", + "once_cell", + "paste", + "psm", + "serde", + "target-lexicon", + "wasmparser", + "wasmtime-environ", + "wasmtime-jit", + "wasmtime-runtime", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4407a7246e7d2f3d8fb1cf0c72fda8dbafdb6dd34d555ae8bea0e5ae031089cc" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-environ" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b8b50962eae38ee319f7b24900b7cf371f03eebdc17400c1dc8575fc10c9a7" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli 0.26.2", + "indexmap", + "log", + "object 0.29.0", + "serde", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-jit" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffaed4f9a234ba5225d8e64eac7b4a5d13b994aeb37353cde2cbeb3febda9eaa" +dependencies = [ + "addr2line 0.17.0", + "anyhow", + "bincode", + "cfg-if", + "cpp_demangle", + "gimli 0.26.2", + "log", + "object 0.29.0", + "rustc-demangle", + "serde", + "target-lexicon", + "wasmtime-environ", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed41cbcbf74ce3ff6f1d07d1b707888166dc408d1a880f651268f4f7c9194b2" +dependencies = [ + "once_cell", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a28ae1e648461bfdbb79db3efdaee1bca5b940872e4175390f465593a2e54c" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-runtime" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e704b126e4252788ccfc3526d4d4511d4b23c521bf123e447ac726c14545217b" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "indexmap", + "libc", + "log", + "mach", + "memfd", + "memoffset 0.6.5", + "paste", + "rand 0.8.5", + "rustix 0.36.13", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-jit-debug", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-types" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e5572c5727c1ee7e8f28717aaa8400e4d22dcbd714ea5457d85b5005206568" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", + "wasmparser", +] + +[[package]] +name = "web-sys" +version = "0.3.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webbrowser" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b692165700260bbd40fbc5ff23766c03e339fbaca907aeea5cb77bf0a553ca83" +dependencies = [ + "core-foundation", + "dirs", + "jni 0.21.1", + "log", + "ndk-context", + "objc", + "raw-window-handle", + "url", + "web-sys", +] + +[[package]] +name = "webkit2gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f859735e4a452aeb28c6c56a852967a8a76c8eb1cc32dbf931ad28a13d6370" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup2", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3" +dependencies = [ + "atk-sys", + "bitflags", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pango-sys", + "pkg-config", + "soup2-sys", + "system-deps 6.1.0", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + +[[package]] +name = "webview2-com" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a769c9f1a64a8734bde70caafac2b96cada12cd4aefa49196b3a386b8b4178" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows 0.39.0", + "windows-implement", +] + +[[package]] +name = "webview2-com-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "webview2-com-sys" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac48ef20ddf657755fdcda8dfed2a7b4fc7e4581acce6fe9b88c3d64f29dee7" +dependencies = [ + "regex", + "serde", + "serde_json", + "thiserror", + "windows 0.39.0", + "windows-bindgen", + "windows-metadata", +] + +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + +[[package]] +name = "wide" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0496a71f3cc6bc4bf0ed91346426a5099e93d89807e663162dc5a1069ff65" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" +dependencies = [ + "windows-implement", + "windows_aarch64_msvc 0.39.0", + "windows_i686_gnu 0.39.0", + "windows_i686_msvc 0.39.0", + "windows_x86_64_gnu 0.39.0", + "windows_x86_64_msvc 0.39.0", +] + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-bindgen" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68003dbd0e38abc0fb85b939240f4bce37c43a5981d3df37ccbaaa981b47cb41" +dependencies = [ + "windows-metadata", + "windows-tokens", +] + +[[package]] +name = "windows-implement" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba01f98f509cb5dc05f4e5fc95e535f78260f15fea8fe1a8abdd08f774f1cee7" +dependencies = [ + "syn 1.0.109", + "windows-tokens", +] + +[[package]] +name = "windows-metadata" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows-tokens" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +dependencies = [ + "memchr", +] + +[[package]] +name = "wry" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c1ad8e2424f554cc5bdebe8aa374ef5b433feff817aebabca0389961fc7ef98" +dependencies = [ + "base64 0.13.1", + "block", + "cocoa", + "core-graphics", + "crossbeam-channel", + "dunce", + "gdk", + "gio", + "glib", + "gtk", + "html5ever", + "http", + "kuchiki", + "libc", + "log", + "objc", + "objc_id", + "once_cell", + "serde", + "serde_json", + "sha2 0.10.6", + "soup2", + "tao", + "thiserror", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows 0.39.0", + "windows-implement", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.8+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +dependencies = [ + "cc", + "libc", + "pkg-config", +] diff --git a/lib/Cargo.toml b/lib/Cargo.toml new file mode 100644 index 0000000000..c796f507cf --- /dev/null +++ b/lib/Cargo.toml @@ -0,0 +1,18 @@ +[workspace] +members = [ + "ain-*", + "cli", + "labs-grpc2", + "labs-dfeye", +] + +default-members = [ + "ain-*", +] + +[profile.release] +lto = true + +[patch.crates-io] +vsdb = { git = 'https://github.com/defich/vsdb.git' } +vsdbsled = { git = 'https://github.com/defich/vsdbsled.git' } diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000000..6ba80834aa --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,82 @@ +CARGO := $(if $(CARGO),$(CARGO),cargo) + +# RUST_TARGET is set from configure. Can be empty. If it is we skip +# setting target. This is done to emulate cargo's default behavior where +# it puts things into `target/` directly where no `--target ` +# is set. If set, it uses `target/` and there's no way to force +# cargo to always just stick to one. +# +# If it's empty, this collapses dir for SPECIFIC_TARGET_DIR to retain +# cargo's behavior +TARGET = $(if $(RUST_TARGET),$(RUST_TARGET),) + +# This is set from configure +ENABLE_DEBUG ?= +# We use DEBUG as well, since that's the more conventional +# setup. Either of them set will result in debug builds +DEBUG ?= $(ENABLE_DEBUG) + +TARGET_DIR ?= $(abs_builddir)/target +SPECIFIC_TARGET_DIR = $(TARGET_DIR)/$(TARGET)/$(if $(DEBUG),debug,release) +CARGO_MANIFEST_PATH = $(abs_srcdir)/Cargo.toml + +# We're resetting DESTDIR so that nested autotools based builds +# don't end up in unexpected places (Currently protobuf-src is affected) + +.PHONY: +all: build + +.PHONY: +build: + DESTDIR= TARGET_DIR="$(TARGET_DIR)" \ + CC="$(CC)" CXX="$(CXX)" \ + CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" \ + LDFLAGS="$(LDFLAGS)" AR="$(AR)" NM="$(NM)" RANLIB="$(RANLIB)" \ + PROTOC="$(PROTOC)" PROTOC_INCLUDE_DIR="$(PROTOC_INCLUDE_DIR)" \ + $(CARGO) build \ + --manifest-path "$(CARGO_MANIFEST_PATH)" \ + --target-dir "$(TARGET_DIR)" \ + $(if $(DEBUG),,--release) \ + $(if $(TARGET),--target $(TARGET),) && \ + cp $(SPECIFIC_TARGET_DIR)/libain_rs_exports.a $(TARGET_DIR)/lib/ + +.PHONY: +check: + DESTDIR= TARGET_DIR="$(TARGET_DIR)" \ + CC="$(CC)" CXX="$(CXX)" \ + CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" \ + LDFLAGS="$(LDFLAGS)" AR="$(AR)" NM="$(NM)" RANLIB="$(RANLIB)" \ + PROTOC="$(PROTOC)" PROTOC_INCLUDE_DIR="$(PROTOC_INCLUDE_DIR)" \ + $(CARGO) test \ + --manifest-path "$(CARGO_MANIFEST_PATH)" \ + --target-dir "$(TARGET_DIR)" \ + $(if $(TARGET),--target $(TARGET),) + +.PHONY: +clippy: + DESTDIR= TARGET_DIR="$(TARGET_DIR)" \ + CC="$(CC)" CXX="$(CXX)" \ + CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" \ + LDFLAGS="$(LDFLAGS)" AR="$(AR)" NM="$(NM)" RANLIB="$(RANLIB)" \ + PROTOC="$(PROTOC)" PROTOC_INCLUDE_DIR="$(PROTOC_INCLUDE_DIR)" \ + $(CARGO) clippy \ + --manifest-path "$(CARGO_MANIFEST_PATH)" \ + --target-dir "$(TARGET_DIR)" \ + $(if $(TARGET),--target $(TARGET),) + +.PHONY: +fmt-check: + $(CARGO) fmt --all --check \ + --manifest-path "$(CARGO_MANIFEST_PATH)" + +.PHONY: +fmt: + $(CARGO) fmt --all \ + --manifest-path "$(CARGO_MANIFEST_PATH)" + +.PHONY: +clean-local: + $(CARGO) clean \ + --manifest-path "$(CARGO_MANIFEST_PATH)" \ + --target-dir "$(TARGET_DIR)" && \ + rm -rf $(TARGET_DIR)/{include,lib,src} diff --git a/lib/ain-cpp-imports/.gitignore b/lib/ain-cpp-imports/.gitignore new file mode 100644 index 0000000000..355298f418 --- /dev/null +++ b/lib/ain-cpp-imports/.gitignore @@ -0,0 +1,14 @@ +*.o +*.so +*.rlib +*.dll +*.swp +*.exe +*.iml +.idea +target +**/result +tests.bin +Cargo.lock +*.cpp +*.h diff --git a/lib/ain-cpp-imports/Cargo.toml b/lib/ain-cpp-imports/Cargo.toml new file mode 100644 index 0000000000..d766b82d44 --- /dev/null +++ b/lib/ain-cpp-imports/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ain-cpp-imports" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cxx = "1.0" + +[build-dependencies] +anyhow = "1.0.70" +cxx-build = "1.0" diff --git a/lib/ain-cpp-imports/build.rs b/lib/ain-cpp-imports/build.rs new file mode 100644 index 0000000000..43e071140f --- /dev/null +++ b/lib/ain-cpp-imports/build.rs @@ -0,0 +1,65 @@ +use anyhow::{format_err, Result}; +use std::env; +use std::path::PathBuf; + +fn main() -> Result<()> { + let pkg_name = env::var("CARGO_PKG_NAME")?; + let manifest_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); + + let cpp_src_path = &manifest_path + .parent() + .and_then(std::path::Path::parent) + .map(|x| x.join("src")) + .ok_or(format_err!("path err"))?; + + let ffi_rs_src_path = &manifest_path.join("src/bridge.rs"); + let ffi_exports_h_path = &cpp_src_path.join("ffi/ffiexports.h"); + + let mut cxx = cxx_build::bridge(ffi_rs_src_path); + cxx.include(cpp_src_path) + .flag("-std=c++17") + .flag("-Wno-unused-parameter") + .cpp_link_stdlib(if cfg!(target_os = "macos") { + "c++" + } else { + "stdc++" + }); + + // Note: For windows, we set the defines to the correct headers are used. + // The cfg! targets can't be used, since the detection heuristic for cc-rs + // is slightly different. But we can infer it from TARGET + let target = env::var("TARGET")?; + if target.contains("windows") { + cxx.define("_MT", None) + .define("WIN32", None) + .define("_WIN32", None) + .define("__GLIBCXX__", None) + // .define("WIN32_LEAN_AND_MEAN", None) + .define("_WINDOWS", None) + .define("_WIN32_WINNT", "0x0601") + .static_flag(true); + } + + cxx.compile(pkg_name.as_str()); + + let path_utf8_err = || format_err!("path utf8 err"); + + println!( + "cargo:rerun-if-changed={}", + ffi_rs_src_path.to_str().ok_or_else(path_utf8_err)? + ); + println!( + "cargo:rerun-if-changed={}", + &ffi_exports_h_path.to_str().ok_or_else(path_utf8_err)? + ); + // Using a direct path for now + let git_head_path = manifest_path.join("../../.git/HEAD"); + if git_head_path.exists() { + println!( + "cargo:rerun-if-changed={}", + git_head_path.to_str().ok_or_else(path_utf8_err)? + ); + } + + Ok(()) +} diff --git a/lib/ain-cpp-imports/src/bridge.rs b/lib/ain-cpp-imports/src/bridge.rs new file mode 100644 index 0000000000..811903d44c --- /dev/null +++ b/lib/ain-cpp-imports/src/bridge.rs @@ -0,0 +1,20 @@ +#[cxx::bridge] +pub mod ffi { + unsafe extern "C++" { + include!("ffi/ffiexports.h"); + + fn getChainId() -> u64; + fn isMining() -> bool; + fn publishEthTransaction(data: Vec) -> String; + fn getAccounts() -> Vec; + fn getDatadir() -> String; + fn getNetwork() -> String; + fn getDifficulty(_block_hash: [u8; 32]) -> u32; + fn getChainWork(_block_hash: [u8; 32]) -> [u8; 32]; + fn getPoolTransactions() -> Vec; + fn getNativeTxSize(data: Vec) -> u64; + fn getMinRelayTxFee() -> u64; + fn getEthPrivKey(key_id: [u8; 20]) -> [u8; 32]; + fn getStateInputJSON() -> String; + } +} diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs new file mode 100644 index 0000000000..4e81a4d5a7 --- /dev/null +++ b/lib/ain-cpp-imports/src/lib.rs @@ -0,0 +1,123 @@ +use std::error::Error; + +#[cfg(not(any(test, bench, example, doc)))] +mod bridge; + +#[cfg(not(any(test, bench, example, doc)))] +use bridge::ffi; + +#[cfg(any(test, bench, example, doc))] +#[allow(non_snake_case)] +mod ffi { + const UNIMPL_MSG: &str = "This cannot be used on a test path"; + pub fn getChainId() -> u64 { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn isMining() -> bool { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn publishEthTransaction(_data: Vec) -> String { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getAccounts() -> Vec { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getDatadir() -> String { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getNetwork() -> String { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getDifficulty(_block_hash: [u8; 32]) -> u32 { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getChainWork(_block_hash: [u8; 32]) -> [u8; 32] { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getPoolTransactions() -> Vec { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getNativeTxSize(_data: Vec) -> u64 { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getMinRelayTxFee() -> u64 { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getEthPrivKey(_key_id: [u8; 20]) -> [u8; 32] { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getStateInputJSON() -> String { + unimplemented!("{}", UNIMPL_MSG) + } +} + +pub fn get_chain_id() -> Result> { + let chain_id = ffi::getChainId(); + Ok(chain_id) +} + +pub fn is_mining() -> Result> { + let is_mining = ffi::isMining(); + Ok(is_mining) +} + +pub fn publish_eth_transaction(data: Vec) -> Result> { + let publish = ffi::publishEthTransaction(data); + Ok(publish) +} + +pub fn get_accounts() -> Result, Box> { + let accounts = ffi::getAccounts(); + Ok(accounts) +} + +pub fn get_datadir() -> Result> { + let datadir = ffi::getDatadir(); + Ok(datadir) +} + +pub fn get_network() -> String { + ffi::getNetwork() +} + +pub fn get_difficulty(block_hash: [u8; 32]) -> Result> { + let bits = ffi::getDifficulty(block_hash); + Ok(bits) +} + +pub fn get_chainwork(block_hash: [u8; 32]) -> Result<[u8; 32], Box> { + let chainwork = ffi::getChainWork(block_hash); + Ok(chainwork) +} + +pub fn get_pool_transactions() -> Result, Box> { + let transactions = ffi::getPoolTransactions(); + Ok(transactions) +} + +pub fn get_native_tx_size(data: Vec) -> Result> { + let tx_size = ffi::getNativeTxSize(data); + Ok(tx_size) +} + +pub fn get_min_relay_tx_fee() -> Result> { + let tx_fee = ffi::getMinRelayTxFee(); + Ok(tx_fee) +} + +pub fn get_eth_priv_key(key_id: [u8; 20]) -> Result<[u8; 32], Box> { + let eth_key = ffi::getEthPrivKey(key_id); + Ok(eth_key) +} + +pub fn get_state_input_json() -> Option { + let json_path = ffi::getStateInputJSON(); + if json_path.is_empty() { + None + } else { + Some(json_path) + } +} + +#[cfg(test)] +mod tests {} diff --git a/lib/ain-evm/.gitignore b/lib/ain-evm/.gitignore new file mode 100644 index 0000000000..355298f418 --- /dev/null +++ b/lib/ain-evm/.gitignore @@ -0,0 +1,14 @@ +*.o +*.so +*.rlib +*.dll +*.swp +*.exe +*.iml +.idea +target +**/result +tests.bin +Cargo.lock +*.cpp +*.h diff --git a/lib/ain-evm/Cargo.toml b/lib/ain-evm/Cargo.toml new file mode 100644 index 0000000000..b305c95d96 --- /dev/null +++ b/lib/ain-evm/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "ain-evm" +version = "0.1.0" +edition = "2021" + +[dependencies] +ain-cpp-imports = { path = "../ain-cpp-imports" } + +evm = { version = "0.39", default-features = false, features = ["with-serde"] } +primitive-types = { version = "0.12", default-features = false, features = ["serde"] } +log = "0.4" +rlp = "0.5.2" +libsecp256k1 = "0.7.1" +ethereum = "0.14.0" +sha3 = "0.10.6" +hex = "0.4.3" +hex-literal = "0.4" +anyhow = "1.0" +bincode = "1.3.3" +rand = "0.8.5" +keccak-hash = "0.10.0" +serde = { version = "1.0", features = ["derive"] } +ethbloom = "0.13.0" +ethereum-types = "0.14.1" +serde_json = "1.0.96" +statrs = "0.16.0" + +# Trie dependencies +hash-db = "0.16.0" +sp-core = "20.0.0" +vsdb_trie_db = { version = "0.7.0", git = "https://github.com/defich/vsdb.git", features = ["rocks_engine"] } +vsdb_core = { version = "0.55.0", git = "https://github.com/defich/vsdb.git", features = ["rocks_engine", "compress"] } +vsdbsled = { git = "https://github.com/defich/vsdbsled.git" } + +# Runtime dependencies +lazy_static = "1.4" +jsonrpsee-core = "0.18" +jsonrpsee-http-server = "0.15" +jsonrpsee-types = "0.18" +tokio = { version = "1.1", features = ["rt-multi-thread"] } + +# Cache dependencies +lru = "0.10.0" + +[dev-dependencies] +tempdir = "0.3.7" +once_cell = "1.17.1" diff --git a/lib/ain-evm/src/backend.rs b/lib/ain-evm/src/backend.rs new file mode 100644 index 0000000000..593da0b26b --- /dev/null +++ b/lib/ain-evm/src/backend.rs @@ -0,0 +1,390 @@ +use ethereum::{Account, Log}; +use evm::backend::{Apply, ApplyBackend, Backend, Basic}; +use hash_db::Hasher as _; +use log::{debug, trace}; +use primitive_types::{H160, H256, U256}; +use rlp::{Decodable, Encodable, Rlp}; +use sp_core::hexdisplay::AsBytesRef; +use sp_core::Blake2Hasher; +use vsdb_trie_db::MptOnce; + +use crate::{ + storage::{traits::BlockStorage, Storage}, + traits::BridgeBackend, + transaction::SignedTx, + trie::TrieDBStore, +}; + +type Hasher = Blake2Hasher; + +fn is_empty_account(account: &Account) -> bool { + account.balance.is_zero() && account.nonce.is_zero() && account.code_hash.is_zero() +} + +#[derive(Default, Debug)] +pub struct Vicinity { + pub gas_price: U256, + pub origin: H160, + pub beneficiary: H160, + pub block_number: U256, + pub timestamp: U256, + pub gas_limit: U256, + pub block_base_fee_per_gas: U256, + pub block_randomness: Option, +} + +pub struct EVMBackend { + state: MptOnce, + trie_store: Arc, + storage: Arc, + pub vicinity: Vicinity, +} + +type Result = std::result::Result; + +impl EVMBackend { + pub fn from_root( + state_root: H256, + trie_store: Arc, + storage: Arc, + vicinity: Vicinity, + ) -> Result { + let state = trie_store + .trie_db + .trie_restore(&[0], None, state_root.into()) + .map_err(|e| EVMBackendError::TrieRestoreFailed(e.to_string()))?; + + Ok(EVMBackend { + state, + trie_store, + storage, + vicinity, + }) + } + + pub fn apply>( + &mut self, + address: H160, + basic: Basic, + code: Option>, + storage: I, + reset_storage: bool, + ) -> Result { + let account = self.get_account(address).unwrap_or(Account { + nonce: U256::zero(), + balance: U256::zero(), + storage_root: H256::zero(), + code_hash: H256::zero(), + }); + + let mut storage_trie = if reset_storage || is_empty_account(&account) { + self.trie_store + .trie_db + .trie_create(address.as_bytes(), None, true) + .map_err(|e| EVMBackendError::TrieCreationFailed(e.to_string()))? + } else { + self.trie_store + .trie_db + .trie_restore(address.as_bytes(), None, account.storage_root.into()) + .map_err(|e| EVMBackendError::TrieRestoreFailed(e.to_string()))? + }; + + storage.into_iter().for_each(|(k, v)| { + let _ = storage_trie.insert(k.as_bytes(), v.as_bytes()); + }); + + let code_hash = code.map_or(account.code_hash, |code| { + let code_hash = Hasher::hash(&code); + self.storage.put_code(code_hash, code); + code_hash + }); + + let new_account = Account { + nonce: basic.nonce, + balance: basic.balance, + code_hash, + storage_root: storage_trie.commit().into(), + }; + + self.state + .insert(address.as_bytes(), new_account.rlp_bytes().as_ref()) + .map_err(|e| EVMBackendError::TrieError(format!("{e}")))?; + + Ok(new_account) + } + + pub fn commit(&mut self) -> H256 { + self.state.commit().into() + } + + // Read-only state root. Does not commit changes to database + pub fn root(&self) -> H256 { + self.state.root().into() + } + + pub fn update_vicinity_from_tx(&mut self, tx: &SignedTx) { + self.vicinity = Vicinity { + origin: tx.sender, + gas_price: tx.gas_price(), + gas_limit: tx.gas_limit(), + ..self.vicinity + }; + } + + pub fn deduct_prepay_gas(&mut self, sender: H160, prepay_gas: U256) { + trace!(target: "backend", "[deduct_prepay_gas] Deducting {:#x} from {:#x}", prepay_gas, sender); + + let basic = self.basic(sender); + let balance = basic.balance.saturating_sub(prepay_gas); + let new_basic = Basic { balance, ..basic }; + self.apply(sender, new_basic, None, Vec::new(), false) + .expect("Error deducting account balance"); + } + + pub fn refund_unused_gas( + &mut self, + sender: H160, + gas_limit: U256, + used_gas: U256, + gas_price: U256, + ) { + let refund_gas = gas_limit.saturating_sub(used_gas); + let refund_amount = refund_gas.saturating_mul(gas_price); + + trace!(target: "backend", "[refund_unused_gas] Refunding {:#x} to {:#x}", refund_amount, sender); + + let basic = self.basic(sender); + let new_basic = Basic { + balance: basic.balance.saturating_add(refund_amount), + ..basic + }; + self.apply(sender, new_basic, None, Vec::new(), false) + .expect("Error refunding account balance"); + } +} + +impl EVMBackend { + pub fn get_account(&self, address: H160) -> Option { + self.state + .get(address.as_bytes()) + .unwrap_or(None) + .and_then(|addr| Account::decode(&Rlp::new(addr.as_bytes_ref())).ok()) + } +} + +impl Backend for EVMBackend { + fn gas_price(&self) -> U256 { + trace!(target: "backend", "[EVMBackend] Getting gas"); + self.vicinity.gas_price + } + + fn origin(&self) -> H160 { + trace!(target: "backend", "[EVMBackend] Getting origin"); + self.vicinity.origin + } + + fn block_hash(&self, number: U256) -> H256 { + trace!(target: "backend", "[EVMBackend] Getting block hash for block {:x?}", number); + self.storage + .get_block_by_number(&number) + .map_or(H256::zero(), |block| block.header.hash()) + } + + fn block_number(&self) -> U256 { + trace!(target: "backend", "[EVMBackend] Getting current block number"); + self.vicinity.block_number + } + + fn block_coinbase(&self) -> H160 { + self.vicinity.beneficiary + } + + fn block_timestamp(&self) -> U256 { + self.vicinity.timestamp + } + + fn block_difficulty(&self) -> U256 { + U256::zero() + } + + fn block_randomness(&self) -> Option { + self.vicinity.block_randomness + } + + fn block_gas_limit(&self) -> U256 { + self.vicinity.gas_limit + } + + fn block_base_fee_per_gas(&self) -> U256 { + trace!(target: "backend", "[EVMBackend] Getting block_base_fee_per_gas"); + self.vicinity.block_base_fee_per_gas + } + + fn chain_id(&self) -> U256 { + U256::from(ain_cpp_imports::get_chain_id().expect("Error getting chain_id")) + } + + fn exists(&self, address: H160) -> bool { + self.state.contains(address.as_bytes()).unwrap_or(false) + } + + fn basic(&self, address: H160) -> Basic { + trace!(target: "backend", "[EVMBackend] basic for address {:x?}", address); + self.get_account(address) + .map(|account| Basic { + balance: account.balance, + nonce: account.nonce, + }) + .unwrap_or_default() + } + + fn code(&self, address: H160) -> Vec { + trace!(target: "backend", "[EVMBackend] code for address {:x?}", address); + self.get_account(address) + .and_then(|account| self.storage.get_code_by_hash(account.code_hash)) + .unwrap_or_default() + } + + fn storage(&self, address: H160, index: H256) -> H256 { + trace!(target: "backend", "[EVMBackend] Getting storage for address {:x?} at index {:x?}", address, index); + self.get_account(address) + .and_then(|account| { + self.trie_store + .trie_db + .trie_restore(address.as_bytes(), None, account.storage_root.into()) + .ok() + }) + .and_then(|trie| trie.get(index.as_bytes()).ok().flatten()) + .map(|res| H256::from_slice(res.as_ref())) + .unwrap_or_default() + } + + fn original_storage(&self, address: H160, index: H256) -> Option { + trace!(target: "backend", "[EVMBackend] Getting original storage for address {:x?} at index {:x?}", address, index); + Some(self.storage(address, index)) + } +} + +impl ApplyBackend for EVMBackend { + fn apply(&mut self, values: A, _logs: L, delete_empty: bool) + where + A: IntoIterator>, + I: IntoIterator, + L: IntoIterator, + { + for apply in values { + match apply { + Apply::Modify { + address, + basic, + code, + storage, + reset_storage, + } => { + let new_account = self + .apply(address, basic, code, storage, reset_storage) + .expect("Error applying state"); + + if is_empty_account(&new_account) && delete_empty { + debug!("Deleting empty address {}", address); + self.trie_store.trie_db.trie_remove(address.as_bytes()); + self.state + .remove(address.as_bytes()) + .expect("Error removing address in state"); + } + } + Apply::Delete { address } => { + debug!("Deleting address {}", address); + self.trie_store.trie_db.trie_remove(address.as_bytes()); + self.state + .remove(address.as_bytes()) + .expect("Error removing address in state"); + } + } + } + } +} + +impl BridgeBackend for EVMBackend { + fn add_balance(&mut self, address: H160, amount: U256) -> Result<()> { + let basic = self.basic(address); + + let new_basic = Basic { + balance: basic.balance + amount, + ..basic + }; + + self.apply(address, new_basic, None, Vec::new(), false)?; + Ok(()) + } + + fn sub_balance(&mut self, address: H160, amount: U256) -> Result<()> { + let account = self + .get_account(address) + .ok_or(EVMBackendError::NoSuchAccount(address))?; + + if account.balance < amount { + Err(EVMBackendError::InsufficientBalance(InsufficientBalance { + address, + account_balance: account.balance, + amount, + })) + } else { + let new_basic = Basic { + balance: account.balance - amount, + nonce: account.nonce, + }; + + self.apply(address, new_basic, None, Vec::new(), false)?; + Ok(()) + } + } +} + +use std::{error::Error, fmt, sync::Arc}; + +#[derive(Debug)] +pub struct InsufficientBalance { + pub address: H160, + pub account_balance: U256, + pub amount: U256, +} + +#[derive(Debug)] +pub enum EVMBackendError { + TrieCreationFailed(String), + TrieRestoreFailed(String), + TrieError(String), + NoSuchAccount(H160), + InsufficientBalance(InsufficientBalance), +} + +impl fmt::Display for EVMBackendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + EVMBackendError::TrieCreationFailed(e) => { + write!(f, "EVMBackendError: Failed to create trie {e}") + } + EVMBackendError::TrieRestoreFailed(e) => { + write!(f, "EVMBackendError: Failed to restore trie {e}") + } + EVMBackendError::TrieError(e) => write!(f, "EVMBackendError: Trie error {e}"), + EVMBackendError::NoSuchAccount(address) => { + write!( + f, + "EVMBackendError: No such acccount for address {}", + address + ) + } + EVMBackendError::InsufficientBalance(InsufficientBalance { + address, + account_balance, + amount, + }) => { + write!(f, "EVMBackendError: Insufficient balance for address {address}, trying to deduct {amount} but address has only {account_balance}") + } + } + } +} + +impl Error for EVMBackendError {} diff --git a/lib/ain-evm/src/block.rs b/lib/ain-evm/src/block.rs new file mode 100644 index 0000000000..1055a8b985 --- /dev/null +++ b/lib/ain-evm/src/block.rs @@ -0,0 +1,291 @@ +use ethereum::{Block, BlockAny, PartialHeader, TransactionAny}; +use keccak_hash::H256; +use log::debug; +use primitive_types::U256; + +use statrs::statistics::{Data, OrderStatistics}; +use std::cmp::{max, Ordering}; +use std::{fs, io::BufReader, path::PathBuf, sync::Arc}; + +use crate::{ + genesis::GenesisData, + storage::{traits::BlockStorage, Storage}, +}; + +pub struct BlockHandler { + storage: Arc, +} + +pub struct FeeHistoryData { + pub oldest_block: H256, + pub base_fee_per_gas: Vec, + pub gas_used_ratio: Vec, + pub reward: Option>>, +} + +impl BlockHandler { + pub fn new(storage: Arc) -> Self { + Self { storage } + } + + pub fn get_latest_block_hash_and_number(&self) -> Option<(H256, U256)> { + self.storage + .get_latest_block() + .map(|latest_block| (latest_block.header.hash(), latest_block.header.number)) + } + + pub fn get_latest_state_root(&self) -> H256 { + self.storage + .get_latest_block() + .map(|block| block.header.state_root) + .unwrap_or_default() + } + + pub fn connect_block(&self, block: BlockAny, base_fee: U256) { + self.storage.put_latest_block(Some(&block)); + self.storage.put_block(&block); + self.storage.set_base_fee(block.header.hash(), base_fee); + } + + pub fn calculate_base_fee(&self, parent_hash: H256) -> U256 { + // constants + let initial_base_fee = U256::from(10_000_000_000u64); // wei + let base_fee_max_change_denominator = U256::from(8); + let elasticity_multiplier = U256::from(2); + + // first block has 1 gwei base fee + if parent_hash == H256::zero() { + return initial_base_fee; + } + + // get parent gas usage, + // https://eips.ethereum.org/EIPS/eip-1559#:~:text=fee%20is%20correct-,if%20INITIAL_FORK_BLOCK_NUMBER%20%3D%3D%20block.number%3A,-expected_base_fee_per_gas%20%3D%20INITIAL_BASE_FEE + let parent_block = self + .storage + .get_block_by_hash(&parent_hash) + .expect("Parent block not found"); + let parent_base_fee = self + .storage + .get_base_fee(&parent_block.header.hash()) + .expect("Parent base fee not found"); + let parent_gas_used = parent_block.header.gas_used.as_u64(); + let parent_gas_target = + parent_block.header.gas_limit.as_u64() / elasticity_multiplier.as_u64(); + + match parent_gas_used.cmp(&parent_gas_target) { + Ordering::Less => parent_base_fee, + Ordering::Equal => { + let gas_used_delta = parent_gas_used - parent_gas_target; + let base_fee_per_gas_delta = max( + parent_base_fee * gas_used_delta + / parent_gas_target + / base_fee_max_change_denominator, + U256::one(), + ); + + max(parent_base_fee + base_fee_per_gas_delta, initial_base_fee) + } + Ordering::Greater => { + let gas_used_delta = parent_gas_target - parent_gas_used; + let base_fee_per_gas_delta = parent_base_fee * gas_used_delta + / parent_gas_target + / base_fee_max_change_denominator; + + max(parent_base_fee - base_fee_per_gas_delta, initial_base_fee) + } + } + } + + pub fn fee_history( + &self, + block_count: usize, + first_block: U256, + priority_fee_percentile: Vec, + ) -> FeeHistoryData { + let mut blocks = Vec::with_capacity(block_count); + let mut block_number = first_block; + + for _ in 0..=block_count { + blocks.push( + self.storage + .get_block_by_number(&block_number) + .unwrap_or_else(|| panic!("Block {} out of range", block_number)), + ); + + block_number -= U256::one(); + } + + let oldest_block = blocks.last().unwrap().header.hash(); + + let (mut base_fee_per_gas, mut gas_used_ratio): (Vec, Vec) = blocks + .iter() + .map(|block| { + debug!("Processing block {}", block.header.number); + let base_fee = self + .storage + .get_base_fee(&block.header.hash()) + .unwrap_or_else(|| panic!("No base fee for block {}", block.header.number)); + + let gas_ratio = if block.header.gas_limit == U256::zero() { + f64::default() // empty block + } else { + block.header.gas_used.as_u64() as f64 / block.header.gas_limit.as_u64() as f64 + }; + + (base_fee, gas_ratio) + }) + .unzip(); + + let reward = if priority_fee_percentile.is_empty() { + None + } else { + let mut eip_transactions = Vec::new(); + + for block in blocks { + let mut block_eip_transaction = Vec::new(); + for tx in block.transactions { + match tx { + TransactionAny::Legacy(_) | TransactionAny::EIP2930(_) => { + continue; + } + TransactionAny::EIP1559(t) => { + block_eip_transaction.push(t); + } + } + } + block_eip_transaction + .sort_by(|a, b| a.max_priority_fee_per_gas.cmp(&b.max_priority_fee_per_gas)); + eip_transactions.push(block_eip_transaction); + } + + /* + TODO: assumption here is that max priority fee = priority fee paid, however + priority fee can be lower if gas costs hit max_fee_per_gas. + we will need to check the base fee paid to get the actual priority fee paid + */ + + let mut reward = Vec::new(); + + for block_eip_tx in eip_transactions { + if block_eip_tx.is_empty() { + reward.push(vec![U256::zero()]); + continue; + } + + let mut block_rewards = Vec::new(); + let priority_fees = block_eip_tx + .iter() + .map(|tx| tx.max_priority_fee_per_gas.as_u64() as f64) + .collect::>(); + let mut data = Data::new(priority_fees); + + for pct in priority_fee_percentile.iter() { + block_rewards.push(U256::from(data.percentile(*pct).ceil() as u64)); + } + + reward.push(block_rewards); + } + + reward.reverse(); + Some(reward) + }; + + base_fee_per_gas.reverse(); + gas_used_ratio.reverse(); + + FeeHistoryData { + oldest_block, + base_fee_per_gas, + gas_used_ratio, + reward, + } + } + + /// Returns the 60th percentile priority fee for the last 20 blocks + /// Ref: https://github.com/ethereum/go-ethereum/blob/c57b3436f4b8aae352cd69c3821879a11b5ee0fb/eth/ethconfig/config.go#L41 + /// TODO: these should be configurable by the user + pub fn suggested_priority_fee(&self) -> U256 { + let mut blocks = Vec::with_capacity(20); + let block = self + .storage + .get_latest_block() + .expect("Unable to find latest block"); + blocks.push(block.clone()); + let mut parent_hash = block.header.parent_hash; + + while blocks.len() <= blocks.capacity() { + match self.storage.get_block_by_hash(&parent_hash) { + Some(block) => { + blocks.push(block.clone()); + parent_hash = block.header.parent_hash; + } + None => break, + } + } + + /* + TODO: assumption here is that max priority fee = priority fee paid, however + priority fee can be lower if gas costs hit max_fee_per_gas. + we will need to check the base fee paid to get the actual priority fee paid + */ + + let mut priority_fees = Vec::new(); + + for block in blocks { + for tx in block.transactions { + match tx { + TransactionAny::Legacy(_) | TransactionAny::EIP2930(_) => { + continue; + } + TransactionAny::EIP1559(t) => { + priority_fees.push(t.max_priority_fee_per_gas.as_u64() as f64); + } + } + } + } + + priority_fees.sort_by(|a, b| a.partial_cmp(b).expect("Invalid f64 value")); + let mut data = Data::new(priority_fees); + + U256::from(data.percentile(60).ceil() as u64) + } + + pub fn get_legacy_fee(&self) -> U256 { + let priority_fee = self.suggested_priority_fee(); + let latest_block_hash = self + .storage + .get_latest_block() + .expect("Unable to get latest block") + .header + .hash(); + let base_fee = self.storage.get_base_fee(&latest_block_hash).unwrap(); + + base_fee + priority_fee + } +} + +pub fn new_block_from_json(path: PathBuf, state_root: H256) -> Result { + let file = fs::File::open(path)?; + let reader = BufReader::new(file); + let genesis: GenesisData = serde_json::from_reader(reader)?; + + Ok(Block::new( + PartialHeader { + state_root, + beneficiary: genesis.coinbase, + timestamp: genesis.timestamp, + difficulty: genesis.difficulty, + extra_data: genesis.extra_data, + number: U256::zero(), + parent_hash: Default::default(), + receipts_root: Default::default(), + logs_bloom: Default::default(), + gas_limit: Default::default(), + gas_used: Default::default(), + mix_hash: Default::default(), + nonce: Default::default(), + }, + Vec::new(), + Vec::new(), + )) +} diff --git a/lib/ain-evm/src/ecrecover.rs b/lib/ain-evm/src/ecrecover.rs new file mode 100644 index 0000000000..cfc09d1117 --- /dev/null +++ b/lib/ain-evm/src/ecrecover.rs @@ -0,0 +1,60 @@ +use libsecp256k1::Error; +use libsecp256k1::{PublicKey, RecoveryId, Signature}; +use primitive_types::{H160, H256}; +use sha3::Digest; + +pub fn recover_public_key( + hash: &H256, + r: &H256, + s: &H256, + recovery_id: u8, +) -> Result { + let msg = libsecp256k1::Message::parse(hash.as_fixed_bytes()); + + let mut standard_slice = [0u8; 64]; + standard_slice[..32].copy_from_slice(r.as_fixed_bytes()); + standard_slice[32..].copy_from_slice(s.as_fixed_bytes()); + let signature = Signature::parse_standard_slice(&standard_slice)?; + + let recovery_id = RecoveryId::parse(recovery_id)?; + libsecp256k1::recover(&msg, &signature, &recovery_id) +} + +pub fn public_key_to_address(pubkey: &PublicKey) -> H160 { + let mut output = [0u8; 32]; + output.copy_from_slice(sha3::Keccak256::digest(&pubkey.serialize()[1..]).as_slice()); + let mut ret = H160::zero(); + ret.as_bytes_mut().copy_from_slice(&output[12..]); + ret +} + +#[cfg(test)] +mod tests { + use hex_literal::hex; + + use primitive_types::H256; + + use super::{public_key_to_address, recover_public_key}; + + #[test] + fn test_recover_public_key_and_address() { + let hash = H256::from_slice(&hex!( + "6091be99153563845f8af2ff710a9854a70551a5a6b914a296931444fa360d40" + )); + let r = H256::from_slice(&hex!( + "f53cdd6fad6cb1014486fbc626f0a8109cce5df1529e6070432bb8798642e548" + )); + let s = H256::from_slice(&hex!( + "759484f7adefce95559ed3c07bb179586ceb74bb4aac060dc1f6d6aa58b95a42" + )); + let recovery_id = 0; + + let pubkey = recover_public_key(&hash, &r, &s, recovery_id); + assert!(pubkey.is_ok()); + let address = public_key_to_address(&pubkey.unwrap()); + assert_eq!( + address, + "89790061e1efe88bda902193c8ab3b061aa4ef2c".parse().unwrap() + ); + } +} diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs new file mode 100644 index 0000000000..511abf11d9 --- /dev/null +++ b/lib/ain-evm/src/evm.rs @@ -0,0 +1,440 @@ +use crate::backend::{EVMBackend, EVMBackendError, InsufficientBalance, Vicinity}; +use crate::executor::TxResponse; +use crate::fee::calculate_prepay_gas; +use crate::storage::traits::{BlockStorage, PersistentStateError}; +use crate::storage::Storage; +use crate::transaction::bridge::{BalanceUpdate, BridgeTx}; +use crate::trie::TrieDBStore; +use crate::tx_queue::{QueueError, QueueTx, TransactionQueueMap}; +use crate::{ + executor::AinExecutor, + traits::{Executor, ExecutorContext}, + transaction::SignedTx, +}; +use anyhow::anyhow; +use ethereum::{AccessList, Account, Block, Log, PartialHeader, TransactionV2}; +use ethereum_types::{Bloom, BloomInput, H160, U256}; + +use hex::FromHex; +use log::debug; +use std::error::Error; +use std::path::PathBuf; +use std::sync::Arc; +use vsdb_core::vsdb_set_base_dir; + +pub type NativeTxHash = [u8; 32]; + +pub struct EVMHandler { + pub tx_queues: Arc, + pub trie_store: Arc, + storage: Arc, +} + +fn init_vsdb() { + debug!(target: "vsdb", "Initializating VSDB"); + let datadir = ain_cpp_imports::get_datadir().expect("Could not get imported datadir"); + let path = PathBuf::from(datadir).join("evm"); + if !path.exists() { + std::fs::create_dir(&path).expect("Error creating `evm` dir"); + } + let vsdb_dir_path = path.join(".vsdb"); + vsdb_set_base_dir(&vsdb_dir_path).expect("Could not update vsdb base dir"); + debug!(target: "vsdb", "VSDB directory : {}", vsdb_dir_path.display()); +} + +impl EVMHandler { + pub fn restore(storage: Arc) -> Self { + init_vsdb(); + + Self { + tx_queues: Arc::new(TransactionQueueMap::new()), + trie_store: Arc::new(TrieDBStore::restore()), + storage, + } + } + + pub fn new_from_json(storage: Arc, path: PathBuf) -> Self { + debug!("Loading genesis state from {}", path.display()); + init_vsdb(); + + let handler = Self { + tx_queues: Arc::new(TransactionQueueMap::new()), + trie_store: Arc::new(TrieDBStore::new()), + storage: Arc::clone(&storage), + }; + let state_root = + TrieDBStore::genesis_state_root_from_json(&handler.trie_store, &handler.storage, path) + .expect("Error getting genesis state root from json"); + + let block: Block = Block::new( + PartialHeader { + state_root, + number: U256::zero(), + parent_hash: Default::default(), + beneficiary: Default::default(), + receipts_root: Default::default(), + logs_bloom: Default::default(), + difficulty: Default::default(), + gas_limit: Default::default(), + gas_used: Default::default(), + timestamp: Default::default(), + extra_data: Default::default(), + mix_hash: Default::default(), + nonce: Default::default(), + }, + Vec::new(), + Vec::new(), + ); + storage.put_latest_block(Some(&block)); + storage.put_block(&block); + + handler + } + + pub fn flush(&self) -> Result<(), PersistentStateError> { + self.trie_store.flush() + } + + pub fn call( + &self, + caller: Option, + to: Option, + value: U256, + data: &[u8], + gas_limit: u64, + access_list: AccessList, + block_number: U256, + ) -> Result> { + let (state_root, block_number) = self + .storage + .get_block_by_number(&block_number) + .map(|block| (block.header.state_root, block.header.number)) + .unwrap_or_default(); + debug!( + "Calling EVM at block number : {:#x}, state_root : {:#x}", + block_number, state_root + ); + + let vicinity = Vicinity { + block_number, + origin: caller.unwrap_or_default(), + gas_limit: U256::from(gas_limit), + ..Default::default() + }; + + let mut backend = EVMBackend::from_root( + state_root, + Arc::clone(&self.trie_store), + Arc::clone(&self.storage), + vicinity, + ) + .map_err(|e| anyhow!("------ Could not restore backend {}", e))?; + Ok(AinExecutor::new(&mut backend).call(ExecutorContext { + caller, + to, + value, + data, + gas_limit, + access_list, + })) + } + + pub fn validate_raw_tx( + &self, + tx: &str, + with_gas_usage: bool, + ) -> Result<(SignedTx, u64), Box> { + debug!("[validate_raw_tx] raw transaction : {:#?}", tx); + let buffer = >::from_hex(tx)?; + let tx: TransactionV2 = ethereum::EnvelopedDecodable::decode(&buffer) + .map_err(|_| anyhow!("Error: decoding raw tx to TransactionV2"))?; + debug!("[validate_raw_tx] TransactionV2 : {:#?}", tx); + + let block_number = self + .storage + .get_latest_block() + .map(|block| block.header.number) + .unwrap_or_default(); + + debug!("[validate_raw_tx] block_number : {:#?}", block_number); + + let signed_tx: SignedTx = tx.try_into()?; + let nonce = self + .get_nonce(signed_tx.sender, block_number) + .map_err(|e| anyhow!("Error getting nonce {e}"))?; + + debug!( + "[validate_raw_tx] signed_tx.sender : {:#?}", + signed_tx.sender + ); + debug!( + "[validate_raw_tx] signed_tx nonce : {:#?}", + signed_tx.nonce() + ); + debug!("[validate_raw_tx] nonce : {:#?}", nonce); + if nonce > signed_tx.nonce() { + return Err(anyhow!( + "Invalid nonce. Account nonce {}, signed_tx nonce {}", + nonce, + signed_tx.nonce() + ) + .into()); + } + + const MIN_GAS_PER_TX: U256 = U256([21_000, 0, 0, 0]); + let balance = self + .get_balance(signed_tx.sender, block_number) + .map_err(|e| anyhow!("Error getting balance {e}"))?; + + debug!("[validate_raw_tx] Accout balance : {:x?}", balance); + + let prepay_gas = calculate_prepay_gas(&signed_tx); + if balance < MIN_GAS_PER_TX || balance < prepay_gas { + debug!("[validate_raw_tx] Insufficiant balance to pay fees"); + return Err(anyhow!("Insufficiant balance to pay fees").into()); + } + + let gas_limit = signed_tx.gas_limit(); + + // TODO lift MAX_GAS_PER_BLOCK + const MAX_GAS_PER_BLOCK: U256 = U256([30_000_000, 0, 0, 0]); + println!("MAX_GAS_PER_BLOCK : {:#x}", MAX_GAS_PER_BLOCK); + if gas_limit > MAX_GAS_PER_BLOCK { + return Err(anyhow!("Gas limit higher than MAX_GAS_PER_BLOCK").into()); + } + + let used_gas = if with_gas_usage { + let TxResponse { used_gas, .. } = self.call( + Some(signed_tx.sender), + signed_tx.to(), + signed_tx.value(), + signed_tx.data(), + signed_tx.gas_limit().as_u64(), + signed_tx.access_list(), + block_number, + )?; + used_gas + } else { + u64::default() + }; + + Ok((signed_tx, used_gas)) + } + + pub fn logs_bloom(logs: Vec, bloom: &mut Bloom) { + for log in logs { + bloom.accrue(BloomInput::Raw(&log.address[..])); + for topic in log.topics { + bloom.accrue(BloomInput::Raw(&topic[..])); + } + } + } +} + +impl EVMHandler { + pub fn queue_tx(&self, context: u64, tx: QueueTx, hash: NativeTxHash) -> Result<(), EVMError> { + self.tx_queues.queue_tx(context, tx, hash)?; + Ok(()) + } + pub fn add_balance( + &self, + context: u64, + address: H160, + amount: U256, + hash: NativeTxHash, + ) -> Result<(), EVMError> { + let queue_tx = QueueTx::BridgeTx(BridgeTx::EvmIn(BalanceUpdate { address, amount })); + self.tx_queues.queue_tx(context, queue_tx, hash)?; + Ok(()) + } + + pub fn sub_balance( + &self, + context: u64, + address: H160, + amount: U256, + hash: NativeTxHash, + ) -> Result<(), EVMError> { + let block_number = self + .storage + .get_latest_block() + .map_or(U256::default(), |block| block.header.number); + let balance = self.get_balance(address, block_number)?; + if balance < amount { + Err(EVMBackendError::InsufficientBalance(InsufficientBalance { + address, + account_balance: balance, + amount, + }) + .into()) + } else { + let queue_tx = QueueTx::BridgeTx(BridgeTx::EvmOut(BalanceUpdate { address, amount })); + self.tx_queues.queue_tx(context, queue_tx, hash)?; + Ok(()) + } + } + + pub fn get_context(&self) -> u64 { + self.tx_queues.get_context() + } + + pub fn clear(&self, context: u64) -> Result<(), EVMError> { + self.tx_queues.clear(context)?; + Ok(()) + } + + pub fn remove(&self, context: u64) { + self.tx_queues.remove(context); + } +} + +impl EVMHandler { + pub fn get_account( + &self, + address: H160, + block_number: U256, + ) -> Result, EVMError> { + let state_root = self + .storage + .get_block_by_number(&block_number) + .or_else(|| self.storage.get_latest_block()) + .map(|block| block.header.state_root) + .unwrap_or_default(); + + let backend = EVMBackend::from_root( + state_root, + Arc::clone(&self.trie_store), + Arc::clone(&self.storage), + Vicinity::default(), + )?; + Ok(backend.get_account(address)) + } + + pub fn get_code(&self, address: H160, block_number: U256) -> Result>, EVMError> { + self.get_account(address, block_number).map(|opt_account| { + opt_account.map_or_else( + || None, + |account| self.storage.get_code_by_hash(account.code_hash), + ) + }) + } + + pub fn get_storage_at( + &self, + address: H160, + position: U256, + block_number: U256, + ) -> Result>, EVMError> { + self.get_account(address, block_number)? + .map_or(Ok(None), |account| { + let storage_trie = self + .trie_store + .trie_db + .trie_restore(address.as_bytes(), None, account.storage_root.into()) + .unwrap(); + + let tmp: &mut [u8; 32] = &mut [0; 32]; + position.to_big_endian(tmp); + storage_trie + .get(tmp.as_slice()) + .map_err(|e| EVMError::TrieError(format!("{e}"))) + }) + } + + pub fn get_balance(&self, address: H160, block_number: U256) -> Result { + let balance = self + .get_account(address, block_number)? + .map_or(U256::zero(), |account| account.balance); + + debug!("Account {:x?} balance {:x?}", address, balance); + Ok(balance) + } + + pub fn get_nonce(&self, address: H160, block_number: U256) -> Result { + let nonce = self + .get_account(address, block_number)? + .map_or(U256::zero(), |account| account.nonce); + + debug!("Account {:x?} nonce {:x?}", address, nonce); + Ok(nonce) + } + + /// Retrieves the next valid nonce for the specified account within a particular context. + /// + /// The method first attempts to retrieve the next valid nonce from the transaction queue associated with the + /// provided context. If no nonce is found in the transaction queue, that means that no transactions have been + /// queued for this account in this context. It falls back to retrieving the nonce from the storage at the latest + /// block. If no nonce is found in the storage (i.e., no transactions for this account have been committed yet), + /// the nonce is defaulted to zero. + /// + /// This method provides a unified view of the nonce for an account, taking into account both transactions that are + /// waiting to be processed in the queue and transactions that have already been processed and committed to the storage. + /// + /// # Arguments + /// + /// * `context` - The context queue number. + /// * `address` - The EVM address of the account whose nonce we want to retrieve. + /// + /// # Returns + /// + /// Returns the next valid nonce as a `U256`. Defaults to U256::zero() + pub fn get_next_valid_nonce_in_context(&self, context: u64, address: H160) -> U256 { + let nonce = self + .tx_queues + .get_next_valid_nonce(context, address) + .unwrap_or_else(|| { + let latest_block = self + .storage + .get_latest_block() + .map(|b| b.header.number) + .unwrap_or_else(U256::zero); + + self.get_nonce(address, latest_block) + .unwrap_or_else(|_| U256::zero()) + }); + + debug!( + "Account {:x?} nonce {:x?} in context {context}", + address, nonce + ); + nonce + } +} + +use std::fmt; +#[derive(Debug)] +pub enum EVMError { + BackendError(EVMBackendError), + QueueError(QueueError), + NoSuchAccount(H160), + TrieError(String), +} + +impl fmt::Display for EVMError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + EVMError::BackendError(e) => write!(f, "EVMError: Backend error: {e}"), + EVMError::QueueError(e) => write!(f, "EVMError: Queue error: {e}"), + EVMError::NoSuchAccount(address) => { + write!(f, "EVMError: No such acccount for address {address:#x}") + } + EVMError::TrieError(e) => { + write!(f, "EVMError: Trie error {e}") + } + } + } +} + +impl From for EVMError { + fn from(e: EVMBackendError) -> Self { + EVMError::BackendError(e) + } +} + +impl From for EVMError { + fn from(e: QueueError) -> Self { + EVMError::QueueError(e) + } +} + +impl std::error::Error for EVMError {} diff --git a/lib/ain-evm/src/executor.rs b/lib/ain-evm/src/executor.rs new file mode 100644 index 0000000000..6f47742073 --- /dev/null +++ b/lib/ain-evm/src/executor.rs @@ -0,0 +1,175 @@ +use crate::{ + backend::{EVMBackend, EVMBackendError}, + evm::EVMHandler, + fee::calculate_prepay_gas, + traits::{BridgeBackend, Executor, ExecutorContext}, + transaction::SignedTx, +}; +use ethereum::{EIP658ReceiptData, Log, ReceiptV3}; +use ethereum_types::{Bloom, U256}; +use evm::{ + backend::ApplyBackend, + executor::stack::{MemoryStackState, StackExecutor, StackSubstateMetadata}, + Config, ExitReason, +}; +use log::trace; +use primitive_types::{H160, H256}; +use std::collections::BTreeMap; + +pub struct AinExecutor<'backend> { + backend: &'backend mut EVMBackend, +} + +impl<'backend> AinExecutor<'backend> {} + +impl<'backend> AinExecutor<'backend> { + pub fn new(backend: &'backend mut EVMBackend) -> Self { + Self { backend } + } + + pub fn add_balance(&mut self, address: H160, amount: U256) -> Result<(), EVMBackendError> { + self.backend.add_balance(address, amount) + } + + pub fn sub_balance(&mut self, address: H160, amount: U256) -> Result<(), EVMBackendError> { + self.backend.sub_balance(address, amount) + } + + pub fn commit(&mut self) -> H256 { + self.backend.commit() + } +} + +impl<'backend> Executor for AinExecutor<'backend> { + const CONFIG: Config = Config::shanghai(); + + /// Read-only call + fn call(&mut self, ctx: ExecutorContext) -> TxResponse { + let metadata = StackSubstateMetadata::new(ctx.gas_limit, &Self::CONFIG); + let state = MemoryStackState::new(metadata, self.backend); + let precompiles = BTreeMap::new(); // TODO Add precompile crate + let mut executor = StackExecutor::new_with_precompiles(state, &Self::CONFIG, &precompiles); + let access_list = ctx + .access_list + .into_iter() + .map(|x| (x.address, x.storage_keys)) + .collect::>(); + + let (exit_reason, data) = match ctx.to { + Some(address) => executor.transact_call( + ctx.caller.unwrap_or_default(), + address, + ctx.value, + ctx.data.to_vec(), + ctx.gas_limit, + access_list, + ), + None => executor.transact_create( + ctx.caller.unwrap_or_default(), + ctx.value, + ctx.data.to_vec(), + ctx.gas_limit, + access_list, + ), + }; + + TxResponse { + exit_reason, + data, + logs: Vec::new(), + used_gas: executor.used_gas(), + } + } + + /// Update state + fn exec(&mut self, signed_tx: &SignedTx) -> (TxResponse, ReceiptV3) { + self.backend.update_vicinity_from_tx(signed_tx); + trace!( + "[Executor] Executing EVM TX with vicinity : {:?}", + self.backend.vicinity + ); + let ctx = ExecutorContext { + caller: Some(signed_tx.sender), + to: signed_tx.to(), + value: signed_tx.value(), + data: signed_tx.data(), + gas_limit: signed_tx.gas_limit().as_u64(), + access_list: signed_tx.access_list(), + }; + + let prepay_gas = calculate_prepay_gas(signed_tx); + + self.backend.deduct_prepay_gas(signed_tx.sender, prepay_gas); + + let metadata = StackSubstateMetadata::new(ctx.gas_limit, &Self::CONFIG); + let state = MemoryStackState::new(metadata, self.backend); + let precompiles = BTreeMap::new(); // TODO Add precompile crate + let mut executor = StackExecutor::new_with_precompiles(state, &Self::CONFIG, &precompiles); + let access_list = ctx + .access_list + .into_iter() + .map(|x| (x.address, x.storage_keys)) + .collect::>(); + + let (exit_reason, data) = match ctx.to { + Some(address) => executor.transact_call( + ctx.caller.unwrap_or_default(), + address, + ctx.value, + ctx.data.to_vec(), + ctx.gas_limit, + access_list, + ), + None => executor.transact_create( + ctx.caller.unwrap_or_default(), + ctx.value, + ctx.data.to_vec(), + ctx.gas_limit, + access_list, + ), + }; + + let used_gas = executor.used_gas(); + let (values, logs) = executor.into_state().deconstruct(); + let logs = logs.into_iter().collect::>(); + if exit_reason.is_succeed() { + ApplyBackend::apply(self.backend, values, logs.clone(), true); + } + + self.backend.refund_unused_gas( + signed_tx.sender, + signed_tx.gas_limit(), + U256::from(used_gas), + signed_tx.gas_price(), + ); + + let receipt = ReceiptV3::EIP1559(EIP658ReceiptData { + logs_bloom: { + let mut bloom: Bloom = Bloom::default(); + EVMHandler::logs_bloom(logs.clone(), &mut bloom); + bloom + }, + status_code: u8::from(exit_reason.is_succeed()), + logs: logs.clone(), + used_gas: U256::from(used_gas), + }); + + ( + TxResponse { + exit_reason, + data, + logs, + used_gas, + }, + receipt, + ) + } +} + +#[derive(Debug)] +pub struct TxResponse { + pub exit_reason: ExitReason, + pub data: Vec, + pub logs: Vec, + pub used_gas: u64, +} diff --git a/lib/ain-evm/src/fee.rs b/lib/ain-evm/src/fee.rs new file mode 100644 index 0000000000..39e6325c4d --- /dev/null +++ b/lib/ain-evm/src/fee.rs @@ -0,0 +1,11 @@ +use ethereum_types::U256; + +use crate::transaction::SignedTx; + +pub fn calculate_prepay_gas(signed_tx: &SignedTx) -> U256 { + match &signed_tx.transaction { + ethereum::TransactionV2::Legacy(tx) => tx.gas_limit.saturating_mul(tx.gas_price), + ethereum::TransactionV2::EIP2930(tx) => tx.gas_limit.saturating_mul(tx.gas_price), + ethereum::TransactionV2::EIP1559(tx) => tx.gas_limit.saturating_mul(tx.max_fee_per_gas), + } +} diff --git a/lib/ain-evm/src/genesis.rs b/lib/ain-evm/src/genesis.rs new file mode 100644 index 0000000000..36693ce997 --- /dev/null +++ b/lib/ain-evm/src/genesis.rs @@ -0,0 +1,33 @@ +use ethereum_types::{H160, H256, H64, U256}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Debug, Serialize, Deserialize)] +struct Config { + chain_id: u32, + homestead_block: u32, + eip150_block: u32, + eip150_hash: String, + eip155_block: u32, + eip158_block: u32, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Alloc { + pub balance: U256, + pub code: Option>, + pub storage: Option>, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GenesisData { + // config: Config, + pub coinbase: H160, + pub difficulty: U256, + pub extra_data: Vec, + pub gas_limit: U256, + pub nonce: H64, + pub timestamp: u64, + pub alloc: HashMap, +} diff --git a/lib/ain-evm/src/handler.rs b/lib/ain-evm/src/handler.rs new file mode 100644 index 0000000000..0bed2d4c3f --- /dev/null +++ b/lib/ain-evm/src/handler.rs @@ -0,0 +1,233 @@ +use crate::backend::{EVMBackend, Vicinity}; +use crate::block::BlockHandler; +use crate::evm::EVMHandler; +use crate::executor::{AinExecutor, TxResponse}; +use crate::receipt::ReceiptHandler; +use crate::storage::traits::BlockStorage; +use crate::storage::Storage; +use crate::traits::Executor; +use crate::transaction::bridge::{BalanceUpdate, BridgeTx}; +use crate::trie::GENESIS_STATE_ROOT; +use crate::tx_queue::QueueTx; + +use anyhow::anyhow; +use ethereum::{Block, PartialHeader, ReceiptV3}; +use ethereum_types::{Bloom, H160, H64, U256}; +use log::debug; +use primitive_types::H256; +use std::error::Error; +use std::path::PathBuf; +use std::sync::Arc; + +pub struct Handlers { + pub evm: EVMHandler, + pub block: BlockHandler, + pub receipt: ReceiptHandler, + pub storage: Arc, +} + +impl Handlers { + /// Constructs a new Handlers instance. Depending on whether the defid -ethstartstate flag is set, + /// it either revives the storage from a previously saved state or initializes new storage using input from a JSON file. + /// This JSON-based initialization is exclusively reserved for regtest environments. + /// + /// # Warning + /// + /// Loading state from JSON will overwrite previous stored state + /// + /// # Errors + /// + /// This method will return an error if an attempt is made to load a genesis state from a JSON file outside of a regtest environment. + /// + /// # Return + /// + /// Returns an instance of the struct, either restored from storage or created from a JSON file. + pub fn new() -> Result { + if let Some(path) = ain_cpp_imports::get_state_input_json() { + if ain_cpp_imports::get_network() != "regtest" { + return Err(anyhow!( + "Loading a genesis from JSON file is restricted to regtest network" + )); + } + let storage = Arc::new(Storage::new()); + Ok(Self { + evm: EVMHandler::new_from_json(Arc::clone(&storage), PathBuf::from(path)), + block: BlockHandler::new(Arc::clone(&storage)), + receipt: ReceiptHandler::new(Arc::clone(&storage)), + storage, + }) + } else { + let storage = Arc::new(Storage::restore()); + Ok(Self { + evm: EVMHandler::restore(Arc::clone(&storage)), + block: BlockHandler::new(Arc::clone(&storage)), + receipt: ReceiptHandler::new(Arc::clone(&storage)), + storage, + }) + } + } + + pub fn finalize_block( + &self, + context: u64, + update_state: bool, + difficulty: u32, + beneficiary: H160, + timestamp: u64, + ) -> Result<([u8; 32], Vec, u64), Box> { + let mut all_transactions = Vec::with_capacity(self.evm.tx_queues.len(context)); + let mut failed_transactions = Vec::with_capacity(self.evm.tx_queues.len(context)); + let mut receipts_v3: Vec = Vec::with_capacity(self.evm.tx_queues.len(context)); + let mut gas_used = 0u64; + let mut logs_bloom: Bloom = Bloom::default(); + + let parent_data = self.block.get_latest_block_hash_and_number(); + let state_root = self + .storage + .get_latest_block() + .map_or(GENESIS_STATE_ROOT.parse().unwrap(), |block| { + block.header.state_root + }); + + let (vicinity, parent_hash, current_block_number) = match parent_data { + None => ( + Vicinity { + beneficiary, + timestamp: U256::from(timestamp), + block_number: U256::from(0), + ..Default::default() + }, + H256::zero(), + U256::from(0), + ), + Some((hash, number)) => ( + Vicinity { + beneficiary, + timestamp: U256::from(timestamp), + block_number: number + 1, + ..Default::default() + }, + hash, + number + 1, + ), + }; + + let mut backend = EVMBackend::from_root( + state_root, + Arc::clone(&self.evm.trie_store), + Arc::clone(&self.storage), + vicinity, + )?; + + let mut executor = AinExecutor::new(&mut backend); + + for (queue_tx, hash) in self.evm.tx_queues.get_cloned_vec(context) { + match queue_tx { + QueueTx::SignedTx(signed_tx) => { + let ( + TxResponse { + exit_reason, + logs, + used_gas, + .. + }, + receipt, + ) = executor.exec(&signed_tx); + debug!( + "receipt : {:#?} for signed_tx : {:#x}", + receipt, + signed_tx.transaction.hash() + ); + + if !exit_reason.is_succeed() { + failed_transactions.push(hex::encode(hash)); + } + + all_transactions.push(signed_tx.clone()); + gas_used += used_gas; + EVMHandler::logs_bloom(logs, &mut logs_bloom); + receipts_v3.push(receipt); + } + QueueTx::BridgeTx(BridgeTx::EvmIn(BalanceUpdate { address, amount })) => { + debug!( + "[finalize_block] EvmIn for address {:x?}, amount: {}, context {}", + address, amount, context + ); + if let Err(e) = executor.add_balance(address, amount) { + debug!("[finalize_block] EvmIn failed with {e}"); + failed_transactions.push(hex::encode(hash)); + } + } + QueueTx::BridgeTx(BridgeTx::EvmOut(BalanceUpdate { address, amount })) => { + debug!( + "[finalize_block] EvmOut for address {}, amount: {}", + address, amount + ); + + if let Err(e) = executor.sub_balance(address, amount) { + debug!("[finalize_block] EvmOut failed with {e}"); + failed_transactions.push(hex::encode(hash)); + } + } + } + + executor.commit(); + } + + if update_state { + self.evm.tx_queues.remove(context); + } + + let block = Block::new( + PartialHeader { + parent_hash, + beneficiary, + state_root: if update_state { + backend.commit() + } else { + backend.root() + }, + receipts_root: ReceiptHandler::get_receipts_root(&receipts_v3), + logs_bloom, + difficulty: U256::from(difficulty), + number: current_block_number, + gas_limit: U256::from(30_000_000), + gas_used: U256::from(gas_used), + timestamp, + extra_data: Vec::default(), + mix_hash: H256::default(), + nonce: H64::default(), + }, + all_transactions + .iter() + .map(|signed_tx| signed_tx.transaction.clone()) + .collect(), + Vec::new(), + ); + + let receipts = self.receipt.generate_receipts( + &all_transactions, + receipts_v3, + block.header.hash(), + block.header.number, + ); + + if update_state { + debug!( + "[finalize_block] Finalizing block number {:#x}, state_root {:#x}", + block.header.number, block.header.state_root + ); + // calculate base fee + let base_fee = self.block.calculate_base_fee(parent_hash); + + self.block.connect_block(block.clone(), base_fee); + self.receipt.put_receipts(receipts); + } + + Ok(( + *block.header.hash().as_fixed_bytes(), + failed_transactions, + gas_used, + )) + } +} diff --git a/lib/ain-evm/src/lib.rs b/lib/ain-evm/src/lib.rs new file mode 100644 index 0000000000..1a59caaa68 --- /dev/null +++ b/lib/ain-evm/src/lib.rs @@ -0,0 +1,15 @@ +mod backend; +pub mod block; +mod ecrecover; +pub mod evm; +pub mod executor; +mod fee; +mod genesis; +pub mod handler; +pub mod receipt; +pub mod runtime; +pub mod storage; +pub mod traits; +pub mod transaction; +mod trie; +mod tx_queue; diff --git a/lib/ain-evm/src/receipt.rs b/lib/ain-evm/src/receipt.rs new file mode 100644 index 0000000000..8b7d64d8e4 --- /dev/null +++ b/lib/ain-evm/src/receipt.rs @@ -0,0 +1,116 @@ +use crate::storage::{traits::ReceiptStorage, Storage}; +use crate::transaction::SignedTx; +use ethereum::{EnvelopedEncodable, ReceiptV3}; +use primitive_types::{H160, H256, U256}; + +use ethereum::util::ordered_trie_root; +use keccak_hash::keccak; +use rlp::RlpStream; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Receipt { + pub tx_hash: H256, + pub receipt: ReceiptV3, + pub block_hash: H256, + pub block_number: U256, + pub from: H160, + pub to: Option, + pub tx_index: usize, + pub tx_type: u8, + pub contract_address: Option, + pub logs_index: usize, + pub cumulative_gas: U256, +} + +pub struct ReceiptHandler { + storage: Arc, +} + +fn get_contract_address(sender: &H160, nonce: &U256) -> H160 { + let mut stream = RlpStream::new_list(2); + stream.append(sender); + stream.append(nonce); + + H160::from(keccak(stream.as_raw())) +} + +impl ReceiptHandler { + pub fn new(storage: Arc) -> Self { + Self { storage } + } + + pub fn get_receipts_root(receipts: &[ReceiptV3]) -> H256 { + ordered_trie_root( + receipts + .iter() + .map(|r| EnvelopedEncodable::encode(r).freeze()), + ) + } + + pub fn generate_receipts( + &self, + transactions: &[Box], + receipts: Vec, + block_hash: H256, + block_number: U256, + ) -> Vec { + let mut logs_size = 0; + let mut cumulative_gas = U256::zero(); + + transactions + .iter() + .enumerate() + .zip(receipts.into_iter()) + .map(|((index, signed_tx), receipt)| { + let receipt_data = match &receipt { + ReceiptV3::Legacy(data) + | ReceiptV3::EIP2930(data) + | ReceiptV3::EIP1559(data) => data, + }; + let logs_len = receipt_data.logs.len(); + logs_size += logs_len; + cumulative_gas += receipt_data.used_gas; + + Receipt { + receipt, + block_hash, + block_number, + tx_hash: signed_tx.transaction.hash(), + from: signed_tx.sender, + to: signed_tx.to(), + tx_index: index, + tx_type: signed_tx.transaction.type_id().unwrap_or_default(), + contract_address: signed_tx + .to() + .is_none() + .then(|| get_contract_address(&signed_tx.sender, &signed_tx.nonce())), + logs_index: logs_size - logs_len, + cumulative_gas, + } + }) + .collect() + } + + pub fn put_receipts(&self, receipts: Vec) { + self.storage.put_receipts(receipts) + } +} + +#[cfg(test)] +mod test { + use crate::receipt::get_contract_address; + use primitive_types::{H160, U256}; + use std::str::FromStr; + + #[test] + pub fn test_contract_address() { + let sender = H160::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); + let expected = H160::from_str("3f09c73a5ed19289fb9bdc72f1742566df146f56").unwrap(); + + let actual = get_contract_address(&sender, &U256::from(88)); + + assert_eq!(actual, expected); + } +} diff --git a/lib/ain-evm/src/runtime.rs b/lib/ain-evm/src/runtime.rs new file mode 100644 index 0000000000..16b252cb85 --- /dev/null +++ b/lib/ain-evm/src/runtime.rs @@ -0,0 +1,68 @@ +use crate::handler::Handlers; +use crate::storage::traits::FlushableStorage; + +use jsonrpsee_http_server::HttpServerHandle; +use std::sync::{Arc, Mutex}; +use std::thread::{self, JoinHandle}; +use tokio::runtime::{Builder, Handle as AsyncHandle}; +use tokio::sync::mpsc::{self, Sender}; + +lazy_static::lazy_static! { + // Global runtime exposed by the library + pub static ref RUNTIME: Runtime = Runtime::new(); +} + +pub struct Runtime { + pub rt_handle: AsyncHandle, + pub tx: Sender<()>, + pub handle: Mutex>>, + pub jrpc_handle: Mutex>, // dropping the handle kills server + pub handlers: Arc, +} + +impl Default for Runtime { + fn default() -> Self { + Self::new() + } +} + +impl Runtime { + pub fn new() -> Self { + let r = Builder::new_multi_thread().enable_all().build().unwrap(); + let (tx, mut rx) = mpsc::channel(1); + + Runtime { + tx, + rt_handle: r.handle().clone(), + handle: Mutex::new(Some(thread::spawn(move || { + log::info!("Starting runtime in a separate thread"); + r.block_on(async move { + rx.recv().await; + }); + }))), + jrpc_handle: Mutex::new(None), + handlers: Arc::new(Handlers::new().expect("Error initializating handlers")), + } + } + + pub fn stop(&self) { + let _ = self.tx.blocking_send(()); + self.handle + .lock() + .unwrap() + .take() + .expect("runtime terminated?") + .join() + .unwrap(); + + // Persist EVM State to disk + self.handlers + .evm + .flush() + .expect("Could not flush evm state"); + self.handlers + .storage + .flush() + .expect("Could not flush storage"); + } +} diff --git a/lib/ain-evm/src/storage/cache.rs b/lib/ain-evm/src/storage/cache.rs new file mode 100644 index 0000000000..02d4859ecc --- /dev/null +++ b/lib/ain-evm/src/storage/cache.rs @@ -0,0 +1,165 @@ +use std::{num::NonZeroUsize, sync::RwLock}; + +use ethereum::{BlockAny, TransactionV2}; +use lru::LruCache; +use primitive_types::{H256, U256}; +use std::borrow::ToOwned; + +use super::traits::{BlockStorage, Rollback, TransactionStorage}; + +#[derive(Debug)] +pub struct Cache { + transactions: RwLock>, + blocks: RwLock>, + block_hashes: RwLock>, + base_fee: RwLock>, + latest_block: RwLock>, +} + +impl Cache { + const DEFAULT_CACHE_SIZE: usize = 1000; + + pub fn new(cache_size: Option) -> Self { + Cache { + transactions: RwLock::new(LruCache::new( + NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), + )), + blocks: RwLock::new(LruCache::new( + NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), + )), + block_hashes: RwLock::new(LruCache::new( + NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), + )), + base_fee: RwLock::new(LruCache::new( + NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), + )), + latest_block: RwLock::new(None), + } + } +} + +impl BlockStorage for Cache { + fn get_block_by_number(&self, number: &U256) -> Option { + self.blocks + .write() + .unwrap() + .get(number) + .map(ToOwned::to_owned) + } + + fn get_block_by_hash(&self, block_hash: &H256) -> Option { + self.block_hashes + .write() + .unwrap() + .get(block_hash) + .and_then(|block_number| self.get_block_by_number(block_number)) + } + + fn put_block(&self, block: &BlockAny) { + self.extend_transactions_from_block(block); + + let block_number = block.header.number; + let hash = block.header.hash(); + self.blocks + .write() + .unwrap() + .put(block_number, block.clone()); + self.block_hashes.write().unwrap().put(hash, block_number); + } + + fn get_latest_block(&self) -> Option { + self.latest_block + .read() + .unwrap() + .as_ref() + .map(ToOwned::to_owned) + } + + fn put_latest_block(&self, block: Option<&BlockAny>) { + let mut cache = self.latest_block.write().unwrap(); + *cache = block.cloned(); + } + + fn get_base_fee(&self, block_hash: &H256) -> Option { + self.base_fee + .write() + .unwrap() + .get(block_hash) + .map(ToOwned::to_owned) + } + + fn set_base_fee(&self, block_hash: H256, base_fee: U256) { + let mut cache = self.base_fee.write().unwrap(); + cache.put(block_hash, base_fee); + } +} + +impl TransactionStorage for Cache { + fn extend_transactions_from_block(&self, block: &BlockAny) { + let mut cache = self.transactions.write().unwrap(); + + for transaction in &block.transactions { + let hash = transaction.hash(); + cache.put(hash, transaction.clone()); + } + } + + fn get_transaction_by_hash(&self, hash: &H256) -> Option { + self.transactions + .write() + .unwrap() + .get(hash) + .map(ToOwned::to_owned) + } + + fn get_transaction_by_block_hash_and_index( + &self, + block_hash: &H256, + index: usize, + ) -> Option { + self.block_hashes + .write() + .unwrap() + .get(block_hash) + .and_then(|block_number| { + self.get_transaction_by_block_number_and_index(block_number, index) + }) + } + + fn get_transaction_by_block_number_and_index( + &self, + block_number: &U256, + index: usize, + ) -> Option { + self.blocks + .write() + .unwrap() + .get(block_number)? + .transactions + .get(index) + .map(ToOwned::to_owned) + } + + fn put_transaction(&self, transaction: &TransactionV2) { + self.transactions + .write() + .unwrap() + .put(transaction.hash(), transaction.clone()); + } +} + +impl Rollback for Cache { + fn disconnect_latest_block(&self) { + if let Some(block) = self.get_latest_block() { + let mut transaction_cache = self.transactions.write().unwrap(); + for tx in &block.transactions { + transaction_cache.pop(&tx.hash()); + } + + self.block_hashes.write().unwrap().pop(&block.header.hash()); + self.blocks.write().unwrap().pop(&block.header.number); + + self.put_latest_block(self.get_block_by_hash(&block.header.parent_hash).as_ref()) + } + } +} diff --git a/lib/ain-evm/src/storage/code.rs b/lib/ain-evm/src/storage/code.rs new file mode 100644 index 0000000000..76c37b05f8 --- /dev/null +++ b/lib/ain-evm/src/storage/code.rs @@ -0,0 +1,43 @@ +use primitive_types::{H256, U256}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +use super::traits::PersistentState; + +/// `CodeHistory` maintains a history of accounts' codes. +/// +/// It tracks the current state (`code_map`), as well as a history (`history`) of code hashes +/// that should be removed if a specific block is rolled back. The correct account code_hash +/// is tracked by the state trie. +/// This structure is solely required for rolling back and preventing ghost entries. +#[derive(Default, Debug, Serialize, Deserialize)] +pub struct CodeHistory { + /// The current state of each code + code_map: HashMap>, + /// A map from block number to a vector of code hashes to remove for that block. + history: HashMap>, +} + +impl PersistentState for CodeHistory {} + +impl CodeHistory { + pub fn insert(&mut self, block_number: U256, code_hash: H256, code: Vec) { + self.code_map.insert(code_hash, code); + self.history + .entry(block_number) + .or_insert_with(Vec::new) + .push(code_hash); + } + + pub fn get(&self, code_hash: &H256) -> Option<&Vec> { + self.code_map.get(code_hash) + } + + pub fn rollback(&mut self, block_number: U256) { + if let Some(code_hashes) = self.history.remove(&block_number) { + for code_hash in &code_hashes { + self.code_map.remove(code_hash); + } + } + } +} diff --git a/lib/ain-evm/src/storage/data_handler.rs b/lib/ain-evm/src/storage/data_handler.rs new file mode 100644 index 0000000000..181a40b6f4 --- /dev/null +++ b/lib/ain-evm/src/storage/data_handler.rs @@ -0,0 +1,279 @@ +use std::{collections::HashMap, sync::RwLock}; + +use ethereum::{BlockAny, TransactionV2}; +use primitive_types::{H256, U256}; +use std::borrow::ToOwned; + +use crate::receipt::Receipt; + +use super::{ + code::CodeHistory, + traits::{ + BlockStorage, FlushableStorage, PersistentState, PersistentStateError, ReceiptStorage, + Rollback, TransactionStorage, + }, +}; + +pub static BLOCK_MAP_PATH: &str = "block_map.bin"; +pub static BLOCK_DATA_PATH: &str = "block_data.bin"; +pub static LATEST_BLOCK_DATA_PATH: &str = "latest_block_data.bin"; +pub static RECEIPT_MAP_PATH: &str = "receipt_map.bin"; +pub static CODE_MAP_PATH: &str = "code_map.bin"; +pub static TRANSACTION_DATA_PATH: &str = "transaction_data.bin"; +pub static BASE_FEE_MAP_PATH: &str = "base_fee_map.bin"; + +type BlockHashtoBlock = HashMap; +type Blocks = HashMap; +type TxHashToTx = HashMap; +type LatestBlockNumber = U256; +type TransactionHashToReceipt = HashMap; +type BlockHashtoBaseFee = HashMap; + +impl PersistentState for BlockHashtoBlock {} +impl PersistentState for Blocks {} +impl PersistentState for LatestBlockNumber {} +impl PersistentState for TransactionHashToReceipt {} +impl PersistentState for TxHashToTx {} + +#[derive(Debug, Default)] +pub struct BlockchainDataHandler { + // Improvements: Add transaction_map behind feature flag -txindex or equivalent + transactions: RwLock, + + receipts: RwLock, + + block_map: RwLock, + blocks: RwLock, + latest_block_number: RwLock>, + base_fee_map: RwLock, + + code_map: RwLock, +} + +impl BlockchainDataHandler { + pub fn restore() -> Self { + BlockchainDataHandler { + transactions: RwLock::new( + TxHashToTx::load_from_disk(TRANSACTION_DATA_PATH) + .expect("Error loading blocks data"), + ), + block_map: RwLock::new( + BlockHashtoBlock::load_from_disk(BLOCK_MAP_PATH) + .expect("Error loading block_map data"), + ), + latest_block_number: RwLock::new( + LatestBlockNumber::load_from_disk(LATEST_BLOCK_DATA_PATH).ok(), + ), + blocks: RwLock::new( + Blocks::load_from_disk(BLOCK_DATA_PATH).expect("Error loading blocks data"), + ), + receipts: RwLock::new( + TransactionHashToReceipt::load_from_disk(RECEIPT_MAP_PATH) + .expect("Error loading receipts data"), + ), + base_fee_map: RwLock::new( + BlockHashtoBaseFee::load_from_disk(BASE_FEE_MAP_PATH).unwrap_or_default(), + ), + code_map: RwLock::new(CodeHistory::load_from_disk(CODE_MAP_PATH).unwrap_or_default()), + } + } +} + +impl TransactionStorage for BlockchainDataHandler { + // TODO: Feature flag + fn extend_transactions_from_block(&self, block: &BlockAny) { + let mut transactions = self.transactions.write().unwrap(); + + for transaction in &block.transactions { + let hash = transaction.hash(); + transactions.insert(hash, transaction.clone()); + } + } + + fn get_transaction_by_hash(&self, hash: &H256) -> Option { + self.transactions + .read() + .unwrap() + .get(hash) + .map(ToOwned::to_owned) + } + + fn get_transaction_by_block_hash_and_index( + &self, + block_hash: &H256, + index: usize, + ) -> Option { + self.block_map + .write() + .unwrap() + .get(block_hash) + .and_then(|block_number| { + self.get_transaction_by_block_number_and_index(block_number, index) + }) + } + + fn get_transaction_by_block_number_and_index( + &self, + block_number: &U256, + index: usize, + ) -> Option { + self.blocks + .write() + .unwrap() + .get(block_number)? + .transactions + .get(index) + .map(ToOwned::to_owned) + } + + fn put_transaction(&self, transaction: &TransactionV2) { + self.transactions + .write() + .unwrap() + .insert(transaction.hash(), transaction.clone()); + } +} + +impl BlockStorage for BlockchainDataHandler { + fn get_block_by_number(&self, number: &U256) -> Option { + self.blocks + .write() + .unwrap() + .get(number) + .map(ToOwned::to_owned) + } + + fn get_block_by_hash(&self, block_hash: &H256) -> Option { + self.block_map + .write() + .unwrap() + .get(block_hash) + .and_then(|block_number| self.get_block_by_number(block_number)) + } + + fn put_block(&self, block: &BlockAny) { + self.extend_transactions_from_block(block); + + let block_number = block.header.number; + let hash = block.header.hash(); + self.blocks + .write() + .unwrap() + .insert(block_number, block.clone()); + self.block_map.write().unwrap().insert(hash, block_number); + } + + fn get_latest_block(&self) -> Option { + self.latest_block_number + .read() + .unwrap() + .as_ref() + .and_then(|number| self.get_block_by_number(number)) + } + + fn put_latest_block(&self, block: Option<&BlockAny>) { + let mut latest_block_number = self.latest_block_number.write().unwrap(); + *latest_block_number = block.map(|b| b.header.number); + } + + fn get_base_fee(&self, block_hash: &H256) -> Option { + self.base_fee_map + .read() + .unwrap() + .get(block_hash) + .map(ToOwned::to_owned) + } + + fn set_base_fee(&self, block_hash: H256, base_fee: U256) { + let mut base_fee_map = self.base_fee_map.write().unwrap(); + base_fee_map.insert(block_hash, base_fee); + } +} + +impl ReceiptStorage for BlockchainDataHandler { + fn get_receipt(&self, tx: &H256) -> Option { + self.receipts.read().unwrap().get(tx).map(ToOwned::to_owned) + } + + fn put_receipts(&self, receipts: Vec) { + let mut receipt_map = self.receipts.write().unwrap(); + for receipt in receipts { + receipt_map.insert(receipt.tx_hash, receipt); + } + } +} + +impl FlushableStorage for BlockchainDataHandler { + fn flush(&self) -> Result<(), PersistentStateError> { + self.block_map + .write() + .unwrap() + .save_to_disk(BLOCK_MAP_PATH)?; + self.blocks.write().unwrap().save_to_disk(BLOCK_DATA_PATH)?; + self.latest_block_number + .write() + .unwrap() + .unwrap_or_default() + .save_to_disk(LATEST_BLOCK_DATA_PATH)?; + self.receipts + .write() + .unwrap() + .save_to_disk(RECEIPT_MAP_PATH)?; + self.transactions + .write() + .unwrap() + .save_to_disk(TRANSACTION_DATA_PATH)?; + self.code_map.write().unwrap().save_to_disk(CODE_MAP_PATH)?; + self.base_fee_map + .write() + .unwrap() + .save_to_disk(BASE_FEE_MAP_PATH) + } +} + +impl BlockchainDataHandler { + pub fn get_code_by_hash(&self, hash: &H256) -> Option> { + self.code_map + .read() + .unwrap() + .get(hash) + .map(ToOwned::to_owned) + } + + pub fn put_code(&self, hash: &H256, code: &[u8]) { + let block_number = self + .get_latest_block() + .map(|b| b.header.number) + .unwrap_or_default() + + 1; + self.code_map + .write() + .unwrap() + .insert(block_number, *hash, code.to_vec()) + } +} + +impl Rollback for BlockchainDataHandler { + fn disconnect_latest_block(&self) { + if let Some(block) = self.get_latest_block() { + println!("disconnecting block number : {:x?}", block.header.number); + let mut transactions = self.transactions.write().unwrap(); + let mut receipts = self.receipts.write().unwrap(); + for tx in &block.transactions { + let hash = &tx.hash(); + transactions.remove(hash); + receipts.remove(hash); + } + + self.block_map.write().unwrap().remove(&block.header.hash()); + self.base_fee_map + .write() + .unwrap() + .remove(&block.header.hash()); + self.blocks.write().unwrap().remove(&block.header.number); + self.code_map.write().unwrap().rollback(block.header.number); + + self.put_latest_block(self.get_block_by_hash(&block.header.parent_hash).as_ref()) + } + } +} diff --git a/lib/ain-evm/src/storage/mod.rs b/lib/ain-evm/src/storage/mod.rs new file mode 100644 index 0000000000..622527f001 --- /dev/null +++ b/lib/ain-evm/src/storage/mod.rs @@ -0,0 +1,207 @@ +mod cache; +mod code; +mod data_handler; +pub mod traits; + +use ethereum::{BlockAny, TransactionV2}; +use primitive_types::{H256, U256}; + +use crate::receipt::Receipt; + +use self::{ + cache::Cache, + data_handler::BlockchainDataHandler, + traits::{ + BlockStorage, FlushableStorage, PersistentStateError, ReceiptStorage, Rollback, + TransactionStorage, + }, +}; + +#[derive(Debug)] +pub struct Storage { + cache: Cache, + blockchain_data_handler: BlockchainDataHandler, +} + +impl Default for Storage { + fn default() -> Self { + Self::new() + } +} + +impl Storage { + pub fn new() -> Self { + Self { + cache: Cache::new(None), + blockchain_data_handler: BlockchainDataHandler::default(), + } + } + + pub fn restore() -> Self { + Self { + cache: Cache::new(None), + blockchain_data_handler: BlockchainDataHandler::restore(), + } + } +} + +impl BlockStorage for Storage { + fn get_block_by_number(&self, number: &U256) -> Option { + self.cache.get_block_by_number(number).or_else(|| { + let block = self.blockchain_data_handler.get_block_by_number(number); + if let Some(ref block) = block { + self.cache.put_block(block); + } + block + }) + } + + fn get_block_by_hash(&self, block_hash: &H256) -> Option { + self.cache.get_block_by_hash(block_hash).or_else(|| { + let block = self.blockchain_data_handler.get_block_by_hash(block_hash); + if let Some(ref block) = block { + self.cache.put_block(block); + } + block + }) + } + + fn put_block(&self, block: &BlockAny) { + self.cache.put_block(block); + self.blockchain_data_handler.put_block(block); + } + + fn get_latest_block(&self) -> Option { + self.cache.get_latest_block().or_else(|| { + let latest_block = self.blockchain_data_handler.get_latest_block(); + if let Some(ref block) = latest_block { + self.cache.put_latest_block(Some(block)); + } + latest_block + }) + } + + fn put_latest_block(&self, block: Option<&BlockAny>) { + self.cache.put_latest_block(block); + self.blockchain_data_handler.put_latest_block(block); + } + + fn get_base_fee(&self, block_hash: &H256) -> Option { + self.cache.get_base_fee(block_hash).or_else(|| { + let base_fee = self.blockchain_data_handler.get_base_fee(block_hash); + if let Some(base_fee) = base_fee { + self.cache.set_base_fee(*block_hash, base_fee); + } + base_fee + }) + } + + fn set_base_fee(&self, block_hash: H256, base_fee: U256) { + self.cache.set_base_fee(block_hash, base_fee); + self.blockchain_data_handler + .set_base_fee(block_hash, base_fee); + } +} + +impl TransactionStorage for Storage { + fn extend_transactions_from_block(&self, block: &BlockAny) { + // Feature flag + self.cache.extend_transactions_from_block(block); + + self.blockchain_data_handler + .extend_transactions_from_block(block); + } + + fn get_transaction_by_hash(&self, hash: &H256) -> Option { + self.cache.get_transaction_by_hash(hash).or_else(|| { + let transaction = self.blockchain_data_handler.get_transaction_by_hash(hash); + if let Some(ref transaction) = transaction { + self.cache.put_transaction(transaction); + } + transaction + }) + } + + fn get_transaction_by_block_hash_and_index( + &self, + hash: &H256, + index: usize, + ) -> Option { + self.cache + .get_transaction_by_block_hash_and_index(hash, index) + .or_else(|| { + let transaction = self + .blockchain_data_handler + .get_transaction_by_block_hash_and_index(hash, index); + if let Some(ref transaction) = transaction { + self.cache.put_transaction(transaction) + } + transaction + }) + } + + fn get_transaction_by_block_number_and_index( + &self, + number: &U256, + index: usize, + ) -> Option { + self.cache + .get_transaction_by_block_number_and_index(number, index) + .or_else(|| { + let transaction = self + .blockchain_data_handler + .get_transaction_by_block_number_and_index(number, index); + if let Some(ref transaction) = transaction { + self.cache.put_transaction(transaction) + } + transaction + }) + } + + fn put_transaction(&self, transaction: &TransactionV2) { + self.cache.put_transaction(transaction); + self.blockchain_data_handler.put_transaction(transaction); + } +} + +impl ReceiptStorage for Storage { + fn get_receipt(&self, tx: &H256) -> Option { + self.blockchain_data_handler.get_receipt(tx) + } + + fn put_receipts(&self, receipts: Vec) { + self.blockchain_data_handler.put_receipts(receipts) + } +} + +impl FlushableStorage for Storage { + fn flush(&self) -> Result<(), PersistentStateError> { + self.blockchain_data_handler.flush() + } +} + +impl Storage { + pub fn get_code_by_hash(&self, hash: H256) -> Option> { + self.blockchain_data_handler.get_code_by_hash(&hash) + } + + pub fn put_code(&self, hash: H256, code: Vec) { + self.blockchain_data_handler.put_code(&hash, &code) + } +} + +impl Storage { + pub fn dump_db(&self) { + println!( + "self.block_data_handler : {:#?}", + self.blockchain_data_handler + ); + } +} + +impl Rollback for Storage { + fn disconnect_latest_block(&self) { + self.cache.disconnect_latest_block(); + self.blockchain_data_handler.disconnect_latest_block(); + } +} diff --git a/lib/ain-evm/src/storage/traits.rs b/lib/ain-evm/src/storage/traits.rs new file mode 100644 index 0000000000..e43d86625b --- /dev/null +++ b/lib/ain-evm/src/storage/traits.rs @@ -0,0 +1,127 @@ +use crate::receipt::Receipt; +use ethereum::BlockAny; +use ethereum::TransactionV2; +use keccak_hash::H256; +use log::debug; +use primitive_types::U256; +use std::fs::File; + +use std::fmt; +use std::io; +use std::io::Write; +use std::path::Path; +use std::path::PathBuf; + +pub trait BlockStorage { + fn get_block_by_number(&self, number: &U256) -> Option; + fn get_block_by_hash(&self, block_hash: &H256) -> Option; + fn put_block(&self, block: &BlockAny); + fn get_latest_block(&self) -> Option; + fn put_latest_block(&self, block: Option<&BlockAny>); + + fn get_base_fee(&self, block_hash: &H256) -> Option; + fn set_base_fee(&self, block_hash: H256, base_fee: U256); +} + +pub trait TransactionStorage { + fn extend_transactions_from_block(&self, block: &BlockAny); + fn get_transaction_by_hash(&self, hash: &H256) -> Option; + fn get_transaction_by_block_hash_and_index( + &self, + hash: &H256, + index: usize, + ) -> Option; + fn get_transaction_by_block_number_and_index( + &self, + number: &U256, + index: usize, + ) -> Option; + fn put_transaction(&self, transaction: &TransactionV2); +} + +pub trait ReceiptStorage { + fn get_receipt(&self, tx: &H256) -> Option; + fn put_receipts(&self, receipts: Vec); +} + +pub trait FlushableStorage { + fn flush(&self) -> Result<(), PersistentStateError>; +} + +pub trait Rollback { + fn disconnect_latest_block(&self); +} + +pub trait PersistentState { + fn save_to_disk(&self, file_path: &str) -> Result<(), PersistentStateError> + where + Self: serde::ser::Serialize, + { + // Automatically resolves from datadir for now + let path = match ain_cpp_imports::get_datadir() { + Ok(path) => { + let path = PathBuf::from(path).join("evm"); + if !path.exists() { + std::fs::create_dir(&path).expect("Error creating `evm` dir"); + } + path.join(file_path) + } + _ => PathBuf::from(file_path), + }; + + let serialized_state = bincode::serialize(self)?; + let mut file = File::create(path)?; + file.write_all(&serialized_state)?; + Ok(()) + } + + fn load_from_disk(file_path: &str) -> Result + where + Self: Sized + serde::de::DeserializeOwned + Default, + { + debug!("Restoring {} from disk", file_path); + + // Automatically resolves from datadir for now + let path = match ain_cpp_imports::get_datadir() { + Ok(path) => PathBuf::from(path).join("evm").join(file_path), + _ => PathBuf::from(file_path), + }; + + if Path::new(&path).exists() { + let file = File::open(path)?; + let new_state: Self = bincode::deserialize_from(file)?; + Ok(new_state) + } else { + Ok(Self::default()) + } + } +} + +#[derive(Debug)] +pub enum PersistentStateError { + IoError(io::Error), + BincodeError(bincode::Error), +} + +impl fmt::Display for PersistentStateError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + PersistentStateError::IoError(err) => write!(f, "IO error: {err}"), + PersistentStateError::BincodeError(err) => write!(f, "Bincode error: {err}"), + } + } +} + +impl std::error::Error for PersistentStateError {} + +impl From for PersistentStateError { + fn from(error: io::Error) -> Self { + PersistentStateError::IoError(error) + } +} + +impl From for PersistentStateError { + fn from(error: bincode::Error) -> Self { + PersistentStateError::BincodeError(error) + } +} diff --git a/lib/ain-evm/src/traits.rs b/lib/ain-evm/src/traits.rs new file mode 100644 index 0000000000..3fab8b4cb7 --- /dev/null +++ b/lib/ain-evm/src/traits.rs @@ -0,0 +1,28 @@ +use crate::{backend::EVMBackendError, executor::TxResponse, transaction::SignedTx}; +use ethereum::{AccessList, ReceiptV3}; +use evm::Config; +use primitive_types::{H160, U256}; + +#[derive(Debug)] +pub struct ExecutorContext<'a> { + pub caller: Option, + pub to: Option, + pub value: U256, + pub data: &'a [u8], + pub gas_limit: u64, + pub access_list: AccessList, +} + +pub trait Executor { + const CONFIG: Config = Config::shanghai(); + + fn call(&mut self, ctx: ExecutorContext) -> TxResponse; + + fn exec(&mut self, tx: &SignedTx) -> (TxResponse, ReceiptV3); +} + +pub trait BridgeBackend { + fn add_balance(&mut self, address: H160, amount: U256) -> Result<(), EVMBackendError>; + + fn sub_balance(&mut self, address: H160, amount: U256) -> Result<(), EVMBackendError>; +} diff --git a/lib/ain-evm/src/transaction/bridge.rs b/lib/ain-evm/src/transaction/bridge.rs new file mode 100644 index 0000000000..2f3d258f64 --- /dev/null +++ b/lib/ain-evm/src/transaction/bridge.rs @@ -0,0 +1,13 @@ +use primitive_types::{H160, U256}; + +#[derive(Debug, Clone)] +pub struct BalanceUpdate { + pub address: H160, + pub amount: U256, +} + +#[derive(Debug, Clone)] +pub enum BridgeTx { + EvmIn(BalanceUpdate), + EvmOut(BalanceUpdate), +} diff --git a/lib/ain-evm/src/transaction/mod.rs b/lib/ain-evm/src/transaction/mod.rs new file mode 100644 index 0000000000..c0f11ddd57 --- /dev/null +++ b/lib/ain-evm/src/transaction/mod.rs @@ -0,0 +1,350 @@ +pub mod bridge; +use crate::ecrecover::{public_key_to_address, recover_public_key}; +use ethereum::{ + AccessList, EnvelopedDecoderError, LegacyTransaction, TransactionAction, TransactionSignature, + TransactionV2, +}; +use libsecp256k1::PublicKey; +use primitive_types::{H160, H256, U256}; + +use rlp::RlpStream; +use sha3::Digest; + +// Lowest acceptable value for r and s in sig. +pub const LOWER_H256: H256 = H256([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +]); + +#[derive(Clone, Debug)] +pub struct LegacyUnsignedTransaction { + pub nonce: U256, + pub gas_price: U256, + pub gas_limit: U256, + pub action: TransactionAction, + pub value: U256, + pub input: Vec, + pub sig: TransactionSignature, +} + +impl LegacyUnsignedTransaction { + fn signing_rlp_append(&self, s: &mut RlpStream, chain_id: u64) { + s.begin_list(9); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas_limit); + s.append(&self.action); + s.append(&self.value); + s.append(&self.input); + s.append(&chain_id); + s.append(&0u8); + s.append(&0u8); + } + + fn signing_hash(&self, chain_id: u64) -> H256 { + let mut stream = RlpStream::new(); + self.signing_rlp_append(&mut stream, chain_id); + let mut output = [0u8; 32]; + output.copy_from_slice(sha3::Keccak256::digest(&stream.out()).as_slice()); + H256::from(output) + } + + pub fn sign(&self, key: &H256, chain_id: u64) -> Result { + self.sign_with_chain_id(key, chain_id) + } + + pub fn sign_with_chain_id( + &self, + key: &H256, + chain_id: u64, + ) -> Result { + let hash = self.signing_hash(chain_id); + let msg = libsecp256k1::Message::parse(hash.as_fixed_bytes()); + let s = libsecp256k1::sign(&msg, &libsecp256k1::SecretKey::parse_slice(&key[..])?); + let sig = s.0.serialize(); + + let sig = TransactionSignature::new( + s.1.serialize() as u64 % 2 + chain_id * 2 + 35, + H256::from_slice(&sig[0..32]), + H256::from_slice(&sig[32..64]), + ) + .ok_or(TransactionError::SignatureError)?; + + Ok(LegacyTransaction { + nonce: self.nonce, + gas_price: self.gas_price, + gas_limit: self.gas_limit, + action: self.action, + value: self.value, + input: self.input.clone(), + signature: sig, + }) + } +} + +impl From<&LegacyTransaction> for LegacyUnsignedTransaction { + fn from(src: &LegacyTransaction) -> LegacyUnsignedTransaction { + LegacyUnsignedTransaction { + nonce: src.nonce, + gas_price: src.gas_price, + gas_limit: src.gas_limit, + action: src.action, + value: src.value, + input: src.input.clone(), + sig: src.signature.clone(), + } + } +} + +#[derive(Clone, Debug)] +pub struct SignedTx { + pub transaction: TransactionV2, + pub sender: H160, + pub pubkey: PublicKey, +} + +impl TryFrom for SignedTx { + type Error = TransactionError; + + fn try_from(src: TransactionV2) -> Result { + let pubkey = match &src { + TransactionV2::Legacy(tx) => { + let t = LegacyUnsignedTransaction { + nonce: tx.nonce, + gas_price: tx.gas_price, + gas_limit: tx.gas_limit, + action: tx.action, + value: tx.value, + input: tx.input.clone(), + sig: tx.signature.clone(), + }; + + recover_public_key( + &t.signing_hash(t.sig.chain_id().unwrap()), + tx.signature.r(), + tx.signature.s(), + tx.signature.standard_v(), + ) + } + TransactionV2::EIP2930(tx) => { + let msg = ethereum::EIP2930TransactionMessage { + chain_id: tx.chain_id, + nonce: tx.nonce, + gas_price: tx.gas_price, + gas_limit: tx.gas_limit, + action: tx.action, + value: tx.value, + input: tx.input.clone(), + access_list: tx.access_list.clone(), + }; + let signing_message = libsecp256k1::Message::parse_slice(&msg.hash()[..]).unwrap(); + let hash = H256::from(signing_message.serialize()); + recover_public_key(&hash, &tx.r, &tx.s, u8::from(tx.odd_y_parity)) + } + TransactionV2::EIP1559(tx) => { + let msg = ethereum::EIP1559TransactionMessage { + chain_id: tx.chain_id, + nonce: tx.nonce, + max_priority_fee_per_gas: tx.max_priority_fee_per_gas, + max_fee_per_gas: tx.max_fee_per_gas, + gas_limit: tx.gas_limit, + action: tx.action, + value: tx.value, + input: tx.input.clone(), + access_list: tx.access_list.clone(), + }; + let signing_message = libsecp256k1::Message::parse_slice(&msg.hash()[..]).unwrap(); + let hash = H256::from(signing_message.serialize()); + recover_public_key(&hash, &tx.r, &tx.s, u8::from(tx.odd_y_parity)) + } + }?; + Ok(SignedTx { + transaction: src, + sender: public_key_to_address(&pubkey), + pubkey, + }) + } +} + +use hex::FromHex; + +impl TryFrom<&str> for SignedTx { + type Error = TransactionError; + + fn try_from(src: &str) -> Result { + let buffer = >::from_hex(src)?; + let tx: TransactionV2 = ethereum::EnvelopedDecodable::decode(&buffer)?; + + tx.try_into() + } +} + +impl SignedTx { + pub fn nonce(&self) -> U256 { + match &self.transaction { + TransactionV2::Legacy(t) => t.nonce, + TransactionV2::EIP2930(t) => t.nonce, + TransactionV2::EIP1559(t) => t.nonce, + } + } + + pub fn to(&self) -> Option { + match self.action() { + TransactionAction::Call(to) => Some(to), + TransactionAction::Create => None, + } + } + + pub fn action(&self) -> TransactionAction { + match &self.transaction { + TransactionV2::Legacy(t) => t.action, + TransactionV2::EIP2930(t) => t.action, + TransactionV2::EIP1559(t) => t.action, + } + } + + pub fn access_list(&self) -> AccessList { + match &self.transaction { + TransactionV2::Legacy(_) => Vec::new(), + TransactionV2::EIP2930(tx) => tx.access_list.clone(), + TransactionV2::EIP1559(tx) => tx.access_list.clone(), + } + } + + pub fn value(&self) -> U256 { + match &self.transaction { + TransactionV2::Legacy(tx) => tx.value, + TransactionV2::EIP2930(tx) => tx.value, + TransactionV2::EIP1559(tx) => tx.value, + } + } + + pub fn gas_limit(&self) -> U256 { + match &self.transaction { + TransactionV2::Legacy(tx) => tx.gas_limit, + TransactionV2::EIP2930(tx) => tx.gas_limit, + TransactionV2::EIP1559(tx) => tx.gas_limit, + } + } + + pub fn gas_price(&self) -> U256 { + match &self.transaction { + TransactionV2::Legacy(tx) => tx.gas_price, + TransactionV2::EIP2930(tx) => tx.gas_price, + TransactionV2::EIP1559(tx) => tx.max_fee_per_gas, + } + } + + pub fn data(&self) -> &[u8] { + match &self.transaction { + TransactionV2::Legacy(tx) => tx.input.as_ref(), + TransactionV2::EIP2930(tx) => tx.input.as_ref(), + TransactionV2::EIP1559(tx) => tx.input.as_ref(), + } + } + + pub fn v(&self) -> u64 { + match &self.transaction { + TransactionV2::Legacy(tx) => tx.signature.v(), + TransactionV2::EIP2930(tx) => tx.chain_id, + TransactionV2::EIP1559(tx) => tx.chain_id, + } + } + + pub fn r(&self) -> H256 { + match &self.transaction { + TransactionV2::Legacy(tx) => *tx.signature.r(), + TransactionV2::EIP2930(tx) => tx.r, + TransactionV2::EIP1559(tx) => tx.r, + } + } + + pub fn s(&self) -> H256 { + match &self.transaction { + TransactionV2::Legacy(tx) => *tx.signature.s(), + TransactionV2::EIP2930(tx) => tx.s, + TransactionV2::EIP1559(tx) => tx.s, + } + } +} + +use std::convert::{TryFrom, TryInto}; +use std::fmt; + +#[derive(Debug)] +pub enum TransactionError { + Secp256k1Error(libsecp256k1::Error), + DecodingError, + SignatureError, + FromHexError(hex::FromHexError), +} + +impl fmt::Display for TransactionError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + TransactionError::Secp256k1Error(ref e) => write!(f, "Secp256k1 error: {e}"), + TransactionError::DecodingError => { + write!(f, "Error decoding raw transaction") + } + TransactionError::SignatureError => { + write!(f, "Error creating new signature") + } + TransactionError::FromHexError(ref e) => { + write!(f, "Error parsing hex: {e}") + } + } + } +} + +impl std::error::Error for TransactionError {} + +use std::convert::From; + +impl From for TransactionError { + fn from(e: libsecp256k1::Error) -> Self { + TransactionError::Secp256k1Error(e) + } +} + +impl From for TransactionError { + fn from(e: hex::FromHexError) -> Self { + TransactionError::FromHexError(e) + } +} + +impl From> for TransactionError { + fn from(_: EnvelopedDecoderError) -> Self { + TransactionError::DecodingError + } +} + +mod tests { + + #[test] + fn test_signed_tx_from_raw_tx() { + // Legacy + let signed_tx = crate::transaction::SignedTx::try_from("f86b8085689451eee18252089434c1ca09a2dc717d89baef2f30ff6a6b2975e17e872386f26fc10000802da0ae5c76f8073460cbc7a911d3cc1b367072db64848a9532343559ce6917c51a46a01d2e4928450c59acca3de8340eb15b7446b37936265a51ab35e63f749a048002").unwrap(); + + assert_eq!(hex::encode(signed_tx.pubkey.serialize()), "044c6412f7cd3ac0e2538c3c9843d27d1e03b422eaf655c6a699da22b57a89802989318dbaeea62f5fc751fa8cd1404e687d67b8ab8513fe0d37bafbf407aa6cf7"); + assert_eq!( + hex::encode(signed_tx.sender.as_fixed_bytes()), + "f829754bae400b679febefdcfc9944c323e1f94e" + ); + + // EIP-1559 + let signed_tx = crate::transaction::SignedTx::try_from("02f871018302fe7f80850735ebc84f827530942f777e9f26aa138ed21c404079e80656b448c7118774ab8279a9e27380c001a0f97db05e9814734c6d7bcca5ce644fc1b780c28e8617eec4a3142712777cabe7a01ad8667f28d7cc1b2e0884340c67d73644fac314da4bab3bfc068cf00c622774").unwrap(); + + assert_eq!( + hex::encode(signed_tx.sender.as_fixed_bytes()), + "95222290dd7278aa3ddd389cc1e1d165cc4bafe5" + ); + + // EIP-2930 + let signed_tx = crate::transaction::SignedTx::try_from("01f86d050185689451eee18252089434c1ca09a2dc717d89baef2f30ff6a6b2975e17e872386f26fc1000080c080a0632502442f6bd0dbe14c087798277ce04bdede53c4642559a0a7d7e20fc7e8f1a0517c7504cb9adfe67f58dd43e00e77b4b2159e9f2c378b7616ba30dfa711ec8f").unwrap(); + + assert_eq!( + hex::encode(signed_tx.sender.as_fixed_bytes()), + "f829754bae400b679febefdcfc9944c323e1f94e" + ); + } +} diff --git a/lib/ain-evm/src/trie.rs b/lib/ain-evm/src/trie.rs new file mode 100644 index 0000000000..3a78a56a5e --- /dev/null +++ b/lib/ain-evm/src/trie.rs @@ -0,0 +1,102 @@ +use crate::backend::{EVMBackend, Vicinity}; +use crate::genesis::GenesisData; +use crate::storage::traits::{PersistentState, PersistentStateError}; +use crate::storage::Storage; + +use evm::backend::{Backend, Basic}; +use log::debug; +use primitive_types::H256; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::io::BufReader; +use std::path::PathBuf; +use std::sync::Arc; +use vsdb_trie_db::MptStore; + +pub static TRIE_DB_STORE: &str = "trie_db_store.bin"; +pub static GENESIS_STATE_ROOT: &str = + "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"; + +#[derive(Serialize, Deserialize)] +pub struct TrieDBStore { + pub trie_db: MptStore, +} + +impl PersistentState for TrieDBStore {} + +impl Default for TrieDBStore { + fn default() -> Self { + Self::new() + } +} + +impl TrieDBStore { + pub fn new() -> Self { + debug!("Creating new trie store"); + let trie_store = MptStore::new(); + let mut trie = trie_store + .trie_create(&[0], None, false) + .expect("Error creating initial backend"); + let state_root: H256 = trie.commit().into(); + debug!("Initial state_root : {:#x}", state_root); + Self { + trie_db: trie_store, + } + } + + pub fn restore() -> Self { + TrieDBStore::load_from_disk(TRIE_DB_STORE).expect("Error loading trie db store") + } + + /// # Warning + /// + /// This function should only be used in a regtest environment. + /// Can conflict with existing chain state if used on another network + pub fn genesis_state_root_from_json( + trie_store: &Arc, + storage: &Arc, + json_file: PathBuf, + ) -> Result { + let state_root: H256 = GENESIS_STATE_ROOT.parse().unwrap(); + + let mut backend = EVMBackend::from_root( + state_root, + Arc::clone(trie_store), + Arc::clone(storage), + Vicinity::default(), + ) + .expect("Could not restore backend"); + + let file = fs::File::open(json_file)?; + let reader = BufReader::new(file); + let genesis: GenesisData = serde_json::from_reader(reader)?; + + for (address, data) in genesis.alloc { + debug!("Setting data {:#?} for address {:x?}", data, address); + let basic = backend.basic(address); + + let new_basic = Basic { + balance: data.balance, + ..basic + }; + backend + .apply( + address, + new_basic, + data.code, + data.storage.unwrap_or_default(), + false, + ) + .expect("Could not set account data"); + backend.commit(); + } + + let state_root = backend.commit(); + debug!("Loaded genesis state_root : {:#x}", state_root); + Ok(state_root) + } + + pub fn flush(&self) -> Result<(), PersistentStateError> { + self.save_to_disk(TRIE_DB_STORE) + } +} diff --git a/lib/ain-evm/src/tx_queue.rs b/lib/ain-evm/src/tx_queue.rs new file mode 100644 index 0000000000..bec3e9658c --- /dev/null +++ b/lib/ain-evm/src/tx_queue.rs @@ -0,0 +1,306 @@ +use ethereum_types::{H160, U256}; +use rand::Rng; +use std::{ + collections::HashMap, + sync::{Mutex, RwLock}, +}; + +use crate::{ + evm::NativeTxHash, + transaction::{bridge::BridgeTx, SignedTx}, +}; + +#[derive(Debug)] +pub struct TransactionQueueMap { + queues: RwLock>, +} + +impl Default for TransactionQueueMap { + fn default() -> Self { + Self::new() + } +} + +/// Holds multiple `TransactionQueue`s, each associated with a unique context ID. +/// +/// Context IDs are randomly generated and used to access distinct transaction queues. +impl TransactionQueueMap { + pub fn new() -> Self { + TransactionQueueMap { + queues: RwLock::new(HashMap::new()), + } + } + + /// `get_context` generates a unique random ID, creates a new `TransactionQueue` for that ID, + /// and then returns the ID. + pub fn get_context(&self) -> u64 { + let mut rng = rand::thread_rng(); + loop { + let context = rng.gen(); + let mut write_guard = self.queues.write().unwrap(); + + if let std::collections::hash_map::Entry::Vacant(e) = write_guard.entry(context) { + e.insert(TransactionQueue::new()); + return context; + } + } + } + + /// Try to remove and return the `TransactionQueue` associated with the provided + /// context ID. + pub fn remove(&self, context_id: u64) -> Option { + self.queues.write().unwrap().remove(&context_id) + } + + /// Clears the `TransactionQueue` vector associated with the provided context ID. + pub fn clear(&self, context_id: u64) -> Result<(), QueueError> { + self.queues + .read() + .unwrap() + .get(&context_id) + .ok_or(QueueError::NoSuchContext) + .map(TransactionQueue::clear) + } + + /// Attempts to add a new transaction to the `TransactionQueue` associated with the + /// provided context ID. If the transaction is a `SignedTx`, it also updates the + /// corresponding account's nonce. + /// Nonces for each account's transactions must be in strictly increasing order. This means that if the last + /// queued transaction for an account has nonce 3, the next one should have nonce 4. If a `SignedTx` with a nonce + /// that is not one more than the previous nonce is added, an error is returned. This helps to ensure the integrity + /// of the transaction queue and enforce correct nonce usage. + /// + /// # Errors + /// + /// Returns `QueueError::NoSuchContext` if no queue is associated with the given context ID. + /// Returns `QueueError::InvalidNonce` if a `SignedTx` is provided with a nonce that is not one more than the + /// previous nonce of transactions from the same sender in the queue. + /// + pub fn queue_tx( + &self, + context_id: u64, + tx: QueueTx, + hash: NativeTxHash, + ) -> Result<(), QueueError> { + self.queues + .read() + .unwrap() + .get(&context_id) + .ok_or(QueueError::NoSuchContext) + .map(|queue| queue.queue_tx((tx, hash)))? + } + + /// `drain_all` returns all transactions from the `TransactionQueue` associated with the + /// provided context ID, removing them from the queue. Transactions are returned in the + /// order they were added. + pub fn drain_all(&self, context_id: u64) -> Vec { + self.queues + .read() + .unwrap() + .get(&context_id) + .map_or(Vec::new(), TransactionQueue::drain_all) + } + + pub fn get_cloned_vec(&self, context_id: u64) -> Vec { + self.queues + .read() + .unwrap() + .get(&context_id) + .map_or(Vec::new(), TransactionQueue::get_cloned_vec) + } + + pub fn len(&self, context_id: u64) -> usize { + self.queues + .read() + .unwrap() + .get(&context_id) + .map_or(0, TransactionQueue::len) + } + + /// `get_next_valid_nonce` returns the next valid nonce for the account with the provided address + /// in the `TransactionQueue` associated with the provided context ID. This method assumes that + /// only signed transactions (which include a nonce) are added to the queue using `queue_tx` + /// and that their nonces are in increasing order. + pub fn get_next_valid_nonce(&self, context_id: u64, address: H160) -> Option { + self.queues + .read() + .unwrap() + .get(&context_id) + .and_then(|queue| queue.get_next_valid_nonce(address)) + } +} + +#[derive(Debug, Clone)] +pub enum QueueTx { + SignedTx(Box), + BridgeTx(BridgeTx), +} + +type QueueTxWithNativeHash = (QueueTx, NativeTxHash); + +/// The `TransactionQueue` holds a queue of transactions and a map of account nonces. +/// It's used to manage and process transactions for different accounts. +/// +#[derive(Debug, Default)] +pub struct TransactionQueue { + transactions: Mutex>, + account_nonces: Mutex>, +} + +impl TransactionQueue { + pub fn new() -> Self { + Self { + transactions: Mutex::new(Vec::new()), + account_nonces: Mutex::new(HashMap::new()), + } + } + + pub fn clear(&self) { + self.transactions.lock().unwrap().clear(); + } + + pub fn drain_all(&self) -> Vec { + self.transactions + .lock() + .unwrap() + .drain(..) + .collect::>() + } + + pub fn get_cloned_vec(&self) -> Vec { + self.transactions.lock().unwrap().clone() + } + + pub fn queue_tx(&self, tx: QueueTxWithNativeHash) -> Result<(), QueueError> { + if let QueueTx::SignedTx(signed_tx) = &tx.0 { + let mut account_nonces = self.account_nonces.lock().unwrap(); + if let Some(nonce) = account_nonces.get(&signed_tx.sender) { + if signed_tx.nonce() != nonce + 1 { + return Err(QueueError::InvalidNonce((signed_tx.clone(), *nonce))); + } + } + account_nonces.insert(signed_tx.sender, signed_tx.nonce()); + } + self.transactions.lock().unwrap().push(tx); + Ok(()) + } + + pub fn len(&self) -> usize { + self.transactions.lock().unwrap().len() + } + + pub fn get_next_valid_nonce(&self, address: H160) -> Option { + self.account_nonces + .lock() + .unwrap() + .get(&address) + .map(ToOwned::to_owned) + .map(|nonce| nonce + 1) + } +} + +impl From for QueueTx { + fn from(tx: SignedTx) -> Self { + Self::SignedTx(Box::new(tx)) + } +} + +#[derive(Debug)] +pub enum QueueError { + NoSuchContext, + InvalidNonce((Box, U256)), +} + +impl std::fmt::Display for QueueError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + QueueError::NoSuchContext => write!(f, "No transaction queue for this context"), + QueueError::InvalidNonce((tx, nonce)) => write!(f, "Invalid nonce {:x?} for tx {:x?}. Previous queued nonce is {}. TXs should be queued in increasing nonce order.", tx.nonce(), tx.transaction.hash(), nonce), + } + } +} + +impl std::error::Error for QueueError {} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use ethereum_types::{H256, U256}; + + use crate::transaction::bridge::BalanceUpdate; + + use super::*; + + #[test] + fn test_invalid_nonce_order() -> Result<(), QueueError> { + let queue = TransactionQueue::new(); + + // Nonce 2, sender 0xe61a3a6eb316d773c773f4ce757a542f673023c6 + let tx1 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869028502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa0adb0386f95848d33b49ee6057c34e530f87f696a29b4e1b04ef90b2a58bbedbca02f500cf29c5c4245608545e7d9d35b36ef0365e5c52d96e69b8f07920d32552f").unwrap())); + + // Nonce 2, sender 0x6bc42fd533d6cb9d973604155e1f7197a3b0e703 + let tx2 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869028502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa09588b47d2cd3f474d6384309cca5cb8e360cb137679f0a1589a1c184a15cb27ca0453ddbf808b83b279cac3226b61a9d83855aba60ae0d3a8407cba0634da7459d").unwrap())); + + // Nonce 0, sender 0xe61a3a6eb316d773c773f4ce757a542f673023c6 + let tx3 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869808502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa03d28d24808c3de08c606c5544772ded91913f648ad56556f181905208e206c85a00ecd0ba938fb89fc4a17ea333ea842c7305090dee9236e2b632578f9e5045cb3").unwrap())); + + queue.queue_tx((tx1, H256::from_low_u64_be(1).into()))?; + queue.queue_tx((tx2, H256::from_low_u64_be(2).into()))?; + // Should fail as nonce 2 is already queued for this sender + let queued = queue.queue_tx((tx3, H256::from_low_u64_be(3).into())); + assert!(matches!(queued, Err(QueueError::InvalidNonce { .. }))); + Ok(()) + } + + #[test] + fn test_invalid_nonce_order_with_transfer_domain() -> Result<(), QueueError> { + let queue = TransactionQueue::new(); + + // Nonce 2, sender 0xe61a3a6eb316d773c773f4ce757a542f673023c6 + let tx1 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869028502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa0adb0386f95848d33b49ee6057c34e530f87f696a29b4e1b04ef90b2a58bbedbca02f500cf29c5c4245608545e7d9d35b36ef0365e5c52d96e69b8f07920d32552f").unwrap())); + + // Nonce 2, sender 0x6bc42fd533d6cb9d973604155e1f7197a3b0e703 + let tx2 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869028502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa09588b47d2cd3f474d6384309cca5cb8e360cb137679f0a1589a1c184a15cb27ca0453ddbf808b83b279cac3226b61a9d83855aba60ae0d3a8407cba0634da7459d").unwrap())); + + // sender 0x6bc42fd533d6cb9d973604155e1f7197a3b0e703 + let tx3 = QueueTx::BridgeTx(BridgeTx::EvmIn(BalanceUpdate { + address: H160::from_str("0x6bc42fd533d6cb9d973604155e1f7197a3b0e703").unwrap(), + amount: U256::one(), + })); + + // Nonce 0, sender 0xe61a3a6eb316d773c773f4ce757a542f673023c6 + let tx4 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869808502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa03d28d24808c3de08c606c5544772ded91913f648ad56556f181905208e206c85a00ecd0ba938fb89fc4a17ea333ea842c7305090dee9236e2b632578f9e5045cb3").unwrap())); + + queue.queue_tx((tx1, H256::from_low_u64_be(1).into()))?; + queue.queue_tx((tx2, H256::from_low_u64_be(2).into()))?; + queue.queue_tx((tx3, H256::from_low_u64_be(3).into()))?; + // Should fail as nonce 2 is already queued for this sender + let queued = queue.queue_tx((tx4, H256::from_low_u64_be(4).into())); + assert!(matches!(queued, Err(QueueError::InvalidNonce { .. }))); + Ok(()) + } + + #[test] + fn test_valid_nonce_order() -> Result<(), QueueError> { + let queue = TransactionQueue::new(); + + // Nonce 0, sender 0xe61a3a6eb316d773c773f4ce757a542f673023c6 + let tx1 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869808502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa03d28d24808c3de08c606c5544772ded91913f648ad56556f181905208e206c85a00ecd0ba938fb89fc4a17ea333ea842c7305090dee9236e2b632578f9e5045cb3").unwrap())); + + // Nonce 1, sender 0xe61a3a6eb316d773c773f4ce757a542f673023c6 + let tx2 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869018502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa0dd1fad9a8465969354d567e8a74af3f6de3e56abbe1b71154d7929d0bd5cc170a0353190adb50e3cfae82a77c2ea56b49a86f72bd0071a70d1c25c49827654aa68").unwrap())); + + // Nonce 2, sender 0xe61a3a6eb316d773c773f4ce757a542f673023c6 + let tx3 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869028502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa0adb0386f95848d33b49ee6057c34e530f87f696a29b4e1b04ef90b2a58bbedbca02f500cf29c5c4245608545e7d9d35b36ef0365e5c52d96e69b8f07920d32552f").unwrap())); + + // Nonce 2, sender 0x6bc42fd533d6cb9d973604155e1f7197a3b0e703 + let tx4 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869028502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa09588b47d2cd3f474d6384309cca5cb8e360cb137679f0a1589a1c184a15cb27ca0453ddbf808b83b279cac3226b61a9d83855aba60ae0d3a8407cba0634da7459d").unwrap())); + + queue.queue_tx((tx1, H256::from_low_u64_be(1).into()))?; + queue.queue_tx((tx2, H256::from_low_u64_be(2).into()))?; + queue.queue_tx((tx3, H256::from_low_u64_be(3).into()))?; + queue.queue_tx((tx4, H256::from_low_u64_be(4).into()))?; + Ok(()) + } +} diff --git a/lib/ain-evm/tests/block.rs b/lib/ain-evm/tests/block.rs new file mode 100644 index 0000000000..7191dc6e06 --- /dev/null +++ b/lib/ain-evm/tests/block.rs @@ -0,0 +1,165 @@ +#![cfg(test_off)] + +use std::str::FromStr; + +use ain_evm::transaction::SignedTx; +use primitive_types::{H160, H256, U256}; + +use ain_evm::handler::Handlers; + +#[test] +fn test_finalize_block_and_do_not_update_state() { + let handler = Handlers::new(); + let context = handler.evm.get_context(); + handler.evm.add_balance( + context, + "0x4a1080c5533cb89edc4b65013f08f78868e382de" + .parse() + .unwrap(), + U256::from_str_radix("100000000000000000000", 10).unwrap(), + ); + + let tx1: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a0b0842b0c78dd7fc33584ec9a81ab5104fe70169878de188ba6c11fe7605e298aa0735dc483f625f17d68d1e1fae779b7160612628e6dde9eecf087892fe60bba4e".try_into().unwrap(); + handler.evm.tx_queues.add_signed_tx(context, tx1); + + let old_state = handler.evm.state.read().unwrap(); + let _ = handler.finalize_block(context, false, 0, None).unwrap(); + + let new_state = handler.evm.state.read().unwrap(); + assert_eq!(*new_state, *old_state); +} + +#[test] +fn test_finalize_block_and_update_state() { + let handler = Handlers::new(); + let context = handler.evm.get_context(); + handler.evm.add_balance( + context, + "0xebf9844ba89c4975bbe4e621dbaf085e6357df3f" + .parse() + .unwrap(), + U256::from_str_radix("100000000000000000000", 10).unwrap(), + ); + + let tx1: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a0b0842b0c78dd7fc33584ec9a81ab5104fe70169878de188ba6c11fe7605e298aa0735dc483f625f17d68d1e1fae779b7160612628e6dde9eecf087892fe60bba4e".try_into().unwrap(); + handler.evm.tx_queues.add_signed_tx(context, tx1.clone()); + + handler.evm.add_balance( + context, + "0x47b16da33f4e7e4a4ed9e52cc561b9ffcb3daf56" + .parse() + .unwrap(), + U256::from_str_radix("100000000000000000000", 10).unwrap(), + ); + let tx2: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a01465e2d999c34b22bf4b8b5c9439918e46341f4f0da1b00a6b0479c541161d4aa074abe79c51bf57086e1e84b57ee483cbb2ecf30e8222bc0472436fabfc57dda8".try_into().unwrap(); + handler.evm.tx_queues.add_signed_tx(context, tx2.clone()); + + let tx3: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a070b21a24cec13c0569099ee2f8221268103fd609646b73f7c9e85efeb7af5c8ea03d5de75bc12ce28a80f7c0401df6021cc82a334cb1c802c8b9d46223c5c8eb40".try_into().unwrap(); + handler.evm.tx_queues.add_signed_tx(context, tx3.clone()); + + assert_eq!(handler.evm.tx_queues.len(context), 3); + assert_eq!(handler.evm.tx_queues.len(handler.evm.get_context()), 0); + + let (block, failed_txs) = handler.finalize_block(context, true, 0, None).unwrap(); + assert_eq!( + block.transactions, + vec![tx1, tx2, tx3.clone()] + .into_iter() + .map(|t| t.transaction) + .collect::>() + ); + assert_eq!( + failed_txs, + vec![tx3] + .into_iter() + .map(|t| hex::encode(ethereum::EnvelopedEncodable::encode(&t.transaction))) + .collect::>() + ); + + let state = handler.evm.state.read().unwrap(); + assert_eq!( + state + .get( + &"0xa8f7c4c78c36e54c3950ad58dad24ca5e0191b29" + .parse() + .unwrap() + ) + .unwrap() + .balance, + U256::from_str_radix("200000000000000000000", 10).unwrap() + ); + assert_eq!( + state + .get( + &"0x47b16da33f4e7e4a4ed9e52cc561b9ffcb3daf56" + .parse() + .unwrap() + ) + .unwrap() + .balance, + U256::from_str_radix("0", 10).unwrap() + ); + assert_eq!( + state + .get( + &"0xebf9844ba89c4975bbe4e621dbaf085e6357df3f" + .parse() + .unwrap() + ) + .unwrap() + .balance, + U256::from_str_radix("0", 10).unwrap() + ); +} + +#[test] +fn test_deploy_and_call_smart_contract() { + let smart_contract_address: H160 = "69762793de93f55ab919c5efdaafb63d413dcbb5".parse().unwrap(); + + let handler = Handlers::new(); + let context = handler.evm.get_context(); + handler.evm.add_balance( + context, + "0x4a1080c5533cb89edc4b65013f08f78868e382de" + .parse() + .unwrap(), + U256::from_str_radix("100000000000000000000", 10).unwrap(), + ); + + // Create simple storage smart contract + let create_smart_contract_tx: SignedTx = "f9044e808504a817c800832dc6c08080b903fb608060405234801561001057600080fd5b506103db806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063131a06801461003b5780632e64cec114610050575b600080fd5b61004e61004936600461015d565b61006e565b005b6100586100b5565b604051610065919061020e565b60405180910390f35b600061007a82826102e5565b507ffe3101cc3119e1fe29a9c3464a3ff7e98501e65122abab6937026311367dc516816040516100aa919061020e565b60405180910390a150565b6060600080546100c49061025c565b80601f01602080910402602001604051908101604052809291908181526020018280546100f09061025c565b801561013d5780601f106101125761010080835404028352916020019161013d565b820191906000526020600020905b81548152906001019060200180831161012057829003601f168201915b5050505050905090565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561016f57600080fd5b813567ffffffffffffffff8082111561018757600080fd5b818401915084601f83011261019b57600080fd5b8135818111156101ad576101ad610147565b604051601f8201601f19908116603f011681019083821181831017156101d5576101d5610147565b816040528281528760208487010111156101ee57600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561023b5785810183015185820160400152820161021f565b506000604082860101526040601f19601f8301168501019250505092915050565b600181811c9082168061027057607f821691505b60208210810361029057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156102e057600081815260208120601f850160051c810160208610156102bd5750805b601f850160051c820191505b818110156102dc578281556001016102c9565b5050505b505050565b815167ffffffffffffffff8111156102ff576102ff610147565b6103138161030d845461025c565b84610296565b602080601f83116001811461034857600084156103305750858301515b600019600386901b1c1916600185901b1785556102dc565b600085815260208120601f198616915b8281101561037757888601518255948401946001909101908401610358565b50858210156103955787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220f5c9bb4feb3fa563cfe06a38d411044d98edf92f98726288036607edd71587b564736f6c634300081100332aa06aa3b6274fbd96df7215c2b791c766e21a65d97467ddbd90c0d869ba51d04387a05512f44e35c5ab3c1716373877503d03a5f9ebdf5b7645e8fb30b308a6f046f8".try_into().unwrap(); + handler + .evm + .tx_queues + .add_signed_tx(context, create_smart_contract_tx); + + handler.finalize_block(context, true, 0, None).unwrap(); + + // Fund caller address + handler.evm.add_balance( + context, + "0xb069baef499f992ff243300f78cf9ca1406a122e" + .parse() + .unwrap(), + U256::from_str_radix("100000000000000000000000000", 10).unwrap(), + ); + let call_smart_contract_tx: SignedTx = "f8ca018504a817c8008302c1789469762793de93f55ab919c5efdaafb63d413dcbb580b864131a06800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c64210000000000000000000000000000000000000029a041fc9c0581885d77263dcba0603d8c6c164a9acfe803ad11188069eafa22169ca0018c1ba512639bd8ce32e76bcc2ea0759073a3f908014e47544d6c6674388b37".try_into().unwrap(); + + // Each block requires a new context + let context = handler.evm.get_context(); + handler + .evm + .tx_queues + .add_signed_tx(context, call_smart_contract_tx); + + handler.finalize_block(context, true, 0, None).unwrap(); + + let smart_contract_storage = handler.evm.get_storage(smart_contract_address); + assert_eq!( + smart_contract_storage.get(&H256::zero()), + Some( + &H256::from_str("0x48656c6c6f2c20576f726c64210000000000000000000000000000000000001a") + .unwrap() + ) + ) +} diff --git a/lib/ain-grpc/Cargo.toml b/lib/ain-grpc/Cargo.toml new file mode 100644 index 0000000000..9bdf4c5d46 --- /dev/null +++ b/lib/ain-grpc/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "ain-grpc" +version = "0.1.0" +edition = "2021" +build = "build.rs" + +[dependencies] +ain-evm = { path = "../ain-evm" } +ain-cpp-imports = { path = "../ain-cpp-imports" } +cxx = "1.0" +env_logger = "0.10" +jsonrpsee = { version = "0.15", features = ["http-server", "macros", "http-client"] } +lazy_static = "1.4" +log = "0.4" +libsecp256k1 = "0.7.1" +num-traits = "0.2" +prost = "0.11" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tokio = { version = "1.1", features = ["rt-multi-thread"] } +tonic = "0.9" +primitive-types = "0.12.1" +ethereum = "0.14.0" +ethereum-types = "0.14.1" +hex = "0.4.3" +async-trait = "0.1.68" +rlp = "0.5.2" +rustc-hex = "2.1.0" + +[build-dependencies] +cxx-gen = "0.7" +heck = "0.4" +proc-macro2 = "1.0" +quote = "1.0" +regex = "1.5" +syn = { version = "2.0", default-features = false, features = ["parsing", "printing"] } +prost-build = "0.11" +tonic-build = "0.9" +prettyplease = "0.2.4" +anyhow = "1.0.70" diff --git a/lib/ain-grpc/build.rs b/lib/ain-grpc/build.rs new file mode 100644 index 0000000000..505f681942 --- /dev/null +++ b/lib/ain-grpc/build.rs @@ -0,0 +1,411 @@ +use anyhow::{format_err, Result}; +use proc_macro2::{Span, TokenStream}; +use prost_build::{Config, Service, ServiceGenerator}; +use quote::{quote, ToTokens}; +use regex::Regex; +use syn::{Attribute, Fields, GenericArgument, Ident, Item, ItemStruct, PathArguments, Type}; + +use std::cell::RefCell; +use std::collections::HashMap; +use std::fs::{DirEntry, File}; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; +use std::rc::Rc; +use std::{env, fs, io}; + +fn main() -> Result<()> { + let manifest_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); + let proto_path = manifest_path + .parent() + .ok_or(format_err!("path err: no parent"))? + .join("proto"); + + let src_path = manifest_path.join("src"); + let out_dir: PathBuf = PathBuf::from(env::var("OUT_DIR")?); + let proto_rs_target_path = out_dir.join("proto"); + std::fs::create_dir_all(&proto_rs_target_path)?; + + let proto_include = std::env::var("PROTOC_INCLUDE_DIR") + .map(PathBuf::from) + .unwrap_or(proto_rs_target_path.clone()); + + let methods = compile_proto_and_generate_services( + &proto_path, + Path::new(&proto_rs_target_path), + Path::new(&proto_include), + ); + modify_generate_code(methods, &Path::new(&proto_rs_target_path).join("types.rs")); + + println!( + "cargo:rerun-if-changed={}", + src_path.join("rpc.rs").to_string_lossy() + ); + // Using a direct path for now + let git_head_path = manifest_path.join("../../.git/HEAD"); + if git_head_path.exists() { + println!("cargo:rerun-if-changed={}", git_head_path.to_string_lossy()); + } + + Ok(()) +} + +fn visit_files(dir: &Path, f: &mut dyn FnMut(&DirEntry)) -> io::Result<()> { + if dir.is_dir() { + for entry in fs::read_dir(dir)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + visit_files(&path, f)?; + } else { + f(&entry); + } + } + } + Ok(()) +} + +struct Attr { + matcher: &'static str, // matcher for names + attr: Option<&'static str>, // attribute to be added to the entity + rename: Option<&'static str>, // whether entity should be renamed + skip: &'static [&'static str], // entities that should be skipped +} + +impl Attr { + fn parse(attr: &str) -> Vec { + let attr = attr.parse::().unwrap(); + // This is an easier way to parse the attributes instead of writing a custom parser + let empty_struct: ItemStruct = syn::parse2(quote! { + #attr + struct S; + }) + .unwrap(); + empty_struct.attrs + } + + fn matches(&self, name: &str, parent: Option<&str>, ty: Option<&str>) -> bool { + let name = parent.map(|p| p.to_owned() + ".").unwrap_or_default() + name; + let combined = format!( + "{}.{}:{}", + parent.unwrap_or_default(), + name, + ty.unwrap_or_default() + ); + let re = Regex::new(self.matcher).unwrap(); + re.is_match(&combined.replace(' ', "")) + && !self.skip.iter().any(|&n| { + let re = Regex::new(n).unwrap(); + re.is_match(&name) + }) + } +} + +const TYPE_ATTRS: &[Attr] = &[ + Attr { + matcher: ".*", + attr: Some("#[derive(Serialize, Deserialize)] #[serde(rename_all=\"camelCase\")]"), + rename: None, + skip: &["^BlockResult", "NonUtxo", "^Transaction"], + }, + Attr { + matcher: ".*", + attr: Some("#[allow(clippy::derive_partial_eq_without_eq)]"), + rename: None, + skip: &[], + }, + Attr { + matcher: "NonUtxo", + attr: Some("#[derive(Serialize, Deserialize)] #[serde(rename_all=\"PascalCase\")]"), + rename: None, + skip: &[], + }, +]; + +const FIELD_ATTRS: &[Attr] = &[ + Attr { + matcher: ":::prost::alloc::string::String", + attr: Some("#[serde(skip_serializing_if = \"String::is_empty\")]"), + rename: None, + skip: &["^BlockResult", "NonUtxo", "^Transaction"], + }, + Attr { + matcher: ":::prost::alloc::vec::Vec", + attr: Some("#[serde(skip_serializing_if = \"Vec::is_empty\")]"), + rename: None, + skip: &[], + }, + Attr { + matcher: "req_sigs", + attr: Some("#[serde(skip_serializing_if = \"ignore_integer\")]"), + rename: None, + skip: &[], + }, + // Attr { + // matcher: "currentblocktx|currentblockweight", + // attr: Some("#[serde(skip_serializing_if = \"is_zero\")]"), + // rename: None, + // skip: &[], + // }, + Attr { + matcher: "asm", + attr: Some("#[serde(rename=\"asm\")]"), + rename: Some("field_asm"), + skip: &[], + }, + Attr { + matcher: "operator", + attr: Some("#[serde(rename = \"operator\")]"), + rename: Some("field_operator"), + skip: &["isoperator"], + }, + Attr { + matcher: "type", + attr: Some("#[serde(rename=\"type\")]"), + rename: Some("field_type"), + skip: &[], + }, + Attr { + matcher: "previous_block_hash", + attr: Some("#[serde(rename=\"previousblockhash\")]"), + rename: None, + skip: &[], + }, + Attr { + matcher: "next_block_hash", + attr: Some("#[serde(rename=\"nextblockhash\")]"), + rename: None, + skip: &[], + }, +]; + +// Custom generator to collect RPC call signatures +struct WrappedGenerator { + methods: Rc>>>, + inner: Box, +} + +#[derive(Debug)] +struct Rpc { + _name: String, + url: Option, + client: bool, + server: bool, + _input_ty: String, + _output_ty: String, +} + +impl ServiceGenerator for WrappedGenerator { + fn generate(&mut self, service: Service, buf: &mut String) { + let re = Regex::new("\\[rpc: (.*?)\\]").unwrap(); + for method in &service.methods { + let mut ref_map = self.methods.borrow_mut(); + let vec = ref_map.entry(service.name.clone()).or_default(); + let mut rpc = Rpc { + _name: method.proto_name.clone(), + _input_ty: method.input_proto_type.clone(), + url: None, + client: true, + server: true, + _output_ty: method.output_proto_type.clone(), + }; + for line in method + .comments + .leading_detached + .iter() + .flatten() + .chain(method.comments.leading.iter()) + .chain(method.comments.trailing.iter()) + { + if line.contains("[ignore]") { + rpc.client = false; + rpc.server = false; + } + if line.contains("[client]") { + rpc.server = false; + } + if line.contains("[server]") { + rpc.client = false; + } + if let Some(captures) = re.captures(line) { + rpc.url = Some(captures.get(1).unwrap().as_str().into()); + } + } + vec.push(rpc); + } + self.inner.generate(service, buf); + } + + fn finalize(&mut self, buf: &mut String) { + self.inner.finalize(buf); + } +} + +fn compile_proto_and_generate_services( + dir: &Path, + out_dir: &Path, + protoc_include: &Path, +) -> HashMap> { + let methods = Rc::new(RefCell::new(HashMap::new())); + let gen = WrappedGenerator { + methods: methods.clone(), + inner: tonic_build::configure() + .build_client(false) + .service_generator(), + }; + + let mut protos = vec![]; + visit_files(dir, &mut |entry: &DirEntry| { + let path = entry.path(); + let file_name = path.file_name().unwrap().to_str().unwrap(); + if file_name.ends_with(".proto") { + println!("cargo:rerun-if-changed={}", path.display()); + protos.push(path); + } + }) + .expect("visiting files"); + + { + // There's no way to compile protos using custom generator in tonic, + // so we're left with creating a prost config and using that for codegen. + let mut config = Config::new(); + config.out_dir(out_dir); + config.service_generator(Box::new(gen)); + config + .compile_protos(&protos, &[dir, protoc_include]) + .expect("compiling protobuf"); + } // drop it so we release rc count + + Rc::try_unwrap(methods).unwrap().into_inner() +} + +fn modify_generate_code(_methods: HashMap>, types_path: &Path) { + let mut contents = String::new(); + File::open(types_path) + .unwrap() + .read_to_string(&mut contents) + .unwrap(); + let parsed_file = syn::parse_file(&contents).unwrap(); + + // Modify structs if needed + let structs = change_types(parsed_file); + contents.clear(); + + let syntax_tree: syn::File = syn::parse2(structs).unwrap(); + let pretty = prettyplease::unparse(&syntax_tree); + contents.push_str(&pretty); + File::create(types_path) + .unwrap() + .write_all(contents.as_bytes()) + .unwrap(); +} + +fn change_types(file: syn::File) -> TokenStream { + let mut map = HashMap::new(); + let mut modified = quote! { + fn ignore_integer(i: &T) -> bool { + T::from(-1).unwrap() == *i + } + // fn is_zero(i: &i64) -> bool { + // *i == 0 + // } + }; + + let mut copied = quote!(); + // Replace prost-specific fields with defaults + for item in file.items { + let mut s = match item { + Item::Struct(s) => s, + _ => continue, + }; + + let name = s.ident.to_string(); + for rule in TYPE_ATTRS { + if !rule.matches(&name, None, None) { + continue; + } + + if let Some(attr) = rule.attr { + s.attrs.extend(Attr::parse(attr)); + } + + if let Some(new_name) = rule.rename { + s.ident = Ident::new(new_name, Span::call_site()); + } + } + + let fields = match &mut s.fields { + Fields::Named(ref mut f) => f, + _ => panic!("unsupported struct"), + }; + for field in &mut fields.named { + let f_name = field.ident.as_ref().unwrap().to_string(); + let t_name = field.ty.to_token_stream().to_string(); + for rule in FIELD_ATTRS { + if !rule.matches(&f_name, Some(&name), Some(&t_name)) { + continue; + } + + if let Some(attr) = rule.attr { + field.attrs.extend(Attr::parse(attr)); + } + + if let Some(new_name) = rule.rename { + field.ident = Some(Ident::new(new_name, Span::call_site())); + } + } + } + + modified.extend(quote!(#s)); + map.insert(s.ident.to_string(), s.clone()); + + s.attrs = Attr::parse("#[derive(Debug, Default, Serialize , Deserialize, PartialEq)]"); + let fields = match &mut s.fields { + Fields::Named(ref mut f) => f, + _ => unreachable!(), + }; + + for field in &mut fields.named { + field.attrs.clear(); // clear attributes + fix_type(&mut field.ty); + } + + copied.extend(quote! { + #s + }); + } + + modified +} + +fn fix_type(ty: &mut Type) { + let t = quote!(#ty).to_string().replace(' ', ""); + if t.contains("::prost::alloc::string::") { + *ty = syn::parse2(quote!(String)).unwrap(); + } + if t.contains("::prost::alloc::vec::") { + let mut inner = get_path_bracketed_ty_simple(ty); + fix_type(&mut inner); + *ty = syn::parse2(quote!(Vec<#inner>)).unwrap(); + } + if t.contains("::core::option::") { + *ty = get_path_bracketed_ty_simple(ty); + } +} + +/// Extracts "T" from `std::option::Option` for example +fn get_path_bracketed_ty_simple(ty: &Type) -> Type { + match ty { + Type::Path(ref p) => { + let last = p.path.segments.last().unwrap(); + match &last.arguments { + PathArguments::AngleBracketed(ref a) => match a.args.first().unwrap() { + GenericArgument::Type(ref t) => t.clone(), + _ => panic!("unsupported generic type: {}", quote!(#ty)), + }, + PathArguments::None => ty.clone(), + _ => panic!("parenthesis type {} not supported", quote!(#ty)), + } + } + _ => panic!("unsupported type {}", quote!(#ty)), + } +} diff --git a/lib/ain-grpc/src/block.rs b/lib/ain-grpc/src/block.rs new file mode 100644 index 0000000000..9811a9fcde --- /dev/null +++ b/lib/ain-grpc/src/block.rs @@ -0,0 +1,354 @@ +use crate::bytes::Bytes; +use ethereum::{BlockAny, TransactionV2}; +use ethereum_types::H64; +use primitive_types::{H160, H256, U256}; +use rlp::Encodable; +use serde::{ + de::{Error, MapAccess, Visitor}, + Deserialize, Deserializer, Serialize, Serializer, +}; +use std::fmt; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct RpcBlock { + pub hash: H256, + pub mix_hash: H256, + pub parent_hash: H256, + pub miner: H160, + pub state_root: H256, + pub transactions_root: H256, + pub receipts_root: H256, + pub number: U256, + pub gas_used: U256, + pub gas_limit: U256, + pub extra_data: Bytes, + pub timestamp: U256, + pub difficulty: U256, + pub total_difficulty: U256, + pub seal_fields: Vec>, + pub uncles: Vec, + pub transactions: BlockTransactions, + pub nonce: H64, + pub sha3_uncles: H256, + pub logs_bloom: String, + pub size: String, + pub base_fee_per_gas: U256, +} + +impl RpcBlock { + pub fn from_block_with_tx_and_base_fee( + block: BlockAny, + full_transactions: bool, + base_fee: U256, + ) -> Self { + let header_size = block.header.rlp_bytes().len(); + RpcBlock { + hash: block.header.hash(), + mix_hash: block.header.hash(), + number: block.header.number, + parent_hash: block.header.parent_hash, + transactions_root: block.header.transactions_root, + state_root: block.header.state_root, + receipts_root: block.header.receipts_root, + miner: block.header.beneficiary, + difficulty: block.header.difficulty, + total_difficulty: U256::zero(), + seal_fields: vec![], + gas_limit: block.header.gas_limit, + gas_used: block.header.gas_used, + timestamp: block.header.timestamp.into(), + transactions: { + if full_transactions { + // Discard failed to retrieved transactions with flat_map. + // Should not happen as the transaction should not make it in the block in the first place. + BlockTransactions::Full( + block + .transactions + .iter() + .enumerate() + .flat_map(|(index, tx)| { + EthTransactionInfo::try_from_tx_block_and_index(tx, &block, index) + }) + .collect(), + ) + } else { + BlockTransactions::Hashes( + block.transactions.iter().map(TransactionV2::hash).collect(), + ) + } + }, + uncles: vec![], + nonce: block.header.nonce, + extra_data: Bytes::from(block.header.extra_data), + sha3_uncles: H256::default(), + logs_bloom: format!("{:#x}", block.header.logs_bloom), + size: format!("{header_size:#x}"), + base_fee_per_gas: base_fee, + } + } +} + +/// Represents rpc api block number param. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)] +pub enum BlockNumber { + /// Hash + Hash { + /// block hash + hash: H256, + /// only return blocks part of the canon chain + require_canonical: bool, + }, + /// Number + Num(u64), + /// Latest block + #[default] + Latest, + /// Earliest block (genesis) + Earliest, + /// Pending block (being mined) + Pending, + /// The most recent crypto-economically secure block. + /// There is no difference between Ethereum's `safe` and `finalized` + /// in Substrate finality gadget. + Safe, + /// The most recent crypto-economically secure block. + Finalized, +} + +impl<'a> Deserialize<'a> for BlockNumber { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'a>, + { + deserializer.deserialize_any(BlockNumberVisitor) + } +} + +impl BlockNumber { + /// Convert block number to min block target. + #[must_use] + pub fn convert_to_min_block_num(&self) -> Option { + match *self { + BlockNumber::Num(ref x) => Some(*x), + BlockNumber::Earliest => Some(0), + _ => None, + } + } +} + +impl Serialize for BlockNumber { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + BlockNumber::Hash { + hash, + require_canonical, + } => serializer.serialize_str(&format!( + "{{ 'hash': '{hash}', 'requireCanonical': '{require_canonical}' }}" + )), + BlockNumber::Num(ref x) => serializer.serialize_str(&format!("0x{x:x}")), + BlockNumber::Latest => serializer.serialize_str("latest"), + BlockNumber::Earliest => serializer.serialize_str("earliest"), + BlockNumber::Pending => serializer.serialize_str("pending"), + BlockNumber::Safe => serializer.serialize_str("safe"), + BlockNumber::Finalized => serializer.serialize_str("finalized"), + } + } +} + +struct BlockNumberVisitor; + +impl<'a> Visitor<'a> for BlockNumberVisitor { + type Value = BlockNumber; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "a block number or 'latest', 'safe', 'finalized', 'earliest' or 'pending'" + ) + } + + fn visit_map(self, mut visitor: V) -> Result + where + V: MapAccess<'a>, + { + let (mut require_canonical, mut block_number, mut block_hash) = + (false, None::, None::); + + loop { + let key_str: Option = visitor.next_key()?; + + match key_str { + Some(key) => match key.as_str() { + "blockNumber" => { + let value: String = visitor.next_value()?; + if let Some(stripped) = value.strip_prefix("0x") { + let number = u64::from_str_radix(stripped, 16) + .map_err(|e| Error::custom(format!("Invalid block number: {e}")))?; + + block_number = Some(number); + break; + } else { + return Err(Error::custom( + "Invalid block number: missing 0x prefix".to_string(), + )); + } + } + "blockHash" => { + block_hash = Some(visitor.next_value()?); + } + "requireCanonical" => { + require_canonical = visitor.next_value()?; + } + key => return Err(Error::custom(format!("Unknown key: {key}"))), + }, + None => break, + }; + } + + if let Some(number) = block_number { + return Ok(BlockNumber::Num(number)); + } + + if let Some(hash) = block_hash { + return Ok(BlockNumber::Hash { + hash, + require_canonical, + }); + } + + Err(Error::custom("Invalid input")) + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "latest" => Ok(BlockNumber::Latest), + "earliest" => Ok(BlockNumber::Earliest), + "pending" => Ok(BlockNumber::Pending), + "safe" => Ok(BlockNumber::Safe), + "finalized" => Ok(BlockNumber::Finalized), + _ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16) + .map(BlockNumber::Num) + .map_err(|e| Error::custom(format!("Invalid block number: {e}"))), + _ => value.parse::().map(BlockNumber::Num).map_err(|_| { + Error::custom("Invalid block number: non-decimal or missing 0x prefix".to_string()) + }), + } + } + + fn visit_string(self, value: String) -> Result + where + E: Error, + { + self.visit_str(value.as_ref()) + } + + fn visit_u64(self, value: u64) -> Result + where + E: Error, + { + Ok(BlockNumber::Num(value)) + } +} + +use ain_evm::block::FeeHistoryData; +use std::str::FromStr; + +use crate::codegen::types::EthTransactionInfo; + +impl FromStr for BlockNumber { + type Err = serde_json::Error; + + fn from_str(s: &str) -> Result { + let visitor = BlockNumberVisitor; + let result = visitor.visit_str(s).map_err(|e: serde::de::value::Error| { + serde_json::Error::custom(format!("Error while parsing BlockNumber: {e}")) + }); + result + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn match_block_number(block_number: BlockNumber) -> Option { + match block_number { + BlockNumber::Num(number) => Some(number), + BlockNumber::Earliest => Some(0), + BlockNumber::Latest => Some(1000), + BlockNumber::Safe => Some(999), + BlockNumber::Finalized => Some(999), + BlockNumber::Pending => Some(1001), + _ => None, + } + } + + #[test] + fn block_number_deserialize() { + let bn_dec: BlockNumber = serde_json::from_str(r#""42""#).unwrap(); + let bn_hex: BlockNumber = serde_json::from_str(r#""0x45""#).unwrap(); + let bn_u64: BlockNumber = serde_json::from_str(r#"420"#).unwrap(); + let bn_tag_earliest: BlockNumber = serde_json::from_str(r#""earliest""#).unwrap(); + let bn_tag_latest: BlockNumber = serde_json::from_str(r#""latest""#).unwrap(); + let bn_tag_safe: BlockNumber = serde_json::from_str(r#""safe""#).unwrap(); + let bn_tag_finalized: BlockNumber = serde_json::from_str(r#""finalized""#).unwrap(); + let bn_tag_pending: BlockNumber = serde_json::from_str(r#""pending""#).unwrap(); + + assert_eq!(match_block_number(bn_dec).unwrap(), 42); + assert_eq!(match_block_number(bn_hex).unwrap(), 69); + assert_eq!(match_block_number(bn_u64).unwrap(), 420); + assert_eq!(match_block_number(bn_tag_earliest).unwrap(), 0); + assert_eq!(match_block_number(bn_tag_latest).unwrap(), 1000); + assert_eq!(match_block_number(bn_tag_safe).unwrap(), 999); + assert_eq!(match_block_number(bn_tag_finalized).unwrap(), 999); + assert_eq!(match_block_number(bn_tag_pending).unwrap(), 1001); + } +} + +/// Block Transactions +#[derive(Debug, Deserialize, Clone, PartialEq)] +pub enum BlockTransactions { + /// Only hashes + Hashes(Vec), + /// Full transactions + Full(Vec), +} + +impl Serialize for BlockTransactions { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + BlockTransactions::Hashes(ref hashes) => hashes.serialize(serializer), + BlockTransactions::Full(ref ts) => ts.serialize(serializer), + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct RpcFeeHistory { + pub oldest_block: H256, + pub base_fee_per_gas: Vec, + pub gas_used_ratio: Vec, + pub reward: Option>>, +} + +impl From for RpcFeeHistory { + fn from(value: FeeHistoryData) -> Self { + Self { + oldest_block: value.oldest_block, + base_fee_per_gas: value.base_fee_per_gas, + gas_used_ratio: value.gas_used_ratio, + reward: value.reward, + } + } +} diff --git a/lib/ain-grpc/src/bytes.rs b/lib/ain-grpc/src/bytes.rs new file mode 100644 index 0000000000..b306957aca --- /dev/null +++ b/lib/ain-grpc/src/bytes.rs @@ -0,0 +1,118 @@ +use rustc_hex::{FromHex, ToHex}; +use serde::{ + de::{Error, Visitor}, + Deserialize, Deserializer, Serialize, Serializer, +}; +use std::fmt; + +/// Wrapper structure around vector of bytes. +#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)] +pub struct Bytes(pub Vec); + +impl Bytes { + /// Simple constructor. + pub fn new(bytes: Vec) -> Bytes { + Bytes(bytes) + } + /// Convert back to vector + pub fn into_vec(self) -> Vec { + self.0 + } +} + +impl From> for Bytes { + fn from(bytes: Vec) -> Bytes { + Bytes(bytes) + } +} + +impl From for Vec { + fn from(bytes: Bytes) -> Vec { + bytes.0 + } +} + +impl Serialize for Bytes { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut serialized = "0x".to_owned(); + serialized.push_str(self.0.to_hex::().as_ref()); + serializer.serialize_str(serialized.as_ref()) + } +} + +impl<'a> Deserialize<'a> for Bytes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'a>, + { + deserializer.deserialize_any(BytesVisitor) + } +} + +struct BytesVisitor; + +impl<'a> Visitor<'a> for BytesVisitor { + type Value = Bytes; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a 0x-prefixed, hex-encoded vector of bytes") + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + if value.len() >= 2 && value.starts_with("0x") && value.len() & 1 == 0 { + Ok(Bytes::new( + FromHex::from_hex(&value[2..]) + .map_err(|e| Error::custom(format!("Invalid hex: {e}")))?, + )) + } else { + Err(Error::custom( + "Invalid bytes format. Expected a 0x-prefixed hex string with even length", + )) + } + } + + fn visit_string(self, value: String) -> Result + where + E: Error, + { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_bytes_serialize() { + let bytes = Bytes("0123456789abcdef".from_hex().unwrap()); + let serialized = serde_json::to_string(&bytes).unwrap(); + assert_eq!(serialized, r#""0x0123456789abcdef""#); + } + + #[test] + fn test_bytes_deserialize() { + let bytes0: Result = serde_json::from_str(r#""∀∂""#); + let bytes1: Result = serde_json::from_str(r#""""#); + let bytes2: Result = serde_json::from_str(r#""0x123""#); + let bytes3: Result = serde_json::from_str(r#""0xgg""#); + + let bytes4: Bytes = serde_json::from_str(r#""0x""#).unwrap(); + let bytes5: Bytes = serde_json::from_str(r#""0x12""#).unwrap(); + let bytes6: Bytes = serde_json::from_str(r#""0x0123""#).unwrap(); + + assert!(bytes0.is_err()); + assert!(bytes1.is_err()); + assert!(bytes2.is_err()); + assert!(bytes3.is_err()); + assert_eq!(bytes4, Bytes(vec![])); + assert_eq!(bytes5, Bytes(vec![0x12])); + assert_eq!(bytes6, Bytes(vec![0x1, 0x23])); + } +} diff --git a/lib/ain-grpc/src/call_request.rs b/lib/ain-grpc/src/call_request.rs new file mode 100644 index 0000000000..85a221d789 --- /dev/null +++ b/lib/ain-grpc/src/call_request.rs @@ -0,0 +1,35 @@ +use ethereum::AccessListItem; +use primitive_types::{H160, U256}; +use serde::Deserialize; + +use crate::bytes::Bytes; + +/// Call request +#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +#[serde(rename_all = "camelCase")] +pub struct CallRequest { + /// From + pub from: Option, + /// To + pub to: Option, + /// Gas Price + pub gas_price: Option, + /// EIP-1559 Max base fee the caller is willing to pay + pub max_fee_per_gas: Option, + /// EIP-1559 Priority fee the caller is paying to the block author + pub max_priority_fee_per_gas: Option, + /// Gas + pub gas: Option, + /// Value + pub value: Option, + /// Data + pub data: Option, + /// Nonce + pub nonce: Option, + /// AccessList + pub access_list: Option>, + /// EIP-2718 type + #[serde(rename = "type")] + pub transaction_type: Option, +} diff --git a/lib/ain-grpc/src/codegen.rs b/lib/ain-grpc/src/codegen.rs new file mode 100644 index 0000000000..09ae36b8f5 --- /dev/null +++ b/lib/ain-grpc/src/codegen.rs @@ -0,0 +1,114 @@ +use serde::{Deserialize, Serialize}; + +pub mod types { + include!(concat!(env!("OUT_DIR"), "/proto/types.rs")); +} + +impl Serialize for types::BlockResult { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + if !self.hash.is_empty() { + return serializer.serialize_str(&self.hash); + } + + if let Some(ref block) = self.block { + return block.serialize(serializer); + } + + serializer.serialize_str("") + } +} + +impl<'de> Deserialize<'de> for types::BlockResult { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(untagged)] + #[allow(clippy::large_enum_variant)] + enum Res { + Hash(String), + Block(types::Block), + } + + match Res::deserialize(deserializer)? { + Res::Hash(s) => Ok(types::BlockResult { + hash: s, + block: None, + }), + Res::Block(b) => Ok(types::BlockResult { + hash: String::new(), + block: Some(b), + }), + } + } +} + +impl Serialize for types::Transaction { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + if !self.hash.is_empty() { + return serializer.serialize_str(&self.hash); + } + + if let Some(ref tx) = self.raw { + return tx.serialize(serializer); + } + + serializer.serialize_str("") + } +} + +impl<'de> Deserialize<'de> for types::Transaction { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(untagged)] + enum Tx { + Hash(String), + Raw(types::RawTransaction), + } + + match Tx::deserialize(deserializer)? { + Tx::Hash(s) => Ok(types::Transaction { hash: s, raw: None }), + Tx::Raw(tx) => Ok(types::Transaction { + hash: String::new(), + raw: Some(tx), + }), + } + } +} + +#[cfg(test)] +mod tests { + use super::types::{BlockResult, Transaction}; + + #[test] + fn test_block_result_json() { + let foo = BlockResult { + hash: "foobar".into(), + block: None, + }; + let res = serde_json::to_value(foo).unwrap(); + let foo2: BlockResult = serde_json::from_value(res).unwrap(); + assert_eq!(serde_json::to_value(foo2).unwrap(), "foobar"); + } + + #[test] + fn test_transaction() { + let foo = Transaction { + hash: "booya".into(), + raw: None, + }; + let res = serde_json::to_value(foo).unwrap(); + let foo2: Transaction = serde_json::from_value(res).unwrap(); + assert_eq!(serde_json::to_value(foo2).unwrap(), "booya"); + } +} diff --git a/lib/ain-grpc/src/impls.rs b/lib/ain-grpc/src/impls.rs new file mode 100644 index 0000000000..df2c5de5b0 --- /dev/null +++ b/lib/ain-grpc/src/impls.rs @@ -0,0 +1,41 @@ +use std::convert::From; +use std::mem::size_of_val; + +use ethereum::BlockAny; + +use crate::codegen::types::EthBlockInfo; +use crate::utils::{format_h256, format_u256}; + +impl From for EthBlockInfo { + fn from(block: BlockAny) -> Self { + EthBlockInfo { + block_number: format!("{:#x}", block.header.number), + hash: format_h256(block.header.hash()), + parent_hash: format_h256(block.header.parent_hash), + nonce: format!("{:#x}", block.header.nonce), + sha3_uncles: format_h256(block.header.ommers_hash), + logs_bloom: format!("{:#x}", block.header.logs_bloom), + transactions_root: format_h256(block.header.transactions_root), + state_root: format_h256(block.header.state_root), + receipt_root: format_h256(block.header.receipts_root), + miner: format!("{:#x}", block.header.beneficiary), + difficulty: format!("{:#x}", block.header.difficulty), + total_difficulty: format_u256(block.header.difficulty), + extra_data: format!("{:#x?}", block.header.extra_data.to_ascii_lowercase()), + size: format!("{:#x}", size_of_val(&block)), + gas_limit: format_u256(block.header.gas_limit), + gas_used: format_u256(block.header.gas_used), + timestamps: format!("0x{:x}", block.header.timestamp), + transactions: block + .transactions + .iter() + .map(|x| x.hash().to_string()) + .collect::>(), + uncles: block + .ommers + .iter() + .map(|x| x.hash().to_string()) + .collect::>(), + } + } +} diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs new file mode 100644 index 0000000000..ed8ef1fc37 --- /dev/null +++ b/lib/ain-grpc/src/lib.rs @@ -0,0 +1,88 @@ +#[macro_use] +extern crate serde; +extern crate serde_json; + +pub mod block; +mod bytes; +pub mod call_request; +pub mod codegen; +mod impls; +mod receipt; +pub mod rpc; +mod transaction; +mod transaction_request; +mod utils; + +use jsonrpsee::core::server::rpc_module::Methods; +use jsonrpsee::http_server::HttpServerBuilder; + +#[allow(unused)] +use log::{debug, info}; + +use crate::rpc::{ + debug::{MetachainDebugRPCModule, MetachainDebugRPCServer}, + eth::{MetachainRPCModule, MetachainRPCServer}, + net::{MetachainNetRPCModule, MetachainNetRPCServer}, +}; + +use std::error::Error; +use std::net::SocketAddr; +use std::sync::Arc; + +use ain_evm::runtime::{Runtime, RUNTIME}; + +#[cfg(test)] +mod tests; + +pub fn add_json_rpc_server(runtime: &Runtime, addr: &str) -> Result<(), Box> { + info!("Starting JSON RPC server at {}", addr); + let addr = addr.parse::()?; + let handle = runtime.rt_handle.clone(); + let server = runtime.rt_handle.block_on( + HttpServerBuilder::default() + .custom_tokio_runtime(handle) + .build(addr), + )?; + let mut methods: Methods = Methods::new(); + methods.merge(MetachainRPCModule::new(Arc::clone(&runtime.handlers)).into_rpc())?; + methods.merge(MetachainDebugRPCModule::new(Arc::clone(&runtime.handlers)).into_rpc())?; + methods.merge(MetachainNetRPCModule::new(Arc::clone(&runtime.handlers)).into_rpc())?; + + *runtime.jrpc_handle.lock().unwrap() = Some(server.start(methods)?); + Ok(()) +} + +pub fn add_grpc_server(_runtime: &Runtime, _addr: &str) -> Result<(), Box> { + // log::info!("Starting gRPC server at {}", addr); + // Commented out for now as nothing to serve + // runtime + // .rt_handle + // .spawn(Server::builder().serve(addr.parse()?)); + + Ok(()) +} + +pub fn preinit() { + env_logger::Builder::from_env( + env_logger::Env::default().default_filter_or(log::Level::Info.as_str()), + ) + .target(env_logger::Target::Stdout) + .init(); + info!("init"); +} + +pub fn init_evm_runtime() { + info!("init evm runtime"); + let _ = &*RUNTIME; +} + +pub fn start_servers(json_addr: &str, grpc_addr: &str) -> Result<(), Box> { + add_json_rpc_server(&RUNTIME, json_addr)?; + add_grpc_server(&RUNTIME, grpc_addr)?; + Ok(()) +} + +pub fn stop_evm_runtime() { + info!("stop evm runtime"); + RUNTIME.stop(); +} diff --git a/lib/ain-grpc/src/receipt.rs b/lib/ain-grpc/src/receipt.rs new file mode 100644 index 0000000000..29324cbcb7 --- /dev/null +++ b/lib/ain-grpc/src/receipt.rs @@ -0,0 +1,83 @@ +use ain_evm::receipt::Receipt; +use ethereum::{EIP658ReceiptData, Log}; +use primitive_types::{H160, H256, U256}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct LogResult { + pub address: H160, + pub topics: Vec, + pub data: String, + pub block_number: U256, + pub block_hash: H256, + pub transaction_hash: H256, + pub transaction_index: String, + pub log_index: String, + pub removed: bool, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct ReceiptResult { + pub block_hash: H256, + pub block_number: U256, + pub contract_address: Option, + pub cumulative_gas_used: U256, + pub effective_gas_price: U256, + pub from: H160, + pub gas_used: U256, + pub logs: Vec, + pub logs_bloom: String, + pub status: String, + pub to: Option, + pub transaction_hash: H256, + pub transaction_index: String, + pub r#type: String, +} + +impl From for ReceiptResult { + fn from(b: Receipt) -> Self { + let data = EIP658ReceiptData::from(b.receipt); + ReceiptResult { + block_hash: b.block_hash, + block_number: b.block_number, + contract_address: b.contract_address, + cumulative_gas_used: b.cumulative_gas, + effective_gas_price: Default::default(), + from: b.from, + gas_used: data.used_gas, + logs: { + data.logs + .into_iter() + .enumerate() + .map( + |( + log_index, + Log { + address, + topics, + data, + }, + )| LogResult { + address, + topics, + data: format!("0x{}", hex::encode(data)), + block_number: b.block_number, + block_hash: b.block_hash, + transaction_hash: b.tx_hash, + transaction_index: format!("{:#x}", b.tx_index), + log_index: { format!("{:#x}", b.logs_index + log_index) }, + removed: false, + }, + ) + .collect::>() + }, + logs_bloom: format!("{:#x}", data.logs_bloom), + status: format!("{:#x}", data.status_code), + to: b.to, + transaction_hash: b.tx_hash, + transaction_index: format!("{:#x}", b.tx_index), + r#type: format!("{:#x}", b.tx_type), + } + } +} diff --git a/lib/ain-grpc/src/rpc/debug.rs b/lib/ain-grpc/src/rpc/debug.rs new file mode 100644 index 0000000000..1b761e3fee --- /dev/null +++ b/lib/ain-grpc/src/rpc/debug.rs @@ -0,0 +1,38 @@ +use ain_evm::handler::Handlers; +use jsonrpsee::core::RpcResult; +use jsonrpsee::proc_macros::rpc; +use log::debug; +use std::sync::Arc; + +#[rpc(server, client, namespace = "debug")] +pub trait MetachainDebugRPC { + #[method(name = "traceTransaction")] + fn trace_transaction(&self) -> RpcResult<()>; + + // Dump full db + #[method(name = "dumpdb")] + fn dump_db(&self) -> RpcResult<()>; +} + +pub struct MetachainDebugRPCModule { + handler: Arc, +} + +impl MetachainDebugRPCModule { + #[must_use] + pub fn new(handler: Arc) -> Self { + Self { handler } + } +} + +impl MetachainDebugRPCServer for MetachainDebugRPCModule { + fn trace_transaction(&self) -> RpcResult<()> { + debug!(target: "rpc", "Tracing transaction"); + Ok(()) + } + + fn dump_db(&self) -> RpcResult<()> { + self.handler.storage.dump_db(); + Ok(()) + } +} diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs new file mode 100644 index 0000000000..da1d608318 --- /dev/null +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -0,0 +1,788 @@ +use crate::block::{BlockNumber, RpcBlock, RpcFeeHistory}; +use crate::bytes::Bytes; +use crate::call_request::CallRequest; +use crate::codegen::types::EthTransactionInfo; + +use crate::receipt::ReceiptResult; +use crate::transaction_request::{TransactionMessage, TransactionRequest}; +use ain_cpp_imports::get_eth_priv_key; +use ain_evm::executor::TxResponse; +use ain_evm::handler::Handlers; + +use ain_evm::storage::traits::{BlockStorage, ReceiptStorage, TransactionStorage}; +use ain_evm::transaction::{SignedTx, TransactionError}; +use ethereum::{EnvelopedEncodable, TransactionV2}; +use jsonrpsee::core::{Error, RpcResult}; +use jsonrpsee::proc_macros::rpc; +use libsecp256k1::SecretKey; +use log::{debug, trace}; +use primitive_types::{H160, H256, U256}; +use std::convert::Into; +use std::str::FromStr; +use std::sync::Arc; + +#[rpc(server, client, namespace = "eth")] +pub trait MetachainRPC { + // ---------------------------------------- + // Client + // ---------------------------------------- + + /// Makes a call to the Ethereum node without creating a transaction on the blockchain. + /// Returns the output data as a hexadecimal string. + #[method(name = "call")] + fn call(&self, input: CallRequest, block_number: Option) -> RpcResult; + + /// Retrieves the list of accounts managed by the node. + /// Returns a vector of Ethereum addresses as hexadecimal strings. + #[method(name = "accounts")] + fn accounts(&self) -> RpcResult>; + + /// Returns the current chain ID as a hexadecimal string. + #[method(name = "chainId")] + fn chain_id(&self) -> RpcResult; + + // ---------------------------------------- + // Block + // ---------------------------------------- + + /// Returns the current block number as U256. + #[method(name = "blockNumber")] + fn block_number(&self) -> RpcResult; + + /// Retrieves a specific block, identified by its block number. + /// Returns full transaction info or transaction hash depending on full_transactions param + #[method(name = "getBlockByNumber")] + fn get_block_by_number( + &self, + block_number: BlockNumber, + full_transactions: Option, + ) -> RpcResult>; + + /// Retrieves a specific block, identified by its hash. + #[method(name = "getBlockByHash")] + fn get_block_by_hash( + &self, + hash: H256, + full_transactions: Option, + ) -> RpcResult>; + + /// Retrieves the transaction count for a specific block, identified by its hash. + #[method(name = "getBlockTransactionCountByHash")] + fn get_block_transaction_count_by_hash(&self, hash: H256) -> RpcResult; + + /// Retrieves the transaction count for a specific block, identified by its block number. + #[method(name = "getBlockTransactionCountByNumber")] + fn get_block_transaction_count_by_number(&self, number: BlockNumber) -> RpcResult; + + // ---------------------------------------- + // Mining + // ---------------------------------------- + + /// Checks if the node is currently mining. + #[method(name = "mining")] + fn mining(&self) -> RpcResult; + + /// Returns the hash of the current block, the seedHash, and the boundary condition to be met ("target"). + #[method(name = "getWork")] + fn get_getwork(&self) -> RpcResult>; + + /// Submits a proof of work solution to the node. + /// Always returns false + #[method(name = "submitWork")] + fn eth_submitwork(&self, nonce: String, hash: String, digest: String) -> RpcResult; + + /// Retrieves the current hash rate of the node. + /// Always returns 0x0 + #[method(name = "hashrate")] + fn hash_rate(&self) -> RpcResult; + + /// Submit mining hashrate. + /// Always returns false + #[method(name = "submitHashrate")] + fn eth_submithashrate(&self, hashrate: String, id: String) -> RpcResult; + + // ---------------------------------------- + // Transaction + // ---------------------------------------- + + /// Retrieves a specific transaction, identified by its hash. + #[method(name = "getTransactionByHash")] + fn get_transaction_by_hash(&self, hash: H256) -> RpcResult>; + + /// Retrieves a specific transaction, identified by the block hash and transaction index. + #[method(name = "getTransactionByBlockHashAndIndex")] + fn get_transaction_by_block_hash_and_index( + &self, + hash: H256, + index: usize, + ) -> RpcResult>; + + /// Retrieves a specific transaction, identified by the block number and transaction index. + #[method(name = "getTransactionByBlockNumberAndIndex")] + fn get_transaction_by_block_number_and_index( + &self, + block_number: U256, + index: usize, + ) -> RpcResult>; + + /// Retrieves the list of pending transactions. + #[method(name = "pendingTransactions")] + fn get_pending_transaction(&self) -> RpcResult>; + + /// Retrieves the receipt of a specific transaction, identified by its hash. + #[method(name = "getTransactionReceipt")] + fn get_receipt(&self, hash: H256) -> RpcResult>; + + // ---------------------------------------- + // Account state + // ---------------------------------------- + + /// Retrieves the balance of a specific Ethereum address at a given block number. + /// Returns the balance as U256. + #[method(name = "getBalance")] + fn get_balance(&self, address: H160, block_number: Option) -> RpcResult; + + /// Retrieves the bytecode of a contract at a specific address. + #[method(name = "getCode")] + fn get_code(&self, address: H160, block_number: Option) -> RpcResult; + + /// Retrieves the storage value at a specific position in a contract. + #[method(name = "getStorageAt")] + fn get_storage_at( + &self, + address: H160, + position: U256, + block_number: Option, + ) -> RpcResult; + + /// Retrieves the number of transactions sent from a specific address. + #[method(name = "getTransactionCount")] + fn get_transaction_count( + &self, + address: H160, + block_number: Option, + ) -> RpcResult; + + // ---------------------------------------- + // Send + // ---------------------------------------- + + /// Sends a signed transaction. + /// Returns the transaction hash as a hexadecimal string. + #[method(name = "sendRawTransaction")] + fn send_raw_transaction(&self, tx: &str) -> RpcResult; + + /// Sends a transaction. + /// Returns the transaction hash as a hexadecimal string. + #[method(name = "sendTransaction")] + fn send_transaction(&self, req: TransactionRequest) -> RpcResult; + + // ---------------------------------------- + // Gas + // ---------------------------------------- + + /// Estimate gas needed for execution of given contract. + #[method(name = "estimateGas")] + fn estimate_gas( + &self, + input: CallRequest, + block_number: Option, + ) -> RpcResult; + + /// Returns current gas_price. + #[method(name = "gasPrice")] + fn gas_price(&self) -> RpcResult; + + #[method(name = "feeHistory")] + fn fee_history( + &self, + block_count: U256, + first_block: U256, + priority_fee_percentile: Vec, + ) -> RpcResult; + + #[method(name = "maxPriorityFeePerGas")] + fn max_priority_fee_per_gas(&self) -> RpcResult; +} + +pub struct MetachainRPCModule { + handler: Arc, +} + +impl MetachainRPCModule { + #[must_use] + pub fn new(handler: Arc) -> Self { + Self { handler } + } + + fn block_number_to_u256(&self, block_number: Option) -> U256 { + match block_number.unwrap_or_default() { + BlockNumber::Hash { + hash, + .. + } => { + self.handler + .storage + .get_block_by_hash(&hash) + .map(|block| block.header.number) + .unwrap_or(U256::max_value()) + } + BlockNumber::Num(n) => { + self.handler + .storage + .get_block_by_number(&U256::from(n)) + .map(|block| block.header.number) + .unwrap_or(U256::max_value()) + }, + _ => { + self.handler + .storage + .get_latest_block() + .map(|block| block.header.number) + .unwrap_or(U256::max_value()) + } + // BlockNumber::Earliest => todo!(), + // BlockNumber::Pending => todo!(), + // BlockNumber::Safe => todo!(), + // BlockNumber::Finalized => todo!(), + } + } +} + +impl MetachainRPCServer for MetachainRPCModule { + fn call(&self, input: CallRequest, block_number: Option) -> RpcResult { + debug!(target:"rpc", "[RPC] Call input {:#?}", input); + let CallRequest { + from, + to, + gas, + value, + data, + .. + } = input; + let TxResponse { data, .. } = self + .handler + .evm + .call( + from, + to, + value.unwrap_or_default(), + &data.map(|d| d.0).unwrap_or_default(), + gas.unwrap_or(U256::from(u64::MAX)).as_u64(), + vec![], + self.block_number_to_u256(block_number), + ) + .map_err(|e| Error::Custom(format!("Error calling EVM : {e:?}")))?; + + Ok(Bytes(data)) + } + + fn accounts(&self) -> RpcResult> { + let accounts = ain_cpp_imports::get_accounts().unwrap(); + Ok(accounts) + } + + // State RPC + + fn get_balance(&self, address: H160, block_number: Option) -> RpcResult { + let block_number = self.block_number_to_u256(block_number); + debug!(target:"rpc", + "Getting balance for address: {:?} at block : {} ", + address, block_number + ); + let balance = self + .handler + .evm + .get_balance(address, block_number) + .unwrap_or(U256::zero()); + + debug!(target:"rpc","Address: {:?} balance : {} ", address, balance); + Ok(balance) + } + + fn get_code(&self, address: H160, block_number: Option) -> RpcResult { + let block_number = self.block_number_to_u256(block_number); + + debug!(target:"rpc", + "Getting code for address: {:?} at block : {}", + address, block_number + ); + + let code = self + .handler + .evm + .get_code(address, block_number) + .map_err(|e| Error::Custom(format!("Error getting address code : {e:?}")))?; + + match code { + Some(code) => Ok(format!("0x{}", hex::encode(code))), + None => Ok(String::from("0x")), + } + } + + fn get_storage_at( + &self, + address: H160, + position: U256, + block_number: Option, + ) -> RpcResult { + let block_number = self.block_number_to_u256(block_number); + debug!(target:"rpc", + "Getting storage for address: {:?}, at position {:?}, for block {}", + address, position, block_number + ); + + self.handler + .evm + .get_storage_at(address, position, block_number) + .map_err(|e| Error::Custom(format!("get_storage_at error : {e:?}")))? + .map_or(Ok(H256::default()), |storage| { + Ok(H256::from_slice(&storage)) + }) + } + + fn get_block_by_hash( + &self, + hash: H256, + full_transactions: Option, + ) -> RpcResult> { + debug!("Getting block by hash {:#x}", hash); + self.handler + .storage + .get_block_by_hash(&hash) + .map_or(Ok(None), |block| { + Ok(Some(RpcBlock::from_block_with_tx_and_base_fee( + block, + full_transactions.unwrap_or_default(), + self.handler.storage.get_base_fee(&hash).unwrap_or_default(), + ))) + }) + } + + fn chain_id(&self) -> RpcResult { + let chain_id = ain_cpp_imports::get_chain_id() + .map_err(|e| Error::Custom(format!("ain_cpp_imports::get_chain_id error : {e:?}")))?; + + Ok(format!("{chain_id:#x}")) + } + + fn hash_rate(&self) -> RpcResult { + Ok(String::from("0x0")) + } + + fn block_number(&self) -> RpcResult { + let count = self + .handler + .storage + .get_latest_block() + .map(|block| block.header.number) + .unwrap_or_default(); + + trace!(target:"rpc", "Current block number: {:?}", count); + Ok(count) + } + + fn get_block_by_number( + &self, + block_number: BlockNumber, + full_transactions: Option, + ) -> RpcResult> { + let block_number = self.block_number_to_u256(Some(block_number)); + debug!(target:"rpc","Getting block by number : {}", block_number); + self.handler + .storage + .get_block_by_number(&block_number) + .map_or(Ok(None), |block| { + let tx_hash = &block.header.hash(); + Ok(Some(RpcBlock::from_block_with_tx_and_base_fee( + block, + full_transactions.unwrap_or_default(), + self.handler + .storage + .get_base_fee(tx_hash) + .unwrap_or_default(), + ))) + }) + } + + fn mining(&self) -> RpcResult { + ain_cpp_imports::is_mining().map_err(|e| Error::Custom(e.to_string())) + } + + fn get_transaction_by_hash(&self, hash: H256) -> RpcResult> { + self.handler + .storage + .get_transaction_by_hash(&hash) + .map_or(Ok(None), |tx| { + let transaction_info = tx + .try_into() + .map_err(|e: TransactionError| Error::Custom(e.to_string()))?; + Ok(Some(transaction_info)) + }) + } + + fn get_pending_transaction(&self) -> RpcResult> { + ain_cpp_imports::get_pool_transactions() + .map(|txs| { + txs.into_iter() + .flat_map(|tx| EthTransactionInfo::try_from(tx.as_str())) + .map(EthTransactionInfo::into_pending_transaction_info) + .collect() + }) + .map_err(|e| Error::Custom(e.to_string())) + } + + fn get_transaction_by_block_hash_and_index( + &self, + hash: H256, + index: usize, + ) -> RpcResult> { + self.handler + .storage + .get_transaction_by_block_hash_and_index(&hash, index) + .map_or(Ok(None), |tx| { + let transaction_info = tx + .try_into() + .map_err(|e: TransactionError| Error::Custom(e.to_string()))?; + Ok(Some(transaction_info)) + }) + } + + fn get_transaction_by_block_number_and_index( + &self, + number: U256, + index: usize, + ) -> RpcResult> { + self.handler + .storage + .get_transaction_by_block_number_and_index(&number, index) + .map_or(Ok(None), |tx| { + let transaction_info = tx + .try_into() + .map_err(|e: TransactionError| Error::Custom(e.to_string()))?; + Ok(Some(transaction_info)) + }) + } + + fn get_block_transaction_count_by_hash(&self, hash: H256) -> RpcResult { + self.handler + .storage + .get_block_by_hash(&hash) + .map_or(Ok(0), |b| Ok(b.transactions.len())) + } + + fn get_block_transaction_count_by_number(&self, block_number: BlockNumber) -> RpcResult { + let block_number = self.block_number_to_u256(Some(block_number)); + self.handler + .storage + .get_block_by_number(&block_number) + .map_or(Ok(0), |b| Ok(b.transactions.len())) + } + + fn send_transaction(&self, request: TransactionRequest) -> RpcResult { + debug!(target:"rpc","[send_transaction] Sending transaction: {:?}", request); + + let from = match request.from { + Some(from) => from, + None => { + let accounts = self.accounts()?; + + match accounts.get(0) { + Some(account) => H160::from_str(account.as_str()).unwrap(), + None => return Err(Error::Custom(String::from("from is not available"))), + } + } + }; + debug!(target:"rpc","[send_transaction] from: {:?}", from); + + let chain_id = ain_cpp_imports::get_chain_id() + .map_err(|e| Error::Custom(format!("ain_cpp_imports::get_chain_id error : {e:?}")))?; + + let block_number = self.block_number()?; + + let nonce = match request.nonce { + Some(nonce) => nonce, + None => self + .handler + .evm + .get_nonce(from, block_number) + .map_err(|e| { + Error::Custom(format!("Error getting address transaction count : {e:?}")) + })?, + }; + + let gas_price = request.gas_price; + let gas_limit = match request.gas { + Some(gas_limit) => gas_limit, + // TODO(): get the gas_limit from block.header + // set 21000 (min gas_limit req) by default first + None => U256::from(21000), + }; + let max_fee_per_gas = request.max_fee_per_gas; + let message: Option = request.into(); + let message = match message { + Some(TransactionMessage::Legacy(mut m)) => { + m.nonce = nonce; + m.chain_id = Some(chain_id); + m.gas_limit = gas_limit; + if gas_price.is_none() { + m.gas_price = self.gas_price().unwrap(); + } + TransactionMessage::Legacy(m) + } + Some(TransactionMessage::EIP2930(mut m)) => { + m.nonce = nonce; + m.chain_id = chain_id; + m.gas_limit = gas_limit; + if gas_price.is_none() { + m.gas_price = self.gas_price().unwrap(); + } + TransactionMessage::EIP2930(m) + } + Some(TransactionMessage::EIP1559(mut m)) => { + m.nonce = nonce; + m.chain_id = chain_id; + m.gas_limit = gas_limit; + if max_fee_per_gas.is_none() { + m.max_fee_per_gas = self.gas_price().unwrap(); + } + TransactionMessage::EIP1559(m) + } + _ => { + return Err(Error::Custom(String::from( + "invalid transaction parameters", + ))) + } + }; + + let transaction = sign(from, message).unwrap(); + + let encoded_bytes = transaction.encode(); + let encoded_string = hex::encode(encoded_bytes); + let encoded = encoded_string.as_str(); + let hash = self.send_raw_transaction(encoded)?; + debug!(target:"rpc","[send_transaction] signed: {:?}", hash); + + Ok(hash) + } + + fn send_raw_transaction(&self, tx: &str) -> RpcResult { + debug!(target:"rpc","[send_raw_transaction] Sending raw transaction: {:?}", tx); + let raw_tx = tx.strip_prefix("0x").unwrap_or(tx); + let hex = + hex::decode(raw_tx).map_err(|e| Error::Custom(format!("Eror decoding TX {e:?}")))?; + + match ain_cpp_imports::publish_eth_transaction(hex) { + Ok(res_string) => { + if res_string.is_empty() { + let signed_tx = SignedTx::try_from(raw_tx) + .map_err(|e| Error::Custom(format!("TX error {e:?}")))?; + + debug!(target:"rpc", + "[send_raw_transaction] signed_tx sender : {:#x}", + signed_tx.sender + ); + debug!(target:"rpc", + "[send_raw_transaction] signed_tx nonce : {:#x}", + signed_tx.nonce() + ); + debug!(target:"rpc", + "[send_raw_transaction] transaction hash : {:#x}", + signed_tx.transaction.hash() + ); + + Ok(format!("{:#x}", signed_tx.transaction.hash())) + } else { + debug!(target:"rpc","[send_raw_transaction] Could not publish raw transaction: {tx} reason: {res_string}"); + Err(Error::Custom(format!( + "Could not publish raw transaction: {tx} reason: {res_string}" + ))) + } + } + Err(e) => { + debug!(target:"rpc","[send_raw_transaction] Error publishing TX {e:?}"); + Err(Error::Custom(format!("Error publishing TX {e:?}"))) + } + } + } + + fn get_transaction_count( + &self, + address: H160, + block_number: Option, + ) -> RpcResult { + debug!(target:"rpc","Getting transaction count for address: {:?}", address); + let block_number = self.block_number_to_u256(block_number); + let nonce = self + .handler + .evm + .get_nonce(address, block_number) + .map_err(|e| { + Error::Custom(format!("Error getting address transaction count : {e:?}")) + })?; + + debug!(target:"rpc","Count: {:#?}", nonce); + Ok(nonce) + } + + fn estimate_gas( + &self, + input: CallRequest, + block_number: Option, + ) -> RpcResult { + let CallRequest { + from, + to, + gas, + value, + data, + .. + } = input; + + let block_number = self.block_number_to_u256(block_number); + let TxResponse { used_gas, .. } = self + .handler + .evm + .call( + from, + to, + value.unwrap_or_default(), + &data.map(|d| d.0).unwrap_or_default(), + gas.unwrap_or(U256::from(u64::MAX)).as_u64(), + vec![], + block_number, + ) + .map_err(|e| Error::Custom(format!("Error calling EVM : {e:?}")))?; + + debug!(target:"rpc", "estimateGas: {:#?} at block {:#x}", used_gas, block_number); + Ok(U256::from(used_gas)) + } + + fn gas_price(&self) -> RpcResult { + let gas_price = self.handler.block.get_legacy_fee(); + debug!(target:"rpc","gasPrice: {:#?}", gas_price); + Ok(gas_price) + } + + fn get_receipt(&self, hash: H256) -> RpcResult> { + self.handler + .storage + .get_receipt(&hash) + .map_or(Ok(None), |receipt| Ok(Some(ReceiptResult::from(receipt)))) + } + + fn get_getwork(&self) -> RpcResult> { + Ok(vec![ + "0x0000000000000000000000000000000000000000000000000000000000000000".to_string(), + "0x0000000000000000000000000000000000000000000000000000000000000000".to_string(), + "0x0000000000000000000000000000000000000000000000000000000000000000".to_string(), + ]) + } + + fn eth_submitwork(&self, _nonce: String, _hash: String, _digest: String) -> RpcResult { + Ok(false) + } + + fn eth_submithashrate(&self, _hashrate: String, _id: String) -> RpcResult { + Ok(false) + } + + fn fee_history( + &self, + block_count: U256, + first_block: U256, + priority_fee_percentile: Vec, + ) -> RpcResult { + Ok(RpcFeeHistory::from(self.handler.block.fee_history( + block_count.as_usize(), + first_block, + priority_fee_percentile, + ))) + } + + fn max_priority_fee_per_gas(&self) -> RpcResult { + Ok(self.handler.block.suggested_priority_fee()) + } +} + +fn sign( + address: H160, + message: TransactionMessage, +) -> Result> { + debug!("sign address {:#x}", address); + let key_id = address.as_fixed_bytes().to_owned(); + let priv_key = get_eth_priv_key(key_id).unwrap(); + let secret_key = SecretKey::parse(&priv_key).unwrap(); + + match message { + TransactionMessage::Legacy(m) => { + let signing_message = libsecp256k1::Message::parse_slice(&m.hash()[..]) + .map_err(|_| Error::Custom(String::from("invalid signing message")))?; + let (signature, recid) = libsecp256k1::sign(&signing_message, &secret_key); + let v = match m.chain_id { + None => 27 + recid.serialize() as u64, + Some(chain_id) => 2 * chain_id + 35 + recid.serialize() as u64, + }; + let rs = signature.serialize(); + let r = H256::from_slice(&rs[0..32]); + let s = H256::from_slice(&rs[32..64]); + + Ok(TransactionV2::Legacy(ethereum::LegacyTransaction { + nonce: m.nonce, + value: m.value, + input: m.input, + signature: ethereum::TransactionSignature::new(v, r, s).ok_or_else(|| { + Error::Custom(String::from("signer generated invalid signature")) + })?, + gas_price: m.gas_price, + gas_limit: m.gas_limit, + action: m.action, + })) + } + TransactionMessage::EIP2930(m) => { + let signing_message = libsecp256k1::Message::parse_slice(&m.hash()[..]) + .map_err(|_| Error::Custom(String::from("invalid signing message")))?; + let (signature, recid) = libsecp256k1::sign(&signing_message, &secret_key); + let rs = signature.serialize(); + let r = H256::from_slice(&rs[0..32]); + let s = H256::from_slice(&rs[32..64]); + + Ok(TransactionV2::EIP2930(ethereum::EIP2930Transaction { + chain_id: m.chain_id, + nonce: m.nonce, + gas_price: m.gas_price, + gas_limit: m.gas_limit, + action: m.action, + value: m.value, + input: m.input.clone(), + access_list: m.access_list, + odd_y_parity: recid.serialize() != 0, + r, + s, + })) + } + TransactionMessage::EIP1559(m) => { + let signing_message = libsecp256k1::Message::parse_slice(&m.hash()[..]) + .map_err(|_| Error::Custom(String::from("invalid signing message")))?; + let (signature, recid) = libsecp256k1::sign(&signing_message, &secret_key); + let rs = signature.serialize(); + let r = H256::from_slice(&rs[0..32]); + let s = H256::from_slice(&rs[32..64]); + + Ok(TransactionV2::EIP1559(ethereum::EIP1559Transaction { + chain_id: m.chain_id, + nonce: m.nonce, + max_priority_fee_per_gas: m.max_priority_fee_per_gas, + max_fee_per_gas: m.max_fee_per_gas, + gas_limit: m.gas_limit, + action: m.action, + value: m.value, + input: m.input.clone(), + access_list: m.access_list, + odd_y_parity: recid.serialize() != 0, + r, + s, + })) + } + } +} diff --git a/lib/ain-grpc/src/rpc/mod.rs b/lib/ain-grpc/src/rpc/mod.rs new file mode 100644 index 0000000000..6798db4e80 --- /dev/null +++ b/lib/ain-grpc/src/rpc/mod.rs @@ -0,0 +1,3 @@ +pub mod debug; +pub mod eth; +pub mod net; diff --git a/lib/ain-grpc/src/rpc/net.rs b/lib/ain-grpc/src/rpc/net.rs new file mode 100644 index 0000000000..b5d6f702df --- /dev/null +++ b/lib/ain-grpc/src/rpc/net.rs @@ -0,0 +1,31 @@ +use ain_evm::handler::Handlers; +use jsonrpsee::core::{Error, RpcResult}; +use jsonrpsee::proc_macros::rpc; +use std::sync::Arc; + +#[rpc(server, client, namespace = "net")] +pub trait MetachainNetRPC { + /// Returns the current network ID as a string. + #[method(name = "version")] + fn net_version(&self) -> RpcResult; +} + +pub struct MetachainNetRPCModule { + _handler: Arc, +} + +impl MetachainNetRPCModule { + #[must_use] + pub fn new(_handler: Arc) -> Self { + Self { _handler } + } +} + +impl MetachainNetRPCServer for MetachainNetRPCModule { + fn net_version(&self) -> RpcResult { + let chain_id = ain_cpp_imports::get_chain_id() + .map_err(|e| Error::Custom(format!("ain_cpp_imports::get_chain_id error : {e:?}")))?; + + Ok(format!("{chain_id}")) + } +} diff --git a/lib/ain-grpc/src/tests.rs b/lib/ain-grpc/src/tests.rs new file mode 100644 index 0000000000..afb2976d9a --- /dev/null +++ b/lib/ain-grpc/src/tests.rs @@ -0,0 +1,260 @@ +#![cfg(test_off)] + +use ethereum::{BlockV2, PartialHeader}; +use std::str::FromStr; +use std::sync::Arc; + +use primitive_types::{H160, U256}; + +use crate::codegen::types::*; +use ain_evm::handler::Handlers; +use ain_evm::transaction::SignedTx; + +const ALICE: &str = "0x0000000000000000000000000000000000000000"; +const BOB: &str = "0x0000000000000000000000000000000000000001"; + +#[test] +fn should_call() { + let handler = Arc::new(Handlers::new()); + let tx_info = EthTransactionInfo { + from: Some(ALICE.to_string()), + to: Some(BOB.to_string()), + gas: Default::default(), + price: Default::default(), + value: Default::default(), + data: Some("0x2394872".to_string()), + nonce: Default::default(), + }; + let input = EthCallInput { + transaction_info: Some(tx_info), + block_number: "latest".to_string(), + }; + let res = EthService::Eth_Call(handler, input.into()); + assert!(res.is_ok()); +} + +#[test] +fn should_get_balance() { + let handler = Arc::new(Handlers::new()); + let input = EthGetBalanceInput { + address: ALICE.to_string(), + block_number: "latest".to_string(), + }; + + let res = EthService::Eth_GetBalance(handler.clone(), input.clone().into()); + assert_eq!(res.unwrap().balance, "0"); + + let ctx = handler.evm.get_context(); + + handler + .evm + .add_balance(ctx, H160::from_str(ALICE).unwrap(), U256::from(1337)); + + let _ = handler.finalize_block(ctx, true, 0, None); + + let res2 = EthService::Eth_GetBalance(handler, input.into()); + assert_eq!(res2.unwrap().balance, "1337"); +} + +#[test] +fn should_get_block_by_hash() { + let handler = Arc::new(Handlers::new()); + let block = BlockV2::new( + PartialHeader { + parent_hash: Default::default(), + beneficiary: Default::default(), + state_root: Default::default(), + receipts_root: Default::default(), + logs_bloom: Default::default(), + difficulty: Default::default(), + number: Default::default(), + gas_limit: Default::default(), + gas_used: Default::default(), + timestamp: 0, + extra_data: vec![], + mix_hash: Default::default(), + nonce: Default::default(), + }, + Vec::new(), + Vec::new(), + ); + handler.block.connect_block(block.clone()); + handler.storage.put_block(block.clone()); + + let block = handler + .block + .get_block_by_hash(block.header.hash()) + .unwrap(); + + let input = EthGetBlockByHashInput { + hash: format!("{:x}", block.header.hash()), + full_transaction: false, + }; + let res = EthService::Eth_GetBlockByHash(handler.clone(), input.clone().into()); + assert_eq!( + format!("{}", res.unwrap().hash), + format!("0x{:x}", block.header.hash()) + ); +} + +#[test] +fn should_get_transaction_by_hash() { + let handler = Arc::new(Handlers::new()); + let signed_tx: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a0b0842b0c78dd7fc33584ec9a81ab5104fe70169878de188ba6c11fe7605e298aa0735dc483f625f17d68d1e1fae779b7160612628e6dde9eecf087892fe60bba4e".try_into().unwrap(); + let tx_hashes = vec![signed_tx.clone().transaction]; + let block = BlockV2::new( + PartialHeader { + parent_hash: Default::default(), + beneficiary: Default::default(), + state_root: Default::default(), + receipts_root: Default::default(), + logs_bloom: Default::default(), + difficulty: Default::default(), + number: Default::default(), + gas_limit: Default::default(), + gas_used: Default::default(), + timestamp: 0, + extra_data: vec![], + mix_hash: Default::default(), + nonce: Default::default(), + }, + tx_hashes, + Vec::new(), + ); + + handler.block.connect_block(block.clone()); + handler.storage.put_block(block.clone()); + + let input = EthGetTransactionByHashInput { + hash: format!("{:x}", signed_tx.transaction.hash()), + }; + + let res = EthService::Eth_GetTransactionByHash(handler.clone(), input.clone().into()).unwrap(); + + assert_eq!(res.from.parse::().unwrap(), signed_tx.sender); + assert_eq!(res.to.parse::().ok(), signed_tx.to()); + assert_eq!(res.gas, signed_tx.gas_limit().as_u64()); + assert_eq!( + U256::from_str_radix(&res.price, 10).unwrap(), + signed_tx.gas_price() + ); + assert_eq!( + U256::from_str_radix(&res.value, 10).unwrap(), + signed_tx.value() + ); + assert_eq!(res.data, hex::encode(signed_tx.data())); + assert_eq!( + U256::from_str_radix(&res.nonce, 10).unwrap(), + signed_tx.nonce() + ); +} + +#[test] +fn should_get_transaction_by_block_hash_and_index() { + let handler = Arc::new(Handlers::new()); + let signed_tx: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a0b0842b0c78dd7fc33584ec9a81ab5104fe70169878de188ba6c11fe7605e298aa0735dc483f625f17d68d1e1fae779b7160612628e6dde9eecf087892fe60bba4e".try_into().unwrap(); + let tx_hashes = vec![signed_tx.clone().transaction]; + let block = BlockV2::new( + PartialHeader { + parent_hash: Default::default(), + beneficiary: Default::default(), + state_root: Default::default(), + receipts_root: Default::default(), + logs_bloom: Default::default(), + difficulty: Default::default(), + number: Default::default(), + gas_limit: Default::default(), + gas_used: Default::default(), + timestamp: 0, + extra_data: vec![], + mix_hash: Default::default(), + nonce: Default::default(), + }, + tx_hashes, + Vec::new(), + ); + + handler.block.connect_block(block.clone()); + handler.storage.put_block(block.clone()); + + let input = EthGetTransactionByBlockHashAndIndexInput { + block_hash: format!("{:x}", block.header.hash()), + index: String::from("0"), + }; + + let res = + EthService::Eth_GetTransactionByBlockHashAndIndex(handler.clone(), input.clone().into()) + .unwrap(); + + assert_eq!(res.from.parse::().unwrap(), signed_tx.sender); + assert_eq!(res.to.parse::().ok(), signed_tx.to()); + assert_eq!(res.gas, signed_tx.gas_limit().as_u64()); + assert_eq!( + U256::from_str_radix(&res.price, 10).unwrap(), + signed_tx.gas_price() + ); + assert_eq!( + U256::from_str_radix(&res.value, 10).unwrap(), + signed_tx.value() + ); + assert_eq!(res.data, hex::encode(signed_tx.data())); + assert_eq!( + U256::from_str_radix(&res.nonce, 10).unwrap(), + signed_tx.nonce() + ); +} + +#[test] +fn should_get_transaction_by_block_number_and_index() { + let handler = Arc::new(Handlers::new()); + let signed_tx: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a0b0842b0c78dd7fc33584ec9a81ab5104fe70169878de188ba6c11fe7605e298aa0735dc483f625f17d68d1e1fae779b7160612628e6dde9eecf087892fe60bba4e".try_into().unwrap(); + let tx_hashes = vec![signed_tx.clone().transaction]; + let block = BlockV2::new( + PartialHeader { + parent_hash: Default::default(), + beneficiary: Default::default(), + state_root: Default::default(), + receipts_root: Default::default(), + logs_bloom: Default::default(), + difficulty: Default::default(), + number: Default::default(), + gas_limit: Default::default(), + gas_used: Default::default(), + timestamp: 0, + extra_data: vec![], + mix_hash: Default::default(), + nonce: Default::default(), + }, + tx_hashes, + Vec::new(), + ); + + handler.block.connect_block(block.clone()); + handler.storage.put_block(block.clone()); + + let input = EthGetTransactionByBlockNumberAndIndexInput { + block_number: format!("{:x}", block.header.number), + index: String::from("0"), + }; + + let res = + EthService::Eth_GetTransactionByBlockNumberAndIndex(handler.clone(), input.clone().into()) + .unwrap(); + + assert_eq!(res.from.parse::().unwrap(), signed_tx.sender); + assert_eq!(res.to.parse::().ok(), signed_tx.to()); + assert_eq!(res.gas, signed_tx.gas_limit().as_u64()); + assert_eq!( + U256::from_str_radix(&res.price, 10).unwrap(), + signed_tx.gas_price() + ); + assert_eq!( + U256::from_str_radix(&res.value, 10).unwrap(), + signed_tx.value() + ); + assert_eq!(res.data, hex::encode(signed_tx.data())); + assert_eq!( + U256::from_str_radix(&res.nonce, 10).unwrap(), + signed_tx.nonce() + ); +} diff --git a/lib/ain-grpc/src/transaction.rs b/lib/ain-grpc/src/transaction.rs new file mode 100644 index 0000000000..8c218269b2 --- /dev/null +++ b/lib/ain-grpc/src/transaction.rs @@ -0,0 +1,80 @@ +use ain_evm::transaction::{SignedTx, TransactionError}; +use ethereum::{BlockAny, TransactionV2}; +use primitive_types::{H256, U256}; + +use crate::{ + codegen::types::EthTransactionInfo, + utils::{format_address, format_h256, format_u256}, +}; + +impl From for EthTransactionInfo { + fn from(signed_tx: SignedTx) -> Self { + let input = if signed_tx.data().is_empty() { + String::from("0x") + } else { + format!("0x{}", hex::encode(signed_tx.data())) + }; + + EthTransactionInfo { + hash: format_h256(signed_tx.transaction.hash()), + from: format_address(signed_tx.sender), + to: signed_tx.to().map(format_address), + gas: format_u256(signed_tx.gas_limit()), + gas_price: format_u256(signed_tx.gas_price()), + value: format_u256(signed_tx.value()), + input, + nonce: format_u256(signed_tx.nonce()), + v: format!("0x{:x}", signed_tx.v()), + r: format_h256(signed_tx.r()), + s: format_h256(signed_tx.s()), + block_hash: None, + block_number: None, + transaction_index: None, + } + } +} + +impl TryFrom for EthTransactionInfo { + type Error = TransactionError; + + fn try_from(tx: TransactionV2) -> Result { + let signed_tx: SignedTx = tx.try_into()?; + Ok(signed_tx.into()) + } +} + +impl TryFrom<&str> for EthTransactionInfo { + type Error = TransactionError; + + fn try_from(raw_tx: &str) -> Result { + let signed_tx: SignedTx = raw_tx.try_into()?; + Ok(signed_tx.into()) + } +} + +impl EthTransactionInfo { + pub fn try_from_tx_block_and_index( + tx: &TransactionV2, + block: &BlockAny, + index: usize, + ) -> Result { + let signed_tx: SignedTx = tx.clone().try_into()?; + + Ok(EthTransactionInfo { + block_hash: Some(format_h256(block.header.hash())), + block_number: Some(format_u256(block.header.number)), + transaction_index: Some(format_u256(U256::from(index))), + ..EthTransactionInfo::from(signed_tx) + }) + } + + #[must_use] + pub fn into_pending_transaction_info(self) -> Self { + Self { + block_hash: Some(format_h256(H256::zero())), + block_number: Some(String::from("null")), + transaction_index: Some(String::from("0x0")), + ..self + } + } +} diff --git a/lib/ain-grpc/src/transaction_request.rs b/lib/ain-grpc/src/transaction_request.rs new file mode 100644 index 0000000000..52cfddf8c0 --- /dev/null +++ b/lib/ain-grpc/src/transaction_request.rs @@ -0,0 +1,99 @@ +use crate::bytes::Bytes; +use ethereum::{ + AccessListItem, EIP1559TransactionMessage, EIP2930TransactionMessage, LegacyTransactionMessage, +}; +use ethereum_types::{H160, U256}; +use serde::{Deserialize, Serialize}; + +pub enum TransactionMessage { + Legacy(LegacyTransactionMessage), + EIP2930(EIP2930TransactionMessage), + EIP1559(EIP1559TransactionMessage), +} + +/// Transaction request coming from RPC +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +#[serde(rename_all = "camelCase")] +pub struct TransactionRequest { + /// Sender + pub from: Option, + /// Recipient + pub to: Option, + /// Gas Price, legacy. + #[serde(default)] + pub gas_price: Option, + /// Max BaseFeePerGas the user is willing to pay. + #[serde(default)] + pub max_fee_per_gas: Option, + /// The miner's tip. + #[serde(default)] + pub max_priority_fee_per_gas: Option, + /// Gas + pub gas: Option, + /// Value of transaction in wei + pub value: Option, + /// Additional data sent with transaction + pub data: Option, + /// Transaction's nonce + pub nonce: Option, + /// Pre-pay to warm storage access. + #[serde(default)] + pub access_list: Option>, + /// EIP-2718 type + #[serde(rename = "type")] + pub transaction_type: Option, +} + +impl From for Option { + fn from(req: TransactionRequest) -> Self { + match (req.gas_price, req.max_fee_per_gas, req.access_list.clone()) { + // Legacy + (Some(_), None, None) => Some(TransactionMessage::Legacy(LegacyTransactionMessage { + nonce: U256::zero(), + gas_price: req.gas_price.unwrap_or_default(), + gas_limit: req.gas.unwrap_or_default(), + value: req.value.unwrap_or_default(), + input: req.data.map(Bytes::into_vec).unwrap_or_default(), + action: match req.to { + Some(to) => ethereum::TransactionAction::Call(to), + None => ethereum::TransactionAction::Create, + }, + chain_id: None, + })), + // EIP2930 + (_, None, Some(_)) => Some(TransactionMessage::EIP2930(EIP2930TransactionMessage { + nonce: U256::zero(), + gas_price: req.gas_price.unwrap_or_default(), + gas_limit: req.gas.unwrap_or_default(), + value: req.value.unwrap_or_default(), + input: req.data.map(Bytes::into_vec).unwrap_or_default(), + action: match req.to { + Some(to) => ethereum::TransactionAction::Call(to), + None => ethereum::TransactionAction::Create, + }, + chain_id: 0, + access_list: req.access_list.unwrap_or_default(), + })), + // EIP1559 + (None, Some(_), _) | (None, None, None) => { + // Empty fields fall back to the canonical transaction schema. + Some(TransactionMessage::EIP1559(EIP1559TransactionMessage { + nonce: U256::zero(), + max_fee_per_gas: req.max_fee_per_gas.unwrap_or_default(), + max_priority_fee_per_gas: req.max_priority_fee_per_gas.unwrap_or_default(), + gas_limit: req.gas.unwrap_or_default(), + value: req.value.unwrap_or_default(), + input: req.data.map(Bytes::into_vec).unwrap_or_default(), + action: match req.to { + Some(to) => ethereum::TransactionAction::Call(to), + None => ethereum::TransactionAction::Create, + }, + chain_id: 0, + access_list: req.access_list.unwrap_or_default(), + })) + } + _ => None, + } + } +} diff --git a/lib/ain-grpc/src/utils.rs b/lib/ain-grpc/src/utils.rs new file mode 100644 index 0000000000..c89e2ca3f8 --- /dev/null +++ b/lib/ain-grpc/src/utils.rs @@ -0,0 +1,13 @@ +use primitive_types::{H160, H256, U256}; + +pub fn format_h256(hash: H256) -> String { + format!("{hash:#x}") +} + +pub fn format_address(hash: H160) -> String { + format!("{hash:#x}") +} + +pub fn format_u256(number: U256) -> String { + format!("{number:#x}") +} diff --git a/lib/ain-rs-exports/Cargo.toml b/lib/ain-rs-exports/Cargo.toml new file mode 100644 index 0000000000..1b144bb152 --- /dev/null +++ b/lib/ain-rs-exports/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "ain-rs-exports" +version = "0.1.0" +edition = "2021" +build = "build.rs" + +[lib] +crate-type = ["staticlib"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ain-evm = { path = "../ain-evm" } +ain-grpc = { path = "../ain-grpc" } + +ethereum = "0.14.0" +rlp = "0.5.2" +primitive-types = "0.12.1" +log = { version = "0.4" } + +# Build +cxx = "1.0" + +[build-dependencies] +cxx-gen = "0.7" +proc-macro2 = "1.0" diff --git a/lib/ain-rs-exports/build.rs b/lib/ain-rs-exports/build.rs new file mode 100644 index 0000000000..64acce5f2e --- /dev/null +++ b/lib/ain-rs-exports/build.rs @@ -0,0 +1,59 @@ +use proc_macro2::TokenStream; + +use std::env; +use std::fs::File; +use std::io::{Read, Write}; +use std::path::PathBuf; + +fn main() -> Result<(), Box> { + let pkg_name = env::var("CARGO_PKG_NAME")?; + let manifest_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); + + // If TARGET_DIR is set, which we do from Makefile, uses that instead of OUT_DIR. + // Otherwise, use the path for OUT_DIR that cargo sets, as usual. + // Reason: Currently setting --out-dir is nightly only, so there's no way to get OUT_DIR + // out of cargo reliably for pointing the C++ link targets to this determinisitcally. + let target_dir: PathBuf = PathBuf::from(env::var("TARGET_DIR").or(env::var("OUT_DIR"))?); + let res = ["src", "include", "lib"].map(|x| target_dir.join(x)); + for x in &res { + std::fs::create_dir_all(x)?; + } + let [out_src_dir, out_include_dir, _out_lib_dir] = res; + + let lib_path = &manifest_path.join("src").join("lib.rs"); + + let mut content = String::new(); + File::open(lib_path)?.read_to_string(&mut content)?; + + let pkg_name_underscored = pkg_name.replace('-', "_"); + let header_file_path = pkg_name_underscored.clone() + ".h"; + let source_file_path = pkg_name_underscored + ".cpp"; + + let tt: TokenStream = content.parse()?; + let mut opt = cxx_gen::Opt::default(); + opt.include.push(cxx_gen::Include { + path: header_file_path.clone(), + kind: cxx_gen::IncludeKind::Bracketed, + }); + + let codegen = cxx_gen::generate_header_and_cc(tt, &opt)?; + let cpp_stuff = String::from_utf8(codegen.implementation)?; + + File::create(out_include_dir.join(header_file_path))?.write_all(&codegen.header)?; + File::create(out_src_dir.join(source_file_path))?.write_all(cpp_stuff.as_bytes())?; + + println!( + "cargo:rerun-if-changed={}", + lib_path.as_path().to_str().ok_or("lib path err")? + ); + // Using a direct path for now + let git_head_path = manifest_path.join("../../.git/HEAD"); + if git_head_path.exists() { + println!( + "cargo:rerun-if-changed={}", + git_head_path.to_str().ok_or("git head path err")? + ); + } + + Ok(()) +} diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs new file mode 100644 index 0000000000..4de57f3d03 --- /dev/null +++ b/lib/ain-rs-exports/src/lib.rs @@ -0,0 +1,444 @@ +use ain_evm::{ + storage::traits::Rollback, + transaction::{self, SignedTx}, +}; +use ain_grpc::{init_evm_runtime, start_servers, stop_evm_runtime}; + +use ain_evm::runtime::RUNTIME; +use log::debug; +use std::error::Error; + +use ethereum::{EnvelopedEncodable, TransactionAction, TransactionSignature}; +use primitive_types::{H160, H256, U256}; +use transaction::{LegacyUnsignedTransaction, TransactionError, LOWER_H256}; + +use crate::ffi::RustRes; + +pub const WEI_TO_GWEI: u64 = 1_000_000_000; +pub const GWEI_TO_SATS: u64 = 10; + +#[cxx::bridge] +pub mod ffi { + pub struct CreateTransactionContext { + chain_id: u64, + nonce: [u8; 32], + gas_price: [u8; 32], + gas_limit: [u8; 32], + to: [u8; 20], + value: [u8; 32], + input: Vec, + priv_key: [u8; 32], + } + + pub struct FinalizeBlockResult { + block_hash: [u8; 32], + failed_transactions: Vec, + miner_fee: u64, + } + + #[derive(Default)] + pub struct ValidateTxResult { + nonce: u64, + sender: [u8; 20], + used_gas: u64, + } + + pub struct RustRes { + ok: bool, + reason: String, + } + + extern "Rust" { + fn evm_get_balance(address: [u8; 20]) -> Result; + fn evm_get_nonce(address: [u8; 20]) -> Result; + fn evm_get_next_valid_nonce_in_context(context: u64, address: [u8; 20]) -> u64; + + fn evm_add_balance( + context: u64, + address: &str, + amount: [u8; 32], + native_tx_hash: [u8; 32], + ) -> Result<()>; + fn evm_sub_balance( + context: u64, + address: &str, + amount: [u8; 32], + native_tx_hash: [u8; 32], + ) -> Result; + + fn evm_try_prevalidate_raw_tx( + result: &mut RustRes, + tx: &str, + with_gas_usage: bool, + ) -> Result; + + fn evm_get_context() -> u64; + fn evm_discard_context(context: u64); + fn evm_try_queue_tx( + result: &mut RustRes, + context: u64, + raw_tx: &str, + native_tx_hash: [u8; 32], + ) -> Result; + + fn evm_finalize( + context: u64, + update_state: bool, + difficulty: u32, + miner_address: [u8; 20], + timestamp: u64, + ) -> Result; + + fn preinit(); + fn init_evm_runtime(); + fn start_servers(json_addr: &str, grpc_addr: &str) -> Result<()>; + fn stop_evm_runtime(); + + fn create_and_sign_tx(ctx: CreateTransactionContext) -> Result>; + + fn evm_disconnect_latest_block() -> Result<()>; + } +} + +/// Creates and signs a transaction. +/// +/// # Arguments +/// +/// * `ctx` - The transaction context. +/// +/// # Errors +/// +/// Returns a `TransactionError` if signing fails. +/// +/// # Returns +/// +/// Returns the signed transaction encoded as a byte vector on success. +pub fn create_and_sign_tx(ctx: ffi::CreateTransactionContext) -> Result, TransactionError> { + let to_action = if ctx.to.is_empty() { + TransactionAction::Create + } else { + TransactionAction::Call(H160::from_slice(&ctx.to)) + }; + + let nonce_u256 = U256::from(ctx.nonce); + let gas_price_u256 = U256::from(ctx.gas_price); + let gas_limit_u256 = U256::from(ctx.gas_limit); + let value_u256 = U256::from(ctx.value); + + // Create + let t = LegacyUnsignedTransaction { + nonce: nonce_u256, + gas_price: gas_price_u256, + gas_limit: gas_limit_u256, + action: to_action, + value: value_u256, + input: ctx.input, + // Dummy sig for now. Needs 27, 28 or > 36 for valid v. + sig: TransactionSignature::new(27, LOWER_H256, LOWER_H256).unwrap(), + }; + + // Sign + let priv_key_h256 = H256::from(ctx.priv_key); + let signed = t.sign(&priv_key_h256, ctx.chain_id)?; + + Ok(signed.encode().into()) +} + +/// Retrieves the balance of an EVM account at latest block height. +/// +/// # Arguments +/// +/// * `address` - The EVM address of the account. +/// +/// # Errors +/// +/// Returns an Error if the address is not a valid EVM address. +/// +/// # Returns +/// +/// Returns the balance of the account as a `u64` on success. +pub fn evm_get_balance(address: [u8; 20]) -> Result> { + let account = H160::from(address); + let (_, latest_block_number) = RUNTIME + .handlers + .block + .get_latest_block_hash_and_number() + .unwrap_or_default(); + let mut balance = RUNTIME + .handlers + .evm + .get_balance(account, latest_block_number) + .unwrap_or_default(); // convert to try_evm_get_balance - Default to 0 for now + balance /= WEI_TO_GWEI; + balance /= GWEI_TO_SATS; + Ok(balance.as_u64()) +} + +/// Retrieves the nonce of an EVM account at latest block height. +/// +/// # Arguments +/// +/// * `address` - The EVM address of the account. +/// +/// # Errors +/// +/// Throws an Error if the address is not a valid EVM address. +/// +/// # Returns +/// +/// Returns the nonce of the account as a `u64` on success. +pub fn evm_get_nonce(address: [u8; 20]) -> Result> { + let account = H160::from(address); + let (_, latest_block_number) = RUNTIME + .handlers + .block + .get_latest_block_hash_and_number() + .unwrap_or_default(); + let nonce = RUNTIME + .handlers + .evm + .get_nonce(account, latest_block_number) + .unwrap_or_default(); + Ok(nonce.as_u64()) +} + +/// Retrieves the next valid nonce of an EVM account in a specific context +/// +/// # Arguments +/// +/// * `context` - The context queue number. +/// * `address` - The EVM address of the account. +/// +/// # Returns +/// +/// Returns the next valid nonce of the account in a specific context as a `u64` +pub fn evm_get_next_valid_nonce_in_context(context: u64, address: [u8; 20]) -> u64 { + let address = H160::from(address); + let nonce = RUNTIME + .handlers + .evm + .get_next_valid_nonce_in_context(context, address); + nonce.as_u64() +} + +/// EvmIn. Send DFI to an EVM account. +/// +/// # Arguments +/// +/// * `context` - The context queue number. +/// * `address` - The EVM address of the account. +/// * `amount` - The amount to add as a byte array. +/// * `hash` - The hash value as a byte array. +/// +/// # Errors +/// +/// Returns an Error if: +/// - the context does not match any existing queue +/// - the address is not a valid EVM address +/// +/// # Returns +/// +/// Returns `Ok(())` on success. +pub fn evm_add_balance( + context: u64, + address: &str, + amount: [u8; 32], + hash: [u8; 32], +) -> Result<(), Box> { + let address = address.parse()?; + + RUNTIME + .handlers + .evm + .add_balance(context, address, amount.into(), hash)?; + Ok(()) +} + +/// EvmOut. Send DFI from an EVM account. +/// +/// # Arguments +/// +/// * `context` - The context queue number. +/// * `address` - The EVM address of the account. +/// * `amount` - The amount to subtract as a byte array. +/// * `hash` - The hash value as a byte array. +/// +/// # Errors +/// +/// Returns an Error if: +/// - the context does not match any existing queue +/// - the address is not a valid EVM address +/// - the account has insufficient balance. +/// +/// # Returns +/// +/// Returns `true` if the balance subtraction is successful, `false` otherwise. +pub fn evm_sub_balance( + context: u64, + address: &str, + amount: [u8; 32], + hash: [u8; 32], +) -> Result> { + let address = address.parse()?; + match RUNTIME + .handlers + .evm + .sub_balance(context, address, amount.into(), hash) + { + Ok(_) => Ok(true), + Err(_) => Ok(false), + } +} + +/// Validates a raw EVM transaction. +/// +/// # Arguments +/// +/// * `result` - Result object +/// * `tx` - The raw transaction string. +/// * `with_gas_usage` - Whether to calculate tx gas usage +/// +/// # Errors +/// +/// Returns an Error if: +/// - The hex data is invalid +/// - The EVM transaction is invalid +/// - Could not fetch the underlying EVM account +/// - Account's nonce does not match raw tx's nonce +/// +/// # Returns +/// +/// Returns the transaction nonce, sender address and gas used if the transaction is valid. +/// logs and set the error reason to result object otherwise. +pub fn evm_try_prevalidate_raw_tx( + result: &mut RustRes, + tx: &str, + with_gas_usage: bool, +) -> Result> { + match RUNTIME.handlers.evm.validate_raw_tx(tx, with_gas_usage) { + Ok((signed_tx, used_gas)) => { + result.ok = true; + Ok(ffi::ValidateTxResult { + nonce: signed_tx.nonce().as_u64(), + sender: signed_tx.sender.to_fixed_bytes(), + used_gas, + }) + } + Err(e) => { + debug!("evm_try_prevalidate_raw_tx fails with error: {e}"); + result.ok = false; + result.reason = e.to_string(); + + Ok(ffi::ValidateTxResult::default()) + } + } +} + +/// Retrieves the EVM context queue. +/// +/// # Returns +/// +/// Returns the EVM context queue number as a `u64`. +#[must_use] +pub fn evm_get_context() -> u64 { + RUNTIME.handlers.evm.get_context() +} + +/// /// Discards an EVM context queue. +/// +/// # Arguments +/// +/// * `context` - The context queue number. +/// +fn evm_discard_context(context: u64) { + RUNTIME.handlers.evm.remove(context) +} + +/// Add an EVM transaction to a specific queue. +/// +/// # Arguments +/// +/// * `context` - The context queue number. +/// * `raw_tx` - The raw transaction string. +/// * `hash` - The native transaction hash. +/// +/// # Errors +/// +/// Returns an Error if: +/// - The `raw_tx` is in invalid format +/// - The queue does not exists. +/// +/// # Returns +/// +/// Returns `true` if the transaction is successfully queued, `false` otherwise. +fn evm_try_queue_tx( + result: &mut RustRes, + context: u64, + raw_tx: &str, + hash: [u8; 32], +) -> Result> { + let signed_tx: SignedTx = raw_tx.try_into()?; + match RUNTIME + .handlers + .evm + .queue_tx(context, signed_tx.into(), hash) + { + Ok(_) => { + result.ok = true; + Ok(true) + } + Err(e) => { + result.ok = false; + result.reason = e.to_string(); + Ok(false) + } + } +} + +/// Finalizes and mine an EVM block. +/// +/// # Arguments +/// +/// * `context` - The context queue number. +/// * `update_state` - A flag indicating whether to update the state. +/// * `difficulty` - The block's difficulty. +/// * `miner_address` - The miner's EVM address as a byte array. +/// * `timestamp` - The block's timestamp. +/// +/// # Errors +/// +/// Returns an Error if there is an error restoring the state trie. +/// +/// # Returns +/// +/// Returns a `FinalizeBlockResult` containing the block hash, failed transactions, and miner fee on success. +fn evm_finalize( + context: u64, + update_state: bool, + difficulty: u32, + miner_address: [u8; 20], + timestamp: u64, +) -> Result> { + let eth_address = H160::from(miner_address); + let (block_hash, failed_txs, gas_used) = RUNTIME.handlers.finalize_block( + context, + update_state, + difficulty, + eth_address, + timestamp, + )?; + Ok(ffi::FinalizeBlockResult { + block_hash, + failed_transactions: failed_txs, + miner_fee: gas_used, + }) +} + +pub fn preinit() { + ain_grpc::preinit(); +} + +fn evm_disconnect_latest_block() -> Result<(), Box> { + RUNTIME.handlers.storage.disconnect_latest_block(); + Ok(()) +} diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml new file mode 100644 index 0000000000..6718ac2130 --- /dev/null +++ b/lib/cli/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "metachain-cli" +version = "0.1.0" +edition = "2021" + +[dependencies] +ain-grpc = { path = "../ain-grpc" } + +jsonrpsee = { version = "0.18", features = ["http-client"] } +structopt = "0.3.26" +primitive-types = "0.12.1" +serde = "1.0.160" +serde_json = "1.0.96" +hex = "0.4.3" +ethereum = "0.14.0" +tokio = "1.27.0" diff --git a/lib/cli/README.md b/lib/cli/README.md new file mode 100644 index 0000000000..3454e17e9b --- /dev/null +++ b/lib/cli/README.md @@ -0,0 +1,51 @@ +# Metachain JSON-RPC CLI + +`metachain-cli` is a command-line interface for interacting with defichain EVM endpoint via JSON-RPC. + +## Features + +- Supports both mainnet and custom chains (e.g., devnet) + +## Usage + +To get started with `metachain-cli`, use the following command: + +```bash +metachain-cli --help +``` + +This will display the available options and subcommands for the CLI. To specify a custom chain, use the -c or --chain option followed by the chain name: + +```bash +metachain-cli -c devnet +``` + +For detailed information on a specific subcommand, run `metachain-cli --help` + +## Available subcommands : + +| Subcommand | Description | +|--------------------------------------------|---------------------------------------------------------------------------| +| `accounts` | Returns a list of accounts owned by the client | +| `block-number` | Returns the number of most recent block | +| `call` | Executes a new message call immediately without creating a transaction on the block chain | +| `chain-id` | Returns the chain ID used by this client | +| `estimate-gas` | Generates and returns an estimate of how much gas is necessary to allow the transaction to complete | +| `gas-price` | Returns the current price per gas in wei | +| `get-balance` | Returns the balance of the account of the given address | +| `get-block-by-hash` | Returns information about a block by its hash | +| `get-block-by-number` | Returns information about a block by its block number | +| `get-block-transaction-count-by-hash` | Returns the number of transactions in a block from a block matching the given block hash | +| `get-block-transaction-count-by-number` | Returns the number of transactions in a block matching the given block number | +| `get-code` | Returns the code at a given address | +| `get-state` | Returns an object representing the current state of the Metachain network | +| `get-storage-at` | Returns the value from a storage position at a given address | +| `get-transaction-by-block-hash-and-index` | Returns information about a transaction by block hash and transaction index position | +| `get-transaction-by-block-number-and-index`| Returns information about a transaction by block number and transaction index position | +| `get-transaction-by-hash` | Returns the information about a transaction requested by its transaction hash | +| `get-transaction-count` | Returns the number of transactions sent from an address | +| `hash-rate` | Returns the number of hashes per second the node is mining with | +| `help` | Prints this message or the help of the given subcommand(s) | +| `mining` | Returns whether the client is mining or not | +| `net-version` | Returns the current network version | +| `send-raw-transaction` | Sends a signed transaction and returns the transaction hash | diff --git a/lib/cli/src/command.rs b/lib/cli/src/command.rs new file mode 100644 index 0000000000..abb2d86149 --- /dev/null +++ b/lib/cli/src/command.rs @@ -0,0 +1,78 @@ +use crate::{result::RpcResult, MetachainCLI}; + +use ain_grpc::rpc::MetachainRPCClient; +use jsonrpsee::http_client::HttpClient; + +pub async fn execute_cli_command( + cmd: MetachainCLI, + client: &HttpClient, +) -> Result { + let result = match cmd { + MetachainCLI::Accounts => client.accounts().await?.into(), + MetachainCLI::ChainId => client.chain_id().await?.into(), + MetachainCLI::NetVersion => client.net_version().await?.into(), + MetachainCLI::Mining => client.mining().await?.into(), + MetachainCLI::Call { input } => client.call((*input).into()).await?.into(), + MetachainCLI::GetBalance { + address, + block_number, + } => client.get_balance(address, block_number).await?.into(), + MetachainCLI::GetBlockByHash { hash } => client.get_block_by_hash(hash).await?.into(), + MetachainCLI::HashRate => client.hash_rate().await?.into(), + MetachainCLI::BlockNumber => client.block_number().await?.into(), + MetachainCLI::GetBlockByNumber { + block_number, + full_transaction, + } => client + .get_block_by_number(block_number, full_transaction) + .await? + .into(), + MetachainCLI::GetTransactionByHash { hash } => { + client.get_transaction_by_hash(hash).await?.into() + } + MetachainCLI::GetTransactionByBlockHashAndIndex { hash, index } => client + .get_transaction_by_block_hash_and_index(hash, index) + .await? + .into(), + MetachainCLI::GetTransactionByBlockNumberAndIndex { + block_number, + index, + } => client + .get_transaction_by_block_number_and_index(block_number, index) + .await? + .into(), + MetachainCLI::GetBlockTransactionCountByHash { hash } => client + .get_block_transaction_count_by_hash(hash) + .await? + .into(), + MetachainCLI::GetBlockTransactionCountByNumber { number } => client + .get_block_transaction_count_by_number(number) + .await? + .into(), + MetachainCLI::GetCode { + address, + block_number, + } => client.get_code(address, block_number).await?.into(), + MetachainCLI::GetStorageAt { + address, + position, + block_number, + } => client + .get_storage_at(address, position, block_number) + .await? + .into(), + MetachainCLI::SendRawTransaction { input } => { + client.send_raw_transaction(&input).await?.into() + } + MetachainCLI::GetTransactionCount { + input, + block_number, + } => client + .get_transaction_count(input, block_number) + .await? + .into(), + MetachainCLI::EstimateGas { input } => client.estimate_gas((*input).into()).await?.into(), + MetachainCLI::GasPrice => client.gas_price().await?.into(), + }; + Ok(result) +} diff --git a/lib/cli/src/format.rs b/lib/cli/src/format.rs new file mode 100644 index 0000000000..09e2a9293f --- /dev/null +++ b/lib/cli/src/format.rs @@ -0,0 +1,21 @@ +use std::str::FromStr; + +#[derive(Debug)] +pub enum Format { + Rust, + Json, + PrettyJson, +} + +impl FromStr for Format { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "json" => Ok(Format::Json), + "rust" => Ok(Format::Rust), + "pp" => Ok(Format::PrettyJson), + _ => Err(format!("Unsupported format: {s}")), + } + } +} diff --git a/lib/cli/src/main.rs b/lib/cli/src/main.rs new file mode 100644 index 0000000000..62c545519d --- /dev/null +++ b/lib/cli/src/main.rs @@ -0,0 +1,148 @@ +mod command; +mod format; +mod params; +mod result; +mod structs; + +use crate::structs::CallRequest; +use ain_grpc::block::BlockNumber; +use command::execute_cli_command; +use format::Format; +use jsonrpsee::http_client::HttpClientBuilder; +use params::{BaseChainParams, Chain}; +use primitive_types::{H160, H256, U256}; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt(name = "metachain-cli", about = "Metachain JSON-RPC CLI")] +struct Opt { + /// The chain to be used. + #[structopt(short, long, default_value = "main")] + chain: Chain, + + /// Format output. + #[structopt(long, default_value = "json")] + format: Format, + + #[structopt(subcommand)] + cmd: MetachainCLI, +} + +#[derive(Debug, StructOpt)] +pub enum MetachainCLI { + /// Returns a list of accounts owned by the client. + Accounts, + /// Returns the chain ID used by this client. + ChainId, + /// Returns the current network version. + NetVersion, + /// Returns whether the client is mining or not. + Mining, + /// Executes a new message call immediately without creating a transaction on the block chain. + Call { + #[structopt(flatten)] + input: Box, + }, + /// Returns the balance of the account of the given address. + GetBalance { + #[structopt(parse(try_from_str))] + address: H160, + #[structopt(parse(try_from_str))] + block_number: Option, + }, + /// Returns information about a block by its hash. + GetBlockByHash { + #[structopt(parse(try_from_str))] + hash: H256, + }, + /// Returns the number of hashes per second the node is mining with. + HashRate, + /// Returns the number of most recent block. + BlockNumber, + /// Returns information about a block by its block number. + GetBlockByNumber { + #[structopt(parse(try_from_str))] + block_number: BlockNumber, + #[structopt(long)] + full_transaction: bool, + }, + /// Returns the information about a transaction requested by its transaction hash. + GetTransactionByHash { + #[structopt(parse(try_from_str))] + hash: H256, + }, + /// Returns information about a transaction by block hash and transaction index position. + GetTransactionByBlockHashAndIndex { + #[structopt(parse(try_from_str))] + hash: H256, + index: usize, + }, + /// Returns information about a transaction by block number and transaction index position. + GetTransactionByBlockNumberAndIndex { + #[structopt(parse(try_from_str))] + block_number: U256, + index: usize, + }, + /// Returns the number of transactions in a block from a block matching the given block hash. + GetBlockTransactionCountByHash { + #[structopt(parse(try_from_str))] + hash: H256, + }, + /// Returns the number of transactions in a block matching the given block number. + GetBlockTransactionCountByNumber { + #[structopt(parse(try_from_str))] + number: BlockNumber, + }, + /// Returns the code at a given address. + GetCode { + #[structopt(parse(try_from_str))] + address: H160, + #[structopt(parse(try_from_str))] + block_number: Option, + }, + /// Returns the value from a storage position at a given address. + GetStorageAt { + #[structopt(parse(try_from_str))] + address: H160, + #[structopt(parse(try_from_str))] + position: U256, + #[structopt(parse(try_from_str))] + block_number: Option, + }, + /// Sends a signed transaction and returns the transaction hash. + SendRawTransaction { input: String }, + /// Returns the number of transactions sent from an address. + GetTransactionCount { + #[structopt(parse(try_from_str))] + input: H160, + #[structopt(parse(try_from_str))] + block_number: Option, + }, + /// Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. + EstimateGas { + #[structopt(flatten)] + input: Box, + }, + /// Returns the current price per gas in wei. + GasPrice, +} + +#[tokio::main] +async fn main() -> Result<(), jsonrpsee::core::Error> { + let opt = Opt::from_args(); + + let client = { + let chain = opt.chain; + let base_chain_params = BaseChainParams::create(&chain); + let json_addr = format!("http://127.0.0.1:{}", base_chain_params.eth_rpc_port); + HttpClientBuilder::default().build(json_addr) + }?; + + let result = execute_cli_command(opt.cmd, &client).await?; + match opt.format { + Format::Rust => println!("{result}"), + Format::Json => println!("{}", serde_json::to_string(&result)?), + Format::PrettyJson => println!("{}", serde_json::to_string_pretty(&result)?), + }; + Ok(()) +} diff --git a/lib/cli/src/params.rs b/lib/cli/src/params.rs new file mode 100644 index 0000000000..4c835f6544 --- /dev/null +++ b/lib/cli/src/params.rs @@ -0,0 +1,74 @@ +use std::str::FromStr; + +#[derive(Debug, Default)] +pub enum Chain { + #[default] + Main, + Testnet, + Devnet, + Regtest, +} + +impl FromStr for Chain { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "main" => Ok(Chain::Main), + "testnet" => Ok(Chain::Testnet), + "devnet" => Ok(Chain::Devnet), + "regtest" => Ok(Chain::Regtest), + _ => Err(format!("Unknown chain: {s}")), + } + } +} + +#[derive(Debug)] +pub struct BaseChainParams { + pub data_dir: String, + pub rpc_port: u16, + pub grpc_port: u16, + pub eth_rpc_port: u16, +} + +impl BaseChainParams { + pub fn create(chain: &Chain) -> Self { + match chain { + Chain::Main => Self { + data_dir: String::new(), + rpc_port: 8554, + grpc_port: 8550, + eth_rpc_port: 8551, + }, + Chain::Testnet => Self { + data_dir: "testnet3".to_string(), + rpc_port: 18554, + grpc_port: 18550, + eth_rpc_port: 18551, + }, + Chain::Devnet => { + if std::env::var("DEVNET_BOOTSTRAP").is_ok() { + Self { + data_dir: "devnet".to_string(), + rpc_port: 18554, + grpc_port: 18550, + eth_rpc_port: 18551, + } + } else { + Self { + data_dir: "devnet".to_string(), + rpc_port: 20554, + grpc_port: 20550, + eth_rpc_port: 20551, + } + } + } + Chain::Regtest => Self { + data_dir: "regtest".to_string(), + rpc_port: 19554, + grpc_port: 19550, + eth_rpc_port: 19551, + }, + } + } +} diff --git a/lib/cli/src/result.rs b/lib/cli/src/result.rs new file mode 100644 index 0000000000..6080722638 --- /dev/null +++ b/lib/cli/src/result.rs @@ -0,0 +1,93 @@ +use ain_grpc::block::RpcBlock; +use ain_grpc::codegen::types::EthTransactionInfo; +use primitive_types::{H256, U256}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +pub enum RpcResult { + String(String), + VecString(Vec), + U256(U256), + H256(H256), + Bool(bool), + EthTransactionInfo(EthTransactionInfo), + Usize(usize), + Block(Box), + Option(Option>), +} + +impl From for RpcResult { + fn from(value: String) -> Self { + RpcResult::String(value) + } +} + +impl From> for RpcResult { + fn from(value: Vec) -> Self { + RpcResult::VecString(value) + } +} + +impl From for RpcResult { + fn from(value: U256) -> Self { + RpcResult::U256(value) + } +} + +impl From for RpcResult { + fn from(value: H256) -> Self { + RpcResult::H256(value) + } +} + +impl From for RpcResult { + fn from(value: bool) -> Self { + RpcResult::Bool(value) + } +} + +impl From for RpcResult { + fn from(value: EthTransactionInfo) -> Self { + RpcResult::EthTransactionInfo(value) + } +} + +impl From for RpcResult { + fn from(value: usize) -> Self { + RpcResult::Usize(value) + } +} + +impl From for RpcResult { + fn from(value: RpcBlock) -> Self { + RpcResult::Block(Box::new(value)) + } +} + +impl + 'static> From> for RpcResult { + fn from(value: Option) -> Self { + RpcResult::Option(value.map(|v| Box::new(v.into()))) + } +} + +use std::fmt::{self, Display, Formatter}; + +impl Display for RpcResult { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + RpcResult::String(value) => write!(f, "{value}"), + RpcResult::VecString(value) => write!(f, "{value:?}"), + RpcResult::U256(value) => write!(f, "{value:#x}"), + RpcResult::H256(value) => write!(f, "{value:#x}"), + RpcResult::Bool(value) => write!(f, "{value}"), + RpcResult::EthTransactionInfo(value) => write!(f, "{value:?}"), + RpcResult::Usize(value) => write!(f, "{value}"), + RpcResult::Block(value) => write!(f, "{value:?}"), + RpcResult::Option(value) => match value { + Some(inner_value) => write!(f, "Some({inner_value})"), + None => write!(f, "None"), + }, + } + } +} diff --git a/lib/cli/src/structs.rs b/lib/cli/src/structs.rs new file mode 100644 index 0000000000..7196e61142 --- /dev/null +++ b/lib/cli/src/structs.rs @@ -0,0 +1,97 @@ +use ethereum::AccessListItem; +use primitive_types::H160; +use primitive_types::U256; +use structopt::StructOpt; + +#[derive(Debug)] +pub struct HexData(Vec); + +pub type AccessList = Vec; + +#[derive(Debug, StructOpt)] +pub struct CallRequest { + /// The sender of the transaction (optional). + #[structopt(long, parse(try_from_str = parse_h160))] + pub from: Option, + + /// The recipient of the transaction (optional). + #[structopt(long, parse(try_from_str = parse_h160))] + pub to: Option, + + /// The gas price for the transaction (optional). + #[structopt(long, parse(try_from_str = parse_u256))] + pub gas_price: Option, + + /// The maximum base fee per gas the caller is willing to pay (optional, used for EIP-1559 transactions). + #[structopt(long = "max-fee-per-gas", parse(try_from_str = parse_u256))] + pub max_fee_per_gas: Option, + + /// The priority fee per gas the caller is paying to the block author (optional, used for EIP-1559 transactions). + #[structopt(long = "max-priority-fee-per-gas", parse(try_from_str = parse_u256))] + pub max_priority_fee_per_gas: Option, + + /// The amount of gas provided for the transaction (optional). + #[structopt(long, parse(try_from_str = parse_u256))] + pub gas: Option, + + /// The amount of DFI (in Wei) sent with the transaction (optional). + #[structopt(long, parse(try_from_str = parse_u256))] + pub value: Option, + + /// The input data for the transaction (optional). + #[structopt(long, parse(try_from_str = parse_hex_data))] + pub data: Option, + + /// The nonce value for the transaction (optional). + #[structopt(long, parse(try_from_str = parse_u256))] + pub nonce: Option, + + /// The access list for the transaction (optional, used for EIP-2930 and EIP-1559 transactions). + #[structopt(long, parse(try_from_str = parse_access_list))] + pub access_list: Option, + + /// The EIP-2718 transaction type (optional, used for typed transactions). + #[structopt(long, parse(try_from_str = parse_u256))] + pub transaction_type: Option, +} + +fn parse_h160(s: &str) -> Result { + s.parse::() + .map_err(|e| format!("Failed to parse H160: {e}")) +} + +fn parse_u256(s: &str) -> Result { + s.parse::() + .map_err(|e| format!("Failed to parse U256: {e}")) +} + +fn parse_hex_data(s: &str) -> Result { + if let Some(stripped) = s.strip_prefix("0x") { + let hex = hex::decode(stripped).map_err(|e| format!("Failed to parse hex data: {e}"))?; + Ok(HexData(hex)) + } else { + Err("Data must start with 0x".to_string()) + } +} + +fn parse_access_list(s: &str) -> Result, String> { + serde_json::from_str(s).map_err(|e| format!("Failed to parse access list: {e}")) +} + +impl From for ain_grpc::call_request::CallRequest { + fn from(val: CallRequest) -> Self { + ain_grpc::call_request::CallRequest { + from: val.from, + to: val.to, + gas_price: val.gas_price, + max_fee_per_gas: val.max_fee_per_gas, + max_priority_fee_per_gas: val.max_priority_fee_per_gas, + gas: val.gas, + value: val.value, + data: val.data.map(|hex| hex.0), + nonce: val.nonce, + access_list: val.access_list, + transaction_type: val.transaction_type, + } + } +} diff --git a/lib/labs-dfeye/Cargo.toml b/lib/labs-dfeye/Cargo.toml new file mode 100644 index 0000000000..d6aa2dd5bc --- /dev/null +++ b/lib/labs-dfeye/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "labs-dfeye" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus = "0.3.2" +dioxus-desktop = "0.3.0" +dioxus-tui = "0.2.2" +dioxus-web = "0.3.1" diff --git a/lib/labs-dfeye/src/bin/cli.rs b/lib/labs-dfeye/src/bin/cli.rs new file mode 100644 index 0000000000..73c34f8c77 --- /dev/null +++ b/lib/labs-dfeye/src/bin/cli.rs @@ -0,0 +1,3 @@ +fn main() { + dioxus_tui::launch(labs_dfeye::app); +} diff --git a/lib/labs-dfeye/src/bin/desktop.rs b/lib/labs-dfeye/src/bin/desktop.rs new file mode 100644 index 0000000000..7f556e23c7 --- /dev/null +++ b/lib/labs-dfeye/src/bin/desktop.rs @@ -0,0 +1,3 @@ +fn main() { + dioxus_desktop::launch(labs_dfeye::app); +} diff --git a/lib/labs-dfeye/src/bin/web.rs b/lib/labs-dfeye/src/bin/web.rs new file mode 100644 index 0000000000..073fadf1b2 --- /dev/null +++ b/lib/labs-dfeye/src/bin/web.rs @@ -0,0 +1,3 @@ +fn main() { + dioxus_web::launch(labs_dfeye::App); +} diff --git a/lib/labs-dfeye/src/lib.rs b/lib/labs-dfeye/src/lib.rs new file mode 100644 index 0000000000..89afddb282 --- /dev/null +++ b/lib/labs-dfeye/src/lib.rs @@ -0,0 +1,9 @@ +use dioxus::prelude::*; + +pub fn app(cx: Scope) -> Element { + cx.render(rsx! { + div { + "dfeye: 👀" + } + }) +} diff --git a/lib/labs-grpc2/Cargo.toml b/lib/labs-grpc2/Cargo.toml new file mode 100644 index 0000000000..bc8fd032b9 --- /dev/null +++ b/lib/labs-grpc2/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "labs-grpc2" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +env_logger = "0.10" +lazy_static = "1.4" +log = "0.4" +num-traits = "0.2" +prost = "0.11" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tonic = "0.9" +fake = "2.5" +rand = "0.8" +anyhow = "1.0.70" +async-trait = "0.1.68" + +[build-dependencies] +prost-build = "0.11" +tonic-build = "0.9" +anyhow = "1.0.70" +tonic = "0.9" + +[dev-dependencies] +erased-serde = "0.3.25" +prost = "0.11" diff --git a/lib/labs-grpc2/build.rs b/lib/labs-grpc2/build.rs new file mode 100644 index 0000000000..d91b90098f --- /dev/null +++ b/lib/labs-grpc2/build.rs @@ -0,0 +1,38 @@ +use anyhow::{format_err, Result}; +use std::path::PathBuf; + +fn main() -> Result<()> { + std::env::set_var("PROTOC", protobuf_src::protoc()); + let proto_include = protobuf_src::include(); + + // let manifest_path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR")?); + // let gen_path = manifest_path.join("gen"); + let gen_path = PathBuf::from(std::env::var("OUT_DIR")?); + + std::fs::create_dir_all(&gen_path)?; + + let prost_build = tonic_build::configure(); + + let default_attrs = r#" + #[derive(Eq, serde::Serialize, serde::Deserialize)] + #[serde(rename_all="camelCase")] + "#; + let _serde_flatten_attr = "#[serde(flatten)]"; + let serde_untagged_attr = "#[serde(untagged)]"; + + prost_build + .out_dir(gen_path) + .enum_attribute(".", serde_untagged_attr) + // .field_attribute("<.>", serde_flatten_attr) + .type_attribute(".", default_attrs) + .compile( + &["proto/services.proto"], + &[ + "proto", + proto_include + .to_str() + .ok_or(format_err!("proto include path err"))?, + ], + )?; + Ok(()) +} diff --git a/lib/labs-grpc2/proto/eth.proto b/lib/labs-grpc2/proto/eth.proto new file mode 100644 index 0000000000..61c1c6216a --- /dev/null +++ b/lib/labs-grpc2/proto/eth.proto @@ -0,0 +1,418 @@ +syntax = "proto3"; +package eth; + +import "google/protobuf/empty.proto"; + +service Api { + /// Returns eth_accounts list. + rpc EthAccounts(google.protobuf.Empty) returns (EthAccountsResponse); + + /// Call contract, returning the output data. Does not create a transaction. + rpc EthCall(EthCallRequest) returns (EthCallResponse); + + /// Returns the balance for the given address. + rpc EthGetBalance(EthGetBalanceRequest) returns (EthGetBalanceResponse); + + /// Returns information about a block by hash. + rpc EthGetBlockByHash(EthGetBlockByHashRequest) returns (EthBlockInfo); + + /// Returns the balance for the given address. + rpc EthSendTransaction(EthSendTransactionRequest) returns (EthSendTransactionResponse); + + /// Returns the chain ID used for signing replay-protected transactions. + rpc EthChainId(google.protobuf.Empty) returns (EthChainIdResponse); + + /// Returns the current network id. + rpc NetVersion(google.protobuf.Empty) returns (EthChainIdResponse); + + /// Returns the number of most recent block. + rpc EthBlockNumber(google.protobuf.Empty) returns (EthBlockNumberResponse); + + /// Returns information about a block by block number. + rpc EthGetBlockByNumber(EthGetBlockByNumberRequest) returns (EthBlockInfo); + + /// Returns the information about a transaction from a transaction hash. + rpc EthGetTransactionByHash(EthGetTransactionByHashRequest) returns (EthTransactionInfo); + + /// Returns information about a transaction given a blockhash and transaction index position. + rpc EthGetTransactionByBlockHashAndIndex(EthGetTransactionByBlockHashAndIndexRequest) returns (EthTransactionInfo); + + /// Returns information about a transaction given a block number and transaction index position. + rpc EthGetTransactionByBlockNumberAndIndex(EthGetTransactionByBlockNumberAndIndexRequest) returns (EthTransactionInfo); + + /// Returns true if client is actively mining new blocks. + rpc EthMining(google.protobuf.Empty) returns (EthMiningResponse); + + /// Returns the number of transactions in a block from a block matching the given block hash. + rpc EthGetBlockTransactionCountByHash(EthGetBlockTransactionCountByHashRequest) returns (EthGetBlockTransactionCountByHashResponse); + + /// Returns the number of transactions in a block matching the given block number. + rpc EthGetBlockTransactionCountByNumber(EthGetBlockTransactionCountByNumberRequest) returns (EthGetBlockTransactionCountByNumberResponse); + + /// Returns code at a given address. + rpc EthGetCode(EthGetCodeRequest) returns (EthGetCodeResponse); + + /// Returns the value from a storage position at a given address. + rpc EthGetStorageAt(EthGetStorageAtRequest) returns (EthGetStorageAtResponse); + + /// Creates new message call transaction or a contract creation for signed transactions. + rpc EthSendRawTransaction(EthSendRawTransactionRequest) returns (EthSendRawTransactionResponse); +} + +message EthAccountsResponse { + repeated string accounts = 1; // The list of accounts (Hex) +} + +message EthTransactionInfo { + optional string from = 1; // The address from which the transaction is sent + optional string to = 2; // The address to which the transaction is addressed + optional uint64 gas = 3; // The integer of gas provided for the transaction execution + optional string price = 4; // The integer of gas price used for each paid gas encoded as hexadecimal + optional string value = 5; // The integer of value sent with this transaction encoded as hexadecimal + optional string data = 6; // The hash of the method signature and encoded parameters. + optional string nonce = 7; // The integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. +} + +message EthChainIdResponse { + string id = 1; // Hexadecimal value as a string representing the integer of the current chain id. +} + +message EthBlockInfo { + string block_number = 1; // The block number. null when its pending block. + string hash = 2; // Hash of the block. null when its pending block. + string parent_hash = 3; // Hash of the parent block. + string nonce = 4; // Hash of the generated proof-of-work. null when its pending block. + string sha3_uncles = 5; // SHA3 of the uncles data in the block. + string logs_bloom = 6; // The bloom filter for the logs of the block. null when its pending block. + string transactions_root = 7; // The root of the transaction trie of the block. + string state_root = 8; // The root of the final state trie of the block. + string receipt_root = 9; // The root of the receipts trie of the block. + string miner = 10; // The address of the beneficiary to whom the mining rewards were given. + string difficulty = 11; // Integer of the difficulty for this block. + string total_difficulty = 12; // Integer of the total difficulty of the chain until this block. + string extra_data = 13; // The "extra data" field of this block. + string size = 14; // Integer the size of this block in bytes. + string gas_limit = 15; // The maximum gas allowed in this block. + string gas_used = 16; // The total used gas by all transactions in this block. + string timestamps = 17; // The unix timestamp for when the block was collated. + repeated string transactions = 18; // Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter. + repeated string uncles = 19; // Array of uncle hashes. +} + +message EthTransactionReceipt { + string transaction_hash = 1; // Hash of the transaction. + string transaction_index = 2; // Integer of the transactions index position in the block. + string block_hash = 3; // Hash of the block where this transaction was in. + string block_number = 4; // Block number where this transaction was in. + string from = 5; // Address of the sender. + string to = 6; // Address of the receiver. null when its a contract creation transaction. + string cumulative_gas_used = 7; // The total amount of gas used when this transaction was executed in the block. + string effective_gas_price = 8; // The sum of the base fee and tip paid per unit of gas. + string gas_used = 9; // The amount of gas used by this specific transaction alone. + string contract_address = 10; // The contract address created, if the transaction was a contract creation, otherwise null. + repeated string logs = 11; // Array of log objects, which this transaction generated. + string logs_bloom = 12; // Bloom filter for light clients to quickly retrieve related logs. + string type = 13; // Integer of the transaction type, 0x00 for legacy transactions, 0x01 for access list types, 0x02 for dynamic fees. It also returns either : + optional string root = 14; // 32 bytes of post-transaction stateroot (pre Byzantium) + optional string status = 15; // Either 1 (success) or 0 (failure) +} + +message EthCallRequest { + EthTransactionInfo transaction_info = 1; // The transaction call object + string block_number = 2; // Block number in hexadecimal format or the string latest, earliest, pending, safe or finalized +} + +message EthCallResponse { + string data = 1; // The return value of the executed contract method +} + +message EthSignRequest { + string address = 1; // Address you want to use to sign the message + string message = 2; // Hexadecimal value of the message that you want to sign +} + +message EthSignResponse { + string signature = 1; // Hexadecimal value of the signed message +} + +message EthGetBalanceRequest { + string address = 1; // Address you want to check the balance + string block_number = 2; // Integer block number, or the string "latest", "earliest" or "pending" (Hex) if it's the block number +} + +message EthGetBalanceResponse { + string balance = 1; // Integer of the current balance in wei (Hex) +} + +message EthSendTransactionRequest { + EthTransactionInfo transaction_info = 1; // The transaction object +} + +message EthSendTransactionResponse { + string hash = 1; // The transaction hash, or the zero hash if the transaction is not yet available +} + +message EthCoinBaseResponse { + string address = 1; // The current coinbase address +} + +message EthMiningResponse { + bool isMining = 1; // True if the client is mining, otherwise False +} + +message EthHashRateResponse { + string hash_rate = 1; // Number of hashes per second (Hex) +} + +message EthGasPriceResponse { + string gas_price = 1; // Integer of the current gas price in wei (Hex) +} + +message EthBlockNumberResponse { + string block_number = 1; // Integer of the current block number the client is on (Hex) +} + +message EthGetTransactionCountRequest { + string address = 1; + string block_number = 2; // Integer block number, or the string "latest", "earliest" or "pending" (Hex) if it's the block number +} + +message EthGetTransactionCountResponse { + string number_transaction = 1; // Integer of the number of transactions send from this address (Hex) +} + +message EthGetBlockTransactionCountByHashRequest { + string block_hash = 1; // Hash of a block (Hex) +} + +message EthGetBlockTransactionCountByHashResponse { + string number_transaction = 1; // Integer of the number of transactions in this block (Hex) +} + +message EthGetBlockTransactionCountByNumberRequest { + string block_number = 1; // Integer block number, or the string "latest", "earliest" or "pending" (Hex) if it's the block number +} + +message EthGetBlockTransactionCountByNumberResponse { + string number_transaction = 1; // Integer of the number of transactions in this block (Hex) +} + +message EthGetUncleCountByBlockHashRequest { + string block_hash = 1; // Hash of a block (Hex) +} + +message EthGetUncleCountByBlockHashResponse { + string number_uncles = 1; // Integer of the number of uncles in this block (Hex) +} + +message EthGetUncleCountByBlockNumberRequest { + string block_number = 1; // Integer block number, or the string "latest", "earliest" or "pending" (Hex) if it's the block number +} + +message EthGetUncleCountByBlockNumberResponse { + string number_uncles = 1; // Integer of the number of uncles in this block (Hex) +} + +message EthGetCodeRequest { + string address = 1; // Address you wan to get the code from + string block_number = 2; // Integer block number, or the string "latest", "earliest" or "pending" (Hex) if it's the block number +} + +message EthGetCodeResponse { + string code = 1; // The code from the given address +} + +message EthSignTransactionRequest { + EthTransactionInfo transaction_info = 1; // The transaction object to be signed +} + +message EthSignTransactionResponse { + string transaction = 1; // The signed transaction object +} + +message EthSendRawTransactionRequest { + string transaction = 1; // Hexadecimal encoded signed transaction +} + +message EthSendRawTransactionResponse { + string hash = 1; // The transaction hash, or the zero hash if the transaction is not yet available. +} + +message EthEstimateGasRequest { + EthTransactionInfo transaction_info = 1; // Transaction info + optional string block_number = 2; // Block number in hexadecimal format or the string latest, earliest, pending, safe or finalized +} + +message EthEstimateGasResponse { + string gas_used = 1; // The amount of gas used (Hex) +} + +message EthGetBlockByHashRequest { + string hash = 1; // Hash of a block (Hex) + bool full_transaction = 2; // If true it returns the full transaction objects, if false only the hashes of the transactions +} + +message EthGetBlockByHashResponse { + EthBlockInfo block_info = 1; // A block object, or null when no block was found +} + +message EthGetBlockByNumberRequest { + string number = 1; // Block number (Hex) + bool full_transaction = 2; // If true it returns the full transaction objects, if false only the hashes of the transactions +} + +message EthGetBlockByNumberResponse { + EthBlockInfo block_info = 1; // A block object, or null when no block was found +} + +message EthGetTransactionByHashRequest { + string hash = 1; // Hash of the transaction +} + +message EthGetTransactionByHashResponse { + EthTransactionInfo transaction = 1; // A transaction object, or null when no transaction was found +} + +message EthGetTransactionByBlockHashAndIndexRequest { + string block_hash = 1; // Hash of a block + string index = 2; // Integer of the transaction index position (Hex) +} + +message EthGetTransactionByBlockHashAndIndexResponse { + EthTransactionInfo transaction = 1; // A transaction object, or null when no transaction was found +} + +message EthGetTransactionByBlockNumberAndIndexRequest { + string block_number = 1; // Integer block number, or the string "latest", "earliest" or "pending" (Hex) if it's the block number + string index = 2; // Integer of the transaction index position (Hex) +} + +message EthGetTransactionByBlockNumberAndIndexResponse { + EthTransactionInfo transaction = 1; // A transaction object, or null when no transaction was found +} + +message EthGetUncleByBlockHashAndIndexRequest { + string block_hash = 1; // Hash of a block + string index = 2; // Integer of the transaction index position (Hex) +} + +message EthGetUncleByBlockHashAndIndexResponse { + EthBlockInfo block_info = 1; // A block object, or null when no block was found +} + +message EthGetUncleByBlockNumberAndIndexRequest { + string block_number = 1; // Integer block number, or the string "latest", "earliest" or "pending" (Hex) if it's the block number + string index = 2; // Integer of the transaction index position (Hex) +} + +message EthGetUncleByBlockNumberAndIndexResponse { + EthBlockInfo block_info = 1; // A block object, or null when no block was found +} + +message EthGetCompilersResponse { + repeated string compilers = 1; // Array of available compilers +} + +message EthCompileSolidityRequest { + string code = 1; // The source code +} + +message EthCompileSolidityResponse { + string compiled_code = 1; // The compiled source code +} + +message EthCompileLLLRequest { + string code = 1; // The source code +} + +message EthCompileLLLResponse { + string compiled_code = 1; // The compiled source code +} + +message EthCompileSerpentRequest { + string code = 1; // The source code +} + +message EthCompileSerpentResponse { + string compiled_code = 1; // The compiled source code +} + +message EthProtocolVersionResponse { + string protocol_version = 1; // The current DMC protocol version +} + +message Web3Sha3Request { + string data = 1; // The data to convert into a SHA3 hash +} + +message Web3Sha3Response { + string data = 1; // The SHA3 result of the given string. +} + +message NetPeerCountResponse { + string number_peer = 1; // Integer of the number of connected peers (Hex) +} + +message NetVersionResponse { + string network_version = 1; // The current network id +} + +message Web3ClientVersionResponse { + string client_version = 1; // The current client version +} + +message EthGetWorkResponse { + string currentblock = 1; // Current block header pow-hash + string seed_hash = 2; // The seed hash used for the DAG. + string target = 3; // The boundary condition ("target"), 2^256 / difficulty. +} + +message EthSubmitWorkRequest { + string nounce = 1; // The nonce found (64 bits) + string pow_hash = 2; // The header's pow-hash (256 bits) + string mix_digest = 3; // The mix digest (256 bits) +} + +message EthSubmitWorkResponse { + bool is_valid = 1; // Returns true if the provided solution is valid, otherwise false +} + +message EthSubmitHashrateRequest { + string hash_rate = 1; // Hexadecimal string representation (32 bytes) of the hashrate + string id = 2; // A random hexadecimal(32 bytes) ID identifying the client +} + +message EthSubmitHashrateResponse { + bool is_valid = 1; // Returns true if submitting went through successfully and false otherwise +} + +message EthGetStorageAtRequest { + string address = 1; // Address of the storage + string position = 2; // integer of the position in the storage (Hex) + string block_number = 3; // Integer block number, or the string "latest", "earliest" or "pending" (Hex) if it's the block number +} + +message EthGetStorageAtResponse { + string value = 1; // The value at this storage position. +} + +message EthGetTransactionReceiptRequest { + string transaction_hash = 1; // Hash of a transaction +} + +message EthGetTransactionReceiptResponse { + EthTransactionReceipt transaction_receipt = 1; // A transaction receipt object, or null when no receipt was found +} + +message EthSyncingInfo { + string starting_block = 1; // The block at which the import started (will only be reset, after the sync reached his head) + string current_block = 2; // The current block, same as eth_blockNumber + string highest_block = 3; // The estimated highest block +} + +message EthSyncingResponse { + oneof value { + bool status = 1; // Return False when not syncing + EthSyncingInfo sync_info = 2; // An object with sync status data + } +} diff --git a/lib/labs-grpc2/proto/services.proto b/lib/labs-grpc2/proto/services.proto new file mode 100644 index 0000000000..5185a31c8a --- /dev/null +++ b/lib/labs-grpc2/proto/services.proto @@ -0,0 +1,3 @@ +syntax = "proto3"; + +import "eth.proto"; \ No newline at end of file diff --git a/lib/labs-grpc2/src/api.rs b/lib/labs-grpc2/src/api.rs new file mode 100644 index 0000000000..75cf38318a --- /dev/null +++ b/lib/labs-grpc2/src/api.rs @@ -0,0 +1,136 @@ +use crate::proto; +use async_trait::async_trait; +use tonic::{Request, Response, Status}; + +use proto::eth::*; + +struct ApiImpl {} + +#[async_trait] +impl proto::eth::api_server::Api for ApiImpl { + async fn eth_accounts( + &self, + request: Request<()>, + ) -> Result, Status> { + todo!() + } + + async fn eth_call( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_get_balance( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_get_block_by_hash( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_send_transaction( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_chain_id( + &self, + request: Request<()>, + ) -> Result, Status> { + todo!() + } + + async fn net_version( + &self, + request: Request<()>, + ) -> Result, Status> { + todo!() + } + + async fn eth_block_number( + &self, + request: Request<()>, + ) -> Result, Status> { + todo!() + } + + async fn eth_get_block_by_number( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_get_transaction_by_hash( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_get_transaction_by_block_hash_and_index( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_get_transaction_by_block_number_and_index( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_mining( + &self, + request: Request<()>, + ) -> Result, Status> { + todo!() + } + + async fn eth_get_block_transaction_count_by_hash( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_get_block_transaction_count_by_number( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_get_code( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_get_storage_at( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } + + async fn eth_send_raw_transaction( + &self, + request: Request, + ) -> Result, Status> { + todo!() + } +} diff --git a/lib/labs-grpc2/src/lib.rs b/lib/labs-grpc2/src/lib.rs new file mode 100644 index 0000000000..0d49b645cd --- /dev/null +++ b/lib/labs-grpc2/src/lib.rs @@ -0,0 +1,52 @@ +mod api; +mod proto; + +#[cfg(test)] +mod tests { + use serde::Serialize; + + use super::*; + use crate::proto::eth::*; + + fn print_debug(val: T) { + println!("{:?}\n{}", val, serde_json::to_string_pretty(&val).unwrap()); + } + + #[test] + fn json_outputs_basic() { + let mut x = EthCallResponse::default(); + x.data = "hello".to_string(); + print_debug(x); + } + + #[test] + fn json_outputs_flattened_enums() { + let mut x: EthSyncingResponse = EthSyncingResponse::default(); + x.value = Some(eth_syncing_response::Value::Status(true)); + print_debug(x); + + let mut x = EthSyncingResponse::default(); + x.value = Some(eth_syncing_response::Value::SyncInfo( + EthSyncingInfo::default(), + )); + print_debug(x); + } + + #[test] + fn json_outputs_transaction_receipts() { + let mut x = EthGetTransactionReceiptResponse::default(); + x.transaction_receipt = None; + print_debug(x); + + let mut x = EthGetTransactionReceiptResponse::default(); + x.transaction_receipt = Some(EthTransactionReceipt::default()); + print_debug(x); + } + + #[test] + fn json_outputs_chain_id() { + let mut x = EthChainIdResponse::default(); + x.id = 100.to_string(); + print_debug(x); + } +} diff --git a/lib/labs-grpc2/src/proto.rs b/lib/labs-grpc2/src/proto.rs new file mode 100644 index 0000000000..5790d412db --- /dev/null +++ b/lib/labs-grpc2/src/proto.rs @@ -0,0 +1,7 @@ +pub mod eth { + include!(concat!(env!("OUT_DIR"), "/eth.rs")); + // include!(concat!(env!("CARGO_MANIFEST_DIR"), "/gen", "/eth.rs")); +} + +// macro_rules! blackhole { ($tt:x) => () } +// blackhole!(1e0); diff --git a/lib/proto/types/block.proto b/lib/proto/types/block.proto new file mode 100644 index 0000000000..d934995a7f --- /dev/null +++ b/lib/proto/types/block.proto @@ -0,0 +1,56 @@ +syntax = "proto3"; +package types; + +import "types/tx.proto"; + +message Block { + string hash = 1; // Block hash (same as input, if any) + int64 confirmations = 2; // The number of confirmations, or -1 if the block is not on the main chain + uint64 size = 3; // Block size + uint64 strippedsize = 4; // Block size without witness data + uint64 weight = 5; // The block weight as defined in BIP 141 + uint64 height = 6; // The block height or index + uint64 version = 7; // The block version + string version_hex = 8; // The block version in hex + string merkleroot = 9; // The merkle root + repeated types.Transaction tx = 10; // List of transaction IDs + uint64 time = 11; // The block time in seconds since UNIX epoch + uint64 mediantime = 12; // The median block time in seconds since UNIX epoch + uint64 nonce = 13; // The nonce used to generate the block (property exists only when PoW is used) + string bits = 14; // The bits which represent the target difficulty + double difficulty = 15; // The difficulty of the block + string chainwork = 16; // Expected number of hashes required to produce the chain up to this block (in hex) + uint32 n_tx = 17; // Number of transactions in the block + string previous_block_hash = 18; // The hash of the previous block + string next_block_hash = 19; // The hash of the next block + + // DeFiChain fields + string masternode = 101; + string minter = 102; + uint64 minted_blocks = 103; + string stake_modifier = 104; + repeated NonUTXO nonutxo = 105; +} + +message NonUTXO { + double anchor_reward = 1; + double burnt = 2; + double incentive_funding = 3; + double loan = 4; + double options = 5; + double unknown = 6; +} + +message BlockInput { + string blockhash = 1; // Block hash + uint32 verbosity = 2; // 0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data [default: 1] +} + +message BlockResult { + string hash = 1; // Hex-encoded data for block hash (for verbosity 0) + Block block = 2; // Block data (for verbosity 1 and 2) +} + +message BlockHashResult { + string hash = 1; // Hex-encoded data for block hash +} diff --git a/lib/proto/types/eth.proto b/lib/proto/types/eth.proto new file mode 100644 index 0000000000..eeb1ca0ef1 --- /dev/null +++ b/lib/proto/types/eth.proto @@ -0,0 +1,370 @@ +syntax = "proto3"; +package types; + +message EthAccountsResult { + repeated string accounts = 1; // Accounts +} + +message EthTransactionInfo { + optional string blockHash = 1; // Hash of the block. null when its pending block. + optional string blockNumber = 2; // The block number. null when its pending block. + string from = 3; // The address from which the transaction is sent + string gas = 4; // The integer of gas provided for the transaction execution. + string gasPrice = 5; // The integer of gas price used for each paid gas encoded as hexadecimal + string hash = 6; // Hash of the transaction. + string input = 7; // The data sent along with the transaction. + string nonce = 8; // The integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. + optional string to = 9; // Address of the receiver. null when its a contract creation transaction. + optional string transactionIndex = 10; // Integer of the transactions index position in the block. + string value = 11; // The integer of value sent with this transaction encoded as hexadecimal. + string v = 12; // Signature v value + string r = 13; // Signature r value + string s = 14; // Signature s value +} + +message EthChainIdResult { + string id = 1; +} + +message EthBlockInfo { + string blockNumber = 1; // The block number. null when its pending block. + string hash = 2; // Hash of the block. null when its pending block. + string parentHash = 3; // Hash of the parent block. + string nonce = 4; // Hash of the generated proof-of-work. null when its pending block. + string sha3Uncles = 5; // SHA3 of the uncles data in the block. + string logsBloom = 6; // The bloom filter for the logs of the block. null when its pending block. + string transactionsRoot = 7; // The root of the transaction trie of the block. + string stateRoot = 8; // The root of the final state trie of the block. + string receiptRoot = 9; // The root of the receipts trie of the block. + string miner = 10; // The address of the beneficiary to whom the mining rewards were given. + string difficulty = 11; // Integer of the difficulty for this block. + string totalDifficulty = 12; // Integer of the total difficulty of the chain until this block. + string extraData = 13; // The "extra data" field of this block. + string size = 14; // Integer the size of this block in bytes. + string gasLimit = 15; // The maximum gas allowed in this block. + string gasUsed = 16; // The total used gas by all transactions in this block. + string timestamps = 17; // The unix timestamp for when the block was collated. + repeated string transactions = 18; // Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter. + repeated string uncles = 19; // Array of uncle hashes. +} + +message EthTransactionReceipt { + string transactionHash = 1; // Hash of the transaction. + string transactionIndex = 2; // Integer of the transactions index position in the block. + string blockHash = 3; // Hash of the block where this transaction was in. + string blockNumber = 4; // Block number where this transaction was in. + string from = 5; // Address of the sender. + string to = 6; // Address of the receiver. null when its a contract creation transaction. + string cumulativeGasUsed = 7; // The total amount of gas used when this transaction was executed in the block. + string effectiveGasPrice = 8; // The sum of the base fee and tip paid per unit of gas. + string gasUsed = 9; // The amount of gas used by this specific transaction alone. + string contractAddress = 10; // The contract address created, if the transaction was a contract creation, otherwise null. + repeated string logs = 11; // Array of log objects, which this transaction generated. + string logsBloom = 12; // Bloom filter for light clients to quickly retrieve related logs. + string type = 13; // Integer of the transaction type, 0x00 for legacy transactions, 0x01 for access list types, 0x02 for dynamic fees. It also returns either : + optional string root = 14; // 32 bytes of post-transaction stateroot (pre Byzantium) + optional string status = 15; // Either 1 (success) or 0 (failure) +} + +message EthCallInput { + EthTransactionInfo transactionInfo = 1; // Transaction info + optional string blockNumber = 2; // Block number in hexadecimal format or the string latest, earliest, pending, safe or finalized +} + +message EthCallResult { + string data = 1; // The return value of the executed contract method +} + +message EthSignInput { + string address = 1; + string message = 2; +} + +message EthSignResult { + string signature = 1; +} + +message EthGetBalanceInput { + string address = 1; + string blockNumber = 2; +} + +message EthGetBalanceResult { + string balance = 1; +} + +message EthSendTransactionInput { + EthTransactionInfo transactionInfo = 1; +} + +message EthSendTransactionResult { + string hash = 1; +} + +message EthCoinBaseResult { + string address = 1; +} + +message EthMiningResult { + bool isMining = 1; +} + +message EthHashRateResult { + string hashRate = 1; +} + +message EthGasPriceResult { + string gasPrice = 1; +} + +message EthBlockNumberResult { + string blockNumber = 1; +} + +message EthGetTransactionCountInput { + string address = 1; + string blockNumber = 2; +} + +message EthGetTransactionCountResult { + string numberTransaction = 1; +} + +message EthGetBlockTransactionCountByHashInput { + string blockHash = 1; +} + +message EthGetBlockTransactionCountByHashResult { + string numberTransaction = 1; +} + +message EthGetBlockTransactionCountByNumberInput { + string blockNumber = 1; +} + +message EthGetBlockTransactionCountByNumberResult { + string numberTransaction = 1; +} + +message EthGetUncleCountByBlockHashInput { + string blockHash = 1; +} + +message EthGetUncleCountByBlockHashResult { + string numberUncles = 1; +} + +message EthGetUncleCountByBlockNumberInput { + string blockNumber = 1; +} + +message EthGetUncleCountByBlockNumberResult { + string numberUncles = 1; +} + +message EthGetCodeInput { + string address = 1; + string blockNumber = 2; +} + +message EthGetCodeResult { + string code = 1; // The code from the given address. +} + +message EthSignTransactionInput { + EthTransactionInfo transactionInfo = 1; +} + +message EthSignTransactionResult { + string transaction = 1; // The signed transaction object. +} + +message EthSendRawTransactionInput { + string transaction = 1; +} + +message EthSendRawTransactionResult { + string hash = 1; // The transaction hash, or the zero hash if the transaction is not yet available. +} + +message EthEstimateGasInput { + optional EthTransactionInfo transactionInfo = 1; // Transaction info + optional string blockNumber = 2; // Block number in hexadecimal format or the string latest, earliest, pending, safe or finalized +} + +message EthEstimateGasResult { + string gasUsed = 1; +} + +message EthGetBlockByHashInput { + string hash = 1; + bool fullTransaction = 2; +} + +message EthGetBlockByHashResult { + EthBlockInfo blockInfo = 1; +} + +message BlockNumber { + string blockNumber = 1; +} + +message EthGetBlockByNumberInput { + BlockNumber blockNumber = 1; + bool fullTransaction = 2; +} + +message EthGetBlockByNumberResult { + EthBlockInfo blockInfo = 1; +} + +message EthGetTransactionByHashInput { + string hash = 1; +} + +message EthGetTransactionByHashResult { + EthTransactionInfo transaction = 1; +} + +message EthGetTransactionByBlockHashAndIndexInput { + string blockHash = 1; + string index = 2; +} + +message EthGetTransactionByBlockHashAndIndexResult { + EthTransactionInfo transaction = 1; +} + +message EthGetTransactionByBlockNumberAndIndexInput { + string blockNumber = 1; + string index = 2; +} + +message EthGetTransactionByBlockNumberAndIndexResult { + EthTransactionInfo transaction = 1; +} + +message EthGetUncleByBlockHashAndIndexInput { + string blockHash = 1; + string index = 2; +} + +message EthGetUncleByBlockHashAndIndexResult { + EthBlockInfo blockInfo = 1; +} + +message EthGetUncleByBlockNumberAndIndexInput { + string blockNumber = 1; + string index = 2; +} + +message EthGetUncleByBlockNumberAndIndexResult { + EthBlockInfo blockInfo = 1; +} + +message EthGetCompilersResult { + repeated string compilers = 1; +} + +message EthCompileSolidityInput { + string code = 1; +} + +message EthCompileSolidityResult { + string compiledCode = 1; +} + +message EthCompileLLLInput { + string code = 1; +} + +message EthCompileLLLResult { + string compiledCode = 1; +} + +message EthCompileSerpentInput { + string code = 1; +} + +message EthCompileSerpentResult { + string compiledCode = 1; +} + +message EthProtocolVersionResult { + string protocolVersion = 1; +} + +message Web3Sha3Input { + string data = 1; // The data to convert into a SHA3 hash +} + +message Web3Sha3Result { + string data = 1; // The SHA3 result of the given string. +} + +message NetPeerCountResult { + string numberPeer = 1; +} + +message NetVersionResult { + string networkVersion = 1; +} + +message Web3ClientVersionResult { + string clientVersion = 1; +} + +message EthGetWorkResult { + string currentblock = 1; // Current block header pow-hash + string seedHash = 2; // The seed hash used for the DAG. + string target = 3; // The boundary condition ("target"), 2^256 / difficulty. +} + +message EthSubmitWorkInput { + string nounce = 1; + string powHash = 2; + string mixDigest = 3; +} + +message EthSubmitWorkResult { + bool isValid = 1; +} + +message EthSubmitHashrateInput { + string hashRate = 1; + string id = 2; +} + +message EthSubmitHashrateResult { + bool isValid = 1; +} + +message EthGetStorageAtInput { + string address = 1; + string position = 2; + string blockNumber = 3; +} + +message EthGetStorageAtResult { + string value = 1; // The value at this storage position. +} + +message EthGetTransactionReceiptInput { + string transactionHash = 1; +} + +message EthGetTransactionReceiptResult { + EthTransactionReceipt transactionReceipt = 1; +} + +message EthSyncingInfo { + string startingBlock = 1; // The block at which the import started (will only be reset, after the sync reached his head) + string currentBlock = 2; // The current block, same as eth_blockNumber + string highestBlock = 3; // The estimated highest block +} + +// TODO make it oneof +message EthSyncingResult { + optional bool status = 1; + optional EthSyncingInfo syncInfo = 2; +} diff --git a/lib/proto/types/tx.proto b/lib/proto/types/tx.proto new file mode 100644 index 0000000000..a8c960bd25 --- /dev/null +++ b/lib/proto/types/tx.proto @@ -0,0 +1,55 @@ +syntax = "proto3"; +package types; + +message Transaction { + string hash = 1; // Transaction hash + RawTransaction raw = 2; // Raw transaction data +} + +message RawTransaction { + bool in_active_chain = 1; // Whether specified block is in the active chain or not (only present with explicit "blockhash" argument) + string hex = 2; // The serialized, hex-encoded data for 'txid' + string txid = 3; // The transaction id (same as provided) + string hash = 4; // The transaction hash (differs from txid for witness transactions) + uint32 size = 5; // The serialized transaction size + uint32 vsize = 6; // The virtual transaction size (differs from size for witness transactions) + uint32 weight = 7; // The transaction's weight (between vsize*4-3 and vsize*4) + uint32 version = 8; // The transaction version + uint64 locktime = 9; // The lock time + repeated Vin vin = 10; // List of inputs + repeated Vout vout = 11; // List of outputs + string blockhash = 12; // The block hash + string confirmations = 13; // The confirmations + uint64 blocktime = 14; // The block time in seconds since UNIX epoch +} + +message Vin { + string txid = 1; // The transaction id + uint32 vout = 2; // The output index + ScriptSig script_sig = 3; // The script signature + uint64 sequence = 4; // The script sequence number + repeated string txinwitness = 5; // Hex-encoded witness data + + // DeFiChain fields + string coinbase = 51; +} + +message ScriptSig { + string asm = 1; + string hex = 2; +} + +message Vout { + double value = 1; + uint64 n = 2; + PubKey script_pub_key = 3; + uint64 token_id = 4; +} + +message PubKey { + string asm = 1; + string hex = 2; + string type = 3; + int32 req_sigs = 4; + repeated string addresses = 5; +} diff --git a/make.sh b/make.sh index 645a2d3cf7..03e4cd5d54 100755 --- a/make.sh +++ b/make.sh @@ -16,21 +16,26 @@ setup_vars() { fi DOCKER_ROOT_CONTEXT=${DOCKER_ROOT_CONTEXT:-"."} - DOCKERFILE=${DOCKERFILE:-""} DOCKERFILES_DIR=${DOCKERFILES_DIR:-"./contrib/dockerfiles"} ROOT_DIR="$(_canonicalize "${_SCRIPT_DIR}")" TARGET=${TARGET:-"$(_get_default_target)"} + DOCKERFILE=${DOCKERFILE:-"$(_get_default_docker_file)"} - RELEASE_DIR=${RELEASE_DIR:-"./build"} - RELEASE_DIR="$(_canonicalize "$RELEASE_DIR")" - RELEASE_TARGET_DIR="${RELEASE_DIR}/${TARGET}" - DEPENDS_DIR=${DEPENDS_DIR:-"${RELEASE_DIR}/depends"} - DEPENDS_DIR="$(_canonicalize "$DEPENDS_DIR")" + BUILD_DIR=${BUILD_DIR:-"./build"} + BUILD_DIR="$(_canonicalize "$BUILD_DIR")" + # Was previously ${BUILD_DIR}/$TARGET for host specific + # But simplifying this since autotools conf ends up in reconf and + # rebuilds anyway, might as well just point manually if needed + BUILD_TARGET_DIR="${BUILD_DIR}" + BUILD_DEPENDS_DIR=${BUILD_DEPENDS_DIR:-"${BUILD_DIR}/depends"} + BUILD_DEPENDS_DIR="$(_canonicalize "$BUILD_DEPENDS_DIR")" CLANG_DEFAULT_VERSION=${CLANG_DEFAULT_VERSION:-"15"} - MAKE_DEBUG=${MAKE_DEBUG:-"0"} + RUST_DEFAULT_VERSION=${RUST_DEFAULT_VERSION:-"1.69.0"} + + MAKE_DEBUG=${MAKE_DEBUG:-"1"} local default_compiler_flags="" if [[ "${TARGET}" == "x86_64-pc-linux-gnu" ]]; then @@ -61,6 +66,7 @@ main() { cd "$_SCRIPT_DIR" _platform_init setup_vars + git_add_hooks # Get all functions declared in this file except ones starting with # '_' or the ones in the list @@ -111,11 +117,11 @@ build_deps() { local make_deps_args=${MAKE_DEPS_ARGS:-} local make_jobs=${MAKE_JOBS} local src_depends_dir=${ROOT_DIR}/depends - local release_depends_dir=${DEPENDS_DIR} + local build_depends_dir=${BUILD_DEPENDS_DIR} echo "> build-deps: target: ${target} / deps_args: ${make_deps_args} / jobs: ${make_jobs}" - _ensure_enter_dir "$release_depends_dir" + _ensure_enter_dir "$build_depends_dir" if [[ "$target" =~ .*darwin.* ]]; then pkg_local_ensure_osx_sysroot fi @@ -123,7 +129,7 @@ build_deps() { _fold_start "build-deps" # shellcheck disable=SC2086 - make -C "${src_depends_dir}" DESTDIR="${release_depends_dir}" \ + make -C "${src_depends_dir}" DESTDIR="${build_depends_dir}" \ HOST="${target}" -j${make_jobs} ${make_deps_args} _fold_end @@ -135,20 +141,20 @@ build_conf() { local make_conf_opts=${MAKE_CONF_ARGS:-} local make_jobs=${MAKE_JOBS} local root_dir=${ROOT_DIR} - local release_target_dir=${RELEASE_TARGET_DIR} - local release_depends_dir=${DEPENDS_DIR} + local build_target_dir=${BUILD_TARGET_DIR} + local build_depends_dir=${BUILD_DEPENDS_DIR} echo "> build-conf: target: ${target} / conf_args: ${make_conf_opts} / jobs: ${make_jobs}" - _ensure_enter_dir "${release_target_dir}" + _ensure_enter_dir "${build_target_dir}" _fold_start "build-conf::autogen" "$root_dir/autogen.sh" _fold_end _fold_start "build-conf::configure" # shellcheck disable=SC2086 - CONFIG_SITE="$release_depends_dir/${target}/share/config.site" \ - $root_dir/configure --prefix="$release_depends_dir/${target}" \ + CONFIG_SITE="$build_depends_dir/${target}/share/config.site" \ + $root_dir/configure --prefix="$build_depends_dir/${target}" \ ${make_conf_opts} _fold_end _exit_dir @@ -158,15 +164,15 @@ build_make() { local target=${1:-${TARGET}} local make_args=${MAKE_ARGS:-} local make_jobs=${MAKE_JOBS} - local release_target_dir=${RELEASE_TARGET_DIR} + local build_target_dir=${BUILD_TARGET_DIR} echo "> build: target: ${target} / args: ${make_args} / jobs: ${make_jobs}" - _ensure_enter_dir "${release_target_dir}" + _ensure_enter_dir "${build_target_dir}" _fold_start "build_make" # shellcheck disable=SC2086 - make DESTDIR="${release_target_dir}" -j${make_jobs} ${make_args} + make DESTDIR="${build_target_dir}" -j${make_jobs} ${make_args} _fold_end @@ -183,48 +189,48 @@ deploy() { local target=${1:-${TARGET}} local img_prefix="${IMAGE_PREFIX}" local img_version="${IMAGE_VERSION}" - local release_dir="${RELEASE_DIR}" - local release_target_dir="${RELEASE_TARGET_DIR}" + local build_dir="${BUILD_DIR}" + local build_target_dir="${BUILD_TARGET_DIR}" local versioned_name="${img_prefix}-${img_version}" - local versioned_release_path - versioned_release_path="$(_canonicalize "${release_dir}/${versioned_name}")" + local versioned_build_path + versioned_build_path="$(_canonicalize "${build_dir}/${versioned_name}")" - echo "> deploy into: ${release_dir} from ${versioned_release_path}" + echo "> deploy into: ${build_dir} from ${versioned_build_path}" - _safe_rm_rf "${versioned_release_path}" && mkdir -p "${versioned_release_path}" + _safe_rm_rf "${versioned_build_path}" && mkdir -p "${versioned_build_path}" - make -C "${release_target_dir}" prefix=/ DESTDIR="${versioned_release_path}" \ - install && cp README.md "${versioned_release_path}/" + make -C "${build_target_dir}" prefix=/ DESTDIR="${versioned_build_path}" \ + install && cp README.md "${versioned_build_path}/" - echo "> deployed: ${versioned_release_path}" + echo "> deployed: ${versioned_build_path}" } package() { local target=${1:-${TARGET}} local img_prefix="${IMAGE_PREFIX}" local img_version="${IMAGE_VERSION}" - local release_dir="${RELEASE_DIR}" + local build_dir="${BUILD_DIR}" local pkg_name="${img_prefix}-${img_version}-${target}" local pkg_tar_file_name="${pkg_name}.tar.gz" local pkg_path - pkg_path="$(_canonicalize "${release_dir}/${pkg_tar_file_name}")" + pkg_path="$(_canonicalize "${build_dir}/${pkg_tar_file_name}")" local versioned_name="${img_prefix}-${img_version}" - local versioned_release_dir="${release_dir}/${versioned_name}" + local versioned_build_dir="${build_dir}/${versioned_name}" - if [[ ! -d "$versioned_release_dir" ]]; then + if [[ ! -d "$versioned_build_dir" ]]; then echo "> error: deployment required to package" echo "> tip: try \`$0 deploy\` or \`$0 docker-deploy\` first" exit 1 fi - echo "> packaging: ${pkg_name} from ${versioned_release_dir}" + echo "> packaging: ${pkg_name} from ${versioned_build_dir}" - _ensure_enter_dir "${versioned_release_dir}" - tar --transform "s,^./,${versioned_name}/," -czf "${pkg_path}" ./* + _ensure_enter_dir "${versioned_build_dir}" + _tar --transform "s,^./,${versioned_name}/," -czf "${pkg_path}" ./* _exit_dir echo "> package: ${pkg_path}" @@ -246,21 +252,21 @@ docker_build() { local img_prefix="${IMAGE_PREFIX}" local img_version="${IMAGE_VERSION}" local docker_context="${DOCKER_ROOT_CONTEXT}" - local docker_file="${DOCKERFILES_DIR}/${DOCKERFILE:-"${target}"}.dockerfile" + local docker_file="${DOCKERFILE}" echo "> docker-build"; local img="${img_prefix}-${target}:${img_version}" echo "> building: ${img}" echo "> docker build: ${img}" - docker build -f "${docker_file}" -t "${img}" "${docker_context}" + docker build -f "${docker_file}" --build-arg TARGET="${target}" -t "${img}" "${docker_context}" } docker_deploy() { local target=${1:-${TARGET}} local img_prefix="${IMAGE_PREFIX}" local img_version="${IMAGE_VERSION}" - local release_dir="${RELEASE_DIR}" + local build_dir="${BUILD_DIR}" echo "> docker-deploy"; @@ -269,19 +275,19 @@ docker_deploy() { local pkg_name="${img_prefix}-${img_version}-${target}" local versioned_name="${img_prefix}-${img_version}" - local versioned_release_dir="${release_dir}/${versioned_name}" + local versioned_build_dir="${build_dir}/${versioned_name}" - _safe_rm_rf "${versioned_release_dir}" && mkdir -p "${versioned_release_dir}" + _safe_rm_rf "${versioned_build_dir}" && mkdir -p "${versioned_build_dir}" local cid cid=$(docker create "${img}") local e=0 - { docker cp "${cid}:/app/." "${versioned_release_dir}" 2>/dev/null && e=1; } || true + { docker cp "${cid}:/app/." "${versioned_build_dir}" 2>/dev/null && e=1; } || true docker rm "${cid}" if [[ "$e" == "1" ]]; then - echo "> deployed into: ${versioned_release_dir}" + echo "> deployed into: ${versioned_build_dir}" else echo "> failed: please ensure package is built first" fi @@ -315,12 +321,21 @@ _docker_clean() { # -------------- Misc ----------------- +debug_env() { + (set -o posix ; set) + (set -x +e + uname -a + gcc -v + "clang-${CLANG_DEFAULT_VERSION}" -v + rustup show) +} + test() { local make_jobs=${MAKE_JOBS} local make_args=${MAKE_ARGS:-} - local release_target_dir=${RELEASE_TARGET_DIR} + local build_target_dir=${BUILD_TARGET_DIR} - _ensure_enter_dir "${release_target_dir}" + _ensure_enter_dir "${build_target_dir}" _fold_start "unit-tests" # shellcheck disable=SC2086 @@ -335,12 +350,30 @@ test() { _exit_dir } +test_py() { + local build_target_dir=${BUILD_TARGET_DIR} + local first_arg="${1:-}" + + if [[ -f "${first_arg}" ]]; then + shift + "${first_arg}" --configfile "${build_target_dir}/test/config.ini" --tmpdirprefix "./test_runner/" --ansi "$@" + return + fi + + _ensure_enter_dir "${build_target_dir}" + + # shellcheck disable=SC2086 + ./test/functional/test_runner.py --tmpdirprefix "./test_runner/" --ansi "$@" + + _exit_dir +} + exec() { local make_jobs=${MAKE_JOBS} local make_args=${MAKE_ARGS:-} - local release_target_dir=${RELEASE_TARGET_DIR} + local build_target_dir=${BUILD_TARGET_DIR} - _ensure_enter_dir "${release_target_dir}" + _ensure_enter_dir "${build_target_dir}" _fold_start "exec:: ${*-(default)}" # shellcheck disable=SC2086,SC2068 @@ -403,7 +436,7 @@ pkg_install_deps() { libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev \ libminiupnpc-dev libzmq3-dev libqrencode-dev wget \ libdb-dev libdb++-dev libdb5.3 libdb5.3-dev libdb5.3++ libdb5.3++-dev \ - curl cmake unzip + curl cmake unzip libc6-dev _fold_end } @@ -417,11 +450,16 @@ pkg_install_deps_mingw_x86_64() { _fold_end } +pkg_setup_mingw_x86_64() { + update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix + update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix +} + pkg_install_deps_armhf() { _fold_start "pkg-install-deps-armhf" apt install -y \ - g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf + g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf libc6-dev-armhf-cross _fold_end } @@ -430,7 +468,7 @@ pkg_install_deps_arm64() { _fold_start "pkg-install-deps-arm64" apt install -y \ - g++-aarch64-linux-gnu binutils-aarch64-linux-gnu + g++-aarch64-linux-gnu binutils-aarch64-linux-gnu libc6-dev-arm64-cross _fold_end } @@ -447,17 +485,20 @@ pkg_install_deps_osx_tools() { pkg_local_ensure_osx_sysroot() { local sdk_name="Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers" local pkg="${sdk_name}.tar.gz" - local release_depends_dir=${DEPENDS_DIR} + local build_depends_dir="${BUILD_DEPENDS_DIR}" + local sdk_base_dir="$build_depends_dir/SDKs" - _ensure_enter_dir "$release_depends_dir/SDKs" - if [[ -d "${sdk_name}" ]]; then return; fi + if [[ -d "${sdk_base_dir}/${sdk_name}" ]]; then + return + fi _fold_start "pkg-local-mac-sdk" + _ensure_enter_dir "${sdk_base_dir}" if [[ ! -f "${pkg}" ]]; then wget https://bitcoincore.org/depends-sources/sdks/${pkg} fi - tar -zxf "${pkg}" + _tar -zxf "${pkg}" rm "${pkg}" 2>/dev/null || true _exit_dir @@ -472,24 +513,41 @@ pkg_install_llvm() { } pkg_install_rust() { - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + _fold_start "pkg-install-rust" + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- \ + --default-toolchain="${RUST_DEFAULT_VERSION}" -y + _fold_end +} + +pkg_install_web3_deps() { + _fold_start "pkg-install-solc" + python3 -m pip install py-solc-x web3 + python3 -c 'from solcx import install_solc;install_solc("0.8.20")' + _fold_end +} + +pkg_setup_rust() { + local target=${TARGET} + local rust_target + rust_target=$(get_rust_target) + rustup target add "${rust_target}" } clean_pkg_local_osx_sysroot() { - local release_depends_dir=${DEPENDS_DIR} - _safe_rm_rf "$release_depends_dir/SDKs" + local build_depends_dir="${BUILD_DEPENDS_DIR}" + _safe_rm_rf "$build_depends_dir/SDKs" } purge() { - local release_dir="${RELEASE_DIR}" - local release_depends_dir=${DEPENDS_DIR} + local build_dir="${BUILD_DIR}" + local build_depends_dir="${BUILD_DEPENDS_DIR}" clean_depends - _safe_rm_rf "$release_depends_dir" + _safe_rm_rf "$build_depends_dir" clean_conf clean_artifacts docker_clean_all - _safe_rm_rf "$release_dir" + _safe_rm_rf "$build_dir" } clean_artifacts() { @@ -501,7 +559,7 @@ clean_artifacts() { local x for x in "${items[@]}"; do - _safe_rm_rf "$(find src -iname "$x" -print0 | xargs -0)" + find src -iname "$x" -exec rm -rf \; done } @@ -547,11 +605,11 @@ clean_conf() { clean_depends() { local root_dir="$ROOT_DIR" - local release_dir="${RELEASE_DIR}" - local release_depends_dir=${DEPENDS_DIR} + local build_dir="${BUILD_DIR}" + local build_depends_dir="${BUILD_DEPENDS_DIR}" - make -C "$root_dir/depends" DESTDIR="${release_depends_dir}" clean-all || true - _ensure_enter_dir "$release_depends_dir" + make -C "$root_dir/depends" DESTDIR="${build_depends_dir}" clean-all || true + _ensure_enter_dir "$build_depends_dir" clean_pkg_local_osx_sysroot _safe_rm_rf built \ work \ @@ -567,8 +625,8 @@ clean_depends() { } clean() { - local release_dir="${RELEASE_TARGET_DIR}" - _ensure_enter_dir "${release_dir}" + local build_dir="${BUILD_TARGET_DIR}" + _ensure_enter_dir "${build_dir}" make clean || true _exit_dir clean_artifacts @@ -615,6 +673,27 @@ _get_default_target() { echo "$default_target" } +_get_default_docker_file() { + local target="${TARGET}" + local dockerfiles_dir="${DOCKERFILES_DIR}" + + local try_files=(\ + "${dockerfiles_dir}/${target}.dockerfile" \ + "${dockerfiles_dir}/${target}" \ + "${dockerfiles_dir}/noarch.dockerfile" \ + ) + + for file in "${try_files[@]}"; do + if [[ -f "$file" ]]; then + echo "$file" + return + fi + done + # If none of these were found, assumes empty val + # Empty will fail if docker cmd requires it, or continue for + # non docker cmds +} + _get_default_conf_args() { local conf_args="" if [[ "$TARGET" =~ .*linux.* ]]; then @@ -629,6 +708,82 @@ _get_default_conf_args() { echo "$conf_args" } + +# Dev tools +# --- + +# shellcheck disable=SC2120 +git_add_hooks() { + local force_update=${1:-0} + local file=".git/hooks/pre-push" + if [[ -f "$file" && $force_update == "0" ]]; then + return; + fi + echo "> add pre-push-hook" + mkdir -p "$(dirname $file)" 2>/dev/null || { true && return; } + cat < "$file" +#!/bin/bash +set -Eeuo pipefail +dir="\$(dirname "\${BASH_SOURCE[0]}")" +_SCRIPT_DIR="\$(cd "\${dir}/" && pwd)" +cd \$_SCRIPT_DIR/../../ +./make.sh check +END + chmod +x "$file" +} + +check() { + check_git_dirty + check_rs +} + +check_git_dirty() { + if [[ $(git status -s) ]]; then + echo "error: Git tree dirty. Please commit or stash first" + exit 1 + fi +} + +check_rs() { + check_enter_build_rs_dir + lint_cargo_check + lint_cargo_clippy + lint_cargo_fmt + _exit_dir +} + +check_enter_build_rs_dir() { + local build_dir="${BUILD_DIR}" + _ensure_enter_dir "$build_dir/lib" || { + echo "Please configure first"; + exit 1; } +} + +lint_cargo_check() { + check_enter_build_rs_dir + make check || { + echo "Error: Please resolve compiler checks before commit"; + exit 1; } + _exit_dir +} + +lint_cargo_clippy() { + check_enter_build_rs_dir + make clippy || { + echo "Error: Please resolve compiler lints before commit"; + exit 1; } + _exit_dir +} + +lint_cargo_fmt() { + check_enter_build_rs_dir + make fmt-check || { + echo "Error: Please format code before commit"; + exit 1; } + _exit_dir +} + + # Platform specifics # --- @@ -637,8 +792,7 @@ _platform_init() { if [[ $(readlink -m . 2> /dev/null) != "${_SCRIPT_DIR}" ]]; then if [[ $(greadlink -m . 2> /dev/null) != "${_SCRIPT_DIR}" ]]; then echo "error: readlink or greadlink with \`-m\` support is required" - echo "tip: debian/ubuntu: apt install coreutils" - echo "tip: osx: brew install coreutils" + _platform_pkg_tip coreutils exit 1 else _canonicalize() { @@ -650,6 +804,30 @@ _platform_init() { readlink -m "$@" } fi + + if tar --version 2> /dev/null | grep -q 'GNU tar'; then + _tar() { + tar "$@" + } + else + if gtar --version 2> /dev/null | grep -q 'GNU tar'; then + _tar() { + gtar "$@" + } + else + echo "error: GNU version of tar is required" + _platform_pkg_tip tar gnu-tar + exit 1 + fi + fi +} + +_platform_pkg_tip() { + local apt_pkg=${1:?pkg required} + local brew_pkg=${2:-${apt_pkg}} + + echo "tip: debian/ubuntu: apt install ${apt_pkg}" + echo "tip: osx: brew install ${brew_pkg}" } _nproc() { @@ -670,6 +848,50 @@ ci_export_vars() { fi } +ci_setup_deps() { + DEBIAN_FRONTEND=noninteractive pkg_update_base + DEBIAN_FRONTEND=noninteractive pkg_install_deps + DEBIAN_FRONTEND=noninteractive pkg_install_llvm + DEBIAN_FRONTEND=noninteractive pkg_install_rust + pkg_setup_rust + pkg_install_web3_deps +} + +ci_setup_deps_target() { + local target=${TARGET} + case $target in + # Nothing to do on host + x86_64-pc-linux-gnu) ;; + aarch64-linux-gnu) + DEBIAN_FRONTEND=noninteractive pkg_install_deps_arm64;; + arm-linux-gnueabihf) + DEBIAN_FRONTEND=noninteractive pkg_install_deps_armhf;; + x86_64-apple-darwin|aarch64-apple-darwin) + DEBIAN_FRONTEND=noninteractive pkg_install_deps_osx_tools;; + x86_64-w64-mingw32) + DEBIAN_FRONTEND=noninteractive pkg_install_deps_mingw_x86_64 + pkg_setup_mingw_x86_64;; + *) + echo "error: unsupported target: ${target}" + exit 1;; + esac +} + +get_rust_target() { + local target=${TARGET} + local rust_target + case $target in + x86_64-pc-linux-gnu) rust_target=x86_64-unknown-linux-gnu;; + aarch64-linux-gnu) rust_target=aarch64-unknown-linux-gnu;; + arm-linux-gnueabihf) rust_target=armv7-unknown-linux-gnueabihf;; + x86_64-apple-darwin) rust_target=x86_64-apple-darwin;; + aarch64-apple-darwin) rust_target=aarch64-apple-darwin;; + x86_64-w64-mingw32) rust_target=x86_64-pc-windows-gnu;; + *) echo "error: unsupported target: ${target}"; exit 1;; + esac + echo "$rust_target" +} + _sign() { # TODO: generate sha sums and sign : diff --git a/src/Makefile.am b/src/Makefile.am index 41a9629f2f..7d380b6cf8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,6 +2,7 @@ # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. +SUBDIRS = ../lib DIST_SUBDIRS = secp256k1 univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS) @@ -25,11 +26,22 @@ LIBDEFI_SPV_INCLUDES = \ -I$(srcdir)/spv/bitcoin \ -I$(srcdir)/spv/bcash -DEFI_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) +LIBAIN_DIR = $(abs_top_builddir)/lib/target +LIBAIN_RS_INCLUDES = -I$(LIBAIN_DIR)/include +LIBAIN_RS_LIB = -L$(LIBAIN_DIR)/lib -lain_rs_exports +LIBAIN_RS_SRC = $(LIBAIN_DIR)/src/ain_rs_exports.cpp +LIBAIN_RS_H = $(LIBAIN_DIR)/include/ain_rs_exports.h +$(LIBAIN_RS_SRC): +$(LIBAIN_RS_H): +$(LIBAIN_RS_LIB): FORCE + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(abs_top_builddir)/lib + +DEFI_INCLUDES = -I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) DEFI_INCLUDES += -I$(srcdir)/secp256k1/include DEFI_INCLUDES += $(UNIVALUE_CFLAGS) DEFI_INCLUDES += $(LIBDEFI_SPV_INCLUDES) +DEFI_INCLUDES += $(LIBAIN_RS_INCLUDES) LIBDEFI_SERVER=libdefi_server.a LIBDEFI_COMMON=libdefi_common.a @@ -76,8 +88,8 @@ EXTRA_LIBRARIES += \ $(LIBDEFI_WALLET) \ $(LIBDEFI_ZMQ) -lib_LIBRARIES = -lib_LTLIBRARIES = +lib_LIBRARIES = +lib_LTLIBRARIES = bin_PROGRAMS = noinst_PROGRAMS = @@ -143,16 +155,17 @@ DEFI_CORE_H = \ dbwrapper.h \ limitedmap.h \ logging.h \ + ffi/ffiexports.h \ masternodes/accounts.h \ masternodes/accountshistory.h \ masternodes/anchors.h \ masternodes/auctionhistory.h \ masternodes/balances.h \ + masternodes/coinselect.h \ masternodes/communityaccounttypes.h \ masternodes/errors.h \ masternodes/evm.h \ masternodes/factory.h \ - masternodes/ffi_temp_stub.h \ masternodes/govvariables/attributes.h \ masternodes/govvariables/icx_takerfee_per_btc.h \ masternodes/govvariables/loan_daily_reward.h \ @@ -281,8 +294,8 @@ DEFI_CORE_H = \ zmq/zmqconfig.h\ zmq/zmqnotificationinterface.h \ zmq/zmqpublishnotifier.h \ - zmq/zmqrpc.h - + zmq/zmqrpc.h \ + $(LIBAIN_RS_H) obj/build.h: FORCE @$(MKDIR_P) $(builddir)/obj @@ -296,7 +309,7 @@ libdefi_spv_a_CPPFLAGS = $(AM_CPPFLAGS) -Wpointer-arith -fpermissive \ -I$(srcdir)/secp256k1 \ -I$(srcdir)/secp256k1/src \ -Wno-format-extra-args - + libdefi_spv_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libdefi_spv_a_SOURCES = \ spv/support/BRAddress.cpp \ @@ -379,11 +392,11 @@ libdefi_server_a_SOURCES = \ interfaces/chain.cpp \ init.cpp \ dbwrapper.cpp \ + ffi/ffiexports.cpp \ masternodes/accounts.cpp \ masternodes/accountshistory.cpp \ masternodes/anchors.cpp \ masternodes/auctionhistory.cpp \ - masternodes/oracles.cpp \ masternodes/govvariables/attributes.cpp \ masternodes/govvariables/icx_takerfee_per_btc.cpp \ masternodes/govvariables/loan_daily_reward.cpp \ @@ -401,6 +414,9 @@ libdefi_server_a_SOURCES = \ masternodes/masternodes.cpp \ masternodes/mn_checks.cpp \ masternodes/mn_rpc.cpp \ + masternodes/oracles.cpp \ + masternodes/poolpairs.cpp \ + masternodes/proposals.cpp \ masternodes/rpc_accounts.cpp \ masternodes/rpc_customtx.cpp \ masternodes/rpc_evm.cpp \ @@ -412,11 +428,9 @@ libdefi_server_a_SOURCES = \ masternodes/rpc_proposals.cpp \ masternodes/rpc_tokens.cpp \ masternodes/rpc_vault.cpp \ + masternodes/skipped_txs.cpp \ masternodes/tokens.cpp \ masternodes/threadpool.cpp \ - masternodes/poolpairs.cpp \ - masternodes/proposals.cpp \ - masternodes/skipped_txs.cpp \ masternodes/undos.cpp \ masternodes/validation.cpp \ masternodes/vault.cpp \ @@ -455,6 +469,7 @@ libdefi_server_a_SOURCES = \ validation.cpp \ validationinterface.cpp \ versionbits.cpp \ + $(LIBAIN_RS_SRC) \ $(DEFI_CORE_H) if ENABLE_WALLET @@ -678,21 +693,19 @@ libdefi_cli_a_SOURCES = \ nodist_libdefi_util_a_SOURCES = $(srcdir)/obj/build.h # -# defid binary # -defid_SOURCES = defid.cpp +# defid binary +defid_SOURCES = $(LIBAIN_RS_SRC) $(LIBAIN_RS_H) defid.cpp defid_CPPFLAGS = $(AM_CPPFLAGS) $(DEFI_INCLUDES) defid_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) defid_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -if TARGET_WINDOWS -defid_SOURCES += defid-res.rc -endif - # Libraries below may be listed more than once to resolve circular dependencies (see # https://eli.thegreenplace.net/2013/07/09/library-order-in-static-linking#circular-dependency) defid_LDADD = \ $(LIBDEFI_SERVER) \ $(LIBDEFI_WALLET) \ + $(LIBAIN_RS_LIB) \ + $(LIBDEFI_SERVER) \ $(LIBDEFI_COMMON) \ $(LIBDEFI_UTIL) \ $(LIBDEFI_CONSENSUS) \ @@ -706,6 +719,19 @@ defid_LDADD = \ defid_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) +if TARGET_DARWIN +defid_LDFLAGS += -framework Security -framework SystemConfiguration -framework CoreFoundation +endif +if TARGET_NOT_DARWIN +defid_LDFLAGS += -Wl,--allow-multiple-definition +endif +if TARGET_NOT_WINDOWS +defid_LDADD += -ldl +endif +if TARGET_WINDOWS +defid_LDADD += -luserenv -lbcrypt +endif + # defi-cli binary # defi_cli_SOURCES = defi-cli.cpp defi_cli_CPPFLAGS = $(AM_CPPFLAGS) $(DEFI_INCLUDES) $(EVENT_CFLAGS) @@ -783,6 +809,7 @@ $(top_srcdir)/$(subdir)/config/defi-config.h.in: $(am__configure_deps) clean-local: -$(MAKE) -C secp256k1 clean -$(MAKE) -C univalue clean + -$(MAKE) -C rust clean -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno -rm -f config.h -rm -rf test/__pycache__ diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 807438114d..5d646f8ed6 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -48,9 +48,11 @@ nodist_bench_bench_defi_SOURCES = $(GENERATED_BENCH_FILES) bench_bench_defi_CPPFLAGS = $(AM_CPPFLAGS) $(DEFI_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/ bench_bench_defi_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +bench_bench_defi_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) bench_bench_defi_LDADD = \ $(LIBDEFI_SERVER) \ $(LIBDEFI_WALLET) \ + $(LIBAIN_RS_LIB) \ $(LIBDEFI_SERVER) \ $(LIBDEFI_COMMON) \ $(LIBDEFI_UTIL) \ @@ -68,13 +70,26 @@ if ENABLE_ZMQ bench_bench_defi_LDADD += $(LIBDEFI_ZMQ) $(ZMQ_LIBS) endif +bench_bench_defi_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) + if ENABLE_WALLET bench_bench_defi_SOURCES += bench/coin_selection.cpp bench_bench_defi_SOURCES += bench/wallet_balance.cpp endif -bench_bench_defi_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) -bench_bench_defi_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) + +if TARGET_DARWIN +bench_bench_defi_LDFLAGS += -framework Security -framework SystemConfiguration -framework CoreFoundation +endif +if TARGET_NOT_DARWIN +defid_LDFLAGS += -Wl,--allow-multiple-definition +endif +if TARGET_NOT_WINDOWS +bench_bench_defi_LDADD += -ldl +endif +if TARGET_WINDOWS +bench_bench_defi_LDADD += -luserenv -lbcrypt +endif CLEAN_DEFI_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 44b0234901..512d86b5e7 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -186,17 +186,45 @@ endif test_test_defi_SOURCES = $(DEFI_TEST_SUITE) $(DEFI_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_defi_CPPFLAGS = $(AM_CPPFLAGS) $(DEFI_INCLUDES) $(TESTDEFS) $(EVENT_CFLAGS) +test_test_defi_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +test_test_defi_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static + test_test_defi_LDADD = if ENABLE_WALLET test_test_defi_LDADD += $(LIBDEFI_WALLET) endif -test_test_defi_LDADD += $(LIBDEFI_SERVER) $(LIBDEFI_CLI) $(LIBDEFI_COMMON) $(LIBDEFI_UTIL) $(LIBDEFI_CONSENSUS) $(LIBDEFI_CRYPTO) $(LIBUNIVALUE) \ - $(LIBDEFI_SPV) $(LIBLEVELDB) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) -test_test_defi_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) - -test_test_defi_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(RAPIDCHECK_LIBS) -test_test_defi_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static +test_test_defi_LDADD += \ + $(LIBDEFI_SERVER) \ + $(LIBDEFI_CLI) \ + $(LIBAIN_RS_LIB) \ + $(LIBDEFI_SERVER) \ + $(LIBDEFI_COMMON) \ + $(LIBDEFI_UTIL) \ + $(LIBDEFI_CONSENSUS) \ + $(LIBDEFI_CRYPTO) \ + $(LIBDEFI_SPV) \ + $(LIBLEVELDB) \ + $(LIBMEMENV) \ + $(LIBSECP256K1) \ + $(LIBUNIVALUE) \ + $(EVENT_PTHREADS_LIBS) \ + $(EVENT_LIBS) + +test_test_defi_LDADD += $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(RAPIDCHECK_LIBS) + +if TARGET_DARWIN +test_test_defi_LDFLAGS += -framework Security -framework SystemConfiguration -framework CoreFoundation +endif +if TARGET_NOT_DARWIN +defid_LDFLAGS += -Wl,--allow-multiple-definition +endif +if TARGET_NOT_WINDOWS +test_test_defi_LDADD += -ldl +endif +if TARGET_WINDOWS +test_test_defi_LDADD += -luserenv -lbcrypt +endif if ENABLE_ZMQ test_test_defi_LDADD += $(LIBDEFI_ZMQ) $(ZMQ_LIBS) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 47247e41ab..bf7f019e14 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -17,6 +17,8 @@ static const unsigned int MAX_BLOCK_WEIGHT = 4000000 * 16; static const int64_t MAX_BLOCK_SIGOPS_COST = 80000 * 16; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ static const int COINBASE_MATURITY = 100; +/** Maximum gas limit per block **/ +static constexpr uint32_t MAX_BLOCK_GAS_LIMIT{30000000}; static const int WITNESS_SCALE_FACTOR = 4; diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index bb02c5826b..39ff74860c 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -180,7 +180,8 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c if (NotAllowedToFail(txType, nSpendHeight) || (nSpendHeight >= chainparams.GetConsensus().GrandCentralHeight && txType == CustomTxType::UpdateMasternode)) { CCustomCSView discardCache(mnview, nullptr, nullptr, nullptr); - auto res = ApplyCustomTx(discardCache, inputs, tx, chainparams.GetConsensus(), nSpendHeight, 0, &canSpend); + uint64_t gasUsed{}; + auto res = ApplyCustomTx(discardCache, inputs, tx, chainparams.GetConsensus(), nSpendHeight, gasUsed, 0, &canSpend); if (!res.ok && (res.code & CustomTxErrCodes::Fatal)) { return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-customtx", res.msg); } diff --git a/src/defid.cpp b/src/defid.cpp index 0c7fa9c432..a387fb5ef8 100644 --- a/src/defid.cpp +++ b/src/defid.cpp @@ -20,9 +20,7 @@ #include #include #include - -#include - +#include #include const std::function G_TRANSLATION_FUN = nullptr; diff --git a/src/ffi/cxx.h b/src/ffi/cxx.h new file mode 100644 index 0000000000..11fe33b249 --- /dev/null +++ b/src/ffi/cxx.h @@ -0,0 +1,1115 @@ +#ifndef DEFI_FFI_CXX_H +#define DEFI_FFI_CXX_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(_WIN32) +#include +#else +#include +#endif + +namespace rust { + inline namespace cxxbridge1 { + + struct unsafe_bitcopy_t; + + namespace { + template + class impl; + } + +#ifndef CXXBRIDGE1_RUST_STRING +#define CXXBRIDGE1_RUST_STRING +// https://cxx.rs/binding/string.html + class String final { + public: + String() noexcept; + String(const String &) noexcept; + String(String &&) noexcept; + ~String() noexcept; + + String(const std::string &); + String(const char *); + String(const char *, std::size_t); + String(const char16_t *); + String(const char16_t *, std::size_t); + + // Replace invalid Unicode data with the replacement character (U+FFFD). + static String lossy(const std::string &) noexcept; + static String lossy(const char *) noexcept; + static String lossy(const char *, std::size_t) noexcept; + static String lossy(const char16_t *) noexcept; + static String lossy(const char16_t *, std::size_t) noexcept; + + String &operator=(const String &) &noexcept; + String &operator=(String &&) &noexcept; + + explicit operator std::string() const; + + // Note: no null terminator. + const char *data() const noexcept; + std::size_t size() const noexcept; + std::size_t length() const noexcept; + bool empty() const noexcept; + + const char *c_str() noexcept; + + std::size_t capacity() const noexcept; + void reserve(size_t new_cap) noexcept; + + using iterator = char *; + iterator begin() noexcept; + iterator end() noexcept; + + using const_iterator = const char *; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + bool operator==(const String &) const noexcept; + bool operator!=(const String &) const noexcept; + bool operator<(const String &) const noexcept; + bool operator<=(const String &) const noexcept; + bool operator>(const String &) const noexcept; + bool operator>=(const String &) const noexcept; + + void swap(String &) noexcept; + + // Internal API only intended for the cxxbridge code generator. + String(unsafe_bitcopy_t, const String &) noexcept; + + private: + struct lossy_t; + String(lossy_t, const char *, std::size_t) noexcept; + String(lossy_t, const char16_t *, std::size_t) noexcept; + friend void swap(String &lhs, String &rhs) noexcept { lhs.swap(rhs); } + + // Size and alignment statically verified by rust_string.rs. + std::array repr; + }; +#endif // CXXBRIDGE1_RUST_STRING + +#ifndef CXXBRIDGE1_RUST_STR +#define CXXBRIDGE1_RUST_STR +// https://cxx.rs/binding/str.html + class Str final { + public: + Str() noexcept; + Str(const String &) noexcept; + Str(const std::string &); + Str(const char *); + Str(const char *, std::size_t); + + Str &operator=(const Str &) &noexcept = default; + + explicit operator std::string() const; + + // Note: no null terminator. + const char *data() const noexcept; + std::size_t size() const noexcept; + std::size_t length() const noexcept; + bool empty() const noexcept; + + // Important in order for System V ABI to pass in registers. + Str(const Str &) noexcept = default; + ~Str() noexcept = default; + + using iterator = const char *; + using const_iterator = const char *; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + bool operator==(const Str &) const noexcept; + bool operator!=(const Str &) const noexcept; + bool operator<(const Str &) const noexcept; + bool operator<=(const Str &) const noexcept; + bool operator>(const Str &) const noexcept; + bool operator>=(const Str &) const noexcept; + + void swap(Str &) noexcept; + + private: + class uninit; + Str(uninit) noexcept; + friend impl; + + std::array repr; + }; +#endif // CXXBRIDGE1_RUST_STR + +#ifndef CXXBRIDGE1_RUST_SLICE + namespace detail { + template + struct copy_assignable_if {}; + + template <> + struct copy_assignable_if { + copy_assignable_if() noexcept = default; + copy_assignable_if(const copy_assignable_if &) noexcept = default; + copy_assignable_if &operator=(const copy_assignable_if &) &noexcept = delete; + copy_assignable_if &operator=(copy_assignable_if &&) &noexcept = default; + }; + } // namespace detail + +// https://cxx.rs/binding/slice.html + template + class Slice final + : private detail::copy_assignable_if::value> { + public: + using value_type = T; + + Slice() noexcept; + Slice(T *, std::size_t count) noexcept; + + Slice &operator=(const Slice &) &noexcept = default; + Slice &operator=(Slice &&) &noexcept = default; + + T *data() const noexcept; + std::size_t size() const noexcept; + std::size_t length() const noexcept; + bool empty() const noexcept; + + T &operator[](std::size_t n) const noexcept; + T &at(std::size_t n) const; + T &front() const noexcept; + T &back() const noexcept; + + // Important in order for System V ABI to pass in registers. + Slice(const Slice &) noexcept = default; + ~Slice() noexcept = default; + + class iterator; + iterator begin() const noexcept; + iterator end() const noexcept; + + void swap(Slice &) noexcept; + + private: + class uninit; + Slice(uninit) noexcept; + friend impl; + friend void sliceInit(void *, const void *, std::size_t) noexcept; + friend void *slicePtr(const void *) noexcept; + friend std::size_t sliceLen(const void *) noexcept; + + std::array repr; + }; + + template + class Slice::iterator final { + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = typename std::add_pointer::type; + using reference = typename std::add_lvalue_reference::type; + + reference operator*() const noexcept; + pointer operator->() const noexcept; + reference operator[](difference_type) const noexcept; + + iterator &operator++() noexcept; + iterator operator++(int) noexcept; + iterator &operator--() noexcept; + iterator operator--(int) noexcept; + + iterator &operator+=(difference_type) noexcept; + iterator &operator-=(difference_type) noexcept; + iterator operator+(difference_type) const noexcept; + iterator operator-(difference_type) const noexcept; + difference_type operator-(const iterator &) const noexcept; + + bool operator==(const iterator &) const noexcept; + bool operator!=(const iterator &) const noexcept; + bool operator<(const iterator &) const noexcept; + bool operator<=(const iterator &) const noexcept; + bool operator>(const iterator &) const noexcept; + bool operator>=(const iterator &) const noexcept; + + private: + friend class Slice; + void *pos; + std::size_t stride; + }; +#endif // CXXBRIDGE1_RUST_SLICE + +#ifndef CXXBRIDGE1_RUST_BOX +// https://cxx.rs/binding/box.html + template + class Box final { + public: + using element_type = T; + using const_pointer = + typename std::add_pointer::type>::type; + using pointer = typename std::add_pointer::type; + + Box() = delete; + Box(Box &&) noexcept; + ~Box() noexcept; + + explicit Box(const T &); + explicit Box(T &&); + + Box &operator=(Box &&) &noexcept; + + const T *operator->() const noexcept; + const T &operator*() const noexcept; + T *operator->() noexcept; + T &operator*() noexcept; + + template + static Box in_place(Fields &&...); + + void swap(Box &) noexcept; + + // Important: requires that `raw` came from an into_raw call. Do not pass a + // pointer from `new` or any other source. + static Box from_raw(T *) noexcept; + + T *into_raw() noexcept; + + /* Deprecated */ using value_type = element_type; + + private: + class uninit; + class allocation; + Box(uninit) noexcept; + void drop() noexcept; + + friend void swap(Box &lhs, Box &rhs) noexcept { lhs.swap(rhs); } + + T *ptr; + }; +#endif // CXXBRIDGE1_RUST_BOX + +#ifndef CXXBRIDGE1_RUST_VEC +// https://cxx.rs/binding/vec.html + template + class Vec final { + public: + using value_type = T; + + Vec() noexcept; + Vec(std::initializer_list); + Vec(const Vec &); + Vec(Vec &&) noexcept; + ~Vec() noexcept; + + Vec &operator=(Vec &&) &noexcept; + Vec &operator=(const Vec &) &; + + std::size_t size() const noexcept; + bool empty() const noexcept; + const T *data() const noexcept; + T *data() noexcept; + std::size_t capacity() const noexcept; + + const T &operator[](std::size_t n) const noexcept; + const T &at(std::size_t n) const; + const T &front() const noexcept; + const T &back() const noexcept; + + T &operator[](std::size_t n) noexcept; + T &at(std::size_t n); + T &front() noexcept; + T &back() noexcept; + + void reserve(std::size_t new_cap); + void push_back(const T &value); + void push_back(T &&value); + template + void emplace_back(Args &&...args); + void truncate(std::size_t len); + void clear(); + + using iterator = typename Slice::iterator; + iterator begin() noexcept; + iterator end() noexcept; + + using const_iterator = typename Slice::iterator; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + void swap(Vec &) noexcept; + + // Internal API only intended for the cxxbridge code generator. + Vec(unsafe_bitcopy_t, const Vec &) noexcept; + + private: + void reserve_total(std::size_t new_cap) noexcept; + void set_len(std::size_t len) noexcept; + void drop() noexcept; + + friend void swap(Vec &lhs, Vec &rhs) noexcept { lhs.swap(rhs); } + + // Size and alignment statically verified by rust_vec.rs. + std::array repr; + }; +#endif // CXXBRIDGE1_RUST_VEC + +#ifndef CXXBRIDGE1_RUST_FN +// https://cxx.rs/binding/fn.html + template + class Fn; + + template + class Fn final { + public: + Ret operator()(Args... args) const noexcept; + Fn operator*() const noexcept; + + private: + Ret (*trampoline)(Args..., void *fn) noexcept; + void *fn; + }; +#endif // CXXBRIDGE1_RUST_FN + +#ifndef CXXBRIDGE1_RUST_ERROR +#define CXXBRIDGE1_RUST_ERROR +// https://cxx.rs/binding/result.html + class Error final : public std::exception { + public: + Error(const Error &); + Error(Error &&) noexcept; + ~Error() noexcept override; + + Error &operator=(const Error &) &; + Error &operator=(Error &&) &noexcept; + + const char *what() const noexcept override; + + private: + Error() noexcept = default; + friend impl; + const char *msg; + std::size_t len; + }; +#endif // CXXBRIDGE1_RUST_ERROR + +#ifndef CXXBRIDGE1_RUST_ISIZE +#define CXXBRIDGE1_RUST_ISIZE +#if defined(_WIN32) + using isize = SSIZE_T; +#else + using isize = ssize_t; +#endif +#endif // CXXBRIDGE1_RUST_ISIZE + + std::ostream &operator<<(std::ostream &, const String &); + std::ostream &operator<<(std::ostream &, const Str &); + +#ifndef CXXBRIDGE1_RUST_OPAQUE +#define CXXBRIDGE1_RUST_OPAQUE +// Base class of generated opaque Rust types. + class Opaque { + public: + Opaque() = delete; + Opaque(const Opaque &) = delete; + ~Opaque() = delete; + }; +#endif // CXXBRIDGE1_RUST_OPAQUE + + template + std::size_t size_of(); + template + std::size_t align_of(); + +// IsRelocatable is used in assertions that a C++ type passed by value +// between Rust and C++ is soundly relocatable by Rust. +// +// There may be legitimate reasons to opt out of the check for support of types +// that the programmer knows are soundly Rust-movable despite not being +// recognized as such by the C++ type system due to a move constructor or +// destructor. To opt out of the relocatability check, do either of the +// following things in any header used by `include!` in the bridge. +// +// --- if you define the type: +// struct MyType { +// ... +// + using IsRelocatable = std::true_type; +// }; +// +// --- otherwise: +// + template <> +// + struct rust::IsRelocatable : std::true_type {}; + template + struct IsRelocatable; + + using u8 = std::uint8_t; + using u16 = std::uint16_t; + using u32 = std::uint32_t; + using u64 = std::uint64_t; + using usize = std::size_t; // see static asserts in cxx.cc + using i8 = std::int8_t; + using i16 = std::int16_t; + using i32 = std::int32_t; + using i64 = std::int64_t; + using f32 = float; + using f64 = double; + +// Snake case aliases for use in code that uses this style for type names. + using string = String; + using str = Str; + template + using slice = Slice; + template + using box = Box; + template + using vec = Vec; + using error = Error; + template + using fn = Fn; + template + using is_relocatable = IsRelocatable; + + + +//////////////////////////////////////////////////////////////////////////////// +/// end public API, begin implementation details + +#ifndef CXXBRIDGE1_PANIC +#define CXXBRIDGE1_PANIC + template + void panic [[noreturn]] (const char *msg); +#endif // CXXBRIDGE1_PANIC + +#ifndef CXXBRIDGE1_RUST_FN +#define CXXBRIDGE1_RUST_FN + template + Ret Fn::operator()(Args... args) const noexcept { + return (*this->trampoline)(std::forward(args)..., this->fn); + } + + template + Fn Fn::operator*() const noexcept { + return *this; +} +#endif // CXXBRIDGE1_RUST_FN + +#ifndef CXXBRIDGE1_RUST_BITCOPY_T +#define CXXBRIDGE1_RUST_BITCOPY_T +struct unsafe_bitcopy_t final { + explicit unsafe_bitcopy_t() = default; +}; +#endif // CXXBRIDGE1_RUST_BITCOPY_T + +#ifndef CXXBRIDGE1_RUST_BITCOPY +#define CXXBRIDGE1_RUST_BITCOPY +constexpr unsafe_bitcopy_t unsafe_bitcopy{}; +#endif // CXXBRIDGE1_RUST_BITCOPY + +#ifndef CXXBRIDGE1_RUST_SLICE +#define CXXBRIDGE1_RUST_SLICE +template +Slice::Slice() noexcept { +sliceInit(this, reinterpret_cast(align_of()), 0); +} + +template +Slice::Slice(T *s, std::size_t count) noexcept { +assert(s != nullptr || count == 0); +sliceInit(this, +s == nullptr && count == 0 +? reinterpret_cast(align_of()) +: const_cast::type *>(s), + count); +} + +template +T *Slice::data() const noexcept { +return reinterpret_cast(slicePtr(this)); +} + +template +std::size_t Slice::size() const noexcept { +return sliceLen(this); +} + +template +std::size_t Slice::length() const noexcept { +return this->size(); +} + +template +bool Slice::empty() const noexcept { +return this->size() == 0; +} + +template +T &Slice::operator[](std::size_t n) const noexcept { +assert(n < this->size()); +auto ptr = static_cast(slicePtr(this)) + size_of() * n; +return *reinterpret_cast(ptr); +} + +template +T &Slice::at(std::size_t n) const { + if (n >= this->size()) { + panic("rust::Slice index out of range"); + } + return (*this)[n]; +} + +template +T &Slice::front() const noexcept { +assert(!this->empty()); +return (*this)[0]; +} + +template +T &Slice::back() const noexcept { +assert(!this->empty()); +return (*this)[this->size() - 1]; +} + +template +typename Slice::iterator::reference +Slice::iterator::operator*() const noexcept { +return *static_cast(this->pos); +} + +template +typename Slice::iterator::pointer +Slice::iterator::operator->() const noexcept { +return static_cast(this->pos); +} + +template +typename Slice::iterator::reference Slice::iterator::operator[]( + typename Slice::iterator::difference_type n) const noexcept { +auto ptr = static_cast(this->pos) + this->stride * n; +return *reinterpret_cast(ptr); +} + +template +typename Slice::iterator &Slice::iterator::operator++() noexcept { +this->pos = static_cast(this->pos) + this->stride; +return *this; +} + +template +typename Slice::iterator Slice::iterator::operator++(int) noexcept { +auto ret = iterator(*this); +this->pos = static_cast(this->pos) + this->stride; +return ret; +} + +template +typename Slice::iterator &Slice::iterator::operator--() noexcept { +this->pos = static_cast(this->pos) - this->stride; +return *this; +} + +template +typename Slice::iterator Slice::iterator::operator--(int) noexcept { +auto ret = iterator(*this); +this->pos = static_cast(this->pos) - this->stride; +return ret; +} + +template +typename Slice::iterator &Slice::iterator::operator+=( + typename Slice::iterator::difference_type n) noexcept { +this->pos = static_cast(this->pos) + this->stride * n; +return *this; +} + +template +typename Slice::iterator &Slice::iterator::operator-=( + typename Slice::iterator::difference_type n) noexcept { +this->pos = static_cast(this->pos) - this->stride * n; +return *this; +} + +template +typename Slice::iterator Slice::iterator::operator+( + typename Slice::iterator::difference_type n) const noexcept { +auto ret = iterator(*this); +ret.pos = static_cast(this->pos) + this->stride * n; +return ret; +} + +template +typename Slice::iterator Slice::iterator::operator-( + typename Slice::iterator::difference_type n) const noexcept { +auto ret = iterator(*this); +ret.pos = static_cast(this->pos) - this->stride * n; +return ret; +} + +template +typename Slice::iterator::difference_type +Slice::iterator::operator-(const iterator &other) const noexcept { +auto diff = std::distance(static_cast(other.pos), + static_cast(this->pos)); +return diff / this->stride; +} + +template +bool Slice::iterator::operator==(const iterator &other) const noexcept { +return this->pos == other.pos; +} + +template +bool Slice::iterator::operator!=(const iterator &other) const noexcept { +return this->pos != other.pos; +} + +template +bool Slice::iterator::operator<(const iterator &other) const noexcept { +return this->pos < other.pos; +} + +template +bool Slice::iterator::operator<=(const iterator &other) const noexcept { +return this->pos <= other.pos; +} + +template +bool Slice::iterator::operator>(const iterator &other) const noexcept { +return this->pos > other.pos; +} + +template +bool Slice::iterator::operator>=(const iterator &other) const noexcept { +return this->pos >= other.pos; +} + +template +typename Slice::iterator Slice::begin() const noexcept { +iterator it; +it.pos = slicePtr(this); +it.stride = size_of(); +return it; +} + +template +typename Slice::iterator Slice::end() const noexcept { +iterator it = this->begin(); +it.pos = static_cast(it.pos) + it.stride * this->size(); +return it; +} + +template +void Slice::swap(Slice &rhs) noexcept { +std::swap(*this, rhs); +} +#endif // CXXBRIDGE1_RUST_SLICE + +#ifndef CXXBRIDGE1_RUST_BOX +#define CXXBRIDGE1_RUST_BOX +template +class Box::uninit {}; + +template +class Box::allocation { + static T *alloc() noexcept; + static void dealloc(T *) noexcept; + +public: + allocation() noexcept : ptr(alloc()) {} + ~allocation() noexcept { + if (this->ptr) { + dealloc(this->ptr); + } + } + T *ptr; +}; + +template +Box::Box(Box &&other) noexcept : ptr(other.ptr) { +other.ptr = nullptr; +} + +template +Box::Box(const T &val) { + allocation alloc; + ::new (alloc.ptr) T(val); + this->ptr = alloc.ptr; + alloc.ptr = nullptr; +} + +template +Box::Box(T &&val) { + allocation alloc; + ::new (alloc.ptr) T(std::move(val)); + this->ptr = alloc.ptr; + alloc.ptr = nullptr; +} + +template +Box::~Box() noexcept { +if (this->ptr) { +this->drop(); +} +} + +template +Box &Box::operator=(Box &&other) &noexcept { +if (this->ptr) { +this->drop(); +} +this->ptr = other.ptr; +other.ptr = nullptr; +return *this; +} + +template +const T *Box::operator->() const noexcept { +return this->ptr; +} + +template +const T &Box::operator*() const noexcept { +return *this->ptr; +} + +template +T *Box::operator->() noexcept { +return this->ptr; +} + +template +T &Box::operator*() noexcept { +return *this->ptr; +} + +template +template +Box Box::in_place(Fields &&...fields) { + allocation alloc; + auto ptr = alloc.ptr; + ::new (ptr) T{std::forward(fields)...}; + alloc.ptr = nullptr; + return from_raw(ptr); +} + +template +void Box::swap(Box &rhs) noexcept { +using std::swap; +swap(this->ptr, rhs.ptr); +} + +template +Box Box::from_raw(T *raw) noexcept { +Box box = uninit{}; +box.ptr = raw; +return box; +} + +template +T *Box::into_raw() noexcept { +T *raw = this->ptr; +this->ptr = nullptr; +return raw; +} + +template +Box::Box(uninit) noexcept {} +#endif // CXXBRIDGE1_RUST_BOX + +#ifndef CXXBRIDGE1_RUST_VEC +#define CXXBRIDGE1_RUST_VEC +template +Vec::Vec(std::initializer_list init) : Vec{} { + this->reserve_total(init.size()); + std::move(init.begin(), init.end(), std::back_inserter(*this)); +} + +template +Vec::Vec(const Vec &other) : Vec() { + this->reserve_total(other.size()); + std::copy(other.begin(), other.end(), std::back_inserter(*this)); +} + +template +Vec::Vec(Vec &&other) noexcept : repr(other.repr) { +new (&other) Vec(); +} + +template +Vec::~Vec() noexcept { +this->drop(); +} + +template +Vec &Vec::operator=(Vec &&other) &noexcept { +this->drop(); +this->repr = other.repr; +new (&other) Vec(); +return *this; +} + +template +Vec &Vec::operator=(const Vec &other) & { + if (this != &other) { + this->drop(); + new (this) Vec(other); + } + return *this; +} + +template +bool Vec::empty() const noexcept { +return this->size() == 0; +} + +template +T *Vec::data() noexcept { +return const_cast(const_cast *>(this)->data()); +} + +template +const T &Vec::operator[](std::size_t n) const noexcept { +assert(n < this->size()); +auto data = reinterpret_cast(this->data()); +return *reinterpret_cast(data + n * size_of()); +} + +template +const T &Vec::at(std::size_t n) const { + if (n >= this->size()) { + panic("rust::Vec index out of range"); + } + return (*this)[n]; +} + +template +const T &Vec::front() const noexcept { +assert(!this->empty()); +return (*this)[0]; +} + +template +const T &Vec::back() const noexcept { +assert(!this->empty()); +return (*this)[this->size() - 1]; +} + +template +T &Vec::operator[](std::size_t n) noexcept { +assert(n < this->size()); +auto data = reinterpret_cast(this->data()); +return *reinterpret_cast(data + n * size_of()); +} + +template +T &Vec::at(std::size_t n) { + if (n >= this->size()) { + panic("rust::Vec index out of range"); + } + return (*this)[n]; +} + +template +T &Vec::front() noexcept { +assert(!this->empty()); +return (*this)[0]; +} + +template +T &Vec::back() noexcept { +assert(!this->empty()); +return (*this)[this->size() - 1]; +} + +template +void Vec::reserve(std::size_t new_cap) { + this->reserve_total(new_cap); +} + +template +void Vec::push_back(const T &value) { + this->emplace_back(value); +} + +template +void Vec::push_back(T &&value) { + this->emplace_back(std::move(value)); +} + +template +template +void Vec::emplace_back(Args &&...args) { + auto size = this->size(); + this->reserve_total(size + 1); + ::new (reinterpret_cast(reinterpret_cast(this->data()) + + size * size_of())) + T(std::forward(args)...); + this->set_len(size + 1); +} + +template +void Vec::clear() { + this->truncate(0); +} + +template +typename Vec::iterator Vec::begin() noexcept { +return Slice(this->data(), this->size()).begin(); +} + +template +typename Vec::iterator Vec::end() noexcept { +return Slice(this->data(), this->size()).end(); +} + +template +typename Vec::const_iterator Vec::begin() const noexcept { +return this->cbegin(); +} + +template +typename Vec::const_iterator Vec::end() const noexcept { +return this->cend(); +} + +template +typename Vec::const_iterator Vec::cbegin() const noexcept { +return Slice(this->data(), this->size()).begin(); +} + +template +typename Vec::const_iterator Vec::cend() const noexcept { +return Slice(this->data(), this->size()).end(); +} + +template +void Vec::swap(Vec &rhs) noexcept { +using std::swap; +swap(this->repr, rhs.repr); +} + +// Internal API only intended for the cxxbridge code generator. +template +Vec::Vec(unsafe_bitcopy_t, const Vec &bits) noexcept : repr(bits.repr) {} +#endif // CXXBRIDGE1_RUST_VEC + +#ifndef CXXBRIDGE1_IS_COMPLETE +#define CXXBRIDGE1_IS_COMPLETE +namespace detail { + namespace { + template + struct is_complete : std::false_type {}; + template + struct is_complete : std::true_type {}; + } // namespace +} // namespace detail +#endif // CXXBRIDGE1_IS_COMPLETE + +#ifndef CXXBRIDGE1_LAYOUT +#define CXXBRIDGE1_LAYOUT +class layout { + template + friend std::size_t size_of(); + template + friend std::size_t align_of(); + template + static typename std::enable_if::value, + std::size_t>::type + do_size_of() { + return T::layout::size(); + } + template + static typename std::enable_if::value, + std::size_t>::type + do_size_of() { + return sizeof(T); + } + template + static + typename std::enable_if::value, std::size_t>::type + size_of() { + return do_size_of(); + } + template + static typename std::enable_if::value, + std::size_t>::type + do_align_of() { + return T::layout::align(); + } + template + static typename std::enable_if::value, + std::size_t>::type + do_align_of() { + return alignof(T); + } + template + static + typename std::enable_if::value, std::size_t>::type + align_of() { + return do_align_of(); + } +}; + +template +std::size_t size_of() { + return layout::size_of(); +} + +template +std::size_t align_of() { + return layout::align_of(); +} +#endif // CXXBRIDGE1_LAYOUT + +#ifndef CXXBRIDGE1_RELOCATABLE +#define CXXBRIDGE1_RELOCATABLE +namespace detail { + template + struct make_void { + using type = void; + }; + + template + using void_t = typename make_void::type; + + template class, typename...> + struct detect : std::false_type {}; + template