diff --git a/.circleci/config.yml b/.circleci/config.yml index 3f676c7b3..2391a4e92 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,26 +1,17 @@ version: 2.1 orbs: aws-cli: circleci/aws-cli@1.3.2 + docker: circleci/docker@2.1.4 executors: golang: docker: # Must match GO_VERSION_MIN in project root - - image: cimg/go:1.18.1 + - image: cimg/go:1.18.8 resource_class: 2xlarge ubuntu: docker: - image: ubuntu:20.04 - packer: - description: | - The HashiCorp provided Packer container - parameters: - packer-version: - type: string - default: "1.8" - docker: - - image: hashicorp/packer:<< parameters.packer-version >> - commands: prepare: @@ -33,6 +24,10 @@ commands: default: false description: is a darwin build environment? type: boolean + darwin-architecture: + default: "amd64" + description: which darwin architecture is being used? + type: string steps: - checkout - git_fetch_all_tags @@ -58,7 +53,7 @@ commands: - run: name: Install Go command: | - curl https://dl.google.com/go/go`cat GO_VERSION_MIN`.darwin-amd64.pkg -o /tmp/go.pkg && \ + curl https://dl.google.com/go/go`cat GO_VERSION_MIN`.darwin-<>.pkg -o /tmp/go.pkg && \ sudo installer -pkg /tmp/go.pkg -target / - run: name: Export Go @@ -104,25 +99,6 @@ commands: name: fetch all tags command: | git fetch --all - packer_build: - description: "Run a packer build" - parameters: - template: - description: | - The name of the packer template file - type: string - default: packer.json - args: - description: | - Arguments to pass to the packer build command - type: string - default: "" - - steps: - - run: - name: "Run a packer build" - command: packer build << parameters.args >> << parameters.template >> - no_output_timeout: 1h jobs: mod-tidy-check: @@ -275,7 +251,9 @@ jobs: - prepare: linux: false darwin: true + darwin-architecture: amd64 - run: make lotus lotus-miner lotus-worker + - run: otool -hv lotus - run: name: check tag and version output match command: ./scripts/version-check.sh ./lotus @@ -297,10 +275,12 @@ jobs: - prepare: linux: false darwin: true + darwin-architecture: arm64 - run: | export CPATH=$(brew --prefix)/include export LIBRARY_PATH=$(brew --prefix)/lib make lotus lotus-miner lotus-worker + - run: otool -hv lotus - run: name: check tag and version output match command: ./scripts/version-check.sh ./lotus @@ -348,56 +328,6 @@ jobs: - run: ./scripts/generate-checksums.sh - run: ./scripts/publish-checksums.sh - build-appimage: - machine: - image: ubuntu-2004:202111-02 - steps: - - checkout - - attach_workspace: - at: /tmp/workspace - - run: - name: Update Go - command: | - sudo rm -rf /usr/local/go && \ - curl -L https://golang.org/dl/go`cat GO_VERSION_MIN`.linux-amd64.tar.gz -o /tmp/go.tar.gz && \ - sudo tar -C /usr/local -xvf /tmp/go.tar.gz - - run: go version - - run: - name: install appimage-builder - command: | - # appimage-builder requires /dev/snd to exist. It creates containers during the testing phase - # that pass sound devices from the host to the testing container. (hard coded!) - # https://github.com/AppImageCrafters/appimage-builder/blob/master/appimagebuilder/modules/test/execution_test.py#L54 - # Circleci doesn't provide a working sound device; this is enough to fake it. - if [ ! -e /dev/snd ] - then - sudo mkdir /dev/snd - sudo mknod /dev/snd/ControlC0 c 1 2 - fi - - # docs: https://appimage-builder.readthedocs.io/en/latest/intro/install.html - sudo apt update - sudo apt install -y python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace - sudo curl -Lo /usr/local/bin/appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage - sudo chmod +x /usr/local/bin/appimagetool - sudo pip3 install appimage-builder - - run: - name: install lotus dependencies - command: sudo apt install ocl-icd-opencl-dev libhwloc-dev - - run: - name: build appimage - command: | - sed -i "s/version: latest/version: ${CIRCLE_TAG:-latest}/" AppImageBuilder.yml - make appimage - - run: | - mkdir -p /tmp/workspace/appimage && \ - mv Lotus-*.AppImage /tmp/workspace/appimage/ - - persist_to_workspace: - root: /tmp/workspace - paths: - - appimage - - gofmt: executor: golang steps: @@ -413,11 +343,9 @@ jobs: - run: go install golang.org/x/tools/cmd/goimports - run: go install github.com/hannahhoward/cbor-gen-for - run: make gen - - run: git --no-pager diff - - run: git --no-pager diff --quiet + - run: git --no-pager diff && git --no-pager diff --quiet - run: make docsgen-cli - - run: git --no-pager diff - - run: git --no-pager diff --quiet + - run: git --no-pager diff && git --no-pager diff --quiet docs-check: executor: golang @@ -432,11 +360,7 @@ jobs: - run: zcat build/openrpc/full.json.gz | jq > ../post-openrpc-full - run: zcat build/openrpc/miner.json.gz | jq > ../post-openrpc-miner - run: zcat build/openrpc/worker.json.gz | jq > ../post-openrpc-worker - - run: git --no-pager diff - - run: diff ../pre-openrpc-full ../post-openrpc-full - - run: diff ../pre-openrpc-miner ../post-openrpc-miner - - run: diff ../pre-openrpc-worker ../post-openrpc-worker - - run: git --no-pager diff --quiet + - run: diff ../pre-openrpc-full ../post-openrpc-full && diff ../pre-openrpc-miner ../post-openrpc-miner && diff ../pre-openrpc-worker ../post-openrpc-worker && git --no-pager diff && git --no-pager diff --quiet lint: &lint description: | @@ -470,249 +394,104 @@ jobs: lint-all: <<: *lint - publish: - description: publish binary artifacts - executor: ubuntu - parameters: - linux: - default: false - description: publish linux binaries? - type: boolean - appimage: - default: false - description: publish appimage binaries? - type: boolean - steps: - - run: - name: Install git jq curl - command: apt update && apt install -y git jq curl sudo - - checkout - - git_fetch_all_tags - - checkout - - install_ipfs - - attach_workspace: - at: /tmp/workspace - - when: - condition: << parameters.linux >> - steps: - - run: ./scripts/build-arch-bundle.sh linux - - run: ./scripts/publish-arch-release.sh linux - - when: - condition: << parameters.appimage >> - steps: - - run: ./scripts/build-appimage-bundle.sh - - run: ./scripts/publish-arch-release.sh appimage - - publish-snapcraft: - description: build and push snapcraft - machine: - image: ubuntu-2004:202104-01 - resource_class: 2xlarge + build-docker: + description: > + Publish to Dockerhub + executor: docker/docker parameters: + image: + type: string + default: lotus + description: > + Passed to the docker build process to determine which image in the + Dockerfile should be built. Expected values are `lotus`, + `lotus-all-in-one` + network: + type: string + default: "mainnet" + description: > + Passed to the docker build process using GOFLAGS+=-tags=<>. + Expected values are `debug`, `2k`, `calibnet`, `butterflynet`, + `interopnet`. channel: - type: string - default: "edge" - description: snapcraft channel - snap-name: - type: string - default: 'lotus-filecoin' - description: name of snap in snap store - steps: - - checkout - - run: - name: Install snapcraft - command: sudo snap install snapcraft --classic - - run: - name: Build << parameters.snap-name >> snap - command: | - if [ "<< parameters.snap-name >>" != 'lotus-filecoin' ]; then - cat snap/snapcraft.yaml | sed 's/lotus-filecoin/lotus/' > edited-snapcraft.yaml - mv edited-snapcraft.yaml snap/snapcraft.yaml - fi - - snapcraft --use-lxd --debug - - run: - name: Publish snap to << parameters.channel >> channel - shell: /bin/bash -o pipefail - command: | - snapcraft upload *.snap --release << parameters.channel >> - - build-and-push-image: - description: build and push docker images to public AWS ECR registry - executor: aws-cli/default - parameters: - profile-name: - type: string - default: "default" - description: AWS profile name to be configured. - - aws-access-key-id: - type: env_var_name - default: AWS_ACCESS_KEY_ID - description: > - AWS access key id for IAM role. Set this to the name of - the environment variable you will set to hold this - value, i.e. AWS_ACCESS_KEY. - - aws-secret-access-key: - type: env_var_name - default: AWS_SECRET_ACCESS_KEY - description: > - AWS secret key for IAM role. Set this to the name of - the environment variable you will set to hold this - value, i.e. AWS_SECRET_ACCESS_KEY. - - region: - type: env_var_name - default: AWS_REGION - description: > - Name of env var storing your AWS region information, - defaults to AWS_REGION - - account-url: - type: env_var_name - default: AWS_ECR_ACCOUNT_URL - description: > - Env var storing Amazon ECR account URL that maps to an AWS account, - e.g. {awsAccountNum}.dkr.ecr.us-west-2.amazonaws.com - defaults to AWS_ECR_ACCOUNT_URL - - dockerfile: - type: string - default: Dockerfile - description: Name of dockerfile to use. Defaults to Dockerfile. - - path: - type: string - default: . - description: Path to the directory containing your Dockerfile and build context. Defaults to . (working directory). - - extra-build-args: type: string default: "" description: > - Extra flags to pass to docker build. For examples, see - https://docs.docker.com/engine/reference/commandline/build - - repo: - type: string - description: Name of an Amazon ECR repository - - tag: - type: string - default: "latest" - description: A comma-separated string containing docker image tags to build and push (default = latest) - - target: - type: string - default: "lotus-all-in-one" - description: Docker target to build - + The release channel to use for this image. + push: + type: boolean + default: false + description: > + When true, pushes the image to Dockerhub steps: - - run: - name: Confirm that environment variables are set - command: | - if [ -z "$AWS_ACCESS_KEY_ID" ]; then - echo "No AWS_ACCESS_KEY_ID is set. Skipping build-and-push job ..." - circleci-agent step halt - fi - - - aws-cli/setup: - profile-name: <> - aws-access-key-id: <> - aws-secret-access-key: <> - aws-region: <> - - - run: - name: Log into Amazon ECR - command: | - aws ecr-public get-login-password --region $<> --profile <> | docker login --username AWS --password-stdin $<> - + - setup_remote_docker - checkout + - git_fetch_all_tags + - run: git submodule sync + - run: git submodule update --init - - setup_remote_docker: - version: 19.03.13 - docker_layer_caching: false - - - run: - name: Build docker image - command: | - registry_id=$(echo $<> | sed "s;\..*;;g") - - docker_tag_args="" - IFS="," read -ra DOCKER_TAGS \<<< "<< parameters.tag >>" - for tag in "${DOCKER_TAGS[@]}"; do - docker_tag_args="$docker_tag_args -t $<>/<>:$tag" - done - - docker build \ - <<#parameters.extra-build-args>><><> \ - --target <> \ - -f <>/<> \ - $docker_tag_args \ - <> - - - run: - name: Push image to Amazon ECR - command: | - IFS="," read -ra DOCKER_TAGS \<<< "<< parameters.tag >>" - for tag in "${DOCKER_TAGS[@]}"; do - docker push $<>/<>:${tag} - done - - publish-packer-snap: - description: build packer image with snap. mainnet only. - executor: - name: packer - steps: - - checkout - - packer_build: - template: tools/packer/lotus-snap.pkr.hcl - publish-dockerhub: - description: publish to dockerhub - machine: - image: ubuntu-2004:202010-01 - parameters: - tag: - type: string - default: latest - steps: - - checkout - - run: - name: dockerhub login - command: echo $DOCKERHUB_PASSWORD | docker login --username $DOCKERHUB_USERNAME --password-stdin - - run: - name: docker build - command: | - docker build --target lotus -t filecoin/lotus:<< parameters.tag >> -f Dockerfile.lotus . - docker build --target lotus-gateway -t filecoin/lotus-gateway:<< parameters.tag >> -f Dockerfile.lotus . - docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:<< parameters.tag >> -f Dockerfile.lotus . - if [[ ! -z $CIRCLE_SHA1 ]]; then - docker build --target lotus -t filecoin/lotus:$CIRCLE_SHA1 -f Dockerfile.lotus . - docker build --target lotus-gateway -t filecoin/lotus-gateway:$CIRCLE_SHA1 -f Dockerfile.lotus . - docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:$CIRCLE_SHA1 -f Dockerfile.lotus . - fi - if [[ ! -z $CIRCLE_TAG ]]; then - docker build --target lotus -t filecoin/lotus:$CIRCLE_TAG -f Dockerfile.lotus . - docker build --target lotus-gateway -t filecoin/lotus-gateway:$CIRCLE_TAG -f Dockerfile.lotus . - docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:$CIRCLE_TAG -f Dockerfile.lotus . - fi - - run: - name: docker push - command: | - docker push filecoin/lotus:<< parameters.tag >> - docker push filecoin/lotus-gateway:<< parameters.tag >> - docker push filecoin/lotus-all-in-one:<< parameters.tag >> - if [[ ! -z $CIRCLE_SHA1 ]]; then - docker push filecoin/lotus:$CIRCLE_SHA1 - docker push filecoin/lotus-gateway:$CIRCLE_SHA1 - docker push filecoin/lotus-all-in-one:$CIRCLE_SHA1 - fi - if [[ ! -z $CIRCLE_TAG ]]; then - docker push filecoin/lotus:$CIRCLE_TAG - docker push filecoin/lotus-gateway:$CIRCLE_TAG - docker push filecoin/lotus-all-in-one:$CIRCLE_TAG - fi + - docker/check: + docker-username: DOCKERHUB_USERNAME + docker-password: DOCKERHUB_PASSWORD + - when: + condition: + equal: [ mainnet, <> ] + steps: + - when: + condition: <> + steps: + - docker/build: + image: filecoin/<> + extra_build_args: --target <> + tag: <> + - run: + name: Docker push + command: | + docker push filecoin/<>:<> + if [[ ! -z $CIRCLE_SHA ]]; then + docker image tag filecoin/<>:<> filecoin/<>:"${CIRCLE_SHA:0:7}" + docker push filecoin/<>:"${CIRCLE_SHA:0:7}" + fi + if [[ ! -z $CIRCLE_TAG ]]; then + docker image tag filecoin/<>:<> filecoin/<>:"${CIRCLE_TAG}" + docker push filecoin/<>:"${CIRCLE_TAG}" + fi + - unless: + condition: <> + steps: + - docker/build: + image: filecoin/<> + extra_build_args: --target <> + - when: + condition: + not: + equal: [ mainnet, <> ] + steps: + - when: + condition: <> + steps: + - docker/build: + image: filecoin/<> + extra_build_args: --target <> --build-arg GOFLAGS=-tags=<> + tag: <>-<> + - run: + name: Docker push + command: | + docker push filecoin/<>:<>-<> + if [[ ! -z $CIRCLE_SHA ]]; then + docker image tag filecoin/<>:<>-<> filecoin/<>:"${CIRCLE_SHA:0:7}"-<> + docker push filecoin/<>:"${CIRCLE_SHA:0:7}"-<> + fi + if [[ ! -z $CIRCLE_TAG ]]; then + docker image tag filecoin/<>:<>-<> filecoin/<>:"${CIRCLE_TAG}"-<> + docker push filecoin/<>:"${CIRCLE_TAG}"-<> + fi + - unless: + condition: <> + steps: + - docker/build: + image: filecoin/<> + extra_build_args: --target <> --build-arg GOFLAGS=-tags=<> workflows: version: 2.1 @@ -824,11 +603,91 @@ workflows: suite: itest-deals target: "./itests/deals_test.go" + - test: + name: test-itest-decode_params + suite: itest-decode_params + target: "./itests/decode_params_test.go" + - test: name: test-itest-dup_mpool_messages suite: itest-dup_mpool_messages target: "./itests/dup_mpool_messages_test.go" + - test: + name: test-itest-eth_account_abstraction + suite: itest-eth_account_abstraction + target: "./itests/eth_account_abstraction_test.go" + + - test: + name: test-itest-eth_api + suite: itest-eth_api + target: "./itests/eth_api_test.go" + + - test: + name: test-itest-eth_balance + suite: itest-eth_balance + target: "./itests/eth_balance_test.go" + + - test: + name: test-itest-eth_block_hash + suite: itest-eth_block_hash + target: "./itests/eth_block_hash_test.go" + + - test: + name: test-itest-eth_bytecode + suite: itest-eth_bytecode + target: "./itests/eth_bytecode_test.go" + + - test: + name: test-itest-eth_config + suite: itest-eth_config + target: "./itests/eth_config_test.go" + + - test: + name: test-itest-eth_conformance + suite: itest-eth_conformance + target: "./itests/eth_conformance_test.go" + + - test: + name: test-itest-eth_deploy + suite: itest-eth_deploy + target: "./itests/eth_deploy_test.go" + + - test: + name: test-itest-eth_fee_history + suite: itest-eth_fee_history + target: "./itests/eth_fee_history_test.go" + + - test: + name: test-itest-eth_filter + suite: itest-eth_filter + target: "./itests/eth_filter_test.go" + + - test: + name: test-itest-eth_hash_lookup + suite: itest-eth_hash_lookup + target: "./itests/eth_hash_lookup_test.go" + + - test: + name: test-itest-eth_transactions + suite: itest-eth_transactions + target: "./itests/eth_transactions_test.go" + + - test: + name: test-itest-fevm_address + suite: itest-fevm_address + target: "./itests/fevm_address_test.go" + + - test: + name: test-itest-fevm_events + suite: itest-fevm_events + target: "./itests/fevm_events_test.go" + + - test: + name: test-itest-fevm + suite: itest-fevm + target: "./itests/fevm_test.go" + - test: name: test-itest-gas_estimation suite: itest-gas_estimation @@ -864,6 +723,11 @@ workflows: suite: itest-migration_nv17 target: "./itests/migration_nv17_test.go" + - test: + name: test-itest-migration_nv18 + suite: itest-migration_nv18 + target: "./itests/migration_nv18_test.go" + - test: name: test-itest-mpool_msg_uuid suite: itest-mpool_msg_uuid @@ -979,6 +843,11 @@ workflows: suite: itest-sector_terminate target: "./itests/sector_terminate_test.go" + - test: + name: test-itest-sector_unseal + suite: itest-sector_unseal + target: "./itests/sector_unseal_test.go" + - test: name: test-itest-self_sent_txn suite: itest-self_sent_txn @@ -1029,6 +898,11 @@ workflows: suite: itest-worker target: "./itests/worker_test.go" + - test: + name: test-itest-worker_upgrade + suite: itest-worker_upgrade + target: "./itests/worker_upgrade_test.go" + - test: name: test-unit-cli suite: utest-unit-cli @@ -1053,11 +927,6 @@ workflows: - test-conformance: suite: conformance target: "./conformance" - - test-conformance: - name: test-conformance-bleeding-edge - suite: conformance-bleeding-edge - target: "./conformance" - vectors-branch: specs-actors-v7 release: jobs: @@ -1112,45 +981,57 @@ workflows: branches: only: - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - - build-appimage: - name: "Build AppImage" + - build-docker: + name: "Docker push (lotus-all-in-one / stable / mainnet)" + image: lotus-all-in-one + channel: stable + network: mainnet + push: true + filters: + branches: + ignore: + - /.*/ + tags: + only: + - /^v\d+\.\d+\.\d+$/ + - build-docker: + name: "Docker push (lotus-all-in-one / candidate / mainnet)" + image: lotus-all-in-one + channel: candidate + network: mainnet + push: true + filters: + branches: + ignore: + - /.*/ + tags: + only: + - /^v\d+\.\d+\.\d+-rc\d+$/ + - build-docker: + name: "Docker push (lotus-all-in-one / edge / mainnet)" + image: lotus-all-in-one + channel: master + network: mainnet + push: true + filters: + branches: + only: + - master + - build-docker: + name: "Docker build (lotus-all-in-one / mainnet)" + image: lotus-all-in-one + network: mainnet + push: false filters: branches: only: - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - publish: - name: "Publish AppImage" - appimage: true - requires: - - "Build AppImage" - filters: - branches: - ignore: - - /.*/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - build-and-push-image: - name: "Publish ECR (lotus-all-in-one)" - dockerfile: Dockerfile.lotus - path: . - repo: lotus-dev - tag: '${CIRCLE_SHA1:0:8}' - target: lotus-all-in-one - - build-and-push-image: - name: "Publish ECR (lotus-test)" - dockerfile: Dockerfile.lotus - path: . - repo: lotus-test - tag: '${CIRCLE_SHA1:0:8}' - target: lotus-test - - publish-snapcraft: - name: "Publish Snapcraft (lotus-filecoin / candidate)" + - build-docker: + name: "Docker push (lotus-all-in-one / stable / butterflynet)" + image: lotus-all-in-one channel: stable - snap-name: lotus-filecoin + network: butterflynet + push: true filters: branches: ignore: @@ -1158,10 +1039,12 @@ workflows: tags: only: - /^v\d+\.\d+\.\d+$/ - - publish-snapcraft: - name: "Publish Snapcraft (lotus-filecoin / candidate)" + - build-docker: + name: "Docker push (lotus-all-in-one / candidate / butterflynet)" + image: lotus-all-in-one channel: candidate - snap-name: lotus-filecoin + network: butterflynet + push: true filters: branches: ignore: @@ -1169,10 +1052,31 @@ workflows: tags: only: - /^v\d+\.\d+\.\d+-rc\d+$/ - - publish-snapcraft: - name: "Publish Snapcraft (lotus / stable)" + - build-docker: + name: "Docker push (lotus-all-in-one / edge / butterflynet)" + image: lotus-all-in-one + channel: master + network: butterflynet + push: true + filters: + branches: + only: + - master + - build-docker: + name: "Docker build (lotus-all-in-one / butterflynet)" + image: lotus-all-in-one + network: butterflynet + push: false + filters: + branches: + only: + - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ + - build-docker: + name: "Docker push (lotus-all-in-one / stable / calibnet)" + image: lotus-all-in-one channel: stable - snap-name: lotus + network: calibnet + push: true filters: branches: ignore: @@ -1180,10 +1084,12 @@ workflows: tags: only: - /^v\d+\.\d+\.\d+$/ - - publish-snapcraft: - name: "Publish Snapcraft (lotus / candidate)" + - build-docker: + name: "Docker push (lotus-all-in-one / candidate / calibnet)" + image: lotus-all-in-one channel: candidate - snap-name: lotus + network: calibnet + push: true filters: branches: ignore: @@ -1191,9 +1097,31 @@ workflows: tags: only: - /^v\d+\.\d+\.\d+-rc\d+$/ - - publish-dockerhub: - name: "Publish Dockerhub (stable)" - tag: stable + - build-docker: + name: "Docker push (lotus-all-in-one / edge / calibnet)" + image: lotus-all-in-one + channel: master + network: calibnet + push: true + filters: + branches: + only: + - master + - build-docker: + name: "Docker build (lotus-all-in-one / calibnet)" + image: lotus-all-in-one + network: calibnet + push: false + filters: + branches: + only: + - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ + - build-docker: + name: "Docker push (lotus-all-in-one / stable / debug)" + image: lotus-all-in-one + channel: stable + network: debug + push: true filters: branches: ignore: @@ -1201,9 +1129,12 @@ workflows: tags: only: - /^v\d+\.\d+\.\d+$/ - - publish-dockerhub: - name: "Publish Dockerhub (candidate)" - tag: candidate + - build-docker: + name: "Docker push (lotus-all-in-one / candidate / debug)" + image: lotus-all-in-one + channel: candidate + network: debug + push: true filters: branches: ignore: @@ -1211,6 +1142,70 @@ workflows: tags: only: - /^v\d+\.\d+\.\d+-rc\d+$/ + - build-docker: + name: "Docker push (lotus-all-in-one / edge / debug)" + image: lotus-all-in-one + channel: master + network: debug + push: true + filters: + branches: + only: + - master + - build-docker: + name: "Docker build (lotus-all-in-one / debug)" + image: lotus-all-in-one + network: debug + push: false + filters: + branches: + only: + - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ + - build-docker: + name: "Docker push (lotus / stable / mainnet)" + image: lotus + channel: stable + network: mainnet + push: true + filters: + branches: + ignore: + - /.*/ + tags: + only: + - /^v\d+\.\d+\.\d+$/ + - build-docker: + name: "Docker push (lotus / candidate / mainnet)" + image: lotus + channel: candidate + network: mainnet + push: true + filters: + branches: + ignore: + - /.*/ + tags: + only: + - /^v\d+\.\d+\.\d+-rc\d+$/ + - build-docker: + name: "Docker push (lotus / master / mainnet)" + image: lotus + channel: master + network: mainnet + push: true + filters: + branches: + only: + - master + - build-docker: + name: "Docker build (lotus / mainnet)" + image: lotus + network: mainnet + push: false + filters: + branches: + only: + - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ nightly: triggers: @@ -1221,24 +1216,27 @@ workflows: only: - master jobs: - - publish-snapcraft: - name: "Publish Snapcraft Nightly (lotus-filecoin / edge)" - channel: edge - snap-name: lotus-filecoin - - publish-snapcraft: - name: "Publish Snapcraft Nightly (lotus / edge)" - channel: edge - snap-name: lotus - - publish-dockerhub: - name: publish-dockerhub-nightly - tag: nightly - biweekly: - triggers: - - schedule: - cron: "0 0 1,15 * *" - filters: - branches: - only: - - master - jobs: - - publish-packer-snap + - build-docker: + name: "Docker (lotus-all-in-one / nightly / mainnet)" + image: lotus-all-in-one + channel: nightly + network: mainnet + push: true + - build-docker: + name: "Docker (lotus-all-in-one / nightly / butterflynet)" + image: lotus-all-in-one + channel: nightly + network: butterflynet + push: true + - build-docker: + name: "Docker (lotus-all-in-one / nightly / calibnet)" + image: lotus-all-in-one + channel: nightly + network: calibnet + push: true + - build-docker: + name: "Docker (lotus-all-in-one / nightly / debug)" + image: lotus-all-in-one + channel: nightly + network: debug + push: true diff --git a/.circleci/gen.go b/.circleci/gen.go index 844348e29..5d951027a 100644 --- a/.circleci/gen.go +++ b/.circleci/gen.go @@ -106,10 +106,12 @@ func main() { // form the input data. type data struct { + Networks []string ItestFiles []string UnitSuites map[string]string } in := data{ + Networks: []string{"mainnet", "butterflynet", "calibnet", "debug"}, ItestFiles: itests, UnitSuites: func() map[string]string { ret := make(map[string]string) diff --git a/.circleci/template.yml b/.circleci/template.yml index 5a2ef1b32..724571ac2 100644 --- a/.circleci/template.yml +++ b/.circleci/template.yml @@ -1,26 +1,17 @@ version: 2.1 orbs: aws-cli: circleci/aws-cli@1.3.2 + docker: circleci/docker@2.1.4 executors: golang: docker: # Must match GO_VERSION_MIN in project root - - image: cimg/go:1.18.1 + - image: cimg/go:1.18.8 resource_class: 2xlarge ubuntu: docker: - image: ubuntu:20.04 - packer: - description: | - The HashiCorp provided Packer container - parameters: - packer-version: - type: string - default: "1.8" - docker: - - image: hashicorp/packer:<< parameters.packer-version >> - commands: prepare: @@ -33,6 +24,10 @@ commands: default: false description: is a darwin build environment? type: boolean + darwin-architecture: + default: "amd64" + description: which darwin architecture is being used? + type: string steps: - checkout - git_fetch_all_tags @@ -58,7 +53,7 @@ commands: - run: name: Install Go command: | - curl https://dl.google.com/go/go`cat GO_VERSION_MIN`.darwin-amd64.pkg -o /tmp/go.pkg && \ + curl https://dl.google.com/go/go`cat GO_VERSION_MIN`.darwin-<>.pkg -o /tmp/go.pkg && \ sudo installer -pkg /tmp/go.pkg -target / - run: name: Export Go @@ -104,25 +99,6 @@ commands: name: fetch all tags command: | git fetch --all - packer_build: - description: "Run a packer build" - parameters: - template: - description: | - The name of the packer template file - type: string - default: packer.json - args: - description: | - Arguments to pass to the packer build command - type: string - default: "" - - steps: - - run: - name: "Run a packer build" - command: packer build << parameters.args >> << parameters.template >> - no_output_timeout: 1h jobs: mod-tidy-check: @@ -275,7 +251,9 @@ jobs: - prepare: linux: false darwin: true + darwin-architecture: amd64 - run: make lotus lotus-miner lotus-worker + - run: otool -hv lotus - run: name: check tag and version output match command: ./scripts/version-check.sh ./lotus @@ -297,10 +275,12 @@ jobs: - prepare: linux: false darwin: true + darwin-architecture: arm64 - run: | export CPATH=$(brew --prefix)/include export LIBRARY_PATH=$(brew --prefix)/lib make lotus lotus-miner lotus-worker + - run: otool -hv lotus - run: name: check tag and version output match command: ./scripts/version-check.sh ./lotus @@ -348,56 +328,6 @@ jobs: - run: ./scripts/generate-checksums.sh - run: ./scripts/publish-checksums.sh - build-appimage: - machine: - image: ubuntu-2004:202111-02 - steps: - - checkout - - attach_workspace: - at: /tmp/workspace - - run: - name: Update Go - command: | - sudo rm -rf /usr/local/go && \ - curl -L https://golang.org/dl/go`cat GO_VERSION_MIN`.linux-amd64.tar.gz -o /tmp/go.tar.gz && \ - sudo tar -C /usr/local -xvf /tmp/go.tar.gz - - run: go version - - run: - name: install appimage-builder - command: | - # appimage-builder requires /dev/snd to exist. It creates containers during the testing phase - # that pass sound devices from the host to the testing container. (hard coded!) - # https://github.com/AppImageCrafters/appimage-builder/blob/master/appimagebuilder/modules/test/execution_test.py#L54 - # Circleci doesn't provide a working sound device; this is enough to fake it. - if [ ! -e /dev/snd ] - then - sudo mkdir /dev/snd - sudo mknod /dev/snd/ControlC0 c 1 2 - fi - - # docs: https://appimage-builder.readthedocs.io/en/latest/intro/install.html - sudo apt update - sudo apt install -y python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace - sudo curl -Lo /usr/local/bin/appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage - sudo chmod +x /usr/local/bin/appimagetool - sudo pip3 install appimage-builder - - run: - name: install lotus dependencies - command: sudo apt install ocl-icd-opencl-dev libhwloc-dev - - run: - name: build appimage - command: | - sed -i "s/version: latest/version: ${CIRCLE_TAG:-latest}/" AppImageBuilder.yml - make appimage - - run: | - mkdir -p /tmp/workspace/appimage && \ - mv Lotus-*.AppImage /tmp/workspace/appimage/ - - persist_to_workspace: - root: /tmp/workspace - paths: - - appimage - - gofmt: executor: golang steps: @@ -413,11 +343,9 @@ jobs: - run: go install golang.org/x/tools/cmd/goimports - run: go install github.com/hannahhoward/cbor-gen-for - run: make gen - - run: git --no-pager diff - - run: git --no-pager diff --quiet + - run: git --no-pager diff && git --no-pager diff --quiet - run: make docsgen-cli - - run: git --no-pager diff - - run: git --no-pager diff --quiet + - run: git --no-pager diff && git --no-pager diff --quiet docs-check: executor: golang @@ -432,11 +360,7 @@ jobs: - run: zcat build/openrpc/full.json.gz | jq > ../post-openrpc-full - run: zcat build/openrpc/miner.json.gz | jq > ../post-openrpc-miner - run: zcat build/openrpc/worker.json.gz | jq > ../post-openrpc-worker - - run: git --no-pager diff - - run: diff ../pre-openrpc-full ../post-openrpc-full - - run: diff ../pre-openrpc-miner ../post-openrpc-miner - - run: diff ../pre-openrpc-worker ../post-openrpc-worker - - run: git --no-pager diff --quiet + - run: diff ../pre-openrpc-full ../post-openrpc-full && diff ../pre-openrpc-miner ../post-openrpc-miner && diff ../pre-openrpc-worker ../post-openrpc-worker && git --no-pager diff && git --no-pager diff --quiet lint: &lint description: | @@ -470,249 +394,104 @@ jobs: lint-all: <<: *lint - publish: - description: publish binary artifacts - executor: ubuntu - parameters: - linux: - default: false - description: publish linux binaries? - type: boolean - appimage: - default: false - description: publish appimage binaries? - type: boolean - steps: - - run: - name: Install git jq curl - command: apt update && apt install -y git jq curl sudo - - checkout - - git_fetch_all_tags - - checkout - - install_ipfs - - attach_workspace: - at: /tmp/workspace - - when: - condition: << parameters.linux >> - steps: - - run: ./scripts/build-arch-bundle.sh linux - - run: ./scripts/publish-arch-release.sh linux - - when: - condition: << parameters.appimage >> - steps: - - run: ./scripts/build-appimage-bundle.sh - - run: ./scripts/publish-arch-release.sh appimage - - publish-snapcraft: - description: build and push snapcraft - machine: - image: ubuntu-2004:202104-01 - resource_class: 2xlarge + build-docker: + description: > + Publish to Dockerhub + executor: docker/docker parameters: + image: + type: string + default: lotus + description: > + Passed to the docker build process to determine which image in the + Dockerfile should be built. Expected values are `lotus`, + `lotus-all-in-one` + network: + type: string + default: "mainnet" + description: > + Passed to the docker build process using GOFLAGS+=-tags=<>. + Expected values are `debug`, `2k`, `calibnet`, `butterflynet`, + `interopnet`. channel: - type: string - default: "edge" - description: snapcraft channel - snap-name: - type: string - default: 'lotus-filecoin' - description: name of snap in snap store - steps: - - checkout - - run: - name: Install snapcraft - command: sudo snap install snapcraft --classic - - run: - name: Build << parameters.snap-name >> snap - command: | - if [ "<< parameters.snap-name >>" != 'lotus-filecoin' ]; then - cat snap/snapcraft.yaml | sed 's/lotus-filecoin/lotus/' > edited-snapcraft.yaml - mv edited-snapcraft.yaml snap/snapcraft.yaml - fi - - snapcraft --use-lxd --debug - - run: - name: Publish snap to << parameters.channel >> channel - shell: /bin/bash -o pipefail - command: | - snapcraft upload *.snap --release << parameters.channel >> - - build-and-push-image: - description: build and push docker images to public AWS ECR registry - executor: aws-cli/default - parameters: - profile-name: - type: string - default: "default" - description: AWS profile name to be configured. - - aws-access-key-id: - type: env_var_name - default: AWS_ACCESS_KEY_ID - description: > - AWS access key id for IAM role. Set this to the name of - the environment variable you will set to hold this - value, i.e. AWS_ACCESS_KEY. - - aws-secret-access-key: - type: env_var_name - default: AWS_SECRET_ACCESS_KEY - description: > - AWS secret key for IAM role. Set this to the name of - the environment variable you will set to hold this - value, i.e. AWS_SECRET_ACCESS_KEY. - - region: - type: env_var_name - default: AWS_REGION - description: > - Name of env var storing your AWS region information, - defaults to AWS_REGION - - account-url: - type: env_var_name - default: AWS_ECR_ACCOUNT_URL - description: > - Env var storing Amazon ECR account URL that maps to an AWS account, - e.g. {awsAccountNum}.dkr.ecr.us-west-2.amazonaws.com - defaults to AWS_ECR_ACCOUNT_URL - - dockerfile: - type: string - default: Dockerfile - description: Name of dockerfile to use. Defaults to Dockerfile. - - path: - type: string - default: . - description: Path to the directory containing your Dockerfile and build context. Defaults to . (working directory). - - extra-build-args: type: string default: "" description: > - Extra flags to pass to docker build. For examples, see - https://docs.docker.com/engine/reference/commandline/build - - repo: - type: string - description: Name of an Amazon ECR repository - - tag: - type: string - default: "latest" - description: A comma-separated string containing docker image tags to build and push (default = latest) - - target: - type: string - default: "lotus-all-in-one" - description: Docker target to build - + The release channel to use for this image. + push: + type: boolean + default: false + description: > + When true, pushes the image to Dockerhub steps: - - run: - name: Confirm that environment variables are set - command: | - if [ -z "$AWS_ACCESS_KEY_ID" ]; then - echo "No AWS_ACCESS_KEY_ID is set. Skipping build-and-push job ..." - circleci-agent step halt - fi - - - aws-cli/setup: - profile-name: <> - aws-access-key-id: <> - aws-secret-access-key: <> - aws-region: <> - - - run: - name: Log into Amazon ECR - command: | - aws ecr-public get-login-password --region $<> --profile <> | docker login --username AWS --password-stdin $<> - + - setup_remote_docker - checkout + - git_fetch_all_tags + - run: git submodule sync + - run: git submodule update --init - - setup_remote_docker: - version: 19.03.13 - docker_layer_caching: false - - - run: - name: Build docker image - command: | - registry_id=$(echo $<> | sed "s;\..*;;g") - - docker_tag_args="" - IFS="," read -ra DOCKER_TAGS \<<< "<< parameters.tag >>" - for tag in "${DOCKER_TAGS[@]}"; do - docker_tag_args="$docker_tag_args -t $<>/<>:$tag" - done - - docker build \ - <<#parameters.extra-build-args>><><> \ - --target <> \ - -f <>/<> \ - $docker_tag_args \ - <> - - - run: - name: Push image to Amazon ECR - command: | - IFS="," read -ra DOCKER_TAGS \<<< "<< parameters.tag >>" - for tag in "${DOCKER_TAGS[@]}"; do - docker push $<>/<>:${tag} - done - - publish-packer-snap: - description: build packer image with snap. mainnet only. - executor: - name: packer - steps: - - checkout - - packer_build: - template: tools/packer/lotus-snap.pkr.hcl - publish-dockerhub: - description: publish to dockerhub - machine: - image: ubuntu-2004:202010-01 - parameters: - tag: - type: string - default: latest - steps: - - checkout - - run: - name: dockerhub login - command: echo $DOCKERHUB_PASSWORD | docker login --username $DOCKERHUB_USERNAME --password-stdin - - run: - name: docker build - command: | - docker build --target lotus -t filecoin/lotus:<< parameters.tag >> -f Dockerfile.lotus . - docker build --target lotus-gateway -t filecoin/lotus-gateway:<< parameters.tag >> -f Dockerfile.lotus . - docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:<< parameters.tag >> -f Dockerfile.lotus . - if [["[[ ! -z $CIRCLE_SHA1 ]]"]]; then - docker build --target lotus -t filecoin/lotus:$CIRCLE_SHA1 -f Dockerfile.lotus . - docker build --target lotus-gateway -t filecoin/lotus-gateway:$CIRCLE_SHA1 -f Dockerfile.lotus . - docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:$CIRCLE_SHA1 -f Dockerfile.lotus . - fi - if [["[[ ! -z $CIRCLE_TAG ]]"]]; then - docker build --target lotus -t filecoin/lotus:$CIRCLE_TAG -f Dockerfile.lotus . - docker build --target lotus-gateway -t filecoin/lotus-gateway:$CIRCLE_TAG -f Dockerfile.lotus . - docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:$CIRCLE_TAG -f Dockerfile.lotus . - fi - - run: - name: docker push - command: | - docker push filecoin/lotus:<< parameters.tag >> - docker push filecoin/lotus-gateway:<< parameters.tag >> - docker push filecoin/lotus-all-in-one:<< parameters.tag >> - if [["[[ ! -z $CIRCLE_SHA1 ]]"]]; then - docker push filecoin/lotus:$CIRCLE_SHA1 - docker push filecoin/lotus-gateway:$CIRCLE_SHA1 - docker push filecoin/lotus-all-in-one:$CIRCLE_SHA1 - fi - if [["[[ ! -z $CIRCLE_TAG ]]"]]; then - docker push filecoin/lotus:$CIRCLE_TAG - docker push filecoin/lotus-gateway:$CIRCLE_TAG - docker push filecoin/lotus-all-in-one:$CIRCLE_TAG - fi + - docker/check: + docker-username: DOCKERHUB_USERNAME + docker-password: DOCKERHUB_PASSWORD + - when: + condition: + equal: [ mainnet, <> ] + steps: + - when: + condition: <> + steps: + - docker/build: + image: filecoin/<> + extra_build_args: --target <> + tag: <> + - run: + name: Docker push + command: | + docker push filecoin/<>:<> + if [["[[ ! -z $CIRCLE_SHA ]]"]]; then + docker image tag filecoin/<>:<> filecoin/<>:"${CIRCLE_SHA:0:7}" + docker push filecoin/<>:"${CIRCLE_SHA:0:7}" + fi + if [["[[ ! -z $CIRCLE_TAG ]]"]]; then + docker image tag filecoin/<>:<> filecoin/<>:"${CIRCLE_TAG}" + docker push filecoin/<>:"${CIRCLE_TAG}" + fi + - unless: + condition: <> + steps: + - docker/build: + image: filecoin/<> + extra_build_args: --target <> + - when: + condition: + not: + equal: [ mainnet, <> ] + steps: + - when: + condition: <> + steps: + - docker/build: + image: filecoin/<> + extra_build_args: --target <> --build-arg GOFLAGS=-tags=<> + tag: <>-<> + - run: + name: Docker push + command: | + docker push filecoin/<>:<>-<> + if [["[[ ! -z $CIRCLE_SHA ]]"]]; then + docker image tag filecoin/<>:<>-<> filecoin/<>:"${CIRCLE_SHA:0:7}"-<> + docker push filecoin/<>:"${CIRCLE_SHA:0:7}"-<> + fi + if [["[[ ! -z $CIRCLE_TAG ]]"]]; then + docker image tag filecoin/<>:<>-<> filecoin/<>:"${CIRCLE_TAG}"-<> + docker push filecoin/<>:"${CIRCLE_TAG}"-<> + fi + - unless: + condition: <> + steps: + - docker/build: + image: filecoin/<> + extra_build_args: --target <> --build-arg GOFLAGS=-tags=<> workflows: version: 2.1 @@ -748,11 +527,6 @@ workflows: - test-conformance: suite: conformance target: "./conformance" - - test-conformance: - name: test-conformance-bleeding-edge - suite: conformance-bleeding-edge - target: "./conformance" - vectors-branch: specs-actors-v7 release: jobs: @@ -807,45 +581,59 @@ workflows: branches: only: - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - - build-appimage: - name: "Build AppImage" + [[- range .Networks]] + - build-docker: + name: "Docker push (lotus-all-in-one / stable / [[.]])" + image: lotus-all-in-one + channel: stable + network: [[.]] + push: true + filters: + branches: + ignore: + - /.*/ + tags: + only: + - /^v\d+\.\d+\.\d+$/ + - build-docker: + name: "Docker push (lotus-all-in-one / candidate / [[.]])" + image: lotus-all-in-one + channel: candidate + network: [[.]] + push: true + filters: + branches: + ignore: + - /.*/ + tags: + only: + - /^v\d+\.\d+\.\d+-rc\d+$/ + - build-docker: + name: "Docker push (lotus-all-in-one / edge / [[.]])" + image: lotus-all-in-one + channel: master + network: [[.]] + push: true + filters: + branches: + only: + - master + - build-docker: + name: "Docker build (lotus-all-in-one / [[.]])" + image: lotus-all-in-one + network: [[.]] + push: false filters: branches: only: - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - publish: - name: "Publish AppImage" - appimage: true - requires: - - "Build AppImage" - filters: - branches: - ignore: - - /.*/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - build-and-push-image: - name: "Publish ECR (lotus-all-in-one)" - dockerfile: Dockerfile.lotus - path: . - repo: lotus-dev - tag: '${CIRCLE_SHA1:0:8}' - target: lotus-all-in-one - - build-and-push-image: - name: "Publish ECR (lotus-test)" - dockerfile: Dockerfile.lotus - path: . - repo: lotus-test - tag: '${CIRCLE_SHA1:0:8}' - target: lotus-test - - publish-snapcraft: - name: "Publish Snapcraft (lotus-filecoin / candidate)" + [[- end]] + - build-docker: + name: "Docker push (lotus / stable / mainnet)" + image: lotus channel: stable - snap-name: lotus-filecoin + network: mainnet + push: true filters: branches: ignore: @@ -853,10 +641,12 @@ workflows: tags: only: - /^v\d+\.\d+\.\d+$/ - - publish-snapcraft: - name: "Publish Snapcraft (lotus-filecoin / candidate)" + - build-docker: + name: "Docker push (lotus / candidate / mainnet)" + image: lotus channel: candidate - snap-name: lotus-filecoin + network: mainnet + push: true filters: branches: ignore: @@ -864,48 +654,25 @@ workflows: tags: only: - /^v\d+\.\d+\.\d+-rc\d+$/ - - publish-snapcraft: - name: "Publish Snapcraft (lotus / stable)" - channel: stable - snap-name: lotus + - build-docker: + name: "Docker push (lotus / master / mainnet)" + image: lotus + channel: master + network: mainnet + push: true filters: branches: - ignore: - - /.*/ - tags: only: - - /^v\d+\.\d+\.\d+$/ - - publish-snapcraft: - name: "Publish Snapcraft (lotus / candidate)" - channel: candidate - snap-name: lotus + - master + - build-docker: + name: "Docker build (lotus / mainnet)" + image: lotus + network: mainnet + push: false filters: branches: - ignore: - - /.*/ - tags: only: - - /^v\d+\.\d+\.\d+-rc\d+$/ - - publish-dockerhub: - name: "Publish Dockerhub (stable)" - tag: stable - filters: - branches: - ignore: - - /.*/ - tags: - only: - - /^v\d+\.\d+\.\d+$/ - - publish-dockerhub: - name: "Publish Dockerhub (candidate)" - tag: candidate - filters: - branches: - ignore: - - /.*/ - tags: - only: - - /^v\d+\.\d+\.\d+-rc\d+$/ + - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ nightly: triggers: @@ -916,24 +683,11 @@ workflows: only: - master jobs: - - publish-snapcraft: - name: "Publish Snapcraft Nightly (lotus-filecoin / edge)" - channel: edge - snap-name: lotus-filecoin - - publish-snapcraft: - name: "Publish Snapcraft Nightly (lotus / edge)" - channel: edge - snap-name: lotus - - publish-dockerhub: - name: publish-dockerhub-nightly - tag: nightly - biweekly: - triggers: - - schedule: - cron: "0 0 1,15 * *" - filters: - branches: - only: - - master - jobs: - - publish-packer-snap + [[- range .Networks]] + - build-docker: + name: "Docker (lotus-all-in-one / nightly / [[.]])" + image: lotus-all-in-one + channel: nightly + network: [[.]] + push: true + [[- end]] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..cf5b209d7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +chain/actors/builtin/*/v* linguist-generated=true +chain/actors/builtin/*/message* linguist-generated=true diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 70d15c60c..0cba5457e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,10 +13,14 @@ name: "CodeQL" on: push: - branches: [ master ] + branches: + - master + - 'release/*' pull_request: # The branches below must be a subset of the branches above - branches: [ master ] + branches: + - master + - 'release/*' jobs: analyze: @@ -33,17 +37,17 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - - uses: actions/setup-go@v1 + - uses: actions/setup-go@v3 with: - go-version: '1.18.1' + go-version: '1.18.8' # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: - languages: ${{ matrix.language }} + languages: go # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. @@ -52,7 +56,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -66,4 +70,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.gitignore b/.gitignore index 5ff2726f2..2e9dcd0ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -/AppDir -/appimage-builder-cache -*.AppImage /lotus /lotus-miner /lotus-worker @@ -50,3 +47,8 @@ build/builtin-actors/v* build/builtin-actors/*.car dist/ + + +# The following files are checked into git and result +# in dirty git state if removed from the docker context +!extern/filecoin-ffi/rust/filecoin.pc diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 7e96e3ce8..766f4f30a 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -65,6 +65,7 @@ archives: - id: primary format: tar.gz wrap_in_directory: true + name_template: "{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}" files: # this is a dumb but required hack so it doesn't include the default files # https://github.com/goreleaser/goreleaser/issues/602 @@ -105,4 +106,4 @@ checksum: disable: true snapshot: - name_template: "{{ .Tag }}" + name_template: "{{ .Version }}" diff --git a/AppDir/usr/share/icons/icon.svg b/AppDir/usr/share/icons/icon.svg deleted file mode 100644 index da992296a..000000000 --- a/AppDir/usr/share/icons/icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml deleted file mode 100644 index 4f1f56bbb..000000000 --- a/AppImageBuilder.yml +++ /dev/null @@ -1,71 +0,0 @@ -version: 1 -AppDir: - path: ./AppDir - app_info: - id: io.filecoin.lotus - name: Lotus - icon: icon - version: latest - exec: usr/bin/lotus - exec_args: $@ - apt: - arch: amd64 - allow_unauthenticated: true - sources: - - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal main restricted - - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted - - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal universe - - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates universe - - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal multiverse - - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates multiverse - - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-backports main restricted - universe multiverse - - sourceline: deb http://security.ubuntu.com/ubuntu focal-security main restricted - - sourceline: deb http://security.ubuntu.com/ubuntu focal-security universe - - sourceline: deb http://security.ubuntu.com/ubuntu focal-security multiverse - - sourceline: deb https://cli-assets.heroku.com/apt ./ - - sourceline: deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu focal main - - sourceline: deb http://ppa.launchpad.net/git-core/ppa/ubuntu focal main - - sourceline: deb http://archive.canonical.com/ubuntu focal partner - include: - - ocl-icd-libopencl1 - - libhwloc15 - exclude: [] - files: - include: - - /usr/lib/x86_64-linux-gnu/libgcc_s.so.1 - - /usr/lib/x86_64-linux-gnu/libpthread-2.31.so - - /usr/lib/x86_64-linux-gnu/libm-2.31.so - - /usr/lib/x86_64-linux-gnu/libdl-2.31.so - - /usr/lib/x86_64-linux-gnu/libc-2.31.so - - /usr/lib/x86_64-linux-gnu/libudev.so.1.6.17 - exclude: - - usr/share/man - - usr/share/doc/*/README.* - - usr/share/doc/*/changelog.* - - usr/share/doc/*/NEWS.* - - usr/share/doc/*/TODO.* - test: - fedora: - image: appimagecrafters/tests-env:fedora-30 - command: ./AppRun - use_host_x: false - debian: - image: appimagecrafters/tests-env:debian-stable - command: ./AppRun - use_host_x: false - arch: - image: appimagecrafters/tests-env:archlinux-latest - command: ./AppRun - use_host_x: false - centos: - image: appimagecrafters/tests-env:centos-7 - command: ./AppRun - use_host_x: false - ubuntu: - image: appimagecrafters/tests-env:ubuntu-xenial - command: ./AppRun - use_host_x: false -AppImage: - arch: x86_64 - diff --git a/CHANGELOG.md b/CHANGELOG.md index cd450afd2..af84828d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,78 @@ # Lotus changelog +# 1.20.0 / 2023-02-28 + +This is a MANDATORY release of Lotus that delivers the [Hygge network upgrade](https://github.com/filecoin-project/community/discussions/74?sort=top#discussioncomment-4313888), introducing Filecoin network version 18. The centerpiece of the upgrade is the introduction of the [Filecoin Virtual Machine (FVM)’s Milestone 2.1](https://fvm.filecoin.io/), which will allow for EVM-compatible contracts to be deployed on the Filecoin network. This upgrade delivers user-programmablity to the Filecoin network for the first time! + +The Filecoin mainnet is scheduled to upgrade to nv18 at epoch 2683348, on March 14th at 2023-03-14T15:14:00Z. All node operators, including storage providers, must upgrade to this release before that time. Storage providers must update their daemons, miners, market and worker(s)/boost. +At the upgrade, a short migration will run that converts code actors v9 code CIDs to v10 CIDs, and installs the new Ethereum Address Manager singleton (see below). This is expected to be a lightweight migration that causes no service disruption. + +The Hygge upgrade introduces the following Filecoin Improvement Proposals (FIPs), delivered in FVM3 (see FVM [v3.0.0](https://github.com/filecoin-project/ref-fvm/pull/1683)) and builtin-actors v10 (see actors [v10.0.0](https://github.com/filecoin-project/builtin-actors/releases/tag/v10.0.0)): + +- [FIP-0048](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0048.md): f4 Address Class +- [FIP-0049](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0049.md): Actor events +- [FIP-0050](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0050.md): API between user-programmed actors and built-in actors +- [FIP-0054](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0054.md): Filecoin EVM runtime (FEVM) +- [FIP-0055](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0055.md): Supporting Ethereum Accounts, Addresses, and Transactions +- [FIP-0057](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0057.md): Update gas charging schedule and system limits for FEVM + +## Filecoin Ethereum Virtual Machine (FEVM) + +The Filecoin Ethereum Virtual Machine (FEVM) is built on top of the WASM-based execution environment introduced in the Skyr v16 upgrade. The chief feature introduced is the ability for anyone participating in the Filecoin network to deploy their own EVM-compatible contracts onto the blockchain, and invoke them as appropriate. + +## New Built-in Actors + +The FEVM is principally delivered through the introduction of **the new [EVM actor](https://github.com/filecoin-project/builtin-actors/tree/master/actors/evm)**. This actor “represents” smart contracts on the Filecoin network, and includes an interpreter that implements all EVM opcodes as their Filecoin equivalents, and translates state I/O operations to be compatible with Filecoin’s IPLD-based data model. For more on the EVM actors, please see [FIP-0054](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0054.md). + +The creation of EVM actors is managed by **the new** [Ethereum Address Manager actor (EAM)](https://github.com/filecoin-project/builtin-actors/tree/master/actors/eam), a singleton that is invoked in order to deploy EVM actors. In order to make usage of the FEVM as seamless as possible for users familiar with the Ethereum ecosystem, this upgrades also introduces **a dedicated actor to serve as “[Ethereum Accounts](https://github.com/filecoin-project/builtin-actors/tree/master/actors/ethaccount)”**. This actor exists to allow for secp keys to be used in the Ethereum addressing scheme. **The last new built-in actor introduced is [the Placeholder actor](https://github.com/filecoin-project/builtin-actors/tree/master/actors/placeholder)**, a thin “shell” of an actor that can transform into either EVM or EthAccount actors. For more on the EAM, EthAccount, and Placeholder actors, please see [FIP-0055](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0055.md). + +### v10 Built-in actor bundles + +Bundles for all networks (mainnet, calibnet, etc.) are included in the lotus source tree (`build/actors/`) and embedded on build, for v10 actors you can find it [here](https://github.com/filecoin-project/lotus/blob/master/build/actors/v10.tar.zst). +Reminder: Lotus verifies that the bundle CIDs are the right ones upon build & upgrade against the values in `build/builtin_actors_gen.go`, according to the network you are building. You may also check the bundle manifest CID matches the bundle gen-ed values by running `lotus state actor-cids --network-version 18`. + +The manifest CID & full list of actor code CIDs for nv18 using [actor v10](https://github.com/filecoin-project/builtin-actors/releases/tag/v10.0.0) is: + + "_manifest": "bafy2bzacecsuyf7mmvrhkx2evng5gnz5canlnz2fdlzu2lvcgptiq2pzuovos" + "account": "bafk2bzaceampw4romta75hyz5p4cqriypmpbgnkxncgxgqn6zptv5lsp2w2bo" + "cron": "bafk2bzacedcbtsifegiu432m5tysjzkxkmoczxscb6hqpmrr6img7xzdbbs2g" + "datacap": "bafk2bzacealj5uk7wixhvk7l5tnredtelralwnceafqq34nb2lbylhtuyo64u" + "eam": "bafk2bzacedrpm5gbleh4xkyo2jvs7p5g6f34soa6dpv7ashcdgy676snsum6g" + "ethaccount": "bafk2bzaceaqoc5zakbhjxn3jljc4lxnthllzunhdor7sxhwgmskvc6drqc3fa" + "evm": "bafk2bzaceahmzdxhqsm7cu2mexusjp6frm7r4kdesvti3etv5evfqboos2j4g" + "init": "bafk2bzaced2f5rhir3hbpqbz5ght7ohv2kgj42g5ykxrypuo2opxsup3ykwl6" + "multisig": "bafk2bzaceduf3hayh63jnl4z2knxv7cnrdenoubni22fxersc4octlwpxpmy4" + "paymentchannel": "bafk2bzaceartlg4mrbwgzcwric6mtvyawpbgx2xclo2vj27nna57nxynf3pgc" + "placeholder": "bafk2bzacedfvut2myeleyq67fljcrw4kkmn5pb5dpyozovj7jpoez5irnc3ro" + "reward": "bafk2bzacebnhtaejfjtzymyfmbdrfmo7vgj3zsof6zlucbmkhrvcuotw5dxpq" + "storagemarket": "bafk2bzaceclejwjtpu2dhw3qbx6ow7b4pmhwa7ocrbbiqwp36sq5yeg6jz2bc" + "storageminer": "bafk2bzaced4h7noksockro7glnssz2jnmo2rpzd7dvnmfs4p24zx3h6gtx47s" + "storagepower": "bafk2bzacec4ay4crzo73ypmh7o3fjendhbqrxake46bprabw67fvwjz5q6ixq" + "system": "bafk2bzacedakk5nofebyup4m7nvx6djksfwhnxzrfuq4oyemhpl4lllaikr64" + "verifiedregistry": "bafk2bzacedfel6edzqpe5oujno7fog4i526go4dtcs6vwrdtbpy2xq6htvcg6" + +## Node Operators + +FVM has been running in lotus since v1.16.0 and up, and the new FEVM does not increase any node hardware spec requirement. + +With FEVM on Filecoin, we aim to provide full compatibility with the existing EVM ecosystem and its tooling out of the box. +Consequently, lotus now provides a full set of [Ethereum-styled APIs](https://github.com/filecoin-project/lotus/blob/release/v1.20.0/node/impl/full/eth.go) for developers and token holders to interact with the Filecoin network as well. +For full documentation on this new tooling, please see the [Lotus docs website](https://lotus.filecoin.io/lotus/configure/ethereum-rpc/). + +**Enabling Ethereum JSON RPC API** + +Note that Ethereum APIs are only supported in the lotus v1 API, meaning that any node operator who wants to enable Eth API services must be using the v1 API, instead of the v0 API. To enable Eth RPC, simply set `EnableEthRPC` to `true` in your node config.toml file; or set env var `LOTUS_FEVM_ENABLEETHRPC` to `1` before starting your lotus node. + +**Eth tx hash and Filecoin message CID** + +Most of the Eth APIs take Eth accounts and tx has as an input, and they start with `0x` , and that is what Ethereum tooling support. However, in Filecoin, we have Filecoin account formats where things start with `f` (`f410` specifically for eth accounts on Filecoin) and the messages are in the format of CIDs. To enable a smooth developer experience, Lotus internally converts between Ethereum address and Filecoin account address as needed. In addition, lotus also keeps a Eth tx hash <> Filecoin message CID map and stores them in a SQLite database as node sees a FEVM messages. The database is initiated and the maps are populated automatically in `~//sqlite/txhash.db` for any node that as Eth RPC enabled. Node operators can configure how many historical mappings they wanna store by configuring `EthTxHashMappingLifetimeDays` . + +**Events** + +[FIP-0049 introduces actor events](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0049.md) that can be emitted and externally observable during message execution. An `events.db` is created automatically under `~//sqlite` to store these events if the node has Eth RPC enabled. Node operators can configure the events support base on their needs by configuration `Events` configurations. + +Note: All three features are new, and we welcome user feedback, please create an issue if you have any enhancements that you’d like to see! + # 1.19.0 / 2022-12-07 This is an optional feature release of Lotus. This feature release includes the SplitStore beta, the experimental Lotus node cluster feature, as well as numerous enhancments and bugfixes. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..81089517b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,136 @@ +##################################### +FROM golang:1.18.8-buster AS lotus-builder +MAINTAINER Lotus Development Team + +RUN apt-get update && apt-get install -y ca-certificates build-essential clang ocl-icd-opencl-dev ocl-icd-libopencl1 jq libhwloc-dev + +ENV XDG_CACHE_HOME="/tmp" + +### taken from https://github.com/rust-lang/docker-rust/blob/master/1.63.0/buster/Dockerfile +ENV RUSTUP_HOME=/usr/local/rustup \ + CARGO_HOME=/usr/local/cargo \ + PATH=/usr/local/cargo/bin:$PATH \ + RUST_VERSION=1.63.0 + +RUN set -eux; \ + dpkgArch="$(dpkg --print-architecture)"; \ + case "${dpkgArch##*-}" in \ + amd64) rustArch='x86_64-unknown-linux-gnu'; rustupSha256='5cc9ffd1026e82e7fb2eec2121ad71f4b0f044e88bca39207b3f6b769aaa799c' ;; \ + arm64) rustArch='aarch64-unknown-linux-gnu'; rustupSha256='e189948e396d47254103a49c987e7fb0e5dd8e34b200aa4481ecc4b8e41fb929' ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac; \ + url="https://static.rust-lang.org/rustup/archive/1.25.1/${rustArch}/rustup-init"; \ + wget "$url"; \ + echo "${rustupSha256} *rustup-init" | sha256sum -c -; \ + chmod +x rustup-init; \ + ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch}; \ + rm rustup-init; \ + chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \ + rustup --version; \ + cargo --version; \ + rustc --version; + +COPY ./ /opt/filecoin +WORKDIR /opt/filecoin + +RUN scripts/docker-git-state-check.sh + +### make configurable filecoin-ffi build +ARG FFI_BUILD_FROM_SOURCE=0 +ENV FFI_BUILD_FROM_SOURCE=${FFI_BUILD_FROM_SOURCE} + +RUN make clean deps + +ARG RUSTFLAGS="" +ARG GOFLAGS="" + +RUN make buildall + +##################################### +FROM ubuntu:20.04 AS lotus-base +MAINTAINER Lotus Development Team + +# Base resources +COPY --from=lotus-builder /etc/ssl/certs /etc/ssl/certs +COPY --from=lotus-builder /lib/*/libdl.so.2 /lib/ +COPY --from=lotus-builder /lib/*/librt.so.1 /lib/ +COPY --from=lotus-builder /lib/*/libgcc_s.so.1 /lib/ +COPY --from=lotus-builder /lib/*/libutil.so.1 /lib/ +COPY --from=lotus-builder /usr/lib/*/libltdl.so.7 /lib/ +COPY --from=lotus-builder /usr/lib/*/libnuma.so.1 /lib/ +COPY --from=lotus-builder /usr/lib/*/libhwloc.so.5 /lib/ +COPY --from=lotus-builder /usr/lib/*/libOpenCL.so.1 /lib/ + +RUN useradd -r -u 532 -U fc \ + && mkdir -p /etc/OpenCL/vendors \ + && echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd + +##################################### +FROM lotus-base AS lotus +MAINTAINER Lotus Development Team + +COPY --from=lotus-builder /opt/filecoin/lotus /usr/local/bin/ +COPY --from=lotus-builder /opt/filecoin/lotus-shed /usr/local/bin/ +COPY scripts/docker-lotus-entrypoint.sh / + +ARG DOCKER_LOTUS_IMPORT_SNAPSHOT https://snapshots.mainnet.filops.net/minimal/latest +ENV DOCKER_LOTUS_IMPORT_SNAPSHOT ${DOCKER_LOTUS_IMPORT_SNAPSHOT} +ENV FILECOIN_PARAMETER_CACHE /var/tmp/filecoin-proof-parameters +ENV LOTUS_PATH /var/lib/lotus +ENV DOCKER_LOTUS_IMPORT_WALLET "" + +RUN mkdir /var/lib/lotus /var/tmp/filecoin-proof-parameters +RUN chown fc: /var/lib/lotus /var/tmp/filecoin-proof-parameters + +VOLUME /var/lib/lotus +VOLUME /var/tmp/filecoin-proof-parameters + +USER fc + +EXPOSE 1234 + +ENTRYPOINT ["/docker-lotus-entrypoint.sh"] + +CMD ["-help"] + +##################################### +FROM lotus-base AS lotus-all-in-one + +ENV FILECOIN_PARAMETER_CACHE /var/tmp/filecoin-proof-parameters +ENV LOTUS_MINER_PATH /var/lib/lotus-miner +ENV LOTUS_PATH /var/lib/lotus +ENV LOTUS_WORKER_PATH /var/lib/lotus-worker +ENV WALLET_PATH /var/lib/lotus-wallet + +COPY --from=lotus-builder /opt/filecoin/lotus /usr/local/bin/ +COPY --from=lotus-builder /opt/filecoin/lotus-seed /usr/local/bin/ +COPY --from=lotus-builder /opt/filecoin/lotus-shed /usr/local/bin/ +COPY --from=lotus-builder /opt/filecoin/lotus-wallet /usr/local/bin/ +COPY --from=lotus-builder /opt/filecoin/lotus-gateway /usr/local/bin/ +COPY --from=lotus-builder /opt/filecoin/lotus-miner /usr/local/bin/ +COPY --from=lotus-builder /opt/filecoin/lotus-worker /usr/local/bin/ +COPY --from=lotus-builder /opt/filecoin/lotus-stats /usr/local/bin/ +COPY --from=lotus-builder /opt/filecoin/lotus-fountain /usr/local/bin/ + +RUN mkdir /var/tmp/filecoin-proof-parameters +RUN mkdir /var/lib/lotus +RUN mkdir /var/lib/lotus-miner +RUN mkdir /var/lib/lotus-worker +RUN mkdir /var/lib/lotus-wallet +RUN chown fc: /var/tmp/filecoin-proof-parameters +RUN chown fc: /var/lib/lotus +RUN chown fc: /var/lib/lotus-miner +RUN chown fc: /var/lib/lotus-worker +RUN chown fc: /var/lib/lotus-wallet + + +VOLUME /var/tmp/filecoin-proof-parameters +VOLUME /var/lib/lotus +VOLUME /var/lib/lotus-miner +VOLUME /var/lib/lotus-worker +VOLUME /var/lib/lotus-wallet + +EXPOSE 1234 +EXPOSE 2345 +EXPOSE 3456 +EXPOSE 1777 diff --git a/Dockerfile.lotus b/Dockerfile.lotus index 7037a5813..2278e8511 100644 --- a/Dockerfile.lotus +++ b/Dockerfile.lotus @@ -1,4 +1,6 @@ -FROM golang:1.18.1-buster AS builder-deps +##### DEPRECATED + +FROM golang:1.18.8-buster AS builder-deps MAINTAINER Lotus Development Team RUN apt-get update && apt-get install -y ca-certificates build-essential clang ocl-icd-opencl-dev ocl-icd-libopencl1 jq libhwloc-dev diff --git a/GO_VERSION_MIN b/GO_VERSION_MIN index ec6d649be..1a31d398c 100644 --- a/GO_VERSION_MIN +++ b/GO_VERSION_MIN @@ -1 +1 @@ -1.18.1 +1.18.8 diff --git a/Makefile b/Makefile index 8f780a900..d1e7d159a 100644 --- a/Makefile +++ b/Makefile @@ -298,7 +298,7 @@ actors-gen: actors-code-gen fiximports .PHONY: actors-gen bundle-gen: - $(GOCC) run ./gen/bundle + $(GOCC) run ./gen/bundle $(VERSION) $(RELEASE) $(RELEASE_OVERRIDES) $(GOCC) fmt ./build/... .PHONY: bundle-gen @@ -354,7 +354,7 @@ docsgen-openrpc-gateway: docsgen-openrpc-bin fiximports: ./scripts/fiximports -gen: actors-code-gen type-gen cfgdoc-gen docsgen api-gen circleci bundle-gen fiximports +gen: actors-code-gen type-gen cfgdoc-gen docsgen api-gen circleci fiximports @echo ">>> IF YOU'VE MODIFIED THE CLI OR CONFIG, REMEMBER TO ALSO MAKE docsgen-cli" .PHONY: gen @@ -366,7 +366,7 @@ snap: lotus lotus-miner lotus-worker # separate from gen because it needs binaries docsgen-cli: lotus lotus-miner lotus-worker - python ./scripts/generate-lotus-cli.py + python3 ./scripts/generate-lotus-cli.py ./lotus config default > documentation/en/default-lotus-config.toml ./lotus-miner config default > documentation/en/default-lotus-miner-config.toml .PHONY: docsgen-cli diff --git a/README.md b/README.md index 23f3eb2d9..76cac2c7e 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ - +

@@ -71,10 +71,10 @@ For other distributions you can find the required dependencies [here.](https://l #### Go -To build Lotus, you need a working installation of [Go 1.18.1 or higher](https://golang.org/dl/): +To build Lotus, you need a working installation of [Go 1.18.8 or higher](https://golang.org/dl/): ```bash -wget -c https://golang.org/dl/go1.18.1.linux-amd64.tar.gz -O - | sudo tar -xz -C /usr/local +wget -c https://golang.org/dl/go1.18.8.linux-amd64.tar.gz -O - | sudo tar -xz -C /usr/local ``` **TIP:** diff --git a/api/api_full.go b/api/api_full.go index 0c281c12d..1f7c38edf 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -7,8 +7,8 @@ import ( "time" "github.com/google/uuid" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-libp2p/core/peer" "github.com/filecoin-project/go-address" @@ -16,6 +16,7 @@ import ( datatransfer "github.com/filecoin-project/go-data-transfer" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-jsonrpc" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/builtin/v8/paych" @@ -31,6 +32,7 @@ import ( lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors/builtin/power" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/repo/imports" ) @@ -151,7 +153,7 @@ type FullNode interface { // ChainGetPath returns a set of revert/apply operations needed to get from // one tipset to another, for example: - //``` + // ``` // to // ^ // from tAA @@ -160,7 +162,7 @@ type FullNode interface { // ^---*--^ // ^ // tRR - //``` + // ``` // Would return `[revert(tBA), apply(tAB), apply(tAA)]` ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*HeadChange, error) //perm:read @@ -182,6 +184,9 @@ type FullNode interface { // ChainBlockstoreInfo returns some basic information about the blockstore ChainBlockstoreInfo(context.Context) (map[string]interface{}, error) //perm:read + // ChainGetEvents returns the events under an event AMT root CID. + ChainGetEvents(context.Context, cid.Cid) ([]types.Event, error) //perm:read + // GasEstimateFeeCap estimates gas fee cap GasEstimateFeeCap(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error) //perm:read @@ -388,12 +393,12 @@ type FullNode interface { ClientCancelRetrievalDeal(ctx context.Context, dealid retrievalmarket.DealID) error //perm:write // ClientUnimport removes references to the specified file from filestore - //ClientUnimport(path string) + // ClientUnimport(path string) // ClientListImports lists imported files and their root CIDs ClientListImports(ctx context.Context) ([]Import, error) //perm:write - //ClientListAsks() []Ask + // ClientListAsks() []Ask // MethodGroup: State // The State methods are used to query, inspect, and interact with chain state. @@ -640,14 +645,14 @@ type FullNode interface { // It takes the following params: , , MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) //perm:read - //MsigGetPending returns pending transactions for the given multisig - //wallet. Once pending transactions are fully approved, they will no longer - //appear here. + // MsigGetPending returns pending transactions for the given multisig + // wallet. Once pending transactions are fully approved, they will no longer + // appear here. MsigGetPending(context.Context, address.Address, types.TipSetKey) ([]*MsigTransaction, error) //perm:read // MsigCreate creates a multisig wallet // It takes the following params: , , - //, , + // , , MsigCreate(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (*MessagePrototype, error) //perm:sign // MsigPropose proposes a multisig message @@ -759,6 +764,86 @@ type FullNode interface { NodeStatus(ctx context.Context, inclChainStatus bool) (NodeStatus, error) //perm:read + // MethodGroup: Eth + // These methods are used for Ethereum-compatible JSON-RPC calls + // + // EthAccounts will always return [] since we don't expect Lotus to manage private keys + EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) //perm:read + // EthAddressToFilecoinAddress converts an EthAddress into an f410 Filecoin Address + EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) //perm:read + // FilecoinAddressToEthAddress converts an f410 or f0 Filecoin Address to an EthAddress + FilecoinAddressToEthAddress(ctx context.Context, filecoinAddress address.Address) (ethtypes.EthAddress, error) //perm:read + // EthBlockNumber returns the height of the latest (heaviest) TipSet + EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) //perm:read + // EthGetBlockTransactionCountByNumber returns the number of messages in the TipSet + EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) //perm:read + // EthGetBlockTransactionCountByHash returns the number of messages in the TipSet + EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) //perm:read + + EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read + EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read + EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read + EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) //perm:read + EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) //perm:read + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) //perm:read + EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read + EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read + EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read + + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) //perm:read + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) //perm:read + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) //perm:read + EthChainId(ctx context.Context) (ethtypes.EthUint64, error) //perm:read + NetVersion(ctx context.Context) (string, error) //perm:read + NetListening(ctx context.Context) (bool, error) //perm:read + EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) //perm:read + EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) //perm:read + EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) //perm:read + + EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) //perm:read + EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) //perm:read + EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) //perm:read + + EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) //perm:read + + // Returns event logs matching given filter spec. + EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) //perm:read + + // Polling method for a filter, returns event logs which occurred since last poll. + // (requires write perm since timestamp of last filter execution will be written) + EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) //perm:write + + // Returns event logs matching filter with given id. + // (requires write perm since timestamp of last filter execution will be written) + EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) //perm:write + + // Installs a persistent filter based on given filter spec. + EthNewFilter(ctx context.Context, filter *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) //perm:write + + // Installs a persistent filter to notify when a new block arrives. + EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) //perm:write + + // Installs a persistent filter to notify when new messages arrive in the message pool. + EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) //perm:write + + // Uninstalls a filter with given id. + EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) //perm:write + + // Subscribe to different event types using websockets + // eventTypes is one or more of: + // - newHeads: notify when new blocks arrive. + // - pendingTransactions: notify when new messages arrive in the message pool. + // - logs: notify new event logs that match a criteria + // params contains additional parameters used with the log event type + // The client will receive a stream of EthSubscriptionResponse values until EthUnsubscribe is called. + EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) //perm:write + + // Unsubscribe from a websocket subscription + EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) //perm:write + + // Returns the client version + Web3ClientVersion(ctx context.Context) (string, error) //perm:read + // CreateBackup creates node backup onder the specified file name. The // method requires that the lotus daemon is running with the // LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that @@ -769,6 +854,12 @@ type FullNode interface { RaftLeader(ctx context.Context) (peer.ID, error) //perm:read } +// reverse interface to the client, called after EthSubscribe +type EthSubscriber interface { + // note: the parameter is ethtypes.EthSubscriptionResponse serialized as json object + EthSubscription(ctx context.Context, r jsonrpc.RawParams) error // rpc_method:eth_subscription notify:true +} + type StorageAsk struct { Response *storagemarket.StorageAsk @@ -1252,3 +1343,21 @@ type PruneOpts struct { MovingGC bool RetainState int64 } + +type EthTxReceipt struct { + TransactionHash ethtypes.EthHash `json:"transactionHash"` + TransactionIndex ethtypes.EthUint64 `json:"transactionIndex"` + BlockHash ethtypes.EthHash `json:"blockHash"` + BlockNumber ethtypes.EthUint64 `json:"blockNumber"` + From ethtypes.EthAddress `json:"from"` + To *ethtypes.EthAddress `json:"to"` + StateRoot ethtypes.EthHash `json:"root"` + Status ethtypes.EthUint64 `json:"status"` + ContractAddress *ethtypes.EthAddress `json:"contractAddress"` + CumulativeGasUsed ethtypes.EthUint64 `json:"cumulativeGasUsed"` + GasUsed ethtypes.EthUint64 `json:"gasUsed"` + EffectiveGasPrice ethtypes.EthBigInt `json:"effectiveGasPrice"` + LogsBloom ethtypes.EthBytes `json:"logsBloom"` + Logs []ethtypes.EthLog `json:"logs"` + Type ethtypes.EthUint64 `json:"type"` +} diff --git a/api/api_gateway.go b/api/api_gateway.go index b95299493..2e877fb1a 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -3,16 +3,18 @@ package api import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/builtin/v9/miner" "github.com/filecoin-project/go-state-types/dline" apitypes "github.com/filecoin-project/lotus/api/types" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" ) // MODIFYING THE API INTERFACE @@ -69,4 +71,41 @@ type Gateway interface { WalletBalance(context.Context, address.Address) (types.BigInt, error) Version(context.Context) (APIVersion, error) Discover(context.Context) (apitypes.OpenRPCDocument, error) + + EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) + EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) + EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) + EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) + EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) + EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) + EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) + EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) + EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) + EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) + EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) + EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) + EthChainId(ctx context.Context) (ethtypes.EthUint64, error) + NetVersion(ctx context.Context) (string, error) + NetListening(ctx context.Context) (bool, error) + EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) + EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) + EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) + EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) + EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) + EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) + EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) + EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) + EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) + EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) + EthNewFilter(ctx context.Context, filter *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) + EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) + EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) + EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) + EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) + EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) + Web3ClientVersion(ctx context.Context) (string, error) } diff --git a/api/api_storage.go b/api/api_storage.go index 9a6eeb230..0c00b9b93 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -22,7 +22,7 @@ import ( "github.com/filecoin-project/go-state-types/builtin/v9/miner" abinetwork "github.com/filecoin-project/go-state-types/network" - "github.com/filecoin-project/lotus/chain/actors/builtin" + builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/storage/pipeline/sealiface" "github.com/filecoin-project/lotus/storage/sealer/fsutil" @@ -152,7 +152,7 @@ type StorageMiner interface { WorkerStats(context.Context) (map[uuid.UUID]storiface.WorkerStats, error) //perm:admin WorkerJobs(context.Context) (map[uuid.UUID][]storiface.WorkerJob, error) //perm:admin - //storiface.WorkerReturn + // storiface.WorkerReturn ReturnDataCid(ctx context.Context, callID storiface.CallID, pi abi.PieceInfo, err *storiface.CallError) error //perm:admin retry:true ReturnAddPiece(ctx context.Context, callID storiface.CallID, pi abi.PieceInfo, err *storiface.CallError) error //perm:admin retry:true ReturnSealPreCommit1(ctx context.Context, callID storiface.CallID, p1o storiface.PreCommit1Out, err *storiface.CallError) error //perm:admin retry:true @@ -175,7 +175,7 @@ type StorageMiner interface { // SealingSchedDiag dumps internal sealing scheduler state SealingSchedDiag(ctx context.Context, doSched bool) (interface{}, error) //perm:admin SealingAbort(ctx context.Context, call storiface.CallID) error //perm:admin - //SealingSchedRemove removes a request from sealing pipeline + // SealingSchedRemove removes a request from sealing pipeline SealingRemoveRequest(ctx context.Context, schedId uuid.UUID) error //perm:admin // paths.SectorIndex @@ -322,7 +322,7 @@ type StorageMiner interface { CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storiface.SectorRef) (map[abi.SectorNumber]string, error) //perm:admin - ComputeProof(ctx context.Context, ssi []builtin.ExtendedSectorInfo, rand abi.PoStRandomness, poStEpoch abi.ChainEpoch, nv abinetwork.Version) ([]builtin.PoStProof, error) //perm:read + ComputeProof(ctx context.Context, ssi []builtinactors.ExtendedSectorInfo, rand abi.PoStRandomness, poStEpoch abi.ChainEpoch, nv abinetwork.Version) ([]builtinactors.PoStProof, error) //perm:read // RecoverFault can be used to declare recoveries manually. It sends messages // to the miner actor with details of recovered sectors and returns the CID of messages. It honors the @@ -417,6 +417,10 @@ func (st *SealSeed) Equals(ost *SealSeed) bool { type SectorState string +func (s *SectorState) String() string { + return string(*s) +} + type AddrUse int const ( diff --git a/api/api_worker.go b/api/api_worker.go index cca929d39..197ca898d 100644 --- a/api/api_worker.go +++ b/api/api_worker.go @@ -39,13 +39,13 @@ type Worker interface { SealPreCommit2(ctx context.Context, sector storiface.SectorRef, pc1o storiface.PreCommit1Out) (storiface.CallID, error) //perm:admin SealCommit1(ctx context.Context, sector storiface.SectorRef, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, cids storiface.SectorCids) (storiface.CallID, error) //perm:admin SealCommit2(ctx context.Context, sector storiface.SectorRef, c1o storiface.Commit1Out) (storiface.CallID, error) //perm:admin - FinalizeSector(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) //perm:admin - FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) //perm:admin + FinalizeSector(ctx context.Context, sector storiface.SectorRef) (storiface.CallID, error) //perm:admin + FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef) (storiface.CallID, error) //perm:admin ReplicaUpdate(ctx context.Context, sector storiface.SectorRef, pieces []abi.PieceInfo) (storiface.CallID, error) //perm:admin ProveReplicaUpdate1(ctx context.Context, sector storiface.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid) (storiface.CallID, error) //perm:admin ProveReplicaUpdate2(ctx context.Context, sector storiface.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid, vanillaProofs storiface.ReplicaVanillaProofs) (storiface.CallID, error) //perm:admin GenerateSectorKeyFromData(ctx context.Context, sector storiface.SectorRef, commD cid.Cid) (storiface.CallID, error) //perm:admin - ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, safeToFree []storiface.Range) (storiface.CallID, error) //perm:admin + ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) //perm:admin MoveStorage(ctx context.Context, sector storiface.SectorRef, types storiface.SectorFileType) (storiface.CallID, error) //perm:admin UnsealPiece(context.Context, storiface.SectorRef, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) (storiface.CallID, error) //perm:admin Fetch(context.Context, storiface.SectorRef, storiface.SectorFileType, storiface.PathType, storiface.AcquireMode) (storiface.CallID, error) //perm:admin diff --git a/api/client/client.go b/api/client/client.go index 32583097e..8b159c5b1 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -35,10 +35,10 @@ func NewFullNodeRPCV0(ctx context.Context, addr string, requestHeader http.Heade } // NewFullNodeRPCV1 creates a new http jsonrpc client. -func NewFullNodeRPCV1(ctx context.Context, addr string, requestHeader http.Header) (api.FullNode, jsonrpc.ClientCloser, error) { +func NewFullNodeRPCV1(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (api.FullNode, jsonrpc.ClientCloser, error) { var res v1api.FullNodeStruct closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", - api.GetInternalStructs(&res), requestHeader, jsonrpc.WithErrors(api.RPCErrors)) + api.GetInternalStructs(&res), requestHeader, append([]jsonrpc.Option{jsonrpc.WithErrors(api.RPCErrors)}, opts...)...) return &res, closer, err } diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index 96fc068cc..65d71d208 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -14,9 +14,9 @@ import ( "unicode" "github.com/google/uuid" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" "github.com/ipfs/go-graphsync" + blocks "github.com/ipfs/go-libipfs/blocks" textselector "github.com/ipld/go-ipld-selector-text-lite" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/metrics" @@ -41,6 +41,7 @@ import ( "github.com/filecoin-project/lotus/api/v0api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/repo/imports" sealing "github.com/filecoin-project/lotus/storage/pipeline" @@ -68,6 +69,7 @@ func init() { } ExampleValues[reflect.TypeOf(c)] = c + ExampleValues[reflect.TypeOf(&c)] = &c c2, err := cid.Decode("bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve") if err != nil { @@ -298,7 +300,8 @@ func init() { "title": "Lotus RPC API", "version": "1.2.1/generated=2020-11-22T08:22:42-06:00", }, - "methods": []interface{}{}}, + "methods": []interface{}{}, + }, ) addExample(api.CheckStatusCode(0)) @@ -335,7 +338,8 @@ func init() { NumConnsInbound: 3, NumConnsOutbound: 4, NumFD: 5, - }}) + }, + }) addExample(api.NetLimit{ Memory: 123, StreamsInbound: 1, @@ -346,6 +350,7 @@ func init() { Conns: 4, FD: 5, }) + addExample(map[string]bitfield.BitField{ "": bitfield.NewFromSet([]uint64{5, 6, 7, 10}), }) @@ -365,11 +370,40 @@ func init() { Headers: nil, }, }) + + ethint := ethtypes.EthUint64(5) + addExample(ethint) + addExample(ðint) + + ethaddr, _ := ethtypes.ParseEthAddress("0x5CbEeCF99d3fDB3f25E309Cc264f240bb0664031") + addExample(ethaddr) + addExample(ðaddr) + + ethhash, _ := ethtypes.EthHashFromCid(c) + addExample(ethhash) + addExample(ðhash) + + ethFeeHistoryReward := [][]ethtypes.EthBigInt{} + addExample(ðFeeHistoryReward) + addExample(&uuid.UUID{}) + + filterid := ethtypes.EthFilterID(ethhash) + addExample(filterid) + addExample(&filterid) + + subid := ethtypes.EthSubscriptionID(ethhash) + addExample(subid) + addExample(&subid) + + pstring := func(s string) *string { return &s } + addExample(ðtypes.EthFilterSpec{ + FromBlock: pstring("2301220"), + Address: []ethtypes.EthAddress{ethaddr}, + }) } func GetAPIType(name, pkg string) (i interface{}, t reflect.Type, permStruct []reflect.Type) { - switch pkg { case "api": // latest switch name { @@ -439,7 +473,7 @@ func ExampleValue(method string, t, parent reflect.Type) interface{} { case reflect.Ptr: if t.Elem().Kind() == reflect.Struct { es := exampleStruct(method, t.Elem(), t) - //ExampleValues[t] = es + ExampleValues[t] = es return es } case reflect.Interface: @@ -456,7 +490,8 @@ func exampleStruct(method string, t, parent reflect.Type) interface{} { if f.Type == parent { continue } - if strings.Title(f.Name) == f.Name { + + if f.IsExported() { ns.Elem().Field(i).Set(reflect.ValueOf(ExampleValue(method, f.Type, t))) } } diff --git a/api/eth_aliases.go b/api/eth_aliases.go new file mode 100644 index 000000000..ccf0317d9 --- /dev/null +++ b/api/eth_aliases.go @@ -0,0 +1,46 @@ +package api + +import apitypes "github.com/filecoin-project/lotus/api/types" + +func CreateEthRPCAliases(as apitypes.Aliaser) { + // TODO: maybe use reflect to automatically register all the eth aliases + as.AliasMethod("eth_accounts", "Filecoin.EthAccounts") + as.AliasMethod("eth_blockNumber", "Filecoin.EthBlockNumber") + as.AliasMethod("eth_getBlockTransactionCountByNumber", "Filecoin.EthGetBlockTransactionCountByNumber") + as.AliasMethod("eth_getBlockTransactionCountByHash", "Filecoin.EthGetBlockTransactionCountByHash") + + as.AliasMethod("eth_getBlockByHash", "Filecoin.EthGetBlockByHash") + as.AliasMethod("eth_getBlockByNumber", "Filecoin.EthGetBlockByNumber") + as.AliasMethod("eth_getTransactionByHash", "Filecoin.EthGetTransactionByHash") + as.AliasMethod("eth_getTransactionCount", "Filecoin.EthGetTransactionCount") + as.AliasMethod("eth_getTransactionReceipt", "Filecoin.EthGetTransactionReceipt") + as.AliasMethod("eth_getTransactionByBlockHashAndIndex", "Filecoin.EthGetTransactionByBlockHashAndIndex") + as.AliasMethod("eth_getTransactionByBlockNumberAndIndex", "Filecoin.EthGetTransactionByBlockNumberAndIndex") + + as.AliasMethod("eth_getCode", "Filecoin.EthGetCode") + as.AliasMethod("eth_getStorageAt", "Filecoin.EthGetStorageAt") + as.AliasMethod("eth_getBalance", "Filecoin.EthGetBalance") + as.AliasMethod("eth_chainId", "Filecoin.EthChainId") + as.AliasMethod("eth_feeHistory", "Filecoin.EthFeeHistory") + as.AliasMethod("eth_protocolVersion", "Filecoin.EthProtocolVersion") + as.AliasMethod("eth_maxPriorityFeePerGas", "Filecoin.EthMaxPriorityFeePerGas") + as.AliasMethod("eth_gasPrice", "Filecoin.EthGasPrice") + as.AliasMethod("eth_sendRawTransaction", "Filecoin.EthSendRawTransaction") + as.AliasMethod("eth_estimateGas", "Filecoin.EthEstimateGas") + as.AliasMethod("eth_call", "Filecoin.EthCall") + + as.AliasMethod("eth_getLogs", "Filecoin.EthGetLogs") + as.AliasMethod("eth_getFilterChanges", "Filecoin.EthGetFilterChanges") + as.AliasMethod("eth_getFilterLogs", "Filecoin.EthGetFilterLogs") + as.AliasMethod("eth_newFilter", "Filecoin.EthNewFilter") + as.AliasMethod("eth_newBlockFilter", "Filecoin.EthNewBlockFilter") + as.AliasMethod("eth_newPendingTransactionFilter", "Filecoin.EthNewPendingTransactionFilter") + as.AliasMethod("eth_uninstallFilter", "Filecoin.EthUninstallFilter") + as.AliasMethod("eth_subscribe", "Filecoin.EthSubscribe") + as.AliasMethod("eth_unsubscribe", "Filecoin.EthUnsubscribe") + + as.AliasMethod("net_version", "Filecoin.NetVersion") + as.AliasMethod("net_listening", "Filecoin.NetListening") + + as.AliasMethod("web3_clientVersion", "Filecoin.Web3ClientVersion") +} diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 4a7cbe54a..370a213a0 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -12,8 +12,8 @@ import ( gomock "github.com/golang/mock/gomock" uuid "github.com/google/uuid" - blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" metrics "github.com/libp2p/go-libp2p/core/metrics" network0 "github.com/libp2p/go-libp2p/core/network" peer "github.com/libp2p/go-libp2p/core/peer" @@ -23,6 +23,7 @@ import ( bitfield "github.com/filecoin-project/go-bitfield" datatransfer "github.com/filecoin-project/go-data-transfer" retrievalmarket "github.com/filecoin-project/go-fil-markets/retrievalmarket" + jsonrpc "github.com/filecoin-project/go-jsonrpc" auth "github.com/filecoin-project/go-jsonrpc/auth" abi "github.com/filecoin-project/go-state-types/abi" big "github.com/filecoin-project/go-state-types/big" @@ -37,6 +38,7 @@ import ( apitypes "github.com/filecoin-project/lotus/api/types" miner0 "github.com/filecoin-project/lotus/chain/actors/builtin/miner" types "github.com/filecoin-project/lotus/chain/types" + ethtypes "github.com/filecoin-project/lotus/chain/types/ethtypes" alerting "github.com/filecoin-project/lotus/journal/alerting" dtypes "github.com/filecoin-project/lotus/node/modules/dtypes" imports "github.com/filecoin-project/lotus/node/repo/imports" @@ -183,6 +185,21 @@ func (mr *MockFullNodeMockRecorder) ChainGetBlockMessages(arg0, arg1 interface{} return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetBlockMessages", reflect.TypeOf((*MockFullNode)(nil).ChainGetBlockMessages), arg0, arg1) } +// ChainGetEvents mocks base method. +func (m *MockFullNode) ChainGetEvents(arg0 context.Context, arg1 cid.Cid) ([]types.Event, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChainGetEvents", arg0, arg1) + ret0, _ := ret[0].([]types.Event) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ChainGetEvents indicates an expected call of ChainGetEvents. +func (mr *MockFullNodeMockRecorder) ChainGetEvents(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetEvents", reflect.TypeOf((*MockFullNode)(nil).ChainGetEvents), arg0, arg1) +} + // ChainGetGenesis mocks base method. func (m *MockFullNode) ChainGetGenesis(arg0 context.Context) (*types.TipSet, error) { m.ctrl.T.Helper() @@ -921,6 +938,531 @@ func (mr *MockFullNodeMockRecorder) Discover(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Discover", reflect.TypeOf((*MockFullNode)(nil).Discover), arg0) } +// EthAccounts mocks base method. +func (m *MockFullNode) EthAccounts(arg0 context.Context) ([]ethtypes.EthAddress, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthAccounts", arg0) + ret0, _ := ret[0].([]ethtypes.EthAddress) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthAccounts indicates an expected call of EthAccounts. +func (mr *MockFullNodeMockRecorder) EthAccounts(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthAccounts", reflect.TypeOf((*MockFullNode)(nil).EthAccounts), arg0) +} + +// EthAddressToFilecoinAddress mocks base method. +func (m *MockFullNode) EthAddressToFilecoinAddress(arg0 context.Context, arg1 ethtypes.EthAddress) (address.Address, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthAddressToFilecoinAddress", arg0, arg1) + ret0, _ := ret[0].(address.Address) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthAddressToFilecoinAddress indicates an expected call of EthAddressToFilecoinAddress. +func (mr *MockFullNodeMockRecorder) EthAddressToFilecoinAddress(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthAddressToFilecoinAddress", reflect.TypeOf((*MockFullNode)(nil).EthAddressToFilecoinAddress), arg0, arg1) +} + +// EthBlockNumber mocks base method. +func (m *MockFullNode) EthBlockNumber(arg0 context.Context) (ethtypes.EthUint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthBlockNumber", arg0) + ret0, _ := ret[0].(ethtypes.EthUint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthBlockNumber indicates an expected call of EthBlockNumber. +func (mr *MockFullNodeMockRecorder) EthBlockNumber(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthBlockNumber", reflect.TypeOf((*MockFullNode)(nil).EthBlockNumber), arg0) +} + +// EthCall mocks base method. +func (m *MockFullNode) EthCall(arg0 context.Context, arg1 ethtypes.EthCall, arg2 string) (ethtypes.EthBytes, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthCall", arg0, arg1, arg2) + ret0, _ := ret[0].(ethtypes.EthBytes) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthCall indicates an expected call of EthCall. +func (mr *MockFullNodeMockRecorder) EthCall(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthCall", reflect.TypeOf((*MockFullNode)(nil).EthCall), arg0, arg1, arg2) +} + +// EthChainId mocks base method. +func (m *MockFullNode) EthChainId(arg0 context.Context) (ethtypes.EthUint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthChainId", arg0) + ret0, _ := ret[0].(ethtypes.EthUint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthChainId indicates an expected call of EthChainId. +func (mr *MockFullNodeMockRecorder) EthChainId(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthChainId", reflect.TypeOf((*MockFullNode)(nil).EthChainId), arg0) +} + +// EthEstimateGas mocks base method. +func (m *MockFullNode) EthEstimateGas(arg0 context.Context, arg1 ethtypes.EthCall) (ethtypes.EthUint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthEstimateGas", arg0, arg1) + ret0, _ := ret[0].(ethtypes.EthUint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthEstimateGas indicates an expected call of EthEstimateGas. +func (mr *MockFullNodeMockRecorder) EthEstimateGas(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthEstimateGas", reflect.TypeOf((*MockFullNode)(nil).EthEstimateGas), arg0, arg1) +} + +// EthFeeHistory mocks base method. +func (m *MockFullNode) EthFeeHistory(arg0 context.Context, arg1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthFeeHistory", arg0, arg1) + ret0, _ := ret[0].(ethtypes.EthFeeHistory) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthFeeHistory indicates an expected call of EthFeeHistory. +func (mr *MockFullNodeMockRecorder) EthFeeHistory(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthFeeHistory", reflect.TypeOf((*MockFullNode)(nil).EthFeeHistory), arg0, arg1) +} + +// EthGasPrice mocks base method. +func (m *MockFullNode) EthGasPrice(arg0 context.Context) (ethtypes.EthBigInt, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGasPrice", arg0) + ret0, _ := ret[0].(ethtypes.EthBigInt) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGasPrice indicates an expected call of EthGasPrice. +func (mr *MockFullNodeMockRecorder) EthGasPrice(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGasPrice", reflect.TypeOf((*MockFullNode)(nil).EthGasPrice), arg0) +} + +// EthGetBalance mocks base method. +func (m *MockFullNode) EthGetBalance(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 string) (ethtypes.EthBigInt, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetBalance", arg0, arg1, arg2) + ret0, _ := ret[0].(ethtypes.EthBigInt) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetBalance indicates an expected call of EthGetBalance. +func (mr *MockFullNodeMockRecorder) EthGetBalance(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBalance", reflect.TypeOf((*MockFullNode)(nil).EthGetBalance), arg0, arg1, arg2) +} + +// EthGetBlockByHash mocks base method. +func (m *MockFullNode) EthGetBlockByHash(arg0 context.Context, arg1 ethtypes.EthHash, arg2 bool) (ethtypes.EthBlock, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetBlockByHash", arg0, arg1, arg2) + ret0, _ := ret[0].(ethtypes.EthBlock) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetBlockByHash indicates an expected call of EthGetBlockByHash. +func (mr *MockFullNodeMockRecorder) EthGetBlockByHash(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockByHash", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockByHash), arg0, arg1, arg2) +} + +// EthGetBlockByNumber mocks base method. +func (m *MockFullNode) EthGetBlockByNumber(arg0 context.Context, arg1 string, arg2 bool) (ethtypes.EthBlock, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetBlockByNumber", arg0, arg1, arg2) + ret0, _ := ret[0].(ethtypes.EthBlock) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetBlockByNumber indicates an expected call of EthGetBlockByNumber. +func (mr *MockFullNodeMockRecorder) EthGetBlockByNumber(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockByNumber", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockByNumber), arg0, arg1, arg2) +} + +// EthGetBlockTransactionCountByHash mocks base method. +func (m *MockFullNode) EthGetBlockTransactionCountByHash(arg0 context.Context, arg1 ethtypes.EthHash) (ethtypes.EthUint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetBlockTransactionCountByHash", arg0, arg1) + ret0, _ := ret[0].(ethtypes.EthUint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetBlockTransactionCountByHash indicates an expected call of EthGetBlockTransactionCountByHash. +func (mr *MockFullNodeMockRecorder) EthGetBlockTransactionCountByHash(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockTransactionCountByHash", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockTransactionCountByHash), arg0, arg1) +} + +// EthGetBlockTransactionCountByNumber mocks base method. +func (m *MockFullNode) EthGetBlockTransactionCountByNumber(arg0 context.Context, arg1 ethtypes.EthUint64) (ethtypes.EthUint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetBlockTransactionCountByNumber", arg0, arg1) + ret0, _ := ret[0].(ethtypes.EthUint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetBlockTransactionCountByNumber indicates an expected call of EthGetBlockTransactionCountByNumber. +func (mr *MockFullNodeMockRecorder) EthGetBlockTransactionCountByNumber(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockTransactionCountByNumber", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockTransactionCountByNumber), arg0, arg1) +} + +// EthGetCode mocks base method. +func (m *MockFullNode) EthGetCode(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 string) (ethtypes.EthBytes, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetCode", arg0, arg1, arg2) + ret0, _ := ret[0].(ethtypes.EthBytes) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetCode indicates an expected call of EthGetCode. +func (mr *MockFullNodeMockRecorder) EthGetCode(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetCode", reflect.TypeOf((*MockFullNode)(nil).EthGetCode), arg0, arg1, arg2) +} + +// EthGetFilterChanges mocks base method. +func (m *MockFullNode) EthGetFilterChanges(arg0 context.Context, arg1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetFilterChanges", arg0, arg1) + ret0, _ := ret[0].(*ethtypes.EthFilterResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetFilterChanges indicates an expected call of EthGetFilterChanges. +func (mr *MockFullNodeMockRecorder) EthGetFilterChanges(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetFilterChanges", reflect.TypeOf((*MockFullNode)(nil).EthGetFilterChanges), arg0, arg1) +} + +// EthGetFilterLogs mocks base method. +func (m *MockFullNode) EthGetFilterLogs(arg0 context.Context, arg1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetFilterLogs", arg0, arg1) + ret0, _ := ret[0].(*ethtypes.EthFilterResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetFilterLogs indicates an expected call of EthGetFilterLogs. +func (mr *MockFullNodeMockRecorder) EthGetFilterLogs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetFilterLogs", reflect.TypeOf((*MockFullNode)(nil).EthGetFilterLogs), arg0, arg1) +} + +// EthGetLogs mocks base method. +func (m *MockFullNode) EthGetLogs(arg0 context.Context, arg1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetLogs", arg0, arg1) + ret0, _ := ret[0].(*ethtypes.EthFilterResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetLogs indicates an expected call of EthGetLogs. +func (mr *MockFullNodeMockRecorder) EthGetLogs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetLogs", reflect.TypeOf((*MockFullNode)(nil).EthGetLogs), arg0, arg1) +} + +// EthGetMessageCidByTransactionHash mocks base method. +func (m *MockFullNode) EthGetMessageCidByTransactionHash(arg0 context.Context, arg1 *ethtypes.EthHash) (*cid.Cid, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetMessageCidByTransactionHash", arg0, arg1) + ret0, _ := ret[0].(*cid.Cid) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetMessageCidByTransactionHash indicates an expected call of EthGetMessageCidByTransactionHash. +func (mr *MockFullNodeMockRecorder) EthGetMessageCidByTransactionHash(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetMessageCidByTransactionHash", reflect.TypeOf((*MockFullNode)(nil).EthGetMessageCidByTransactionHash), arg0, arg1) +} + +// EthGetStorageAt mocks base method. +func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 string) (ethtypes.EthBytes, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetStorageAt", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(ethtypes.EthBytes) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetStorageAt indicates an expected call of EthGetStorageAt. +func (mr *MockFullNodeMockRecorder) EthGetStorageAt(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetStorageAt", reflect.TypeOf((*MockFullNode)(nil).EthGetStorageAt), arg0, arg1, arg2, arg3) +} + +// EthGetTransactionByBlockHashAndIndex mocks base method. +func (m *MockFullNode) EthGetTransactionByBlockHashAndIndex(arg0 context.Context, arg1 ethtypes.EthHash, arg2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetTransactionByBlockHashAndIndex", arg0, arg1, arg2) + ret0, _ := ret[0].(ethtypes.EthTx) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetTransactionByBlockHashAndIndex indicates an expected call of EthGetTransactionByBlockHashAndIndex. +func (mr *MockFullNodeMockRecorder) EthGetTransactionByBlockHashAndIndex(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionByBlockHashAndIndex", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionByBlockHashAndIndex), arg0, arg1, arg2) +} + +// EthGetTransactionByBlockNumberAndIndex mocks base method. +func (m *MockFullNode) EthGetTransactionByBlockNumberAndIndex(arg0 context.Context, arg1, arg2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetTransactionByBlockNumberAndIndex", arg0, arg1, arg2) + ret0, _ := ret[0].(ethtypes.EthTx) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetTransactionByBlockNumberAndIndex indicates an expected call of EthGetTransactionByBlockNumberAndIndex. +func (mr *MockFullNodeMockRecorder) EthGetTransactionByBlockNumberAndIndex(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionByBlockNumberAndIndex", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionByBlockNumberAndIndex), arg0, arg1, arg2) +} + +// EthGetTransactionByHash mocks base method. +func (m *MockFullNode) EthGetTransactionByHash(arg0 context.Context, arg1 *ethtypes.EthHash) (*ethtypes.EthTx, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetTransactionByHash", arg0, arg1) + ret0, _ := ret[0].(*ethtypes.EthTx) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetTransactionByHash indicates an expected call of EthGetTransactionByHash. +func (mr *MockFullNodeMockRecorder) EthGetTransactionByHash(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionByHash", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionByHash), arg0, arg1) +} + +// EthGetTransactionCount mocks base method. +func (m *MockFullNode) EthGetTransactionCount(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 string) (ethtypes.EthUint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetTransactionCount", arg0, arg1, arg2) + ret0, _ := ret[0].(ethtypes.EthUint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetTransactionCount indicates an expected call of EthGetTransactionCount. +func (mr *MockFullNodeMockRecorder) EthGetTransactionCount(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionCount", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionCount), arg0, arg1, arg2) +} + +// EthGetTransactionHashByCid mocks base method. +func (m *MockFullNode) EthGetTransactionHashByCid(arg0 context.Context, arg1 cid.Cid) (*ethtypes.EthHash, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetTransactionHashByCid", arg0, arg1) + ret0, _ := ret[0].(*ethtypes.EthHash) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetTransactionHashByCid indicates an expected call of EthGetTransactionHashByCid. +func (mr *MockFullNodeMockRecorder) EthGetTransactionHashByCid(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionHashByCid", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionHashByCid), arg0, arg1) +} + +// EthGetTransactionReceipt mocks base method. +func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 ethtypes.EthHash) (*api.EthTxReceipt, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthGetTransactionReceipt", arg0, arg1) + ret0, _ := ret[0].(*api.EthTxReceipt) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthGetTransactionReceipt indicates an expected call of EthGetTransactionReceipt. +func (mr *MockFullNodeMockRecorder) EthGetTransactionReceipt(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionReceipt", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionReceipt), arg0, arg1) +} + +// EthMaxPriorityFeePerGas mocks base method. +func (m *MockFullNode) EthMaxPriorityFeePerGas(arg0 context.Context) (ethtypes.EthBigInt, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthMaxPriorityFeePerGas", arg0) + ret0, _ := ret[0].(ethtypes.EthBigInt) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthMaxPriorityFeePerGas indicates an expected call of EthMaxPriorityFeePerGas. +func (mr *MockFullNodeMockRecorder) EthMaxPriorityFeePerGas(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthMaxPriorityFeePerGas", reflect.TypeOf((*MockFullNode)(nil).EthMaxPriorityFeePerGas), arg0) +} + +// EthNewBlockFilter mocks base method. +func (m *MockFullNode) EthNewBlockFilter(arg0 context.Context) (ethtypes.EthFilterID, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthNewBlockFilter", arg0) + ret0, _ := ret[0].(ethtypes.EthFilterID) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthNewBlockFilter indicates an expected call of EthNewBlockFilter. +func (mr *MockFullNodeMockRecorder) EthNewBlockFilter(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthNewBlockFilter", reflect.TypeOf((*MockFullNode)(nil).EthNewBlockFilter), arg0) +} + +// EthNewFilter mocks base method. +func (m *MockFullNode) EthNewFilter(arg0 context.Context, arg1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthNewFilter", arg0, arg1) + ret0, _ := ret[0].(ethtypes.EthFilterID) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthNewFilter indicates an expected call of EthNewFilter. +func (mr *MockFullNodeMockRecorder) EthNewFilter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthNewFilter", reflect.TypeOf((*MockFullNode)(nil).EthNewFilter), arg0, arg1) +} + +// EthNewPendingTransactionFilter mocks base method. +func (m *MockFullNode) EthNewPendingTransactionFilter(arg0 context.Context) (ethtypes.EthFilterID, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthNewPendingTransactionFilter", arg0) + ret0, _ := ret[0].(ethtypes.EthFilterID) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthNewPendingTransactionFilter indicates an expected call of EthNewPendingTransactionFilter. +func (mr *MockFullNodeMockRecorder) EthNewPendingTransactionFilter(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthNewPendingTransactionFilter", reflect.TypeOf((*MockFullNode)(nil).EthNewPendingTransactionFilter), arg0) +} + +// EthProtocolVersion mocks base method. +func (m *MockFullNode) EthProtocolVersion(arg0 context.Context) (ethtypes.EthUint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthProtocolVersion", arg0) + ret0, _ := ret[0].(ethtypes.EthUint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthProtocolVersion indicates an expected call of EthProtocolVersion. +func (mr *MockFullNodeMockRecorder) EthProtocolVersion(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthProtocolVersion", reflect.TypeOf((*MockFullNode)(nil).EthProtocolVersion), arg0) +} + +// EthSendRawTransaction mocks base method. +func (m *MockFullNode) EthSendRawTransaction(arg0 context.Context, arg1 ethtypes.EthBytes) (ethtypes.EthHash, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthSendRawTransaction", arg0, arg1) + ret0, _ := ret[0].(ethtypes.EthHash) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthSendRawTransaction indicates an expected call of EthSendRawTransaction. +func (mr *MockFullNodeMockRecorder) EthSendRawTransaction(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthSendRawTransaction", reflect.TypeOf((*MockFullNode)(nil).EthSendRawTransaction), arg0, arg1) +} + +// EthSubscribe mocks base method. +func (m *MockFullNode) EthSubscribe(arg0 context.Context, arg1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthSubscribe", arg0, arg1) + ret0, _ := ret[0].(ethtypes.EthSubscriptionID) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthSubscribe indicates an expected call of EthSubscribe. +func (mr *MockFullNodeMockRecorder) EthSubscribe(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthSubscribe", reflect.TypeOf((*MockFullNode)(nil).EthSubscribe), arg0, arg1) +} + +// EthUninstallFilter mocks base method. +func (m *MockFullNode) EthUninstallFilter(arg0 context.Context, arg1 ethtypes.EthFilterID) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthUninstallFilter", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthUninstallFilter indicates an expected call of EthUninstallFilter. +func (mr *MockFullNodeMockRecorder) EthUninstallFilter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthUninstallFilter", reflect.TypeOf((*MockFullNode)(nil).EthUninstallFilter), arg0, arg1) +} + +// EthUnsubscribe mocks base method. +func (m *MockFullNode) EthUnsubscribe(arg0 context.Context, arg1 ethtypes.EthSubscriptionID) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthUnsubscribe", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthUnsubscribe indicates an expected call of EthUnsubscribe. +func (mr *MockFullNodeMockRecorder) EthUnsubscribe(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthUnsubscribe", reflect.TypeOf((*MockFullNode)(nil).EthUnsubscribe), arg0, arg1) +} + +// FilecoinAddressToEthAddress mocks base method. +func (m *MockFullNode) FilecoinAddressToEthAddress(arg0 context.Context, arg1 address.Address) (ethtypes.EthAddress, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FilecoinAddressToEthAddress", arg0, arg1) + ret0, _ := ret[0].(ethtypes.EthAddress) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FilecoinAddressToEthAddress indicates an expected call of FilecoinAddressToEthAddress. +func (mr *MockFullNodeMockRecorder) FilecoinAddressToEthAddress(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FilecoinAddressToEthAddress", reflect.TypeOf((*MockFullNode)(nil).FilecoinAddressToEthAddress), arg0, arg1) +} + // GasEstimateFeeCap mocks base method. func (m *MockFullNode) GasEstimateFeeCap(arg0 context.Context, arg1 *types.Message, arg2 int64, arg3 types.TipSetKey) (big.Int, error) { m.ctrl.T.Helper() @@ -1843,6 +2385,21 @@ func (mr *MockFullNodeMockRecorder) NetLimit(arg0, arg1 interface{}) *gomock.Cal return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetLimit", reflect.TypeOf((*MockFullNode)(nil).NetLimit), arg0, arg1) } +// NetListening mocks base method. +func (m *MockFullNode) NetListening(arg0 context.Context) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NetListening", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NetListening indicates an expected call of NetListening. +func (mr *MockFullNodeMockRecorder) NetListening(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetListening", reflect.TypeOf((*MockFullNode)(nil).NetListening), arg0) +} + // NetPeerInfo mocks base method. func (m *MockFullNode) NetPeerInfo(arg0 context.Context, arg1 peer.ID) (*api.ExtendedPeerInfo, error) { m.ctrl.T.Helper() @@ -1975,6 +2532,21 @@ func (mr *MockFullNodeMockRecorder) NetStat(arg0, arg1 interface{}) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetStat", reflect.TypeOf((*MockFullNode)(nil).NetStat), arg0, arg1) } +// NetVersion mocks base method. +func (m *MockFullNode) NetVersion(arg0 context.Context) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NetVersion", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NetVersion indicates an expected call of NetVersion. +func (mr *MockFullNodeMockRecorder) NetVersion(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetVersion", reflect.TypeOf((*MockFullNode)(nil).NetVersion), arg0) +} + // NodeStatus mocks base method. func (m *MockFullNode) NodeStatus(arg0 context.Context, arg1 bool) (api.NodeStatus, error) { m.ctrl.T.Helper() @@ -2394,10 +2966,10 @@ func (mr *MockFullNodeMockRecorder) StateCall(arg0, arg1, arg2 interface{}) *gom } // StateChangedActors mocks base method. -func (m *MockFullNode) StateChangedActors(arg0 context.Context, arg1, arg2 cid.Cid) (map[string]types.Actor, error) { +func (m *MockFullNode) StateChangedActors(arg0 context.Context, arg1, arg2 cid.Cid) (map[string]types.ActorV5, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateChangedActors", arg0, arg1, arg2) - ret0, _ := ret[0].(map[string]types.Actor) + ret0, _ := ret[0].(map[string]types.ActorV5) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -2499,10 +3071,10 @@ func (mr *MockFullNodeMockRecorder) StateEncodeParams(arg0, arg1, arg2, arg3 int } // StateGetActor mocks base method. -func (m *MockFullNode) StateGetActor(arg0 context.Context, arg1 address.Address, arg2 types.TipSetKey) (*types.Actor, error) { +func (m *MockFullNode) StateGetActor(arg0 context.Context, arg1 address.Address, arg2 types.TipSetKey) (*types.ActorV5, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateGetActor", arg0, arg1, arg2) - ret0, _ := ret[0].(*types.Actor) + ret0, _ := ret[0].(*types.ActorV5) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -3555,3 +4127,18 @@ func (mr *MockFullNodeMockRecorder) WalletVerify(arg0, arg1, arg2, arg3 interfac mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletVerify", reflect.TypeOf((*MockFullNode)(nil).WalletVerify), arg0, arg1, arg2, arg3) } + +// Web3ClientVersion mocks base method. +func (m *MockFullNode) Web3ClientVersion(arg0 context.Context) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Web3ClientVersion", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Web3ClientVersion indicates an expected call of Web3ClientVersion. +func (mr *MockFullNodeMockRecorder) Web3ClientVersion(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Web3ClientVersion", reflect.TypeOf((*MockFullNode)(nil).Web3ClientVersion), arg0) +} diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 0631a22bd..ef257e69b 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -8,8 +8,8 @@ import ( "time" "github.com/google/uuid" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-libp2p/core/metrics" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" @@ -22,6 +22,7 @@ import ( "github.com/filecoin-project/go-fil-markets/piecestore" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-jsonrpc" "github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/builtin/v8/paych" @@ -33,9 +34,10 @@ import ( "github.com/filecoin-project/go-state-types/proof" apitypes "github.com/filecoin-project/lotus/api/types" - "github.com/filecoin-project/lotus/chain/actors/builtin" + builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin" lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/journal/alerting" "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/repo/imports" @@ -48,42 +50,46 @@ import ( var ErrNotSupported = xerrors.New("method not supported") type ChainIOStruct struct { - Internal struct { - ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) `` + Internal ChainIOMethods +} - ChainPutObj func(p0 context.Context, p1 blocks.Block) error `` +type ChainIOMethods struct { + ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) `` - ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `` - } + ChainPutObj func(p0 context.Context, p1 blocks.Block) error `` + + ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `` } type ChainIOStub struct { } type CommonStruct struct { - Internal struct { - AuthNew func(p0 context.Context, p1 []auth.Permission) ([]byte, error) `perm:"admin"` + Internal CommonMethods +} - AuthVerify func(p0 context.Context, p1 string) ([]auth.Permission, error) `perm:"read"` +type CommonMethods struct { + AuthNew func(p0 context.Context, p1 []auth.Permission) ([]byte, error) `perm:"admin"` - Closing func(p0 context.Context) (<-chan struct{}, error) `perm:"read"` + AuthVerify func(p0 context.Context, p1 string) ([]auth.Permission, error) `perm:"read"` - Discover func(p0 context.Context) (apitypes.OpenRPCDocument, error) `perm:"read"` + Closing func(p0 context.Context) (<-chan struct{}, error) `perm:"read"` - LogAlerts func(p0 context.Context) ([]alerting.Alert, error) `perm:"admin"` + Discover func(p0 context.Context) (apitypes.OpenRPCDocument, error) `perm:"read"` - LogList func(p0 context.Context) ([]string, error) `perm:"write"` + LogAlerts func(p0 context.Context) ([]alerting.Alert, error) `perm:"admin"` - LogSetLevel func(p0 context.Context, p1 string, p2 string) error `perm:"write"` + LogList func(p0 context.Context) ([]string, error) `perm:"write"` - Session func(p0 context.Context) (uuid.UUID, error) `perm:"read"` + LogSetLevel func(p0 context.Context, p1 string, p2 string) error `perm:"write"` - Shutdown func(p0 context.Context) error `perm:"admin"` + Session func(p0 context.Context) (uuid.UUID, error) `perm:"read"` - StartTime func(p0 context.Context) (time.Time, error) `perm:"read"` + Shutdown func(p0 context.Context) error `perm:"admin"` - Version func(p0 context.Context) (APIVersion, error) `perm:"read"` - } + StartTime func(p0 context.Context) (time.Time, error) `perm:"read"` + + Version func(p0 context.Context) (APIVersion, error) `perm:"read"` } type CommonStub struct { @@ -94,8 +100,10 @@ type CommonNetStruct struct { NetStruct - Internal struct { - } + Internal CommonNetMethods +} + +type CommonNetMethods struct { } type CommonNetStub struct { @@ -104,412 +112,503 @@ type CommonNetStub struct { NetStub } +type EthSubscriberStruct struct { + Internal EthSubscriberMethods +} + +type EthSubscriberMethods struct { + EthSubscription func(p0 context.Context, p1 jsonrpc.RawParams) error `notify:"true"rpc_method:"eth_subscription"` +} + +type EthSubscriberStub struct { +} + type FullNodeStruct struct { CommonStruct NetStruct - Internal struct { - ChainBlockstoreInfo func(p0 context.Context) (map[string]interface{}, error) `perm:"read"` + Internal FullNodeMethods +} - ChainCheckBlockstore func(p0 context.Context) error `perm:"admin"` +type FullNodeMethods struct { + ChainBlockstoreInfo func(p0 context.Context) (map[string]interface{}, error) `perm:"read"` - ChainDeleteObj func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` + ChainCheckBlockstore func(p0 context.Context) error `perm:"admin"` - ChainExport func(p0 context.Context, p1 abi.ChainEpoch, p2 bool, p3 types.TipSetKey) (<-chan []byte, error) `perm:"read"` + ChainDeleteObj func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` - ChainGetBlock func(p0 context.Context, p1 cid.Cid) (*types.BlockHeader, error) `perm:"read"` + ChainExport func(p0 context.Context, p1 abi.ChainEpoch, p2 bool, p3 types.TipSetKey) (<-chan []byte, error) `perm:"read"` - ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) `perm:"read"` + ChainGetBlock func(p0 context.Context, p1 cid.Cid) (*types.BlockHeader, error) `perm:"read"` - ChainGetGenesis func(p0 context.Context) (*types.TipSet, error) `perm:"read"` + ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) `perm:"read"` - ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `perm:"read"` + ChainGetEvents func(p0 context.Context, p1 cid.Cid) ([]types.Event, error) `perm:"read"` - ChainGetMessagesInTipset func(p0 context.Context, p1 types.TipSetKey) ([]Message, error) `perm:"read"` + ChainGetGenesis func(p0 context.Context) (*types.TipSet, error) `perm:"read"` - ChainGetNode func(p0 context.Context, p1 string) (*IpldObject, error) `perm:"read"` + ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `perm:"read"` - ChainGetParentMessages func(p0 context.Context, p1 cid.Cid) ([]Message, error) `perm:"read"` + ChainGetMessagesInTipset func(p0 context.Context, p1 types.TipSetKey) ([]Message, error) `perm:"read"` - ChainGetParentReceipts func(p0 context.Context, p1 cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"` + ChainGetNode func(p0 context.Context, p1 string) (*IpldObject, error) `perm:"read"` - ChainGetPath func(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey) ([]*HeadChange, error) `perm:"read"` + ChainGetParentMessages func(p0 context.Context, p1 cid.Cid) ([]Message, error) `perm:"read"` - ChainGetTipSet func(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) `perm:"read"` + ChainGetParentReceipts func(p0 context.Context, p1 cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"` - ChainGetTipSetAfterHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `perm:"read"` + ChainGetPath func(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey) ([]*HeadChange, error) `perm:"read"` - ChainGetTipSetByHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `perm:"read"` + ChainGetTipSet func(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) `perm:"read"` - ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) `perm:"read"` + ChainGetTipSetAfterHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `perm:"read"` - ChainHead func(p0 context.Context) (*types.TipSet, error) `perm:"read"` + ChainGetTipSetByHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `perm:"read"` - ChainNotify func(p0 context.Context) (<-chan []*HeadChange, error) `perm:"read"` + ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) `perm:"read"` - ChainPrune func(p0 context.Context, p1 PruneOpts) error `perm:"admin"` + ChainHead func(p0 context.Context) (*types.TipSet, error) `perm:"read"` - ChainPutObj func(p0 context.Context, p1 blocks.Block) error `perm:"admin"` + ChainNotify func(p0 context.Context) (<-chan []*HeadChange, error) `perm:"read"` - ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `perm:"read"` + ChainPrune func(p0 context.Context, p1 PruneOpts) error `perm:"admin"` - ChainSetHead func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"` + ChainPutObj func(p0 context.Context, p1 blocks.Block) error `perm:"admin"` - ChainStatObj func(p0 context.Context, p1 cid.Cid, p2 cid.Cid) (ObjStat, error) `perm:"read"` + ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `perm:"read"` - ChainTipSetWeight func(p0 context.Context, p1 types.TipSetKey) (types.BigInt, error) `perm:"read"` + ChainSetHead func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"` - ClientCalcCommP func(p0 context.Context, p1 string) (*CommPRet, error) `perm:"write"` + ChainStatObj func(p0 context.Context, p1 cid.Cid, p2 cid.Cid) (ObjStat, error) `perm:"read"` - ClientCancelDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` + ChainTipSetWeight func(p0 context.Context, p1 types.TipSetKey) (types.BigInt, error) `perm:"read"` - ClientCancelRetrievalDeal func(p0 context.Context, p1 retrievalmarket.DealID) error `perm:"write"` + ClientCalcCommP func(p0 context.Context, p1 string) (*CommPRet, error) `perm:"write"` - ClientDataTransferUpdates func(p0 context.Context) (<-chan DataTransferChannel, error) `perm:"write"` + ClientCancelDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` - ClientDealPieceCID func(p0 context.Context, p1 cid.Cid) (DataCIDSize, error) `perm:"read"` + ClientCancelRetrievalDeal func(p0 context.Context, p1 retrievalmarket.DealID) error `perm:"write"` - ClientDealSize func(p0 context.Context, p1 cid.Cid) (DataSize, error) `perm:"read"` + ClientDataTransferUpdates func(p0 context.Context) (<-chan DataTransferChannel, error) `perm:"write"` - ClientExport func(p0 context.Context, p1 ExportRef, p2 FileRef) error `perm:"admin"` + ClientDealPieceCID func(p0 context.Context, p1 cid.Cid) (DataCIDSize, error) `perm:"read"` - ClientFindData func(p0 context.Context, p1 cid.Cid, p2 *cid.Cid) ([]QueryOffer, error) `perm:"read"` + ClientDealSize func(p0 context.Context, p1 cid.Cid) (DataSize, error) `perm:"read"` - ClientGenCar func(p0 context.Context, p1 FileRef, p2 string) error `perm:"write"` + ClientExport func(p0 context.Context, p1 ExportRef, p2 FileRef) error `perm:"admin"` - ClientGetDealInfo func(p0 context.Context, p1 cid.Cid) (*DealInfo, error) `perm:"read"` + ClientFindData func(p0 context.Context, p1 cid.Cid, p2 *cid.Cid) ([]QueryOffer, error) `perm:"read"` - ClientGetDealStatus func(p0 context.Context, p1 uint64) (string, error) `perm:"read"` + ClientGenCar func(p0 context.Context, p1 FileRef, p2 string) error `perm:"write"` - ClientGetDealUpdates func(p0 context.Context) (<-chan DealInfo, error) `perm:"write"` + ClientGetDealInfo func(p0 context.Context, p1 cid.Cid) (*DealInfo, error) `perm:"read"` - ClientGetRetrievalUpdates func(p0 context.Context) (<-chan RetrievalInfo, error) `perm:"write"` + ClientGetDealStatus func(p0 context.Context, p1 uint64) (string, error) `perm:"read"` - ClientHasLocal func(p0 context.Context, p1 cid.Cid) (bool, error) `perm:"write"` + ClientGetDealUpdates func(p0 context.Context) (<-chan DealInfo, error) `perm:"write"` - ClientImport func(p0 context.Context, p1 FileRef) (*ImportRes, error) `perm:"admin"` + ClientGetRetrievalUpdates func(p0 context.Context) (<-chan RetrievalInfo, error) `perm:"write"` - ClientListDataTransfers func(p0 context.Context) ([]DataTransferChannel, error) `perm:"write"` + ClientHasLocal func(p0 context.Context, p1 cid.Cid) (bool, error) `perm:"write"` - ClientListDeals func(p0 context.Context) ([]DealInfo, error) `perm:"write"` + ClientImport func(p0 context.Context, p1 FileRef) (*ImportRes, error) `perm:"admin"` - ClientListImports func(p0 context.Context) ([]Import, error) `perm:"write"` + ClientListDataTransfers func(p0 context.Context) ([]DataTransferChannel, error) `perm:"write"` - ClientListRetrievals func(p0 context.Context) ([]RetrievalInfo, error) `perm:"write"` + ClientListDeals func(p0 context.Context) ([]DealInfo, error) `perm:"write"` - ClientMinerQueryOffer func(p0 context.Context, p1 address.Address, p2 cid.Cid, p3 *cid.Cid) (QueryOffer, error) `perm:"read"` + ClientListImports func(p0 context.Context) ([]Import, error) `perm:"write"` - ClientQueryAsk func(p0 context.Context, p1 peer.ID, p2 address.Address) (*StorageAsk, error) `perm:"read"` + ClientListRetrievals func(p0 context.Context) ([]RetrievalInfo, error) `perm:"write"` - ClientRemoveImport func(p0 context.Context, p1 imports.ID) error `perm:"admin"` + ClientMinerQueryOffer func(p0 context.Context, p1 address.Address, p2 cid.Cid, p3 *cid.Cid) (QueryOffer, error) `perm:"read"` - ClientRestartDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` + ClientQueryAsk func(p0 context.Context, p1 peer.ID, p2 address.Address) (*StorageAsk, error) `perm:"read"` - ClientRetrieve func(p0 context.Context, p1 RetrievalOrder) (*RestrievalRes, error) `perm:"admin"` + ClientRemoveImport func(p0 context.Context, p1 imports.ID) error `perm:"admin"` - ClientRetrieveTryRestartInsufficientFunds func(p0 context.Context, p1 address.Address) error `perm:"write"` + ClientRestartDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` - ClientRetrieveWait func(p0 context.Context, p1 retrievalmarket.DealID) error `perm:"admin"` + ClientRetrieve func(p0 context.Context, p1 RetrievalOrder) (*RestrievalRes, error) `perm:"admin"` - ClientStartDeal func(p0 context.Context, p1 *StartDealParams) (*cid.Cid, error) `perm:"admin"` + ClientRetrieveTryRestartInsufficientFunds func(p0 context.Context, p1 address.Address) error `perm:"write"` - ClientStatelessDeal func(p0 context.Context, p1 *StartDealParams) (*cid.Cid, error) `perm:"write"` + ClientRetrieveWait func(p0 context.Context, p1 retrievalmarket.DealID) error `perm:"admin"` - CreateBackup func(p0 context.Context, p1 string) error `perm:"admin"` + ClientStartDeal func(p0 context.Context, p1 *StartDealParams) (*cid.Cid, error) `perm:"admin"` - GasEstimateFeeCap func(p0 context.Context, p1 *types.Message, p2 int64, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` + ClientStatelessDeal func(p0 context.Context, p1 *StartDealParams) (*cid.Cid, error) `perm:"write"` - GasEstimateGasLimit func(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (int64, error) `perm:"read"` + CreateBackup func(p0 context.Context, p1 string) error `perm:"admin"` - GasEstimateGasPremium func(p0 context.Context, p1 uint64, p2 address.Address, p3 int64, p4 types.TipSetKey) (types.BigInt, error) `perm:"read"` + EthAccounts func(p0 context.Context) ([]ethtypes.EthAddress, error) `perm:"read"` - GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `perm:"read"` + EthAddressToFilecoinAddress func(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) `perm:"read"` - MarketAddBalance func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` + EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"` - MarketGetReserved func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"sign"` + EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) `perm:"read"` - MarketReleaseFunds func(p0 context.Context, p1 address.Address, p2 types.BigInt) error `perm:"sign"` + EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"` - MarketReserveFunds func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` + EthEstimateGas func(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) `perm:"read"` - MarketWithdraw func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` + EthFeeHistory func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) `perm:"read"` - MinerCreateBlock func(p0 context.Context, p1 *BlockTemplate) (*types.BlockMsg, error) `perm:"write"` + EthGasPrice func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"` - MinerGetBaseInfo func(p0 context.Context, p1 address.Address, p2 abi.ChainEpoch, p3 types.TipSetKey) (*MiningBaseInfo, error) `perm:"read"` + EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) `perm:"read"` - MpoolBatchPush func(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) `perm:"write"` + EthGetBlockByHash func(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) `perm:"read"` - MpoolBatchPushMessage func(p0 context.Context, p1 []*types.Message, p2 *MessageSendSpec) ([]*types.SignedMessage, error) `perm:"sign"` + EthGetBlockByNumber func(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) `perm:"read"` - MpoolBatchPushUntrusted func(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) `perm:"write"` + EthGetBlockTransactionCountByHash func(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) `perm:"read"` - MpoolCheckMessages func(p0 context.Context, p1 []*MessagePrototype) ([][]MessageCheckStatus, error) `perm:"read"` + EthGetBlockTransactionCountByNumber func(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) `perm:"read"` - MpoolCheckPendingMessages func(p0 context.Context, p1 address.Address) ([][]MessageCheckStatus, error) `perm:"read"` + EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) `perm:"read"` - MpoolCheckReplaceMessages func(p0 context.Context, p1 []*types.Message) ([][]MessageCheckStatus, error) `perm:"read"` + EthGetFilterChanges func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `perm:"write"` - MpoolClear func(p0 context.Context, p1 bool) error `perm:"write"` + EthGetFilterLogs func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `perm:"write"` - MpoolGetConfig func(p0 context.Context) (*types.MpoolConfig, error) `perm:"read"` + EthGetLogs func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) `perm:"read"` - MpoolGetNonce func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"read"` + EthGetMessageCidByTransactionHash func(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) `perm:"read"` - MpoolPending func(p0 context.Context, p1 types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"` + EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `perm:"read"` - MpoolPush func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `perm:"write"` + EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"` - MpoolPushMessage func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec) (*types.SignedMessage, error) `perm:"sign"` + EthGetTransactionByBlockNumberAndIndex func(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"` - MpoolPushUntrusted func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `perm:"write"` + EthGetTransactionByHash func(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) `perm:"read"` - MpoolSelect func(p0 context.Context, p1 types.TipSetKey, p2 float64) ([]*types.SignedMessage, error) `perm:"read"` + EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `perm:"read"` - MpoolSetConfig func(p0 context.Context, p1 *types.MpoolConfig) error `perm:"admin"` + EthGetTransactionHashByCid func(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) `perm:"read"` - MpoolSub func(p0 context.Context) (<-chan MpoolUpdate, error) `perm:"read"` + EthGetTransactionReceipt func(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) `perm:"read"` - MsigAddApprove func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address, p6 bool) (*MessagePrototype, error) `perm:"sign"` + EthMaxPriorityFeePerGas func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"` - MsigAddCancel func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 bool) (*MessagePrototype, error) `perm:"sign"` + EthNewBlockFilter func(p0 context.Context) (ethtypes.EthFilterID, error) `perm:"write"` - MsigAddPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 bool) (*MessagePrototype, error) `perm:"sign"` + EthNewFilter func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) `perm:"write"` - MsigApprove func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address) (*MessagePrototype, error) `perm:"sign"` + EthNewPendingTransactionFilter func(p0 context.Context) (ethtypes.EthFilterID, error) `perm:"write"` - MsigApproveTxnHash func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 address.Address, p5 types.BigInt, p6 address.Address, p7 uint64, p8 []byte) (*MessagePrototype, error) `perm:"sign"` + EthProtocolVersion func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"` - MsigCancel func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address) (*MessagePrototype, error) `perm:"sign"` + EthSendRawTransaction func(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) `perm:"read"` - MsigCancelTxnHash func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 types.BigInt, p5 address.Address, p6 uint64, p7 []byte) (*MessagePrototype, error) `perm:"sign"` + EthSubscribe func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) `perm:"write"` - MsigCreate func(p0 context.Context, p1 uint64, p2 []address.Address, p3 abi.ChainEpoch, p4 types.BigInt, p5 address.Address, p6 types.BigInt) (*MessagePrototype, error) `perm:"sign"` + EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) `perm:"write"` - MsigGetAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `perm:"read"` + EthUnsubscribe func(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) `perm:"write"` - MsigGetPending func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*MsigTransaction, error) `perm:"read"` + FilecoinAddressToEthAddress func(p0 context.Context, p1 address.Address) (ethtypes.EthAddress, error) `perm:"read"` - MsigGetVested func(p0 context.Context, p1 address.Address, p2 types.TipSetKey, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` + GasEstimateFeeCap func(p0 context.Context, p1 *types.Message, p2 int64, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` - MsigGetVestingSchedule func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MsigVesting, error) `perm:"read"` + GasEstimateGasLimit func(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (int64, error) `perm:"read"` - MsigPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt, p4 address.Address, p5 uint64, p6 []byte) (*MessagePrototype, error) `perm:"sign"` + GasEstimateGasPremium func(p0 context.Context, p1 uint64, p2 address.Address, p3 int64, p4 types.TipSetKey) (types.BigInt, error) `perm:"read"` - MsigRemoveSigner func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 bool) (*MessagePrototype, error) `perm:"sign"` + GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `perm:"read"` - MsigSwapApprove func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address, p6 address.Address) (*MessagePrototype, error) `perm:"sign"` + MarketAddBalance func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` - MsigSwapCancel func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address) (*MessagePrototype, error) `perm:"sign"` + MarketGetReserved func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"sign"` - MsigSwapPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 address.Address) (*MessagePrototype, error) `perm:"sign"` + MarketReleaseFunds func(p0 context.Context, p1 address.Address, p2 types.BigInt) error `perm:"sign"` - NodeStatus func(p0 context.Context, p1 bool) (NodeStatus, error) `perm:"read"` + MarketReserveFunds func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` - PaychAllocateLane func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"sign"` + MarketWithdraw func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` - PaychAvailableFunds func(p0 context.Context, p1 address.Address) (*ChannelAvailableFunds, error) `perm:"sign"` + MinerCreateBlock func(p0 context.Context, p1 *BlockTemplate) (*types.BlockMsg, error) `perm:"write"` - PaychAvailableFundsByFromTo func(p0 context.Context, p1 address.Address, p2 address.Address) (*ChannelAvailableFunds, error) `perm:"sign"` + MinerGetBaseInfo func(p0 context.Context, p1 address.Address, p2 abi.ChainEpoch, p3 types.TipSetKey) (*MiningBaseInfo, error) `perm:"read"` - PaychCollect func(p0 context.Context, p1 address.Address) (cid.Cid, error) `perm:"sign"` + MpoolBatchPush func(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) `perm:"write"` - PaychFund func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (*ChannelInfo, error) `perm:"sign"` + MpoolBatchPushMessage func(p0 context.Context, p1 []*types.Message, p2 *MessageSendSpec) ([]*types.SignedMessage, error) `perm:"sign"` - PaychGet func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt, p4 PaychGetOpts) (*ChannelInfo, error) `perm:"sign"` + MpoolBatchPushUntrusted func(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) `perm:"write"` - PaychGetWaitReady func(p0 context.Context, p1 cid.Cid) (address.Address, error) `perm:"sign"` + MpoolCheckMessages func(p0 context.Context, p1 []*MessagePrototype) ([][]MessageCheckStatus, error) `perm:"read"` - PaychList func(p0 context.Context) ([]address.Address, error) `perm:"read"` + MpoolCheckPendingMessages func(p0 context.Context, p1 address.Address) ([][]MessageCheckStatus, error) `perm:"read"` - PaychNewPayment func(p0 context.Context, p1 address.Address, p2 address.Address, p3 []VoucherSpec) (*PaymentInfo, error) `perm:"sign"` + MpoolCheckReplaceMessages func(p0 context.Context, p1 []*types.Message) ([][]MessageCheckStatus, error) `perm:"read"` - PaychSettle func(p0 context.Context, p1 address.Address) (cid.Cid, error) `perm:"sign"` + MpoolClear func(p0 context.Context, p1 bool) error `perm:"write"` - PaychStatus func(p0 context.Context, p1 address.Address) (*PaychStatus, error) `perm:"read"` + MpoolGetConfig func(p0 context.Context) (*types.MpoolConfig, error) `perm:"read"` - PaychVoucherAdd func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 types.BigInt) (types.BigInt, error) `perm:"write"` + MpoolGetNonce func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"read"` - PaychVoucherCheckSpendable func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 []byte) (bool, error) `perm:"read"` + MpoolPending func(p0 context.Context, p1 types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"` - PaychVoucherCheckValid func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher) error `perm:"read"` + MpoolPush func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `perm:"write"` - PaychVoucherCreate func(p0 context.Context, p1 address.Address, p2 types.BigInt, p3 uint64) (*VoucherCreateResult, error) `perm:"sign"` + MpoolPushMessage func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec) (*types.SignedMessage, error) `perm:"sign"` - PaychVoucherList func(p0 context.Context, p1 address.Address) ([]*paych.SignedVoucher, error) `perm:"write"` + MpoolPushUntrusted func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `perm:"write"` - PaychVoucherSubmit func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 []byte) (cid.Cid, error) `perm:"sign"` + MpoolSelect func(p0 context.Context, p1 types.TipSetKey, p2 float64) ([]*types.SignedMessage, error) `perm:"read"` - RaftLeader func(p0 context.Context) (peer.ID, error) `perm:"read"` + MpoolSetConfig func(p0 context.Context, p1 *types.MpoolConfig) error `perm:"admin"` - RaftState func(p0 context.Context) (*RaftStateData, error) `perm:"read"` + MpoolSub func(p0 context.Context) (<-chan MpoolUpdate, error) `perm:"read"` - StateAccountKey func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` + MsigAddApprove func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address, p6 bool) (*MessagePrototype, error) `perm:"sign"` - StateActorCodeCIDs func(p0 context.Context, p1 abinetwork.Version) (map[string]cid.Cid, error) `perm:"read"` + MsigAddCancel func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 bool) (*MessagePrototype, error) `perm:"sign"` - StateActorManifestCID func(p0 context.Context, p1 abinetwork.Version) (cid.Cid, error) `perm:"read"` + MsigAddPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 bool) (*MessagePrototype, error) `perm:"sign"` - StateAllMinerFaults func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) ([]*Fault, error) `perm:"read"` + MsigApprove func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address) (*MessagePrototype, error) `perm:"sign"` - StateCall func(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (*InvocResult, error) `perm:"read"` + MsigApproveTxnHash func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 address.Address, p5 types.BigInt, p6 address.Address, p7 uint64, p8 []byte) (*MessagePrototype, error) `perm:"sign"` - StateChangedActors func(p0 context.Context, p1 cid.Cid, p2 cid.Cid) (map[string]types.Actor, error) `perm:"read"` + MsigCancel func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address) (*MessagePrototype, error) `perm:"sign"` - StateCirculatingSupply func(p0 context.Context, p1 types.TipSetKey) (abi.TokenAmount, error) `perm:"read"` + MsigCancelTxnHash func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 types.BigInt, p5 address.Address, p6 uint64, p7 []byte) (*MessagePrototype, error) `perm:"sign"` - StateCompute func(p0 context.Context, p1 abi.ChainEpoch, p2 []*types.Message, p3 types.TipSetKey) (*ComputeStateOutput, error) `perm:"read"` + MsigCreate func(p0 context.Context, p1 uint64, p2 []address.Address, p3 abi.ChainEpoch, p4 types.BigInt, p5 address.Address, p6 types.BigInt) (*MessagePrototype, error) `perm:"sign"` - StateComputeDataCID func(p0 context.Context, p1 address.Address, p2 abi.RegisteredSealProof, p3 []abi.DealID, p4 types.TipSetKey) (cid.Cid, error) `perm:"read"` + MsigGetAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `perm:"read"` - StateDealProviderCollateralBounds func(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (DealCollateralBounds, error) `perm:"read"` + MsigGetPending func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*MsigTransaction, error) `perm:"read"` - StateDecodeParams func(p0 context.Context, p1 address.Address, p2 abi.MethodNum, p3 []byte, p4 types.TipSetKey) (interface{}, error) `perm:"read"` + MsigGetVested func(p0 context.Context, p1 address.Address, p2 types.TipSetKey, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` - StateEncodeParams func(p0 context.Context, p1 cid.Cid, p2 abi.MethodNum, p3 json.RawMessage) ([]byte, error) `perm:"read"` + MsigGetVestingSchedule func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MsigVesting, error) `perm:"read"` - StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) `perm:"read"` + MsigPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt, p4 address.Address, p5 uint64, p6 []byte) (*MessagePrototype, error) `perm:"sign"` - StateGetAllocation func(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) `perm:"read"` + MsigRemoveSigner func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 bool) (*MessagePrototype, error) `perm:"sign"` - StateGetAllocationForPendingDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) `perm:"read"` + MsigSwapApprove func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address, p6 address.Address) (*MessagePrototype, error) `perm:"sign"` - StateGetAllocations func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) `perm:"read"` + MsigSwapCancel func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address) (*MessagePrototype, error) `perm:"sign"` - StateGetBeaconEntry func(p0 context.Context, p1 abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"` + MsigSwapPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 address.Address) (*MessagePrototype, error) `perm:"sign"` - StateGetClaim func(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) `perm:"read"` + NetListening func(p0 context.Context) (bool, error) `perm:"read"` - StateGetClaims func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) `perm:"read"` + NetVersion func(p0 context.Context) (string, error) `perm:"read"` - StateGetNetworkParams func(p0 context.Context) (*NetworkParams, error) `perm:"read"` + NodeStatus func(p0 context.Context, p1 bool) (NodeStatus, error) `perm:"read"` - StateGetRandomnessFromBeacon func(p0 context.Context, p1 crypto.DomainSeparationTag, p2 abi.ChainEpoch, p3 []byte, p4 types.TipSetKey) (abi.Randomness, error) `perm:"read"` + PaychAllocateLane func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"sign"` - StateGetRandomnessFromTickets func(p0 context.Context, p1 crypto.DomainSeparationTag, p2 abi.ChainEpoch, p3 []byte, p4 types.TipSetKey) (abi.Randomness, error) `perm:"read"` + PaychAvailableFunds func(p0 context.Context, p1 address.Address) (*ChannelAvailableFunds, error) `perm:"sign"` - StateListActors func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `perm:"read"` + PaychAvailableFundsByFromTo func(p0 context.Context, p1 address.Address, p2 address.Address) (*ChannelAvailableFunds, error) `perm:"sign"` - StateListMessages func(p0 context.Context, p1 *MessageMatch, p2 types.TipSetKey, p3 abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"` + PaychCollect func(p0 context.Context, p1 address.Address) (cid.Cid, error) `perm:"sign"` - StateListMiners func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `perm:"read"` + PaychFund func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (*ChannelInfo, error) `perm:"sign"` - StateLookupID func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` + PaychGet func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt, p4 PaychGetOpts) (*ChannelInfo, error) `perm:"sign"` - StateLookupRobustAddress func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` + PaychGetWaitReady func(p0 context.Context, p1 cid.Cid) (address.Address, error) `perm:"sign"` - StateMarketBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MarketBalance, error) `perm:"read"` + PaychList func(p0 context.Context) ([]address.Address, error) `perm:"read"` - StateMarketDeals func(p0 context.Context, p1 types.TipSetKey) (map[string]*MarketDeal, error) `perm:"read"` + PaychNewPayment func(p0 context.Context, p1 address.Address, p2 address.Address, p3 []VoucherSpec) (*PaymentInfo, error) `perm:"sign"` - StateMarketParticipants func(p0 context.Context, p1 types.TipSetKey) (map[string]MarketBalance, error) `perm:"read"` + PaychSettle func(p0 context.Context, p1 address.Address) (cid.Cid, error) `perm:"sign"` - StateMarketStorageDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*MarketDeal, error) `perm:"read"` + PaychStatus func(p0 context.Context, p1 address.Address) (*PaychStatus, error) `perm:"read"` - StateMinerActiveSectors func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"` + PaychVoucherAdd func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 types.BigInt) (types.BigInt, error) `perm:"write"` - StateMinerAllocated func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*bitfield.BitField, error) `perm:"read"` + PaychVoucherCheckSpendable func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 []byte) (bool, error) `perm:"read"` - StateMinerAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `perm:"read"` + PaychVoucherCheckValid func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher) error `perm:"read"` - StateMinerDeadlines func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]Deadline, error) `perm:"read"` + PaychVoucherCreate func(p0 context.Context, p1 address.Address, p2 types.BigInt, p3 uint64) (*VoucherCreateResult, error) `perm:"sign"` - StateMinerFaults func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (bitfield.BitField, error) `perm:"read"` + PaychVoucherList func(p0 context.Context, p1 address.Address) ([]*paych.SignedVoucher, error) `perm:"write"` - StateMinerInfo func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MinerInfo, error) `perm:"read"` + PaychVoucherSubmit func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 []byte) (cid.Cid, error) `perm:"sign"` - StateMinerInitialPledgeCollateral func(p0 context.Context, p1 address.Address, p2 miner.SectorPreCommitInfo, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` + RaftLeader func(p0 context.Context) (peer.ID, error) `perm:"read"` - StateMinerPartitions func(p0 context.Context, p1 address.Address, p2 uint64, p3 types.TipSetKey) ([]Partition, error) `perm:"read"` + RaftState func(p0 context.Context) (*RaftStateData, error) `perm:"read"` - StateMinerPower func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*MinerPower, error) `perm:"read"` + StateAccountKey func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` - StateMinerPreCommitDepositForPower func(p0 context.Context, p1 address.Address, p2 miner.SectorPreCommitInfo, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` + StateActorCodeCIDs func(p0 context.Context, p1 abinetwork.Version) (map[string]cid.Cid, error) `perm:"read"` - StateMinerProvingDeadline func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*dline.Info, error) `perm:"read"` + StateActorManifestCID func(p0 context.Context, p1 abinetwork.Version) (cid.Cid, error) `perm:"read"` - StateMinerRecoveries func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (bitfield.BitField, error) `perm:"read"` + StateAllMinerFaults func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) ([]*Fault, error) `perm:"read"` - StateMinerSectorAllocated func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (bool, error) `perm:"read"` + StateCall func(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (*InvocResult, error) `perm:"read"` - StateMinerSectorCount func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MinerSectors, error) `perm:"read"` + StateChangedActors func(p0 context.Context, p1 cid.Cid, p2 cid.Cid) (map[string]types.Actor, error) `perm:"read"` - StateMinerSectors func(p0 context.Context, p1 address.Address, p2 *bitfield.BitField, p3 types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"` + StateCirculatingSupply func(p0 context.Context, p1 types.TipSetKey) (abi.TokenAmount, error) `perm:"read"` - StateNetworkName func(p0 context.Context) (dtypes.NetworkName, error) `perm:"read"` + StateCompute func(p0 context.Context, p1 abi.ChainEpoch, p2 []*types.Message, p3 types.TipSetKey) (*ComputeStateOutput, error) `perm:"read"` - StateNetworkVersion func(p0 context.Context, p1 types.TipSetKey) (apitypes.NetworkVersion, error) `perm:"read"` + StateComputeDataCID func(p0 context.Context, p1 address.Address, p2 abi.RegisteredSealProof, p3 []abi.DealID, p4 types.TipSetKey) (cid.Cid, error) `perm:"read"` - StateReadState func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*ActorState, error) `perm:"read"` + StateDealProviderCollateralBounds func(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (DealCollateralBounds, error) `perm:"read"` - StateReplay func(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid) (*InvocResult, error) `perm:"read"` + StateDecodeParams func(p0 context.Context, p1 address.Address, p2 abi.MethodNum, p3 []byte, p4 types.TipSetKey) (interface{}, error) `perm:"read"` - StateSearchMsg func(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `perm:"read"` + StateEncodeParams func(p0 context.Context, p1 cid.Cid, p2 abi.MethodNum, p3 json.RawMessage) ([]byte, error) `perm:"read"` - StateSectorExpiration func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*lminer.SectorExpiration, error) `perm:"read"` + StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) `perm:"read"` - StateSectorGetInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorOnChainInfo, error) `perm:"read"` + StateGetAllocation func(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) `perm:"read"` - StateSectorPartition func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*lminer.SectorLocation, error) `perm:"read"` + StateGetAllocationForPendingDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) `perm:"read"` - StateSectorPreCommitInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) `perm:"read"` + StateGetAllocations func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) `perm:"read"` - StateVMCirculatingSupplyInternal func(p0 context.Context, p1 types.TipSetKey) (CirculatingSupply, error) `perm:"read"` + StateGetBeaconEntry func(p0 context.Context, p1 abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"` - StateVerifiedClientStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `perm:"read"` + StateGetClaim func(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) `perm:"read"` - StateVerifiedRegistryRootKey func(p0 context.Context, p1 types.TipSetKey) (address.Address, error) `perm:"read"` + StateGetClaims func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) `perm:"read"` - StateVerifierStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `perm:"read"` + StateGetNetworkParams func(p0 context.Context) (*NetworkParams, error) `perm:"read"` - StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `perm:"read"` + StateGetRandomnessFromBeacon func(p0 context.Context, p1 crypto.DomainSeparationTag, p2 abi.ChainEpoch, p3 []byte, p4 types.TipSetKey) (abi.Randomness, error) `perm:"read"` - SyncCheckBad func(p0 context.Context, p1 cid.Cid) (string, error) `perm:"read"` + StateGetRandomnessFromTickets func(p0 context.Context, p1 crypto.DomainSeparationTag, p2 abi.ChainEpoch, p3 []byte, p4 types.TipSetKey) (abi.Randomness, error) `perm:"read"` - SyncCheckpoint func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"` + StateListActors func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `perm:"read"` - SyncIncomingBlocks func(p0 context.Context) (<-chan *types.BlockHeader, error) `perm:"read"` + StateListMessages func(p0 context.Context, p1 *MessageMatch, p2 types.TipSetKey, p3 abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"` - SyncMarkBad func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` + StateListMiners func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `perm:"read"` - SyncState func(p0 context.Context) (*SyncState, error) `perm:"read"` + StateLookupID func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` - SyncSubmitBlock func(p0 context.Context, p1 *types.BlockMsg) error `perm:"write"` + StateLookupRobustAddress func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` - SyncUnmarkAllBad func(p0 context.Context) error `perm:"admin"` + StateMarketBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MarketBalance, error) `perm:"read"` - SyncUnmarkBad func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` + StateMarketDeals func(p0 context.Context, p1 types.TipSetKey) (map[string]*MarketDeal, error) `perm:"read"` - SyncValidateTipset func(p0 context.Context, p1 types.TipSetKey) (bool, error) `perm:"read"` + StateMarketParticipants func(p0 context.Context, p1 types.TipSetKey) (map[string]MarketBalance, error) `perm:"read"` - WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"read"` + StateMarketStorageDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*MarketDeal, error) `perm:"read"` - WalletDefaultAddress func(p0 context.Context) (address.Address, error) `perm:"write"` + StateMinerActiveSectors func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"` - WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"` + StateMinerAllocated func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*bitfield.BitField, error) `perm:"read"` - WalletExport func(p0 context.Context, p1 address.Address) (*types.KeyInfo, error) `perm:"admin"` + StateMinerAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `perm:"read"` - WalletHas func(p0 context.Context, p1 address.Address) (bool, error) `perm:"write"` + StateMinerDeadlines func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]Deadline, error) `perm:"read"` - WalletImport func(p0 context.Context, p1 *types.KeyInfo) (address.Address, error) `perm:"admin"` + StateMinerFaults func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (bitfield.BitField, error) `perm:"read"` - WalletList func(p0 context.Context) ([]address.Address, error) `perm:"write"` + StateMinerInfo func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MinerInfo, error) `perm:"read"` - WalletNew func(p0 context.Context, p1 types.KeyType) (address.Address, error) `perm:"write"` + StateMinerInitialPledgeCollateral func(p0 context.Context, p1 address.Address, p2 miner.SectorPreCommitInfo, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` - WalletSetDefault func(p0 context.Context, p1 address.Address) error `perm:"write"` + StateMinerPartitions func(p0 context.Context, p1 address.Address, p2 uint64, p3 types.TipSetKey) ([]Partition, error) `perm:"read"` - WalletSign func(p0 context.Context, p1 address.Address, p2 []byte) (*crypto.Signature, error) `perm:"sign"` + StateMinerPower func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*MinerPower, error) `perm:"read"` - WalletSignMessage func(p0 context.Context, p1 address.Address, p2 *types.Message) (*types.SignedMessage, error) `perm:"sign"` + StateMinerPreCommitDepositForPower func(p0 context.Context, p1 address.Address, p2 miner.SectorPreCommitInfo, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` - WalletValidateAddress func(p0 context.Context, p1 string) (address.Address, error) `perm:"read"` + StateMinerProvingDeadline func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*dline.Info, error) `perm:"read"` - WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"` - } + StateMinerRecoveries func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (bitfield.BitField, error) `perm:"read"` + + StateMinerSectorAllocated func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (bool, error) `perm:"read"` + + StateMinerSectorCount func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MinerSectors, error) `perm:"read"` + + StateMinerSectors func(p0 context.Context, p1 address.Address, p2 *bitfield.BitField, p3 types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"` + + StateNetworkName func(p0 context.Context) (dtypes.NetworkName, error) `perm:"read"` + + StateNetworkVersion func(p0 context.Context, p1 types.TipSetKey) (apitypes.NetworkVersion, error) `perm:"read"` + + StateReadState func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*ActorState, error) `perm:"read"` + + StateReplay func(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid) (*InvocResult, error) `perm:"read"` + + StateSearchMsg func(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `perm:"read"` + + StateSectorExpiration func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*lminer.SectorExpiration, error) `perm:"read"` + + StateSectorGetInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorOnChainInfo, error) `perm:"read"` + + StateSectorPartition func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*lminer.SectorLocation, error) `perm:"read"` + + StateSectorPreCommitInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) `perm:"read"` + + StateVMCirculatingSupplyInternal func(p0 context.Context, p1 types.TipSetKey) (CirculatingSupply, error) `perm:"read"` + + StateVerifiedClientStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `perm:"read"` + + StateVerifiedRegistryRootKey func(p0 context.Context, p1 types.TipSetKey) (address.Address, error) `perm:"read"` + + StateVerifierStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `perm:"read"` + + StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `perm:"read"` + + SyncCheckBad func(p0 context.Context, p1 cid.Cid) (string, error) `perm:"read"` + + SyncCheckpoint func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"` + + SyncIncomingBlocks func(p0 context.Context) (<-chan *types.BlockHeader, error) `perm:"read"` + + SyncMarkBad func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` + + SyncState func(p0 context.Context) (*SyncState, error) `perm:"read"` + + SyncSubmitBlock func(p0 context.Context, p1 *types.BlockMsg) error `perm:"write"` + + SyncUnmarkAllBad func(p0 context.Context) error `perm:"admin"` + + SyncUnmarkBad func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` + + SyncValidateTipset func(p0 context.Context, p1 types.TipSetKey) (bool, error) `perm:"read"` + + WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"read"` + + WalletDefaultAddress func(p0 context.Context) (address.Address, error) `perm:"write"` + + WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"` + + WalletExport func(p0 context.Context, p1 address.Address) (*types.KeyInfo, error) `perm:"admin"` + + WalletHas func(p0 context.Context, p1 address.Address) (bool, error) `perm:"write"` + + WalletImport func(p0 context.Context, p1 *types.KeyInfo) (address.Address, error) `perm:"admin"` + + WalletList func(p0 context.Context) ([]address.Address, error) `perm:"write"` + + WalletNew func(p0 context.Context, p1 types.KeyType) (address.Address, error) `perm:"write"` + + WalletSetDefault func(p0 context.Context, p1 address.Address) error `perm:"write"` + + WalletSign func(p0 context.Context, p1 address.Address, p2 []byte) (*crypto.Signature, error) `perm:"sign"` + + WalletSignMessage func(p0 context.Context, p1 address.Address, p2 *types.Message) (*types.SignedMessage, error) `perm:"sign"` + + WalletValidateAddress func(p0 context.Context, p1 string) (address.Address, error) `perm:"read"` + + WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"` + + Web3ClientVersion func(p0 context.Context) (string, error) `perm:"read"` } type FullNodeStub struct { @@ -519,149 +618,227 @@ type FullNodeStub struct { } type GatewayStruct struct { - Internal struct { - ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) `` + Internal GatewayMethods +} - ChainGetGenesis func(p0 context.Context) (*types.TipSet, error) `` +type GatewayMethods struct { + ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) `` - ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `` + ChainGetGenesis func(p0 context.Context) (*types.TipSet, error) `` - ChainGetParentMessages func(p0 context.Context, p1 cid.Cid) ([]Message, error) `` + ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `` - ChainGetParentReceipts func(p0 context.Context, p1 cid.Cid) ([]*types.MessageReceipt, error) `` + ChainGetParentMessages func(p0 context.Context, p1 cid.Cid) ([]Message, error) `` - ChainGetPath func(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey) ([]*HeadChange, error) `` + ChainGetParentReceipts func(p0 context.Context, p1 cid.Cid) ([]*types.MessageReceipt, error) `` - ChainGetTipSet func(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) `` + ChainGetPath func(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey) ([]*HeadChange, error) `` - ChainGetTipSetAfterHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `` + ChainGetTipSet func(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) `` - ChainGetTipSetByHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `` + ChainGetTipSetAfterHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `` - ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) `` + ChainGetTipSetByHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `` - ChainHead func(p0 context.Context) (*types.TipSet, error) `` + ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) `` - ChainNotify func(p0 context.Context) (<-chan []*HeadChange, error) `` + ChainHead func(p0 context.Context) (*types.TipSet, error) `` - ChainPutObj func(p0 context.Context, p1 blocks.Block) error `` + ChainNotify func(p0 context.Context) (<-chan []*HeadChange, error) `` - ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `` + ChainPutObj func(p0 context.Context, p1 blocks.Block) error `` - Discover func(p0 context.Context) (apitypes.OpenRPCDocument, error) `` + ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `` - GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `` + Discover func(p0 context.Context) (apitypes.OpenRPCDocument, error) `` - MpoolPush func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `` + EthAccounts func(p0 context.Context) ([]ethtypes.EthAddress, error) `` - MsigGetAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `` + EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `` - MsigGetPending func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*MsigTransaction, error) `` + EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) `` - MsigGetVested func(p0 context.Context, p1 address.Address, p2 types.TipSetKey, p3 types.TipSetKey) (types.BigInt, error) `` + EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `` - MsigGetVestingSchedule func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MsigVesting, error) `` + EthEstimateGas func(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) `` - StateAccountKey func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `` + EthFeeHistory func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) `` - StateDealProviderCollateralBounds func(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (DealCollateralBounds, error) `` + EthGasPrice func(p0 context.Context) (ethtypes.EthBigInt, error) `` - StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) `` + EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) `` - StateListMiners func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `` + EthGetBlockByHash func(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) `` - StateLookupID func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `` + EthGetBlockByNumber func(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) `` - StateMarketBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MarketBalance, error) `` + EthGetBlockTransactionCountByHash func(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) `` - StateMarketStorageDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*MarketDeal, error) `` + EthGetBlockTransactionCountByNumber func(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) `` - StateMinerInfo func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MinerInfo, error) `` + EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) `` - StateMinerPower func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*MinerPower, error) `` + EthGetFilterChanges func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `` - StateMinerProvingDeadline func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*dline.Info, error) `` + EthGetFilterLogs func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `` - StateNetworkVersion func(p0 context.Context, p1 types.TipSetKey) (apitypes.NetworkVersion, error) `` + EthGetLogs func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) `` - StateReadState func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*ActorState, error) `perm:"read"` + EthGetMessageCidByTransactionHash func(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) `` - StateSearchMsg func(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `` + EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `` - StateSectorGetInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorOnChainInfo, error) `` + EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `` - StateVerifiedClientStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `` + EthGetTransactionByBlockNumberAndIndex func(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `` - StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `` + EthGetTransactionByHash func(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) `` - Version func(p0 context.Context) (APIVersion, error) `` + EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `` - WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `` - } + EthGetTransactionHashByCid func(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) `` + + EthGetTransactionReceipt func(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) `` + + EthMaxPriorityFeePerGas func(p0 context.Context) (ethtypes.EthBigInt, error) `` + + EthNewBlockFilter func(p0 context.Context) (ethtypes.EthFilterID, error) `` + + EthNewFilter func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) `` + + EthNewPendingTransactionFilter func(p0 context.Context) (ethtypes.EthFilterID, error) `` + + EthProtocolVersion func(p0 context.Context) (ethtypes.EthUint64, error) `` + + EthSendRawTransaction func(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) `` + + EthSubscribe func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) `` + + EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) `` + + EthUnsubscribe func(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) `` + + GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `` + + MpoolPush func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `` + + MsigGetAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `` + + MsigGetPending func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*MsigTransaction, error) `` + + MsigGetVested func(p0 context.Context, p1 address.Address, p2 types.TipSetKey, p3 types.TipSetKey) (types.BigInt, error) `` + + MsigGetVestingSchedule func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MsigVesting, error) `` + + NetListening func(p0 context.Context) (bool, error) `` + + NetVersion func(p0 context.Context) (string, error) `` + + StateAccountKey func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `` + + StateDealProviderCollateralBounds func(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (DealCollateralBounds, error) `` + + StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) `` + + StateListMiners func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `` + + StateLookupID func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `` + + StateMarketBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MarketBalance, error) `` + + StateMarketStorageDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*MarketDeal, error) `` + + StateMinerInfo func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MinerInfo, error) `` + + StateMinerPower func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*MinerPower, error) `` + + StateMinerProvingDeadline func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*dline.Info, error) `` + + StateNetworkVersion func(p0 context.Context, p1 types.TipSetKey) (apitypes.NetworkVersion, error) `` + + StateReadState func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*ActorState, error) `perm:"read"` + + StateSearchMsg func(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `` + + StateSectorGetInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorOnChainInfo, error) `` + + StateVerifiedClientStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `` + + StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `` + + Version func(p0 context.Context) (APIVersion, error) `` + + WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `` + + Web3ClientVersion func(p0 context.Context) (string, error) `` } type GatewayStub struct { } type NetStruct struct { - Internal struct { - ID func(p0 context.Context) (peer.ID, error) `perm:"read"` + Internal NetMethods +} - NetAddrsListen func(p0 context.Context) (peer.AddrInfo, error) `perm:"read"` +type NetMethods struct { + ID func(p0 context.Context) (peer.ID, error) `perm:"read"` - NetAgentVersion func(p0 context.Context, p1 peer.ID) (string, error) `perm:"read"` + NetAddrsListen func(p0 context.Context) (peer.AddrInfo, error) `perm:"read"` - NetAutoNatStatus func(p0 context.Context) (NatInfo, error) `perm:"read"` + NetAgentVersion func(p0 context.Context, p1 peer.ID) (string, error) `perm:"read"` - NetBandwidthStats func(p0 context.Context) (metrics.Stats, error) `perm:"read"` + NetAutoNatStatus func(p0 context.Context) (NatInfo, error) `perm:"read"` - NetBandwidthStatsByPeer func(p0 context.Context) (map[string]metrics.Stats, error) `perm:"read"` + NetBandwidthStats func(p0 context.Context) (metrics.Stats, error) `perm:"read"` - NetBandwidthStatsByProtocol func(p0 context.Context) (map[protocol.ID]metrics.Stats, error) `perm:"read"` + NetBandwidthStatsByPeer func(p0 context.Context) (map[string]metrics.Stats, error) `perm:"read"` - NetBlockAdd func(p0 context.Context, p1 NetBlockList) error `perm:"admin"` + NetBandwidthStatsByProtocol func(p0 context.Context) (map[protocol.ID]metrics.Stats, error) `perm:"read"` - NetBlockList func(p0 context.Context) (NetBlockList, error) `perm:"read"` + NetBlockAdd func(p0 context.Context, p1 NetBlockList) error `perm:"admin"` - NetBlockRemove func(p0 context.Context, p1 NetBlockList) error `perm:"admin"` + NetBlockList func(p0 context.Context) (NetBlockList, error) `perm:"read"` - NetConnect func(p0 context.Context, p1 peer.AddrInfo) error `perm:"write"` + NetBlockRemove func(p0 context.Context, p1 NetBlockList) error `perm:"admin"` - NetConnectedness func(p0 context.Context, p1 peer.ID) (network.Connectedness, error) `perm:"read"` + NetConnect func(p0 context.Context, p1 peer.AddrInfo) error `perm:"write"` - NetDisconnect func(p0 context.Context, p1 peer.ID) error `perm:"write"` + NetConnectedness func(p0 context.Context, p1 peer.ID) (network.Connectedness, error) `perm:"read"` - NetFindPeer func(p0 context.Context, p1 peer.ID) (peer.AddrInfo, error) `perm:"read"` + NetDisconnect func(p0 context.Context, p1 peer.ID) error `perm:"write"` - NetLimit func(p0 context.Context, p1 string) (NetLimit, error) `perm:"read"` + NetFindPeer func(p0 context.Context, p1 peer.ID) (peer.AddrInfo, error) `perm:"read"` - NetPeerInfo func(p0 context.Context, p1 peer.ID) (*ExtendedPeerInfo, error) `perm:"read"` + NetLimit func(p0 context.Context, p1 string) (NetLimit, error) `perm:"read"` - NetPeers func(p0 context.Context) ([]peer.AddrInfo, error) `perm:"read"` + NetPeerInfo func(p0 context.Context, p1 peer.ID) (*ExtendedPeerInfo, error) `perm:"read"` - NetPing func(p0 context.Context, p1 peer.ID) (time.Duration, error) `perm:"read"` + NetPeers func(p0 context.Context) ([]peer.AddrInfo, error) `perm:"read"` - NetProtectAdd func(p0 context.Context, p1 []peer.ID) error `perm:"admin"` + NetPing func(p0 context.Context, p1 peer.ID) (time.Duration, error) `perm:"read"` - NetProtectList func(p0 context.Context) ([]peer.ID, error) `perm:"read"` + NetProtectAdd func(p0 context.Context, p1 []peer.ID) error `perm:"admin"` - NetProtectRemove func(p0 context.Context, p1 []peer.ID) error `perm:"admin"` + NetProtectList func(p0 context.Context) ([]peer.ID, error) `perm:"read"` - NetPubsubScores func(p0 context.Context) ([]PubsubScore, error) `perm:"read"` + NetProtectRemove func(p0 context.Context, p1 []peer.ID) error `perm:"admin"` - NetSetLimit func(p0 context.Context, p1 string, p2 NetLimit) error `perm:"admin"` + NetPubsubScores func(p0 context.Context) ([]PubsubScore, error) `perm:"read"` - NetStat func(p0 context.Context, p1 string) (NetStat, error) `perm:"read"` - } + NetSetLimit func(p0 context.Context, p1 string, p2 NetLimit) error `perm:"admin"` + + NetStat func(p0 context.Context, p1 string) (NetStat, error) `perm:"read"` } type NetStub struct { } type SignableStruct struct { - Internal struct { - Sign func(p0 context.Context, p1 SignFunc) error `` - } + Internal SignableMethods +} + +type SignableMethods struct { + Sign func(p0 context.Context, p1 SignFunc) error `` } type SignableStub struct { @@ -672,271 +849,273 @@ type StorageMinerStruct struct { NetStruct - Internal struct { - ActorAddress func(p0 context.Context) (address.Address, error) `perm:"read"` + Internal StorageMinerMethods +} - ActorAddressConfig func(p0 context.Context) (AddressConfig, error) `perm:"read"` +type StorageMinerMethods struct { + ActorAddress func(p0 context.Context) (address.Address, error) `perm:"read"` - ActorSectorSize func(p0 context.Context, p1 address.Address) (abi.SectorSize, error) `perm:"read"` + ActorAddressConfig func(p0 context.Context) (AddressConfig, error) `perm:"read"` - ActorWithdrawBalance func(p0 context.Context, p1 abi.TokenAmount) (cid.Cid, error) `perm:"admin"` + ActorSectorSize func(p0 context.Context, p1 address.Address) (abi.SectorSize, error) `perm:"read"` - BeneficiaryWithdrawBalance func(p0 context.Context, p1 abi.TokenAmount) (cid.Cid, error) `perm:"admin"` + ActorWithdrawBalance func(p0 context.Context, p1 abi.TokenAmount) (cid.Cid, error) `perm:"admin"` - CheckProvable func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storiface.SectorRef) (map[abi.SectorNumber]string, error) `perm:"admin"` + BeneficiaryWithdrawBalance func(p0 context.Context, p1 abi.TokenAmount) (cid.Cid, error) `perm:"admin"` - ComputeDataCid func(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data) (abi.PieceInfo, error) `perm:"admin"` + CheckProvable func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storiface.SectorRef) (map[abi.SectorNumber]string, error) `perm:"admin"` - ComputeProof func(p0 context.Context, p1 []builtin.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtin.PoStProof, error) `perm:"read"` + ComputeDataCid func(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data) (abi.PieceInfo, error) `perm:"admin"` - ComputeWindowPoSt func(p0 context.Context, p1 uint64, p2 types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) `perm:"admin"` + ComputeProof func(p0 context.Context, p1 []builtinactors.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtinactors.PoStProof, error) `perm:"read"` - CreateBackup func(p0 context.Context, p1 string) error `perm:"admin"` + ComputeWindowPoSt func(p0 context.Context, p1 uint64, p2 types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) `perm:"admin"` - DagstoreGC func(p0 context.Context) ([]DagstoreShardResult, error) `perm:"admin"` + CreateBackup func(p0 context.Context, p1 string) error `perm:"admin"` - DagstoreInitializeAll func(p0 context.Context, p1 DagstoreInitializeAllParams) (<-chan DagstoreInitializeAllEvent, error) `perm:"write"` + DagstoreGC func(p0 context.Context) ([]DagstoreShardResult, error) `perm:"admin"` - DagstoreInitializeShard func(p0 context.Context, p1 string) error `perm:"write"` + DagstoreInitializeAll func(p0 context.Context, p1 DagstoreInitializeAllParams) (<-chan DagstoreInitializeAllEvent, error) `perm:"write"` - DagstoreListShards func(p0 context.Context) ([]DagstoreShardInfo, error) `perm:"read"` + DagstoreInitializeShard func(p0 context.Context, p1 string) error `perm:"write"` - DagstoreLookupPieces func(p0 context.Context, p1 cid.Cid) ([]DagstoreShardInfo, error) `perm:"admin"` + DagstoreListShards func(p0 context.Context) ([]DagstoreShardInfo, error) `perm:"read"` - DagstoreRecoverShard func(p0 context.Context, p1 string) error `perm:"write"` + DagstoreLookupPieces func(p0 context.Context, p1 cid.Cid) ([]DagstoreShardInfo, error) `perm:"admin"` - DagstoreRegisterShard func(p0 context.Context, p1 string) error `perm:"admin"` + DagstoreRecoverShard func(p0 context.Context, p1 string) error `perm:"write"` - DealsConsiderOfflineRetrievalDeals func(p0 context.Context) (bool, error) `perm:"admin"` + DagstoreRegisterShard func(p0 context.Context, p1 string) error `perm:"admin"` - DealsConsiderOfflineStorageDeals func(p0 context.Context) (bool, error) `perm:"admin"` + DealsConsiderOfflineRetrievalDeals func(p0 context.Context) (bool, error) `perm:"admin"` - DealsConsiderOnlineRetrievalDeals func(p0 context.Context) (bool, error) `perm:"admin"` + DealsConsiderOfflineStorageDeals func(p0 context.Context) (bool, error) `perm:"admin"` - DealsConsiderOnlineStorageDeals func(p0 context.Context) (bool, error) `perm:"admin"` + DealsConsiderOnlineRetrievalDeals func(p0 context.Context) (bool, error) `perm:"admin"` - DealsConsiderUnverifiedStorageDeals func(p0 context.Context) (bool, error) `perm:"admin"` + DealsConsiderOnlineStorageDeals func(p0 context.Context) (bool, error) `perm:"admin"` - DealsConsiderVerifiedStorageDeals func(p0 context.Context) (bool, error) `perm:"admin"` + DealsConsiderUnverifiedStorageDeals func(p0 context.Context) (bool, error) `perm:"admin"` - DealsImportData func(p0 context.Context, p1 cid.Cid, p2 string) error `perm:"admin"` + DealsConsiderVerifiedStorageDeals func(p0 context.Context) (bool, error) `perm:"admin"` - DealsList func(p0 context.Context) ([]*MarketDeal, error) `perm:"admin"` + DealsImportData func(p0 context.Context, p1 cid.Cid, p2 string) error `perm:"admin"` - DealsPieceCidBlocklist func(p0 context.Context) ([]cid.Cid, error) `perm:"admin"` + DealsList func(p0 context.Context) ([]*MarketDeal, error) `perm:"admin"` - DealsSetConsiderOfflineRetrievalDeals func(p0 context.Context, p1 bool) error `perm:"admin"` + DealsPieceCidBlocklist func(p0 context.Context) ([]cid.Cid, error) `perm:"admin"` - DealsSetConsiderOfflineStorageDeals func(p0 context.Context, p1 bool) error `perm:"admin"` + DealsSetConsiderOfflineRetrievalDeals func(p0 context.Context, p1 bool) error `perm:"admin"` - DealsSetConsiderOnlineRetrievalDeals func(p0 context.Context, p1 bool) error `perm:"admin"` + DealsSetConsiderOfflineStorageDeals func(p0 context.Context, p1 bool) error `perm:"admin"` - DealsSetConsiderOnlineStorageDeals func(p0 context.Context, p1 bool) error `perm:"admin"` + DealsSetConsiderOnlineRetrievalDeals func(p0 context.Context, p1 bool) error `perm:"admin"` - DealsSetConsiderUnverifiedStorageDeals func(p0 context.Context, p1 bool) error `perm:"admin"` + DealsSetConsiderOnlineStorageDeals func(p0 context.Context, p1 bool) error `perm:"admin"` - DealsSetConsiderVerifiedStorageDeals func(p0 context.Context, p1 bool) error `perm:"admin"` + DealsSetConsiderUnverifiedStorageDeals func(p0 context.Context, p1 bool) error `perm:"admin"` - DealsSetPieceCidBlocklist func(p0 context.Context, p1 []cid.Cid) error `perm:"admin"` + DealsSetConsiderVerifiedStorageDeals func(p0 context.Context, p1 bool) error `perm:"admin"` - IndexerAnnounceAllDeals func(p0 context.Context) error `perm:"admin"` + DealsSetPieceCidBlocklist func(p0 context.Context, p1 []cid.Cid) error `perm:"admin"` - IndexerAnnounceDeal func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` + IndexerAnnounceAllDeals func(p0 context.Context) error `perm:"admin"` - MarketCancelDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` + IndexerAnnounceDeal func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` - MarketDataTransferDiagnostics func(p0 context.Context, p1 peer.ID) (*TransferDiagnostics, error) `perm:"write"` + MarketCancelDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` - MarketDataTransferUpdates func(p0 context.Context) (<-chan DataTransferChannel, error) `perm:"write"` + MarketDataTransferDiagnostics func(p0 context.Context, p1 peer.ID) (*TransferDiagnostics, error) `perm:"write"` - MarketGetAsk func(p0 context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"` + MarketDataTransferUpdates func(p0 context.Context) (<-chan DataTransferChannel, error) `perm:"write"` - MarketGetDealUpdates func(p0 context.Context) (<-chan storagemarket.MinerDeal, error) `perm:"read"` + MarketGetAsk func(p0 context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"` - MarketGetRetrievalAsk func(p0 context.Context) (*retrievalmarket.Ask, error) `perm:"read"` + MarketGetDealUpdates func(p0 context.Context) (<-chan storagemarket.MinerDeal, error) `perm:"read"` - MarketImportDealData func(p0 context.Context, p1 cid.Cid, p2 string) error `perm:"write"` + MarketGetRetrievalAsk func(p0 context.Context) (*retrievalmarket.Ask, error) `perm:"read"` - MarketListDataTransfers func(p0 context.Context) ([]DataTransferChannel, error) `perm:"write"` + MarketImportDealData func(p0 context.Context, p1 cid.Cid, p2 string) error `perm:"write"` - MarketListDeals func(p0 context.Context) ([]*MarketDeal, error) `perm:"read"` + MarketListDataTransfers func(p0 context.Context) ([]DataTransferChannel, error) `perm:"write"` - MarketListIncompleteDeals func(p0 context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"` + MarketListDeals func(p0 context.Context) ([]*MarketDeal, error) `perm:"read"` - MarketListRetrievalDeals func(p0 context.Context) ([]retrievalmarket.ProviderDealState, error) `perm:"read"` + MarketListIncompleteDeals func(p0 context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"` - MarketPendingDeals func(p0 context.Context) (PendingDealInfo, error) `perm:"write"` + MarketListRetrievalDeals func(p0 context.Context) ([]retrievalmarket.ProviderDealState, error) `perm:"read"` - MarketPublishPendingDeals func(p0 context.Context) error `perm:"admin"` + MarketPendingDeals func(p0 context.Context) (PendingDealInfo, error) `perm:"write"` - MarketRestartDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` + MarketPublishPendingDeals func(p0 context.Context) error `perm:"admin"` - MarketRetryPublishDeal func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` + MarketRestartDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` - MarketSetAsk func(p0 context.Context, p1 types.BigInt, p2 types.BigInt, p3 abi.ChainEpoch, p4 abi.PaddedPieceSize, p5 abi.PaddedPieceSize) error `perm:"admin"` + MarketRetryPublishDeal func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` - MarketSetRetrievalAsk func(p0 context.Context, p1 *retrievalmarket.Ask) error `perm:"admin"` + MarketSetAsk func(p0 context.Context, p1 types.BigInt, p2 types.BigInt, p3 abi.ChainEpoch, p4 abi.PaddedPieceSize, p5 abi.PaddedPieceSize) error `perm:"admin"` - MiningBase func(p0 context.Context) (*types.TipSet, error) `perm:"read"` + MarketSetRetrievalAsk func(p0 context.Context, p1 *retrievalmarket.Ask) error `perm:"admin"` - PiecesGetCIDInfo func(p0 context.Context, p1 cid.Cid) (*piecestore.CIDInfo, error) `perm:"read"` + MiningBase func(p0 context.Context) (*types.TipSet, error) `perm:"read"` - PiecesGetPieceInfo func(p0 context.Context, p1 cid.Cid) (*piecestore.PieceInfo, error) `perm:"read"` + PiecesGetCIDInfo func(p0 context.Context, p1 cid.Cid) (*piecestore.CIDInfo, error) `perm:"read"` - PiecesListCidInfos func(p0 context.Context) ([]cid.Cid, error) `perm:"read"` + PiecesGetPieceInfo func(p0 context.Context, p1 cid.Cid) (*piecestore.PieceInfo, error) `perm:"read"` - PiecesListPieces func(p0 context.Context) ([]cid.Cid, error) `perm:"read"` + PiecesListCidInfos func(p0 context.Context) ([]cid.Cid, error) `perm:"read"` - PledgeSector func(p0 context.Context) (abi.SectorID, error) `perm:"write"` + PiecesListPieces func(p0 context.Context) ([]cid.Cid, error) `perm:"read"` - RecoverFault func(p0 context.Context, p1 []abi.SectorNumber) ([]cid.Cid, error) `perm:"admin"` + PledgeSector func(p0 context.Context) (abi.SectorID, error) `perm:"write"` - ReturnAddPiece func(p0 context.Context, p1 storiface.CallID, p2 abi.PieceInfo, p3 *storiface.CallError) error `perm:"admin"` + RecoverFault func(p0 context.Context, p1 []abi.SectorNumber) ([]cid.Cid, error) `perm:"admin"` - ReturnDataCid func(p0 context.Context, p1 storiface.CallID, p2 abi.PieceInfo, p3 *storiface.CallError) error `perm:"admin"` + ReturnAddPiece func(p0 context.Context, p1 storiface.CallID, p2 abi.PieceInfo, p3 *storiface.CallError) error `perm:"admin"` - ReturnDownloadSector func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnDataCid func(p0 context.Context, p1 storiface.CallID, p2 abi.PieceInfo, p3 *storiface.CallError) error `perm:"admin"` - ReturnFetch func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnDownloadSector func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` - ReturnFinalizeReplicaUpdate func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnFetch func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` - ReturnFinalizeSector func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnFinalizeReplicaUpdate func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` - ReturnGenerateSectorKeyFromData func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnFinalizeSector func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` - ReturnMoveStorage func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnGenerateSectorKeyFromData func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` - ReturnProveReplicaUpdate1 func(p0 context.Context, p1 storiface.CallID, p2 storiface.ReplicaVanillaProofs, p3 *storiface.CallError) error `perm:"admin"` + ReturnMoveStorage func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` - ReturnProveReplicaUpdate2 func(p0 context.Context, p1 storiface.CallID, p2 storiface.ReplicaUpdateProof, p3 *storiface.CallError) error `perm:"admin"` + ReturnProveReplicaUpdate1 func(p0 context.Context, p1 storiface.CallID, p2 storiface.ReplicaVanillaProofs, p3 *storiface.CallError) error `perm:"admin"` - ReturnReadPiece func(p0 context.Context, p1 storiface.CallID, p2 bool, p3 *storiface.CallError) error `perm:"admin"` + ReturnProveReplicaUpdate2 func(p0 context.Context, p1 storiface.CallID, p2 storiface.ReplicaUpdateProof, p3 *storiface.CallError) error `perm:"admin"` - ReturnReleaseUnsealed func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnReadPiece func(p0 context.Context, p1 storiface.CallID, p2 bool, p3 *storiface.CallError) error `perm:"admin"` - ReturnReplicaUpdate func(p0 context.Context, p1 storiface.CallID, p2 storiface.ReplicaUpdateOut, p3 *storiface.CallError) error `perm:"admin"` + ReturnReleaseUnsealed func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` - ReturnSealCommit1 func(p0 context.Context, p1 storiface.CallID, p2 storiface.Commit1Out, p3 *storiface.CallError) error `perm:"admin"` + ReturnReplicaUpdate func(p0 context.Context, p1 storiface.CallID, p2 storiface.ReplicaUpdateOut, p3 *storiface.CallError) error `perm:"admin"` - ReturnSealCommit2 func(p0 context.Context, p1 storiface.CallID, p2 storiface.Proof, p3 *storiface.CallError) error `perm:"admin"` + ReturnSealCommit1 func(p0 context.Context, p1 storiface.CallID, p2 storiface.Commit1Out, p3 *storiface.CallError) error `perm:"admin"` - ReturnSealPreCommit1 func(p0 context.Context, p1 storiface.CallID, p2 storiface.PreCommit1Out, p3 *storiface.CallError) error `perm:"admin"` + ReturnSealCommit2 func(p0 context.Context, p1 storiface.CallID, p2 storiface.Proof, p3 *storiface.CallError) error `perm:"admin"` - ReturnSealPreCommit2 func(p0 context.Context, p1 storiface.CallID, p2 storiface.SectorCids, p3 *storiface.CallError) error `perm:"admin"` + ReturnSealPreCommit1 func(p0 context.Context, p1 storiface.CallID, p2 storiface.PreCommit1Out, p3 *storiface.CallError) error `perm:"admin"` - ReturnUnsealPiece func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnSealPreCommit2 func(p0 context.Context, p1 storiface.CallID, p2 storiface.SectorCids, p3 *storiface.CallError) error `perm:"admin"` - RuntimeSubsystems func(p0 context.Context) (MinerSubsystems, error) `perm:"read"` + ReturnUnsealPiece func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` - SealingAbort func(p0 context.Context, p1 storiface.CallID) error `perm:"admin"` + RuntimeSubsystems func(p0 context.Context) (MinerSubsystems, error) `perm:"read"` - SealingRemoveRequest func(p0 context.Context, p1 uuid.UUID) error `perm:"admin"` + SealingAbort func(p0 context.Context, p1 storiface.CallID) error `perm:"admin"` - SealingSchedDiag func(p0 context.Context, p1 bool) (interface{}, error) `perm:"admin"` + SealingRemoveRequest func(p0 context.Context, p1 uuid.UUID) error `perm:"admin"` - SectorAbortUpgrade func(p0 context.Context, p1 abi.SectorNumber) error `perm:"admin"` + SealingSchedDiag func(p0 context.Context, p1 bool) (interface{}, error) `perm:"admin"` - SectorAddPieceToAny func(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data, p3 PieceDealInfo) (SectorOffset, error) `perm:"admin"` + SectorAbortUpgrade func(p0 context.Context, p1 abi.SectorNumber) error `perm:"admin"` - SectorCommitFlush func(p0 context.Context) ([]sealiface.CommitBatchRes, error) `perm:"admin"` + SectorAddPieceToAny func(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data, p3 PieceDealInfo) (SectorOffset, error) `perm:"admin"` - SectorCommitPending func(p0 context.Context) ([]abi.SectorID, error) `perm:"admin"` + SectorCommitFlush func(p0 context.Context) ([]sealiface.CommitBatchRes, error) `perm:"admin"` - SectorGetExpectedSealDuration func(p0 context.Context) (time.Duration, error) `perm:"read"` + SectorCommitPending func(p0 context.Context) ([]abi.SectorID, error) `perm:"admin"` - SectorGetSealDelay func(p0 context.Context) (time.Duration, error) `perm:"read"` + SectorGetExpectedSealDuration func(p0 context.Context) (time.Duration, error) `perm:"read"` - SectorMarkForUpgrade func(p0 context.Context, p1 abi.SectorNumber, p2 bool) error `perm:"admin"` + SectorGetSealDelay func(p0 context.Context) (time.Duration, error) `perm:"read"` - SectorMatchPendingPiecesToOpenSectors func(p0 context.Context) error `perm:"admin"` + SectorMarkForUpgrade func(p0 context.Context, p1 abi.SectorNumber, p2 bool) error `perm:"admin"` - SectorNumAssignerMeta func(p0 context.Context) (NumAssignerMeta, error) `perm:"read"` + SectorMatchPendingPiecesToOpenSectors func(p0 context.Context) error `perm:"admin"` - SectorNumFree func(p0 context.Context, p1 string) error `perm:"admin"` + SectorNumAssignerMeta func(p0 context.Context) (NumAssignerMeta, error) `perm:"read"` - SectorNumReservations func(p0 context.Context) (map[string]bitfield.BitField, error) `perm:"read"` + SectorNumFree func(p0 context.Context, p1 string) error `perm:"admin"` - SectorNumReserve func(p0 context.Context, p1 string, p2 bitfield.BitField, p3 bool) error `perm:"admin"` + SectorNumReservations func(p0 context.Context) (map[string]bitfield.BitField, error) `perm:"read"` - SectorNumReserveCount func(p0 context.Context, p1 string, p2 uint64) (bitfield.BitField, error) `perm:"admin"` + SectorNumReserve func(p0 context.Context, p1 string, p2 bitfield.BitField, p3 bool) error `perm:"admin"` - SectorPreCommitFlush func(p0 context.Context) ([]sealiface.PreCommitBatchRes, error) `perm:"admin"` + SectorNumReserveCount func(p0 context.Context, p1 string, p2 uint64) (bitfield.BitField, error) `perm:"admin"` - SectorPreCommitPending func(p0 context.Context) ([]abi.SectorID, error) `perm:"admin"` + SectorPreCommitFlush func(p0 context.Context) ([]sealiface.PreCommitBatchRes, error) `perm:"admin"` - SectorReceive func(p0 context.Context, p1 RemoteSectorMeta) error `perm:"admin"` + SectorPreCommitPending func(p0 context.Context) ([]abi.SectorID, error) `perm:"admin"` - SectorRemove func(p0 context.Context, p1 abi.SectorNumber) error `perm:"admin"` + SectorReceive func(p0 context.Context, p1 RemoteSectorMeta) error `perm:"admin"` - SectorSetExpectedSealDuration func(p0 context.Context, p1 time.Duration) error `perm:"write"` + SectorRemove func(p0 context.Context, p1 abi.SectorNumber) error `perm:"admin"` - SectorSetSealDelay func(p0 context.Context, p1 time.Duration) error `perm:"write"` + SectorSetExpectedSealDuration func(p0 context.Context, p1 time.Duration) error `perm:"write"` - SectorStartSealing func(p0 context.Context, p1 abi.SectorNumber) error `perm:"write"` + SectorSetSealDelay func(p0 context.Context, p1 time.Duration) error `perm:"write"` - SectorTerminate func(p0 context.Context, p1 abi.SectorNumber) error `perm:"admin"` + SectorStartSealing func(p0 context.Context, p1 abi.SectorNumber) error `perm:"write"` - SectorTerminateFlush func(p0 context.Context) (*cid.Cid, error) `perm:"admin"` + SectorTerminate func(p0 context.Context, p1 abi.SectorNumber) error `perm:"admin"` - SectorTerminatePending func(p0 context.Context) ([]abi.SectorID, error) `perm:"admin"` + SectorTerminateFlush func(p0 context.Context) (*cid.Cid, error) `perm:"admin"` - SectorsList func(p0 context.Context) ([]abi.SectorNumber, error) `perm:"read"` + SectorTerminatePending func(p0 context.Context) ([]abi.SectorID, error) `perm:"admin"` - SectorsListInStates func(p0 context.Context, p1 []SectorState) ([]abi.SectorNumber, error) `perm:"read"` + SectorsList func(p0 context.Context) ([]abi.SectorNumber, error) `perm:"read"` - SectorsRefs func(p0 context.Context) (map[string][]SealedRef, error) `perm:"read"` + SectorsListInStates func(p0 context.Context, p1 []SectorState) ([]abi.SectorNumber, error) `perm:"read"` - SectorsStatus func(p0 context.Context, p1 abi.SectorNumber, p2 bool) (SectorInfo, error) `perm:"read"` + SectorsRefs func(p0 context.Context) (map[string][]SealedRef, error) `perm:"read"` - SectorsSummary func(p0 context.Context) (map[SectorState]int, error) `perm:"read"` + SectorsStatus func(p0 context.Context, p1 abi.SectorNumber, p2 bool) (SectorInfo, error) `perm:"read"` - SectorsUnsealPiece func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.UnpaddedByteIndex, p3 abi.UnpaddedPieceSize, p4 abi.SealRandomness, p5 *cid.Cid) error `perm:"admin"` + SectorsSummary func(p0 context.Context) (map[SectorState]int, error) `perm:"read"` - SectorsUpdate func(p0 context.Context, p1 abi.SectorNumber, p2 SectorState) error `perm:"admin"` + SectorsUnsealPiece func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.UnpaddedByteIndex, p3 abi.UnpaddedPieceSize, p4 abi.SealRandomness, p5 *cid.Cid) error `perm:"admin"` - StorageAddLocal func(p0 context.Context, p1 string) error `perm:"admin"` + SectorsUpdate func(p0 context.Context, p1 abi.SectorNumber, p2 SectorState) error `perm:"admin"` - StorageAttach func(p0 context.Context, p1 storiface.StorageInfo, p2 fsutil.FsStat) error `perm:"admin"` + StorageAddLocal func(p0 context.Context, p1 string) error `perm:"admin"` - StorageAuthVerify func(p0 context.Context, p1 string) ([]auth.Permission, error) `perm:"read"` + StorageAttach func(p0 context.Context, p1 storiface.StorageInfo, p2 fsutil.FsStat) error `perm:"admin"` - StorageBestAlloc func(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType) ([]storiface.StorageInfo, error) `perm:"admin"` + StorageAuthVerify func(p0 context.Context, p1 string) ([]auth.Permission, error) `perm:"read"` - StorageDeclareSector func(p0 context.Context, p1 storiface.ID, p2 abi.SectorID, p3 storiface.SectorFileType, p4 bool) error `perm:"admin"` + StorageBestAlloc func(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType) ([]storiface.StorageInfo, error) `perm:"admin"` - StorageDetach func(p0 context.Context, p1 storiface.ID, p2 string) error `perm:"admin"` + StorageDeclareSector func(p0 context.Context, p1 storiface.ID, p2 abi.SectorID, p3 storiface.SectorFileType, p4 bool) error `perm:"admin"` - StorageDetachLocal func(p0 context.Context, p1 string) error `perm:"admin"` + StorageDetach func(p0 context.Context, p1 storiface.ID, p2 string) error `perm:"admin"` - StorageDropSector func(p0 context.Context, p1 storiface.ID, p2 abi.SectorID, p3 storiface.SectorFileType) error `perm:"admin"` + StorageDetachLocal func(p0 context.Context, p1 string) error `perm:"admin"` - StorageFindSector func(p0 context.Context, p1 abi.SectorID, p2 storiface.SectorFileType, p3 abi.SectorSize, p4 bool) ([]storiface.SectorStorageInfo, error) `perm:"admin"` + StorageDropSector func(p0 context.Context, p1 storiface.ID, p2 abi.SectorID, p3 storiface.SectorFileType) error `perm:"admin"` - StorageGetLocks func(p0 context.Context) (storiface.SectorLocks, error) `perm:"admin"` + StorageFindSector func(p0 context.Context, p1 abi.SectorID, p2 storiface.SectorFileType, p3 abi.SectorSize, p4 bool) ([]storiface.SectorStorageInfo, error) `perm:"admin"` - StorageInfo func(p0 context.Context, p1 storiface.ID) (storiface.StorageInfo, error) `perm:"admin"` + StorageGetLocks func(p0 context.Context) (storiface.SectorLocks, error) `perm:"admin"` - StorageList func(p0 context.Context) (map[storiface.ID][]storiface.Decl, error) `perm:"admin"` + StorageInfo func(p0 context.Context, p1 storiface.ID) (storiface.StorageInfo, error) `perm:"admin"` - StorageLocal func(p0 context.Context) (map[storiface.ID]string, error) `perm:"admin"` + StorageList func(p0 context.Context) (map[storiface.ID][]storiface.Decl, error) `perm:"admin"` - StorageLock func(p0 context.Context, p1 abi.SectorID, p2 storiface.SectorFileType, p3 storiface.SectorFileType) error `perm:"admin"` + StorageLocal func(p0 context.Context) (map[storiface.ID]string, error) `perm:"admin"` - StorageRedeclareLocal func(p0 context.Context, p1 *storiface.ID, p2 bool) error `perm:"admin"` + StorageLock func(p0 context.Context, p1 abi.SectorID, p2 storiface.SectorFileType, p3 storiface.SectorFileType) error `perm:"admin"` - StorageReportHealth func(p0 context.Context, p1 storiface.ID, p2 storiface.HealthReport) error `perm:"admin"` + StorageRedeclareLocal func(p0 context.Context, p1 *storiface.ID, p2 bool) error `perm:"admin"` - StorageStat func(p0 context.Context, p1 storiface.ID) (fsutil.FsStat, error) `perm:"admin"` + StorageReportHealth func(p0 context.Context, p1 storiface.ID, p2 storiface.HealthReport) error `perm:"admin"` - StorageTryLock func(p0 context.Context, p1 abi.SectorID, p2 storiface.SectorFileType, p3 storiface.SectorFileType) (bool, error) `perm:"admin"` + StorageStat func(p0 context.Context, p1 storiface.ID) (fsutil.FsStat, error) `perm:"admin"` - WorkerConnect func(p0 context.Context, p1 string) error `perm:"admin"` + StorageTryLock func(p0 context.Context, p1 abi.SectorID, p2 storiface.SectorFileType, p3 storiface.SectorFileType) (bool, error) `perm:"admin"` - WorkerJobs func(p0 context.Context) (map[uuid.UUID][]storiface.WorkerJob, error) `perm:"admin"` + WorkerConnect func(p0 context.Context, p1 string) error `perm:"admin"` - WorkerStats func(p0 context.Context) (map[uuid.UUID]storiface.WorkerStats, error) `perm:"admin"` - } + WorkerJobs func(p0 context.Context) (map[uuid.UUID][]storiface.WorkerJob, error) `perm:"admin"` + + WorkerStats func(p0 context.Context) (map[uuid.UUID]storiface.WorkerStats, error) `perm:"admin"` } type StorageMinerStub struct { @@ -946,102 +1125,106 @@ type StorageMinerStub struct { } type WalletStruct struct { - Internal struct { - WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"` + Internal WalletMethods +} - WalletExport func(p0 context.Context, p1 address.Address) (*types.KeyInfo, error) `perm:"admin"` +type WalletMethods struct { + WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"` - WalletHas func(p0 context.Context, p1 address.Address) (bool, error) `perm:"admin"` + WalletExport func(p0 context.Context, p1 address.Address) (*types.KeyInfo, error) `perm:"admin"` - WalletImport func(p0 context.Context, p1 *types.KeyInfo) (address.Address, error) `perm:"admin"` + WalletHas func(p0 context.Context, p1 address.Address) (bool, error) `perm:"admin"` - WalletList func(p0 context.Context) ([]address.Address, error) `perm:"admin"` + WalletImport func(p0 context.Context, p1 *types.KeyInfo) (address.Address, error) `perm:"admin"` - WalletNew func(p0 context.Context, p1 types.KeyType) (address.Address, error) `perm:"admin"` + WalletList func(p0 context.Context) ([]address.Address, error) `perm:"admin"` - WalletSign func(p0 context.Context, p1 address.Address, p2 []byte, p3 MsgMeta) (*crypto.Signature, error) `perm:"admin"` - } + WalletNew func(p0 context.Context, p1 types.KeyType) (address.Address, error) `perm:"admin"` + + WalletSign func(p0 context.Context, p1 address.Address, p2 []byte, p3 MsgMeta) (*crypto.Signature, error) `perm:"admin"` } type WalletStub struct { } type WorkerStruct struct { - Internal struct { - AddPiece func(p0 context.Context, p1 storiface.SectorRef, p2 []abi.UnpaddedPieceSize, p3 abi.UnpaddedPieceSize, p4 storiface.Data) (storiface.CallID, error) `perm:"admin"` + Internal WorkerMethods +} - DataCid func(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data) (storiface.CallID, error) `perm:"admin"` +type WorkerMethods struct { + AddPiece func(p0 context.Context, p1 storiface.SectorRef, p2 []abi.UnpaddedPieceSize, p3 abi.UnpaddedPieceSize, p4 storiface.Data) (storiface.CallID, error) `perm:"admin"` - DownloadSectorData func(p0 context.Context, p1 storiface.SectorRef, p2 bool, p3 map[storiface.SectorFileType]storiface.SectorLocation) (storiface.CallID, error) `perm:"admin"` + DataCid func(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data) (storiface.CallID, error) `perm:"admin"` - Enabled func(p0 context.Context) (bool, error) `perm:"admin"` + DownloadSectorData func(p0 context.Context, p1 storiface.SectorRef, p2 bool, p3 map[storiface.SectorFileType]storiface.SectorLocation) (storiface.CallID, error) `perm:"admin"` - Fetch func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.SectorFileType, p3 storiface.PathType, p4 storiface.AcquireMode) (storiface.CallID, error) `perm:"admin"` + Enabled func(p0 context.Context) (bool, error) `perm:"admin"` - FinalizeReplicaUpdate func(p0 context.Context, p1 storiface.SectorRef, p2 []storiface.Range) (storiface.CallID, error) `perm:"admin"` + Fetch func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.SectorFileType, p3 storiface.PathType, p4 storiface.AcquireMode) (storiface.CallID, error) `perm:"admin"` - FinalizeSector func(p0 context.Context, p1 storiface.SectorRef, p2 []storiface.Range) (storiface.CallID, error) `perm:"admin"` + FinalizeReplicaUpdate func(p0 context.Context, p1 storiface.SectorRef) (storiface.CallID, error) `perm:"admin"` - GenerateSectorKeyFromData func(p0 context.Context, p1 storiface.SectorRef, p2 cid.Cid) (storiface.CallID, error) `perm:"admin"` + FinalizeSector func(p0 context.Context, p1 storiface.SectorRef) (storiface.CallID, error) `perm:"admin"` - GenerateWindowPoSt func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 abi.ActorID, p3 []storiface.PostSectorChallenge, p4 int, p5 abi.PoStRandomness) (storiface.WindowPoStResult, error) `perm:"admin"` + GenerateSectorKeyFromData func(p0 context.Context, p1 storiface.SectorRef, p2 cid.Cid) (storiface.CallID, error) `perm:"admin"` - GenerateWinningPoSt func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 abi.ActorID, p3 []storiface.PostSectorChallenge, p4 abi.PoStRandomness) ([]proof.PoStProof, error) `perm:"admin"` + GenerateWindowPoSt func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 abi.ActorID, p3 []storiface.PostSectorChallenge, p4 int, p5 abi.PoStRandomness) (storiface.WindowPoStResult, error) `perm:"admin"` - Info func(p0 context.Context) (storiface.WorkerInfo, error) `perm:"admin"` + GenerateWinningPoSt func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 abi.ActorID, p3 []storiface.PostSectorChallenge, p4 abi.PoStRandomness) ([]proof.PoStProof, error) `perm:"admin"` - MoveStorage func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.SectorFileType) (storiface.CallID, error) `perm:"admin"` + Info func(p0 context.Context) (storiface.WorkerInfo, error) `perm:"admin"` - Paths func(p0 context.Context) ([]storiface.StoragePath, error) `perm:"admin"` + MoveStorage func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.SectorFileType) (storiface.CallID, error) `perm:"admin"` - ProcessSession func(p0 context.Context) (uuid.UUID, error) `perm:"admin"` + Paths func(p0 context.Context) ([]storiface.StoragePath, error) `perm:"admin"` - ProveReplicaUpdate1 func(p0 context.Context, p1 storiface.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid) (storiface.CallID, error) `perm:"admin"` + ProcessSession func(p0 context.Context) (uuid.UUID, error) `perm:"admin"` - ProveReplicaUpdate2 func(p0 context.Context, p1 storiface.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid, p5 storiface.ReplicaVanillaProofs) (storiface.CallID, error) `perm:"admin"` + ProveReplicaUpdate1 func(p0 context.Context, p1 storiface.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid) (storiface.CallID, error) `perm:"admin"` - ReleaseUnsealed func(p0 context.Context, p1 storiface.SectorRef, p2 []storiface.Range) (storiface.CallID, error) `perm:"admin"` + ProveReplicaUpdate2 func(p0 context.Context, p1 storiface.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid, p5 storiface.ReplicaVanillaProofs) (storiface.CallID, error) `perm:"admin"` - Remove func(p0 context.Context, p1 abi.SectorID) error `perm:"admin"` + ReleaseUnsealed func(p0 context.Context, p1 storiface.SectorRef, p2 []storiface.Range) (storiface.CallID, error) `perm:"admin"` - ReplicaUpdate func(p0 context.Context, p1 storiface.SectorRef, p2 []abi.PieceInfo) (storiface.CallID, error) `perm:"admin"` + Remove func(p0 context.Context, p1 abi.SectorID) error `perm:"admin"` - SealCommit1 func(p0 context.Context, p1 storiface.SectorRef, p2 abi.SealRandomness, p3 abi.InteractiveSealRandomness, p4 []abi.PieceInfo, p5 storiface.SectorCids) (storiface.CallID, error) `perm:"admin"` + ReplicaUpdate func(p0 context.Context, p1 storiface.SectorRef, p2 []abi.PieceInfo) (storiface.CallID, error) `perm:"admin"` - SealCommit2 func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.Commit1Out) (storiface.CallID, error) `perm:"admin"` + SealCommit1 func(p0 context.Context, p1 storiface.SectorRef, p2 abi.SealRandomness, p3 abi.InteractiveSealRandomness, p4 []abi.PieceInfo, p5 storiface.SectorCids) (storiface.CallID, error) `perm:"admin"` - SealPreCommit1 func(p0 context.Context, p1 storiface.SectorRef, p2 abi.SealRandomness, p3 []abi.PieceInfo) (storiface.CallID, error) `perm:"admin"` + SealCommit2 func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.Commit1Out) (storiface.CallID, error) `perm:"admin"` - SealPreCommit2 func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.PreCommit1Out) (storiface.CallID, error) `perm:"admin"` + SealPreCommit1 func(p0 context.Context, p1 storiface.SectorRef, p2 abi.SealRandomness, p3 []abi.PieceInfo) (storiface.CallID, error) `perm:"admin"` - Session func(p0 context.Context) (uuid.UUID, error) `perm:"admin"` + SealPreCommit2 func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.PreCommit1Out) (storiface.CallID, error) `perm:"admin"` - SetEnabled func(p0 context.Context, p1 bool) error `perm:"admin"` + Session func(p0 context.Context) (uuid.UUID, error) `perm:"admin"` - Shutdown func(p0 context.Context) error `perm:"admin"` + SetEnabled func(p0 context.Context, p1 bool) error `perm:"admin"` - StorageAddLocal func(p0 context.Context, p1 string) error `perm:"admin"` + Shutdown func(p0 context.Context) error `perm:"admin"` - StorageDetachAll func(p0 context.Context) error `perm:"admin"` + StorageAddLocal func(p0 context.Context, p1 string) error `perm:"admin"` - StorageDetachLocal func(p0 context.Context, p1 string) error `perm:"admin"` + StorageDetachAll func(p0 context.Context) error `perm:"admin"` - StorageLocal func(p0 context.Context) (map[storiface.ID]string, error) `perm:"admin"` + StorageDetachLocal func(p0 context.Context, p1 string) error `perm:"admin"` - StorageRedeclareLocal func(p0 context.Context, p1 *storiface.ID, p2 bool) error `perm:"admin"` + StorageLocal func(p0 context.Context) (map[storiface.ID]string, error) `perm:"admin"` - TaskDisable func(p0 context.Context, p1 sealtasks.TaskType) error `perm:"admin"` + StorageRedeclareLocal func(p0 context.Context, p1 *storiface.ID, p2 bool) error `perm:"admin"` - TaskEnable func(p0 context.Context, p1 sealtasks.TaskType) error `perm:"admin"` + TaskDisable func(p0 context.Context, p1 sealtasks.TaskType) error `perm:"admin"` - TaskTypes func(p0 context.Context) (map[sealtasks.TaskType]struct{}, error) `perm:"admin"` + TaskEnable func(p0 context.Context, p1 sealtasks.TaskType) error `perm:"admin"` - UnsealPiece func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.UnpaddedByteIndex, p3 abi.UnpaddedPieceSize, p4 abi.SealRandomness, p5 cid.Cid) (storiface.CallID, error) `perm:"admin"` + TaskTypes func(p0 context.Context) (map[sealtasks.TaskType]struct{}, error) `perm:"admin"` - Version func(p0 context.Context) (Version, error) `perm:"admin"` + UnsealPiece func(p0 context.Context, p1 storiface.SectorRef, p2 storiface.UnpaddedByteIndex, p3 abi.UnpaddedPieceSize, p4 abi.SealRandomness, p5 cid.Cid) (storiface.CallID, error) `perm:"admin"` - WaitQuiet func(p0 context.Context) error `perm:"admin"` - } + Version func(p0 context.Context) (Version, error) `perm:"admin"` + + WaitQuiet func(p0 context.Context) error `perm:"admin"` } type WorkerStub struct { @@ -1201,6 +1384,17 @@ func (s *CommonStub) Version(p0 context.Context) (APIVersion, error) { return *new(APIVersion), ErrNotSupported } +func (s *EthSubscriberStruct) EthSubscription(p0 context.Context, p1 jsonrpc.RawParams) error { + if s.Internal.EthSubscription == nil { + return ErrNotSupported + } + return s.Internal.EthSubscription(p0, p1) +} + +func (s *EthSubscriberStub) EthSubscription(p0 context.Context, p1 jsonrpc.RawParams) error { + return ErrNotSupported +} + func (s *FullNodeStruct) ChainBlockstoreInfo(p0 context.Context) (map[string]interface{}, error) { if s.Internal.ChainBlockstoreInfo == nil { return *new(map[string]interface{}), ErrNotSupported @@ -1267,6 +1461,17 @@ func (s *FullNodeStub) ChainGetBlockMessages(p0 context.Context, p1 cid.Cid) (*B return nil, ErrNotSupported } +func (s *FullNodeStruct) ChainGetEvents(p0 context.Context, p1 cid.Cid) ([]types.Event, error) { + if s.Internal.ChainGetEvents == nil { + return *new([]types.Event), ErrNotSupported + } + return s.Internal.ChainGetEvents(p0, p1) +} + +func (s *FullNodeStub) ChainGetEvents(p0 context.Context, p1 cid.Cid) ([]types.Event, error) { + return *new([]types.Event), ErrNotSupported +} + func (s *FullNodeStruct) ChainGetGenesis(p0 context.Context) (*types.TipSet, error) { if s.Internal.ChainGetGenesis == nil { return nil, ErrNotSupported @@ -1795,6 +2000,391 @@ func (s *FullNodeStub) CreateBackup(p0 context.Context, p1 string) error { return ErrNotSupported } +func (s *FullNodeStruct) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, error) { + if s.Internal.EthAccounts == nil { + return *new([]ethtypes.EthAddress), ErrNotSupported + } + return s.Internal.EthAccounts(p0) +} + +func (s *FullNodeStub) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, error) { + return *new([]ethtypes.EthAddress), ErrNotSupported +} + +func (s *FullNodeStruct) EthAddressToFilecoinAddress(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) { + if s.Internal.EthAddressToFilecoinAddress == nil { + return *new(address.Address), ErrNotSupported + } + return s.Internal.EthAddressToFilecoinAddress(p0, p1) +} + +func (s *FullNodeStub) EthAddressToFilecoinAddress(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) { + return *new(address.Address), ErrNotSupported +} + +func (s *FullNodeStruct) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) { + if s.Internal.EthBlockNumber == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthBlockNumber(p0) +} + +func (s *FullNodeStub) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *FullNodeStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) { + if s.Internal.EthCall == nil { + return *new(ethtypes.EthBytes), ErrNotSupported + } + return s.Internal.EthCall(p0, p1, p2) +} + +func (s *FullNodeStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) { + return *new(ethtypes.EthBytes), ErrNotSupported +} + +func (s *FullNodeStruct) EthChainId(p0 context.Context) (ethtypes.EthUint64, error) { + if s.Internal.EthChainId == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthChainId(p0) +} + +func (s *FullNodeStub) EthChainId(p0 context.Context) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *FullNodeStruct) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) { + if s.Internal.EthEstimateGas == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthEstimateGas(p0, p1) +} + +func (s *FullNodeStub) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *FullNodeStruct) EthFeeHistory(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { + if s.Internal.EthFeeHistory == nil { + return *new(ethtypes.EthFeeHistory), ErrNotSupported + } + return s.Internal.EthFeeHistory(p0, p1) +} + +func (s *FullNodeStub) EthFeeHistory(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { + return *new(ethtypes.EthFeeHistory), ErrNotSupported +} + +func (s *FullNodeStruct) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error) { + if s.Internal.EthGasPrice == nil { + return *new(ethtypes.EthBigInt), ErrNotSupported + } + return s.Internal.EthGasPrice(p0) +} + +func (s *FullNodeStub) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error) { + return *new(ethtypes.EthBigInt), ErrNotSupported +} + +func (s *FullNodeStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) { + if s.Internal.EthGetBalance == nil { + return *new(ethtypes.EthBigInt), ErrNotSupported + } + return s.Internal.EthGetBalance(p0, p1, p2) +} + +func (s *FullNodeStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) { + return *new(ethtypes.EthBigInt), ErrNotSupported +} + +func (s *FullNodeStruct) EthGetBlockByHash(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) { + if s.Internal.EthGetBlockByHash == nil { + return *new(ethtypes.EthBlock), ErrNotSupported + } + return s.Internal.EthGetBlockByHash(p0, p1, p2) +} + +func (s *FullNodeStub) EthGetBlockByHash(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) { + return *new(ethtypes.EthBlock), ErrNotSupported +} + +func (s *FullNodeStruct) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) { + if s.Internal.EthGetBlockByNumber == nil { + return *new(ethtypes.EthBlock), ErrNotSupported + } + return s.Internal.EthGetBlockByNumber(p0, p1, p2) +} + +func (s *FullNodeStub) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) { + return *new(ethtypes.EthBlock), ErrNotSupported +} + +func (s *FullNodeStruct) EthGetBlockTransactionCountByHash(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) { + if s.Internal.EthGetBlockTransactionCountByHash == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthGetBlockTransactionCountByHash(p0, p1) +} + +func (s *FullNodeStub) EthGetBlockTransactionCountByHash(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *FullNodeStruct) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) { + if s.Internal.EthGetBlockTransactionCountByNumber == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthGetBlockTransactionCountByNumber(p0, p1) +} + +func (s *FullNodeStub) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *FullNodeStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) { + if s.Internal.EthGetCode == nil { + return *new(ethtypes.EthBytes), ErrNotSupported + } + return s.Internal.EthGetCode(p0, p1, p2) +} + +func (s *FullNodeStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) { + return *new(ethtypes.EthBytes), ErrNotSupported +} + +func (s *FullNodeStruct) EthGetFilterChanges(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if s.Internal.EthGetFilterChanges == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetFilterChanges(p0, p1) +} + +func (s *FullNodeStub) EthGetFilterChanges(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + return nil, ErrNotSupported +} + +func (s *FullNodeStruct) EthGetFilterLogs(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if s.Internal.EthGetFilterLogs == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetFilterLogs(p0, p1) +} + +func (s *FullNodeStub) EthGetFilterLogs(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + return nil, ErrNotSupported +} + +func (s *FullNodeStruct) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) { + if s.Internal.EthGetLogs == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetLogs(p0, p1) +} + +func (s *FullNodeStub) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) { + return nil, ErrNotSupported +} + +func (s *FullNodeStruct) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) { + if s.Internal.EthGetMessageCidByTransactionHash == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetMessageCidByTransactionHash(p0, p1) +} + +func (s *FullNodeStub) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) { + return nil, ErrNotSupported +} + +func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) { + if s.Internal.EthGetStorageAt == nil { + return *new(ethtypes.EthBytes), ErrNotSupported + } + return s.Internal.EthGetStorageAt(p0, p1, p2, p3) +} + +func (s *FullNodeStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) { + return *new(ethtypes.EthBytes), ErrNotSupported +} + +func (s *FullNodeStruct) EthGetTransactionByBlockHashAndIndex(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + if s.Internal.EthGetTransactionByBlockHashAndIndex == nil { + return *new(ethtypes.EthTx), ErrNotSupported + } + return s.Internal.EthGetTransactionByBlockHashAndIndex(p0, p1, p2) +} + +func (s *FullNodeStub) EthGetTransactionByBlockHashAndIndex(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + return *new(ethtypes.EthTx), ErrNotSupported +} + +func (s *FullNodeStruct) EthGetTransactionByBlockNumberAndIndex(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + if s.Internal.EthGetTransactionByBlockNumberAndIndex == nil { + return *new(ethtypes.EthTx), ErrNotSupported + } + return s.Internal.EthGetTransactionByBlockNumberAndIndex(p0, p1, p2) +} + +func (s *FullNodeStub) EthGetTransactionByBlockNumberAndIndex(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + return *new(ethtypes.EthTx), ErrNotSupported +} + +func (s *FullNodeStruct) EthGetTransactionByHash(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) { + if s.Internal.EthGetTransactionByHash == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetTransactionByHash(p0, p1) +} + +func (s *FullNodeStub) EthGetTransactionByHash(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) { + return nil, ErrNotSupported +} + +func (s *FullNodeStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) { + if s.Internal.EthGetTransactionCount == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthGetTransactionCount(p0, p1, p2) +} + +func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *FullNodeStruct) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) { + if s.Internal.EthGetTransactionHashByCid == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetTransactionHashByCid(p0, p1) +} + +func (s *FullNodeStub) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) { + return nil, ErrNotSupported +} + +func (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) { + if s.Internal.EthGetTransactionReceipt == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetTransactionReceipt(p0, p1) +} + +func (s *FullNodeStub) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) { + return nil, ErrNotSupported +} + +func (s *FullNodeStruct) EthMaxPriorityFeePerGas(p0 context.Context) (ethtypes.EthBigInt, error) { + if s.Internal.EthMaxPriorityFeePerGas == nil { + return *new(ethtypes.EthBigInt), ErrNotSupported + } + return s.Internal.EthMaxPriorityFeePerGas(p0) +} + +func (s *FullNodeStub) EthMaxPriorityFeePerGas(p0 context.Context) (ethtypes.EthBigInt, error) { + return *new(ethtypes.EthBigInt), ErrNotSupported +} + +func (s *FullNodeStruct) EthNewBlockFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + if s.Internal.EthNewBlockFilter == nil { + return *new(ethtypes.EthFilterID), ErrNotSupported + } + return s.Internal.EthNewBlockFilter(p0) +} + +func (s *FullNodeStub) EthNewBlockFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + return *new(ethtypes.EthFilterID), ErrNotSupported +} + +func (s *FullNodeStruct) EthNewFilter(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) { + if s.Internal.EthNewFilter == nil { + return *new(ethtypes.EthFilterID), ErrNotSupported + } + return s.Internal.EthNewFilter(p0, p1) +} + +func (s *FullNodeStub) EthNewFilter(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) { + return *new(ethtypes.EthFilterID), ErrNotSupported +} + +func (s *FullNodeStruct) EthNewPendingTransactionFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + if s.Internal.EthNewPendingTransactionFilter == nil { + return *new(ethtypes.EthFilterID), ErrNotSupported + } + return s.Internal.EthNewPendingTransactionFilter(p0) +} + +func (s *FullNodeStub) EthNewPendingTransactionFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + return *new(ethtypes.EthFilterID), ErrNotSupported +} + +func (s *FullNodeStruct) EthProtocolVersion(p0 context.Context) (ethtypes.EthUint64, error) { + if s.Internal.EthProtocolVersion == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthProtocolVersion(p0) +} + +func (s *FullNodeStub) EthProtocolVersion(p0 context.Context) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *FullNodeStruct) EthSendRawTransaction(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) { + if s.Internal.EthSendRawTransaction == nil { + return *new(ethtypes.EthHash), ErrNotSupported + } + return s.Internal.EthSendRawTransaction(p0, p1) +} + +func (s *FullNodeStub) EthSendRawTransaction(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) { + return *new(ethtypes.EthHash), ErrNotSupported +} + +func (s *FullNodeStruct) EthSubscribe(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) { + if s.Internal.EthSubscribe == nil { + return *new(ethtypes.EthSubscriptionID), ErrNotSupported + } + return s.Internal.EthSubscribe(p0, p1) +} + +func (s *FullNodeStub) EthSubscribe(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) { + return *new(ethtypes.EthSubscriptionID), ErrNotSupported +} + +func (s *FullNodeStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) { + if s.Internal.EthUninstallFilter == nil { + return false, ErrNotSupported + } + return s.Internal.EthUninstallFilter(p0, p1) +} + +func (s *FullNodeStub) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) { + return false, ErrNotSupported +} + +func (s *FullNodeStruct) EthUnsubscribe(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) { + if s.Internal.EthUnsubscribe == nil { + return false, ErrNotSupported + } + return s.Internal.EthUnsubscribe(p0, p1) +} + +func (s *FullNodeStub) EthUnsubscribe(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) { + return false, ErrNotSupported +} + +func (s *FullNodeStruct) FilecoinAddressToEthAddress(p0 context.Context, p1 address.Address) (ethtypes.EthAddress, error) { + if s.Internal.FilecoinAddressToEthAddress == nil { + return *new(ethtypes.EthAddress), ErrNotSupported + } + return s.Internal.FilecoinAddressToEthAddress(p0, p1) +} + +func (s *FullNodeStub) FilecoinAddressToEthAddress(p0 context.Context, p1 address.Address) (ethtypes.EthAddress, error) { + return *new(ethtypes.EthAddress), ErrNotSupported +} + func (s *FullNodeStruct) GasEstimateFeeCap(p0 context.Context, p1 *types.Message, p2 int64, p3 types.TipSetKey) (types.BigInt, error) { if s.Internal.GasEstimateFeeCap == nil { return *new(types.BigInt), ErrNotSupported @@ -2279,6 +2869,28 @@ func (s *FullNodeStub) MsigSwapPropose(p0 context.Context, p1 address.Address, p return nil, ErrNotSupported } +func (s *FullNodeStruct) NetListening(p0 context.Context) (bool, error) { + if s.Internal.NetListening == nil { + return false, ErrNotSupported + } + return s.Internal.NetListening(p0) +} + +func (s *FullNodeStub) NetListening(p0 context.Context) (bool, error) { + return false, ErrNotSupported +} + +func (s *FullNodeStruct) NetVersion(p0 context.Context) (string, error) { + if s.Internal.NetVersion == nil { + return "", ErrNotSupported + } + return s.Internal.NetVersion(p0) +} + +func (s *FullNodeStub) NetVersion(p0 context.Context) (string, error) { + return "", ErrNotSupported +} + func (s *FullNodeStruct) NodeStatus(p0 context.Context, p1 bool) (NodeStatus, error) { if s.Internal.NodeStatus == nil { return *new(NodeStatus), ErrNotSupported @@ -3401,6 +4013,17 @@ func (s *FullNodeStub) WalletVerify(p0 context.Context, p1 address.Address, p2 [ return false, ErrNotSupported } +func (s *FullNodeStruct) Web3ClientVersion(p0 context.Context) (string, error) { + if s.Internal.Web3ClientVersion == nil { + return "", ErrNotSupported + } + return s.Internal.Web3ClientVersion(p0) +} + +func (s *FullNodeStub) Web3ClientVersion(p0 context.Context) (string, error) { + return "", ErrNotSupported +} + func (s *GatewayStruct) ChainGetBlockMessages(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) { if s.Internal.ChainGetBlockMessages == nil { return nil, ErrNotSupported @@ -3566,6 +4189,369 @@ func (s *GatewayStub) Discover(p0 context.Context) (apitypes.OpenRPCDocument, er return *new(apitypes.OpenRPCDocument), ErrNotSupported } +func (s *GatewayStruct) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, error) { + if s.Internal.EthAccounts == nil { + return *new([]ethtypes.EthAddress), ErrNotSupported + } + return s.Internal.EthAccounts(p0) +} + +func (s *GatewayStub) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, error) { + return *new([]ethtypes.EthAddress), ErrNotSupported +} + +func (s *GatewayStruct) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) { + if s.Internal.EthBlockNumber == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthBlockNumber(p0) +} + +func (s *GatewayStub) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) { + if s.Internal.EthCall == nil { + return *new(ethtypes.EthBytes), ErrNotSupported + } + return s.Internal.EthCall(p0, p1, p2) +} + +func (s *GatewayStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) { + return *new(ethtypes.EthBytes), ErrNotSupported +} + +func (s *GatewayStruct) EthChainId(p0 context.Context) (ethtypes.EthUint64, error) { + if s.Internal.EthChainId == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthChainId(p0) +} + +func (s *GatewayStub) EthChainId(p0 context.Context) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) { + if s.Internal.EthEstimateGas == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthEstimateGas(p0, p1) +} + +func (s *GatewayStub) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthFeeHistory(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { + if s.Internal.EthFeeHistory == nil { + return *new(ethtypes.EthFeeHistory), ErrNotSupported + } + return s.Internal.EthFeeHistory(p0, p1) +} + +func (s *GatewayStub) EthFeeHistory(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { + return *new(ethtypes.EthFeeHistory), ErrNotSupported +} + +func (s *GatewayStruct) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error) { + if s.Internal.EthGasPrice == nil { + return *new(ethtypes.EthBigInt), ErrNotSupported + } + return s.Internal.EthGasPrice(p0) +} + +func (s *GatewayStub) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error) { + return *new(ethtypes.EthBigInt), ErrNotSupported +} + +func (s *GatewayStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) { + if s.Internal.EthGetBalance == nil { + return *new(ethtypes.EthBigInt), ErrNotSupported + } + return s.Internal.EthGetBalance(p0, p1, p2) +} + +func (s *GatewayStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) { + return *new(ethtypes.EthBigInt), ErrNotSupported +} + +func (s *GatewayStruct) EthGetBlockByHash(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) { + if s.Internal.EthGetBlockByHash == nil { + return *new(ethtypes.EthBlock), ErrNotSupported + } + return s.Internal.EthGetBlockByHash(p0, p1, p2) +} + +func (s *GatewayStub) EthGetBlockByHash(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) { + return *new(ethtypes.EthBlock), ErrNotSupported +} + +func (s *GatewayStruct) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) { + if s.Internal.EthGetBlockByNumber == nil { + return *new(ethtypes.EthBlock), ErrNotSupported + } + return s.Internal.EthGetBlockByNumber(p0, p1, p2) +} + +func (s *GatewayStub) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) { + return *new(ethtypes.EthBlock), ErrNotSupported +} + +func (s *GatewayStruct) EthGetBlockTransactionCountByHash(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) { + if s.Internal.EthGetBlockTransactionCountByHash == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthGetBlockTransactionCountByHash(p0, p1) +} + +func (s *GatewayStub) EthGetBlockTransactionCountByHash(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) { + if s.Internal.EthGetBlockTransactionCountByNumber == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthGetBlockTransactionCountByNumber(p0, p1) +} + +func (s *GatewayStub) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) { + if s.Internal.EthGetCode == nil { + return *new(ethtypes.EthBytes), ErrNotSupported + } + return s.Internal.EthGetCode(p0, p1, p2) +} + +func (s *GatewayStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) { + return *new(ethtypes.EthBytes), ErrNotSupported +} + +func (s *GatewayStruct) EthGetFilterChanges(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if s.Internal.EthGetFilterChanges == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetFilterChanges(p0, p1) +} + +func (s *GatewayStub) EthGetFilterChanges(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthGetFilterLogs(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if s.Internal.EthGetFilterLogs == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetFilterLogs(p0, p1) +} + +func (s *GatewayStub) EthGetFilterLogs(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) { + if s.Internal.EthGetLogs == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetLogs(p0, p1) +} + +func (s *GatewayStub) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) { + if s.Internal.EthGetMessageCidByTransactionHash == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetMessageCidByTransactionHash(p0, p1) +} + +func (s *GatewayStub) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) { + if s.Internal.EthGetStorageAt == nil { + return *new(ethtypes.EthBytes), ErrNotSupported + } + return s.Internal.EthGetStorageAt(p0, p1, p2, p3) +} + +func (s *GatewayStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) { + return *new(ethtypes.EthBytes), ErrNotSupported +} + +func (s *GatewayStruct) EthGetTransactionByBlockHashAndIndex(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + if s.Internal.EthGetTransactionByBlockHashAndIndex == nil { + return *new(ethtypes.EthTx), ErrNotSupported + } + return s.Internal.EthGetTransactionByBlockHashAndIndex(p0, p1, p2) +} + +func (s *GatewayStub) EthGetTransactionByBlockHashAndIndex(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + return *new(ethtypes.EthTx), ErrNotSupported +} + +func (s *GatewayStruct) EthGetTransactionByBlockNumberAndIndex(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + if s.Internal.EthGetTransactionByBlockNumberAndIndex == nil { + return *new(ethtypes.EthTx), ErrNotSupported + } + return s.Internal.EthGetTransactionByBlockNumberAndIndex(p0, p1, p2) +} + +func (s *GatewayStub) EthGetTransactionByBlockNumberAndIndex(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + return *new(ethtypes.EthTx), ErrNotSupported +} + +func (s *GatewayStruct) EthGetTransactionByHash(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) { + if s.Internal.EthGetTransactionByHash == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetTransactionByHash(p0, p1) +} + +func (s *GatewayStub) EthGetTransactionByHash(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) { + if s.Internal.EthGetTransactionCount == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthGetTransactionCount(p0, p1, p2) +} + +func (s *GatewayStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) { + if s.Internal.EthGetTransactionHashByCid == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetTransactionHashByCid(p0, p1) +} + +func (s *GatewayStub) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) { + if s.Internal.EthGetTransactionReceipt == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetTransactionReceipt(p0, p1) +} + +func (s *GatewayStub) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthMaxPriorityFeePerGas(p0 context.Context) (ethtypes.EthBigInt, error) { + if s.Internal.EthMaxPriorityFeePerGas == nil { + return *new(ethtypes.EthBigInt), ErrNotSupported + } + return s.Internal.EthMaxPriorityFeePerGas(p0) +} + +func (s *GatewayStub) EthMaxPriorityFeePerGas(p0 context.Context) (ethtypes.EthBigInt, error) { + return *new(ethtypes.EthBigInt), ErrNotSupported +} + +func (s *GatewayStruct) EthNewBlockFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + if s.Internal.EthNewBlockFilter == nil { + return *new(ethtypes.EthFilterID), ErrNotSupported + } + return s.Internal.EthNewBlockFilter(p0) +} + +func (s *GatewayStub) EthNewBlockFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + return *new(ethtypes.EthFilterID), ErrNotSupported +} + +func (s *GatewayStruct) EthNewFilter(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) { + if s.Internal.EthNewFilter == nil { + return *new(ethtypes.EthFilterID), ErrNotSupported + } + return s.Internal.EthNewFilter(p0, p1) +} + +func (s *GatewayStub) EthNewFilter(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) { + return *new(ethtypes.EthFilterID), ErrNotSupported +} + +func (s *GatewayStruct) EthNewPendingTransactionFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + if s.Internal.EthNewPendingTransactionFilter == nil { + return *new(ethtypes.EthFilterID), ErrNotSupported + } + return s.Internal.EthNewPendingTransactionFilter(p0) +} + +func (s *GatewayStub) EthNewPendingTransactionFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + return *new(ethtypes.EthFilterID), ErrNotSupported +} + +func (s *GatewayStruct) EthProtocolVersion(p0 context.Context) (ethtypes.EthUint64, error) { + if s.Internal.EthProtocolVersion == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthProtocolVersion(p0) +} + +func (s *GatewayStub) EthProtocolVersion(p0 context.Context) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthSendRawTransaction(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) { + if s.Internal.EthSendRawTransaction == nil { + return *new(ethtypes.EthHash), ErrNotSupported + } + return s.Internal.EthSendRawTransaction(p0, p1) +} + +func (s *GatewayStub) EthSendRawTransaction(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) { + return *new(ethtypes.EthHash), ErrNotSupported +} + +func (s *GatewayStruct) EthSubscribe(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) { + if s.Internal.EthSubscribe == nil { + return *new(ethtypes.EthSubscriptionID), ErrNotSupported + } + return s.Internal.EthSubscribe(p0, p1) +} + +func (s *GatewayStub) EthSubscribe(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) { + return *new(ethtypes.EthSubscriptionID), ErrNotSupported +} + +func (s *GatewayStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) { + if s.Internal.EthUninstallFilter == nil { + return false, ErrNotSupported + } + return s.Internal.EthUninstallFilter(p0, p1) +} + +func (s *GatewayStub) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) { + return false, ErrNotSupported +} + +func (s *GatewayStruct) EthUnsubscribe(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) { + if s.Internal.EthUnsubscribe == nil { + return false, ErrNotSupported + } + return s.Internal.EthUnsubscribe(p0, p1) +} + +func (s *GatewayStub) EthUnsubscribe(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) { + return false, ErrNotSupported +} + func (s *GatewayStruct) GasEstimateMessageGas(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) { if s.Internal.GasEstimateMessageGas == nil { return nil, ErrNotSupported @@ -3632,6 +4618,28 @@ func (s *GatewayStub) MsigGetVestingSchedule(p0 context.Context, p1 address.Addr return *new(MsigVesting), ErrNotSupported } +func (s *GatewayStruct) NetListening(p0 context.Context) (bool, error) { + if s.Internal.NetListening == nil { + return false, ErrNotSupported + } + return s.Internal.NetListening(p0) +} + +func (s *GatewayStub) NetListening(p0 context.Context) (bool, error) { + return false, ErrNotSupported +} + +func (s *GatewayStruct) NetVersion(p0 context.Context) (string, error) { + if s.Internal.NetVersion == nil { + return "", ErrNotSupported + } + return s.Internal.NetVersion(p0) +} + +func (s *GatewayStub) NetVersion(p0 context.Context) (string, error) { + return "", ErrNotSupported +} + func (s *GatewayStruct) StateAccountKey(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) { if s.Internal.StateAccountKey == nil { return *new(address.Address), ErrNotSupported @@ -3830,6 +4838,17 @@ func (s *GatewayStub) WalletBalance(p0 context.Context, p1 address.Address) (typ return *new(types.BigInt), ErrNotSupported } +func (s *GatewayStruct) Web3ClientVersion(p0 context.Context) (string, error) { + if s.Internal.Web3ClientVersion == nil { + return "", ErrNotSupported + } + return s.Internal.Web3ClientVersion(p0) +} + +func (s *GatewayStub) Web3ClientVersion(p0 context.Context) (string, error) { + return "", ErrNotSupported +} + func (s *NetStruct) ID(p0 context.Context) (peer.ID, error) { if s.Internal.ID == nil { return *new(peer.ID), ErrNotSupported @@ -4182,15 +5201,15 @@ func (s *StorageMinerStub) ComputeDataCid(p0 context.Context, p1 abi.UnpaddedPie return *new(abi.PieceInfo), ErrNotSupported } -func (s *StorageMinerStruct) ComputeProof(p0 context.Context, p1 []builtin.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtin.PoStProof, error) { +func (s *StorageMinerStruct) ComputeProof(p0 context.Context, p1 []builtinactors.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtinactors.PoStProof, error) { if s.Internal.ComputeProof == nil { - return *new([]builtin.PoStProof), ErrNotSupported + return *new([]builtinactors.PoStProof), ErrNotSupported } return s.Internal.ComputeProof(p0, p1, p2, p3, p4) } -func (s *StorageMinerStub) ComputeProof(p0 context.Context, p1 []builtin.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtin.PoStProof, error) { - return *new([]builtin.PoStProof), ErrNotSupported +func (s *StorageMinerStub) ComputeProof(p0 context.Context, p1 []builtinactors.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtinactors.PoStProof, error) { + return *new([]builtinactors.PoStProof), ErrNotSupported } func (s *StorageMinerStruct) ComputeWindowPoSt(p0 context.Context, p1 uint64, p2 types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) { @@ -5689,25 +6708,25 @@ func (s *WorkerStub) Fetch(p0 context.Context, p1 storiface.SectorRef, p2 storif return *new(storiface.CallID), ErrNotSupported } -func (s *WorkerStruct) FinalizeReplicaUpdate(p0 context.Context, p1 storiface.SectorRef, p2 []storiface.Range) (storiface.CallID, error) { +func (s *WorkerStruct) FinalizeReplicaUpdate(p0 context.Context, p1 storiface.SectorRef) (storiface.CallID, error) { if s.Internal.FinalizeReplicaUpdate == nil { return *new(storiface.CallID), ErrNotSupported } - return s.Internal.FinalizeReplicaUpdate(p0, p1, p2) + return s.Internal.FinalizeReplicaUpdate(p0, p1) } -func (s *WorkerStub) FinalizeReplicaUpdate(p0 context.Context, p1 storiface.SectorRef, p2 []storiface.Range) (storiface.CallID, error) { +func (s *WorkerStub) FinalizeReplicaUpdate(p0 context.Context, p1 storiface.SectorRef) (storiface.CallID, error) { return *new(storiface.CallID), ErrNotSupported } -func (s *WorkerStruct) FinalizeSector(p0 context.Context, p1 storiface.SectorRef, p2 []storiface.Range) (storiface.CallID, error) { +func (s *WorkerStruct) FinalizeSector(p0 context.Context, p1 storiface.SectorRef) (storiface.CallID, error) { if s.Internal.FinalizeSector == nil { return *new(storiface.CallID), ErrNotSupported } - return s.Internal.FinalizeSector(p0, p1, p2) + return s.Internal.FinalizeSector(p0, p1) } -func (s *WorkerStub) FinalizeSector(p0 context.Context, p1 storiface.SectorRef, p2 []storiface.Range) (storiface.CallID, error) { +func (s *WorkerStub) FinalizeSector(p0 context.Context, p1 storiface.SectorRef) (storiface.CallID, error) { return *new(storiface.CallID), ErrNotSupported } @@ -6044,6 +7063,7 @@ func (s *WorkerStub) WaitQuiet(p0 context.Context) error { var _ ChainIO = new(ChainIOStruct) var _ Common = new(CommonStruct) var _ CommonNet = new(CommonNetStruct) +var _ EthSubscriber = new(EthSubscriberStruct) var _ FullNode = new(FullNodeStruct) var _ Gateway = new(GatewayStruct) var _ Net = new(NetStruct) diff --git a/api/types.go b/api/types.go index 5cbe0edef..e67903436 100644 --- a/api/types.go +++ b/api/types.go @@ -338,6 +338,7 @@ type ForkUpgradeParams struct { UpgradeOhSnapHeight abi.ChainEpoch UpgradeSkyrHeight abi.ChainEpoch UpgradeSharkHeight abi.ChainEpoch + UpgradeHyggeHeight abi.ChainEpoch } type NonceMapType map[address.Address]uint64 diff --git a/api/types/rpc.go b/api/types/rpc.go new file mode 100644 index 000000000..4bde6dfbc --- /dev/null +++ b/api/types/rpc.go @@ -0,0 +1,5 @@ +package apitypes + +type Aliaser interface { + AliasMethod(alias, original string) +} diff --git a/api/v0api/full.go b/api/v0api/full.go index ca1371794..490cd73c8 100644 --- a/api/v0api/full.go +++ b/api/v0api/full.go @@ -3,8 +3,8 @@ package v0api import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" textselector "github.com/ipld/go-ipld-selector-text-lite" "github.com/libp2p/go-libp2p/core/peer" @@ -141,7 +141,7 @@ type FullNode interface { // ChainGetPath returns a set of revert/apply operations needed to get from // one tipset to another, for example: - //``` + // ``` // to // ^ // from tAA @@ -150,7 +150,7 @@ type FullNode interface { // ^---*--^ // ^ // tRR - //``` + // ``` // Would return `[revert(tBA), apply(tAB), apply(tAA)]` ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*api.HeadChange, error) //perm:read @@ -367,12 +367,12 @@ type FullNode interface { ClientCancelRetrievalDeal(ctx context.Context, dealid retrievalmarket.DealID) error //perm:write // ClientUnimport removes references to the specified file from filestore - //ClientUnimport(path string) + // ClientUnimport(path string) // ClientListImports lists imported files and their root CIDs ClientListImports(ctx context.Context) ([]api.Import, error) //perm:write - //ClientListAsks() []Ask + // ClientListAsks() []Ask // MethodGroup: State // The State methods are used to query, inspect, and interact with chain state. @@ -641,14 +641,14 @@ type FullNode interface { // It takes the following params: , , MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) //perm:read - //MsigGetPending returns pending transactions for the given multisig - //wallet. Once pending transactions are fully approved, they will no longer - //appear here. + // MsigGetPending returns pending transactions for the given multisig + // wallet. Once pending transactions are fully approved, they will no longer + // appear here. MsigGetPending(context.Context, address.Address, types.TipSetKey) ([]*api.MsigTransaction, error) //perm:read // MsigCreate creates a multisig wallet // It takes the following params: , , - //, , + // , , MsigCreate(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) //perm:sign // MsigPropose proposes a multisig message // It takes the following params: , , , diff --git a/api/v0api/gateway.go b/api/v0api/gateway.go index bd55917c7..674371c14 100644 --- a/api/v0api/gateway.go +++ b/api/v0api/gateway.go @@ -3,8 +3,8 @@ package v0api import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" diff --git a/api/v0api/proxy_gen.go b/api/v0api/proxy_gen.go index b1a07dacc..5fa0d949c 100644 --- a/api/v0api/proxy_gen.go +++ b/api/v0api/proxy_gen.go @@ -5,8 +5,8 @@ package v0api import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-libp2p/core/peer" "golang.org/x/xerrors" @@ -39,383 +39,385 @@ type FullNodeStruct struct { NetStruct - Internal struct { - BeaconGetEntry func(p0 context.Context, p1 abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"` + Internal FullNodeMethods +} - ChainDeleteObj func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` +type FullNodeMethods struct { + BeaconGetEntry func(p0 context.Context, p1 abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"` - ChainExport func(p0 context.Context, p1 abi.ChainEpoch, p2 bool, p3 types.TipSetKey) (<-chan []byte, error) `perm:"read"` + ChainDeleteObj func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` - ChainGetBlock func(p0 context.Context, p1 cid.Cid) (*types.BlockHeader, error) `perm:"read"` + ChainExport func(p0 context.Context, p1 abi.ChainEpoch, p2 bool, p3 types.TipSetKey) (<-chan []byte, error) `perm:"read"` - ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*api.BlockMessages, error) `perm:"read"` + ChainGetBlock func(p0 context.Context, p1 cid.Cid) (*types.BlockHeader, error) `perm:"read"` - ChainGetGenesis func(p0 context.Context) (*types.TipSet, error) `perm:"read"` + ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*api.BlockMessages, error) `perm:"read"` - ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `perm:"read"` + ChainGetGenesis func(p0 context.Context) (*types.TipSet, error) `perm:"read"` - ChainGetMessagesInTipset func(p0 context.Context, p1 types.TipSetKey) ([]api.Message, error) `perm:"read"` + ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `perm:"read"` - ChainGetNode func(p0 context.Context, p1 string) (*api.IpldObject, error) `perm:"read"` + ChainGetMessagesInTipset func(p0 context.Context, p1 types.TipSetKey) ([]api.Message, error) `perm:"read"` - ChainGetParentMessages func(p0 context.Context, p1 cid.Cid) ([]api.Message, error) `perm:"read"` + ChainGetNode func(p0 context.Context, p1 string) (*api.IpldObject, error) `perm:"read"` - ChainGetParentReceipts func(p0 context.Context, p1 cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"` + ChainGetParentMessages func(p0 context.Context, p1 cid.Cid) ([]api.Message, error) `perm:"read"` - ChainGetPath func(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"` + ChainGetParentReceipts func(p0 context.Context, p1 cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"` - ChainGetRandomnessFromBeacon func(p0 context.Context, p1 types.TipSetKey, p2 crypto.DomainSeparationTag, p3 abi.ChainEpoch, p4 []byte) (abi.Randomness, error) `perm:"read"` + ChainGetPath func(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"` - ChainGetRandomnessFromTickets func(p0 context.Context, p1 types.TipSetKey, p2 crypto.DomainSeparationTag, p3 abi.ChainEpoch, p4 []byte) (abi.Randomness, error) `perm:"read"` + ChainGetRandomnessFromBeacon func(p0 context.Context, p1 types.TipSetKey, p2 crypto.DomainSeparationTag, p3 abi.ChainEpoch, p4 []byte) (abi.Randomness, error) `perm:"read"` - ChainGetTipSet func(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) `perm:"read"` + ChainGetRandomnessFromTickets func(p0 context.Context, p1 types.TipSetKey, p2 crypto.DomainSeparationTag, p3 abi.ChainEpoch, p4 []byte) (abi.Randomness, error) `perm:"read"` - ChainGetTipSetByHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `perm:"read"` + ChainGetTipSet func(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) `perm:"read"` - ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) `perm:"read"` + ChainGetTipSetByHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `perm:"read"` - ChainHead func(p0 context.Context) (*types.TipSet, error) `perm:"read"` + ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) `perm:"read"` - ChainNotify func(p0 context.Context) (<-chan []*api.HeadChange, error) `perm:"read"` + ChainHead func(p0 context.Context) (*types.TipSet, error) `perm:"read"` - ChainPutObj func(p0 context.Context, p1 blocks.Block) error `` + ChainNotify func(p0 context.Context) (<-chan []*api.HeadChange, error) `perm:"read"` - ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `perm:"read"` + ChainPutObj func(p0 context.Context, p1 blocks.Block) error `` - ChainSetHead func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"` + ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `perm:"read"` - ChainStatObj func(p0 context.Context, p1 cid.Cid, p2 cid.Cid) (api.ObjStat, error) `perm:"read"` + ChainSetHead func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"` - ChainTipSetWeight func(p0 context.Context, p1 types.TipSetKey) (types.BigInt, error) `perm:"read"` + ChainStatObj func(p0 context.Context, p1 cid.Cid, p2 cid.Cid) (api.ObjStat, error) `perm:"read"` - ClientCalcCommP func(p0 context.Context, p1 string) (*api.CommPRet, error) `perm:"write"` + ChainTipSetWeight func(p0 context.Context, p1 types.TipSetKey) (types.BigInt, error) `perm:"read"` - ClientCancelDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` + ClientCalcCommP func(p0 context.Context, p1 string) (*api.CommPRet, error) `perm:"write"` - ClientCancelRetrievalDeal func(p0 context.Context, p1 retrievalmarket.DealID) error `perm:"write"` + ClientCancelDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` - ClientDataTransferUpdates func(p0 context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"` + ClientCancelRetrievalDeal func(p0 context.Context, p1 retrievalmarket.DealID) error `perm:"write"` - ClientDealPieceCID func(p0 context.Context, p1 cid.Cid) (api.DataCIDSize, error) `perm:"read"` + ClientDataTransferUpdates func(p0 context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"` - ClientDealSize func(p0 context.Context, p1 cid.Cid) (api.DataSize, error) `perm:"read"` + ClientDealPieceCID func(p0 context.Context, p1 cid.Cid) (api.DataCIDSize, error) `perm:"read"` - ClientFindData func(p0 context.Context, p1 cid.Cid, p2 *cid.Cid) ([]api.QueryOffer, error) `perm:"read"` + ClientDealSize func(p0 context.Context, p1 cid.Cid) (api.DataSize, error) `perm:"read"` - ClientGenCar func(p0 context.Context, p1 api.FileRef, p2 string) error `perm:"write"` + ClientFindData func(p0 context.Context, p1 cid.Cid, p2 *cid.Cid) ([]api.QueryOffer, error) `perm:"read"` - ClientGetDealInfo func(p0 context.Context, p1 cid.Cid) (*api.DealInfo, error) `perm:"read"` + ClientGenCar func(p0 context.Context, p1 api.FileRef, p2 string) error `perm:"write"` - ClientGetDealStatus func(p0 context.Context, p1 uint64) (string, error) `perm:"read"` + ClientGetDealInfo func(p0 context.Context, p1 cid.Cid) (*api.DealInfo, error) `perm:"read"` - ClientGetDealUpdates func(p0 context.Context) (<-chan api.DealInfo, error) `perm:"write"` + ClientGetDealStatus func(p0 context.Context, p1 uint64) (string, error) `perm:"read"` - ClientGetRetrievalUpdates func(p0 context.Context) (<-chan api.RetrievalInfo, error) `perm:"write"` + ClientGetDealUpdates func(p0 context.Context) (<-chan api.DealInfo, error) `perm:"write"` - ClientHasLocal func(p0 context.Context, p1 cid.Cid) (bool, error) `perm:"write"` + ClientGetRetrievalUpdates func(p0 context.Context) (<-chan api.RetrievalInfo, error) `perm:"write"` - ClientImport func(p0 context.Context, p1 api.FileRef) (*api.ImportRes, error) `perm:"admin"` + ClientHasLocal func(p0 context.Context, p1 cid.Cid) (bool, error) `perm:"write"` - ClientListDataTransfers func(p0 context.Context) ([]api.DataTransferChannel, error) `perm:"write"` + ClientImport func(p0 context.Context, p1 api.FileRef) (*api.ImportRes, error) `perm:"admin"` - ClientListDeals func(p0 context.Context) ([]api.DealInfo, error) `perm:"write"` + ClientListDataTransfers func(p0 context.Context) ([]api.DataTransferChannel, error) `perm:"write"` - ClientListImports func(p0 context.Context) ([]api.Import, error) `perm:"write"` + ClientListDeals func(p0 context.Context) ([]api.DealInfo, error) `perm:"write"` - ClientListRetrievals func(p0 context.Context) ([]api.RetrievalInfo, error) `perm:"write"` + ClientListImports func(p0 context.Context) ([]api.Import, error) `perm:"write"` - ClientMinerQueryOffer func(p0 context.Context, p1 address.Address, p2 cid.Cid, p3 *cid.Cid) (api.QueryOffer, error) `perm:"read"` + ClientListRetrievals func(p0 context.Context) ([]api.RetrievalInfo, error) `perm:"write"` - ClientQueryAsk func(p0 context.Context, p1 peer.ID, p2 address.Address) (*storagemarket.StorageAsk, error) `perm:"read"` + ClientMinerQueryOffer func(p0 context.Context, p1 address.Address, p2 cid.Cid, p3 *cid.Cid) (api.QueryOffer, error) `perm:"read"` - ClientRemoveImport func(p0 context.Context, p1 imports.ID) error `perm:"admin"` + ClientQueryAsk func(p0 context.Context, p1 peer.ID, p2 address.Address) (*storagemarket.StorageAsk, error) `perm:"read"` - ClientRestartDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` + ClientRemoveImport func(p0 context.Context, p1 imports.ID) error `perm:"admin"` - ClientRetrieve func(p0 context.Context, p1 RetrievalOrder, p2 *api.FileRef) error `perm:"admin"` + ClientRestartDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"` - ClientRetrieveTryRestartInsufficientFunds func(p0 context.Context, p1 address.Address) error `perm:"write"` + ClientRetrieve func(p0 context.Context, p1 RetrievalOrder, p2 *api.FileRef) error `perm:"admin"` - ClientRetrieveWithEvents func(p0 context.Context, p1 RetrievalOrder, p2 *api.FileRef) (<-chan marketevents.RetrievalEvent, error) `perm:"admin"` + ClientRetrieveTryRestartInsufficientFunds func(p0 context.Context, p1 address.Address) error `perm:"write"` - ClientStartDeal func(p0 context.Context, p1 *api.StartDealParams) (*cid.Cid, error) `perm:"admin"` + ClientRetrieveWithEvents func(p0 context.Context, p1 RetrievalOrder, p2 *api.FileRef) (<-chan marketevents.RetrievalEvent, error) `perm:"admin"` - ClientStatelessDeal func(p0 context.Context, p1 *api.StartDealParams) (*cid.Cid, error) `perm:"write"` + ClientStartDeal func(p0 context.Context, p1 *api.StartDealParams) (*cid.Cid, error) `perm:"admin"` - CreateBackup func(p0 context.Context, p1 string) error `perm:"admin"` + ClientStatelessDeal func(p0 context.Context, p1 *api.StartDealParams) (*cid.Cid, error) `perm:"write"` - GasEstimateFeeCap func(p0 context.Context, p1 *types.Message, p2 int64, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` + CreateBackup func(p0 context.Context, p1 string) error `perm:"admin"` - GasEstimateGasLimit func(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (int64, error) `perm:"read"` + GasEstimateFeeCap func(p0 context.Context, p1 *types.Message, p2 int64, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` - GasEstimateGasPremium func(p0 context.Context, p1 uint64, p2 address.Address, p3 int64, p4 types.TipSetKey) (types.BigInt, error) `perm:"read"` + GasEstimateGasLimit func(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (int64, error) `perm:"read"` - GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *api.MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `perm:"read"` + GasEstimateGasPremium func(p0 context.Context, p1 uint64, p2 address.Address, p3 int64, p4 types.TipSetKey) (types.BigInt, error) `perm:"read"` - MarketAddBalance func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` + GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *api.MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `perm:"read"` - MarketGetReserved func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"sign"` + MarketAddBalance func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` - MarketReleaseFunds func(p0 context.Context, p1 address.Address, p2 types.BigInt) error `perm:"sign"` + MarketGetReserved func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"sign"` - MarketReserveFunds func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` + MarketReleaseFunds func(p0 context.Context, p1 address.Address, p2 types.BigInt) error `perm:"sign"` - MarketWithdraw func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` + MarketReserveFunds func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` - MinerCreateBlock func(p0 context.Context, p1 *api.BlockTemplate) (*types.BlockMsg, error) `perm:"write"` + MarketWithdraw func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"` - MinerGetBaseInfo func(p0 context.Context, p1 address.Address, p2 abi.ChainEpoch, p3 types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"` + MinerCreateBlock func(p0 context.Context, p1 *api.BlockTemplate) (*types.BlockMsg, error) `perm:"write"` - MpoolBatchPush func(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) `perm:"write"` + MinerGetBaseInfo func(p0 context.Context, p1 address.Address, p2 abi.ChainEpoch, p3 types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"` - MpoolBatchPushMessage func(p0 context.Context, p1 []*types.Message, p2 *api.MessageSendSpec) ([]*types.SignedMessage, error) `perm:"sign"` + MpoolBatchPush func(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) `perm:"write"` - MpoolBatchPushUntrusted func(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) `perm:"write"` + MpoolBatchPushMessage func(p0 context.Context, p1 []*types.Message, p2 *api.MessageSendSpec) ([]*types.SignedMessage, error) `perm:"sign"` - MpoolClear func(p0 context.Context, p1 bool) error `perm:"write"` + MpoolBatchPushUntrusted func(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) `perm:"write"` - MpoolGetConfig func(p0 context.Context) (*types.MpoolConfig, error) `perm:"read"` + MpoolClear func(p0 context.Context, p1 bool) error `perm:"write"` - MpoolGetNonce func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"read"` + MpoolGetConfig func(p0 context.Context) (*types.MpoolConfig, error) `perm:"read"` - MpoolPending func(p0 context.Context, p1 types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"` + MpoolGetNonce func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"read"` - MpoolPush func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `perm:"write"` + MpoolPending func(p0 context.Context, p1 types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"` - MpoolPushMessage func(p0 context.Context, p1 *types.Message, p2 *api.MessageSendSpec) (*types.SignedMessage, error) `perm:"sign"` + MpoolPush func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `perm:"write"` - MpoolPushUntrusted func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `perm:"write"` + MpoolPushMessage func(p0 context.Context, p1 *types.Message, p2 *api.MessageSendSpec) (*types.SignedMessage, error) `perm:"sign"` - MpoolSelect func(p0 context.Context, p1 types.TipSetKey, p2 float64) ([]*types.SignedMessage, error) `perm:"read"` + MpoolPushUntrusted func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `perm:"write"` - MpoolSetConfig func(p0 context.Context, p1 *types.MpoolConfig) error `perm:"admin"` + MpoolSelect func(p0 context.Context, p1 types.TipSetKey, p2 float64) ([]*types.SignedMessage, error) `perm:"read"` - MpoolSub func(p0 context.Context) (<-chan api.MpoolUpdate, error) `perm:"read"` + MpoolSetConfig func(p0 context.Context, p1 *types.MpoolConfig) error `perm:"admin"` - MsigAddApprove func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address, p6 bool) (cid.Cid, error) `perm:"sign"` + MpoolSub func(p0 context.Context) (<-chan api.MpoolUpdate, error) `perm:"read"` - MsigAddCancel func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 bool) (cid.Cid, error) `perm:"sign"` + MsigAddApprove func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address, p6 bool) (cid.Cid, error) `perm:"sign"` - MsigAddPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 bool) (cid.Cid, error) `perm:"sign"` + MsigAddCancel func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 bool) (cid.Cid, error) `perm:"sign"` - MsigApprove func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address) (cid.Cid, error) `perm:"sign"` + MsigAddPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 bool) (cid.Cid, error) `perm:"sign"` - MsigApproveTxnHash func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 address.Address, p5 types.BigInt, p6 address.Address, p7 uint64, p8 []byte) (cid.Cid, error) `perm:"sign"` + MsigApprove func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address) (cid.Cid, error) `perm:"sign"` - MsigCancel func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 types.BigInt, p5 address.Address, p6 uint64, p7 []byte) (cid.Cid, error) `perm:"sign"` + MsigApproveTxnHash func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 address.Address, p5 types.BigInt, p6 address.Address, p7 uint64, p8 []byte) (cid.Cid, error) `perm:"sign"` - MsigCreate func(p0 context.Context, p1 uint64, p2 []address.Address, p3 abi.ChainEpoch, p4 types.BigInt, p5 address.Address, p6 types.BigInt) (cid.Cid, error) `perm:"sign"` + MsigCancel func(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 types.BigInt, p5 address.Address, p6 uint64, p7 []byte) (cid.Cid, error) `perm:"sign"` - MsigGetAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `perm:"read"` + MsigCreate func(p0 context.Context, p1 uint64, p2 []address.Address, p3 abi.ChainEpoch, p4 types.BigInt, p5 address.Address, p6 types.BigInt) (cid.Cid, error) `perm:"sign"` - MsigGetPending func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*api.MsigTransaction, error) `perm:"read"` + MsigGetAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `perm:"read"` - MsigGetVested func(p0 context.Context, p1 address.Address, p2 types.TipSetKey, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` + MsigGetPending func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*api.MsigTransaction, error) `perm:"read"` - MsigGetVestingSchedule func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MsigVesting, error) `perm:"read"` + MsigGetVested func(p0 context.Context, p1 address.Address, p2 types.TipSetKey, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` - MsigPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt, p4 address.Address, p5 uint64, p6 []byte) (cid.Cid, error) `perm:"sign"` + MsigGetVestingSchedule func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MsigVesting, error) `perm:"read"` - MsigRemoveSigner func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 bool) (cid.Cid, error) `perm:"sign"` + MsigPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt, p4 address.Address, p5 uint64, p6 []byte) (cid.Cid, error) `perm:"sign"` - MsigSwapApprove func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address, p6 address.Address) (cid.Cid, error) `perm:"sign"` + MsigRemoveSigner func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 bool) (cid.Cid, error) `perm:"sign"` - MsigSwapCancel func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address) (cid.Cid, error) `perm:"sign"` + MsigSwapApprove func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address, p6 address.Address) (cid.Cid, error) `perm:"sign"` - MsigSwapPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 address.Address) (cid.Cid, error) `perm:"sign"` + MsigSwapCancel func(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address) (cid.Cid, error) `perm:"sign"` - PaychAllocateLane func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"sign"` + MsigSwapPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 address.Address) (cid.Cid, error) `perm:"sign"` - PaychAvailableFunds func(p0 context.Context, p1 address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` + PaychAllocateLane func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"sign"` - PaychAvailableFundsByFromTo func(p0 context.Context, p1 address.Address, p2 address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` + PaychAvailableFunds func(p0 context.Context, p1 address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` - PaychCollect func(p0 context.Context, p1 address.Address) (cid.Cid, error) `perm:"sign"` + PaychAvailableFundsByFromTo func(p0 context.Context, p1 address.Address, p2 address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` - PaychGet func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (*api.ChannelInfo, error) `perm:"sign"` + PaychCollect func(p0 context.Context, p1 address.Address) (cid.Cid, error) `perm:"sign"` - PaychGetWaitReady func(p0 context.Context, p1 cid.Cid) (address.Address, error) `perm:"sign"` + PaychGet func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (*api.ChannelInfo, error) `perm:"sign"` - PaychList func(p0 context.Context) ([]address.Address, error) `perm:"read"` + PaychGetWaitReady func(p0 context.Context, p1 cid.Cid) (address.Address, error) `perm:"sign"` - PaychNewPayment func(p0 context.Context, p1 address.Address, p2 address.Address, p3 []api.VoucherSpec) (*api.PaymentInfo, error) `perm:"sign"` + PaychList func(p0 context.Context) ([]address.Address, error) `perm:"read"` - PaychSettle func(p0 context.Context, p1 address.Address) (cid.Cid, error) `perm:"sign"` + PaychNewPayment func(p0 context.Context, p1 address.Address, p2 address.Address, p3 []api.VoucherSpec) (*api.PaymentInfo, error) `perm:"sign"` - PaychStatus func(p0 context.Context, p1 address.Address) (*api.PaychStatus, error) `perm:"read"` + PaychSettle func(p0 context.Context, p1 address.Address) (cid.Cid, error) `perm:"sign"` - PaychVoucherAdd func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 types.BigInt) (types.BigInt, error) `perm:"write"` + PaychStatus func(p0 context.Context, p1 address.Address) (*api.PaychStatus, error) `perm:"read"` - PaychVoucherCheckSpendable func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 []byte) (bool, error) `perm:"read"` + PaychVoucherAdd func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 types.BigInt) (types.BigInt, error) `perm:"write"` - PaychVoucherCheckValid func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher) error `perm:"read"` + PaychVoucherCheckSpendable func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 []byte) (bool, error) `perm:"read"` - PaychVoucherCreate func(p0 context.Context, p1 address.Address, p2 types.BigInt, p3 uint64) (*api.VoucherCreateResult, error) `perm:"sign"` + PaychVoucherCheckValid func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher) error `perm:"read"` - PaychVoucherList func(p0 context.Context, p1 address.Address) ([]*paych.SignedVoucher, error) `perm:"write"` + PaychVoucherCreate func(p0 context.Context, p1 address.Address, p2 types.BigInt, p3 uint64) (*api.VoucherCreateResult, error) `perm:"sign"` - PaychVoucherSubmit func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 []byte) (cid.Cid, error) `perm:"sign"` + PaychVoucherList func(p0 context.Context, p1 address.Address) ([]*paych.SignedVoucher, error) `perm:"write"` - StateAccountKey func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` + PaychVoucherSubmit func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 []byte) (cid.Cid, error) `perm:"sign"` - StateActorCodeCIDs func(p0 context.Context, p1 abinetwork.Version) (map[string]cid.Cid, error) `perm:"read"` + StateAccountKey func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` - StateActorManifestCID func(p0 context.Context, p1 abinetwork.Version) (cid.Cid, error) `perm:"read"` + StateActorCodeCIDs func(p0 context.Context, p1 abinetwork.Version) (map[string]cid.Cid, error) `perm:"read"` - StateAllMinerFaults func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) ([]*api.Fault, error) `perm:"read"` + StateActorManifestCID func(p0 context.Context, p1 abinetwork.Version) (cid.Cid, error) `perm:"read"` - StateCall func(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (*api.InvocResult, error) `perm:"read"` + StateAllMinerFaults func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) ([]*api.Fault, error) `perm:"read"` - StateChangedActors func(p0 context.Context, p1 cid.Cid, p2 cid.Cid) (map[string]types.Actor, error) `perm:"read"` + StateCall func(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (*api.InvocResult, error) `perm:"read"` - StateCirculatingSupply func(p0 context.Context, p1 types.TipSetKey) (abi.TokenAmount, error) `perm:"read"` + StateChangedActors func(p0 context.Context, p1 cid.Cid, p2 cid.Cid) (map[string]types.Actor, error) `perm:"read"` - StateCompute func(p0 context.Context, p1 abi.ChainEpoch, p2 []*types.Message, p3 types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"` + StateCirculatingSupply func(p0 context.Context, p1 types.TipSetKey) (abi.TokenAmount, error) `perm:"read"` - StateDealProviderCollateralBounds func(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (api.DealCollateralBounds, error) `perm:"read"` + StateCompute func(p0 context.Context, p1 abi.ChainEpoch, p2 []*types.Message, p3 types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"` - StateDecodeParams func(p0 context.Context, p1 address.Address, p2 abi.MethodNum, p3 []byte, p4 types.TipSetKey) (interface{}, error) `perm:"read"` + StateDealProviderCollateralBounds func(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (api.DealCollateralBounds, error) `perm:"read"` - StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) `perm:"read"` + StateDecodeParams func(p0 context.Context, p1 address.Address, p2 abi.MethodNum, p3 []byte, p4 types.TipSetKey) (interface{}, error) `perm:"read"` - StateGetAllocation func(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) `perm:"read"` + StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) `perm:"read"` - StateGetAllocationForPendingDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) `perm:"read"` + StateGetAllocation func(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) `perm:"read"` - StateGetAllocations func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) `perm:"read"` + StateGetAllocationForPendingDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) `perm:"read"` - StateGetClaim func(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) `perm:"read"` + StateGetAllocations func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) `perm:"read"` - StateGetClaims func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) `perm:"read"` + StateGetClaim func(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) `perm:"read"` - StateGetNetworkParams func(p0 context.Context) (*api.NetworkParams, error) `perm:"read"` + StateGetClaims func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) `perm:"read"` - StateGetRandomnessFromBeacon func(p0 context.Context, p1 crypto.DomainSeparationTag, p2 abi.ChainEpoch, p3 []byte, p4 types.TipSetKey) (abi.Randomness, error) `perm:"read"` + StateGetNetworkParams func(p0 context.Context) (*api.NetworkParams, error) `perm:"read"` - StateGetRandomnessFromTickets func(p0 context.Context, p1 crypto.DomainSeparationTag, p2 abi.ChainEpoch, p3 []byte, p4 types.TipSetKey) (abi.Randomness, error) `perm:"read"` + StateGetRandomnessFromBeacon func(p0 context.Context, p1 crypto.DomainSeparationTag, p2 abi.ChainEpoch, p3 []byte, p4 types.TipSetKey) (abi.Randomness, error) `perm:"read"` - StateGetReceipt func(p0 context.Context, p1 cid.Cid, p2 types.TipSetKey) (*types.MessageReceipt, error) `perm:"read"` + StateGetRandomnessFromTickets func(p0 context.Context, p1 crypto.DomainSeparationTag, p2 abi.ChainEpoch, p3 []byte, p4 types.TipSetKey) (abi.Randomness, error) `perm:"read"` - StateListActors func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `perm:"read"` + StateGetReceipt func(p0 context.Context, p1 cid.Cid, p2 types.TipSetKey) (*types.MessageReceipt, error) `perm:"read"` - StateListMessages func(p0 context.Context, p1 *api.MessageMatch, p2 types.TipSetKey, p3 abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"` + StateListActors func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `perm:"read"` - StateListMiners func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `perm:"read"` + StateListMessages func(p0 context.Context, p1 *api.MessageMatch, p2 types.TipSetKey, p3 abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"` - StateLookupID func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` + StateListMiners func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `perm:"read"` - StateMarketBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MarketBalance, error) `perm:"read"` + StateLookupID func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` - StateMarketDeals func(p0 context.Context, p1 types.TipSetKey) (map[string]*api.MarketDeal, error) `perm:"read"` + StateMarketBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MarketBalance, error) `perm:"read"` - StateMarketParticipants func(p0 context.Context, p1 types.TipSetKey) (map[string]api.MarketBalance, error) `perm:"read"` + StateMarketDeals func(p0 context.Context, p1 types.TipSetKey) (map[string]*api.MarketDeal, error) `perm:"read"` - StateMarketStorageDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*api.MarketDeal, error) `perm:"read"` + StateMarketParticipants func(p0 context.Context, p1 types.TipSetKey) (map[string]api.MarketBalance, error) `perm:"read"` - StateMinerActiveSectors func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"` + StateMarketStorageDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*api.MarketDeal, error) `perm:"read"` - StateMinerAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `perm:"read"` + StateMinerActiveSectors func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"` - StateMinerDeadlines func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]api.Deadline, error) `perm:"read"` + StateMinerAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `perm:"read"` - StateMinerFaults func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (bitfield.BitField, error) `perm:"read"` + StateMinerDeadlines func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]api.Deadline, error) `perm:"read"` - StateMinerInfo func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MinerInfo, error) `perm:"read"` + StateMinerFaults func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (bitfield.BitField, error) `perm:"read"` - StateMinerInitialPledgeCollateral func(p0 context.Context, p1 address.Address, p2 miner.SectorPreCommitInfo, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` + StateMinerInfo func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MinerInfo, error) `perm:"read"` - StateMinerPartitions func(p0 context.Context, p1 address.Address, p2 uint64, p3 types.TipSetKey) ([]api.Partition, error) `perm:"read"` + StateMinerInitialPledgeCollateral func(p0 context.Context, p1 address.Address, p2 miner.SectorPreCommitInfo, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` - StateMinerPower func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*api.MinerPower, error) `perm:"read"` + StateMinerPartitions func(p0 context.Context, p1 address.Address, p2 uint64, p3 types.TipSetKey) ([]api.Partition, error) `perm:"read"` - StateMinerPreCommitDepositForPower func(p0 context.Context, p1 address.Address, p2 miner.SectorPreCommitInfo, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` + StateMinerPower func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*api.MinerPower, error) `perm:"read"` - StateMinerProvingDeadline func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*dline.Info, error) `perm:"read"` + StateMinerPreCommitDepositForPower func(p0 context.Context, p1 address.Address, p2 miner.SectorPreCommitInfo, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"` - StateMinerRecoveries func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (bitfield.BitField, error) `perm:"read"` + StateMinerProvingDeadline func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*dline.Info, error) `perm:"read"` - StateMinerSectorAllocated func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (bool, error) `perm:"read"` + StateMinerRecoveries func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (bitfield.BitField, error) `perm:"read"` - StateMinerSectorCount func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MinerSectors, error) `perm:"read"` + StateMinerSectorAllocated func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (bool, error) `perm:"read"` - StateMinerSectors func(p0 context.Context, p1 address.Address, p2 *bitfield.BitField, p3 types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"` + StateMinerSectorCount func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MinerSectors, error) `perm:"read"` - StateNetworkName func(p0 context.Context) (dtypes.NetworkName, error) `perm:"read"` + StateMinerSectors func(p0 context.Context, p1 address.Address, p2 *bitfield.BitField, p3 types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"` - StateNetworkVersion func(p0 context.Context, p1 types.TipSetKey) (apitypes.NetworkVersion, error) `perm:"read"` + StateNetworkName func(p0 context.Context) (dtypes.NetworkName, error) `perm:"read"` - StateReadState func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*api.ActorState, error) `perm:"read"` + StateNetworkVersion func(p0 context.Context, p1 types.TipSetKey) (apitypes.NetworkVersion, error) `perm:"read"` - StateReplay func(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid) (*api.InvocResult, error) `perm:"read"` + StateReadState func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*api.ActorState, error) `perm:"read"` - StateSearchMsg func(p0 context.Context, p1 cid.Cid) (*api.MsgLookup, error) `perm:"read"` + StateReplay func(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid) (*api.InvocResult, error) `perm:"read"` - StateSearchMsgLimited func(p0 context.Context, p1 cid.Cid, p2 abi.ChainEpoch) (*api.MsgLookup, error) `perm:"read"` + StateSearchMsg func(p0 context.Context, p1 cid.Cid) (*api.MsgLookup, error) `perm:"read"` - StateSectorExpiration func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*lminer.SectorExpiration, error) `perm:"read"` + StateSearchMsgLimited func(p0 context.Context, p1 cid.Cid, p2 abi.ChainEpoch) (*api.MsgLookup, error) `perm:"read"` - StateSectorGetInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorOnChainInfo, error) `perm:"read"` + StateSectorExpiration func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*lminer.SectorExpiration, error) `perm:"read"` - StateSectorPartition func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*lminer.SectorLocation, error) `perm:"read"` + StateSectorGetInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorOnChainInfo, error) `perm:"read"` - StateSectorPreCommitInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) `perm:"read"` + StateSectorPartition func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*lminer.SectorLocation, error) `perm:"read"` - StateVMCirculatingSupplyInternal func(p0 context.Context, p1 types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"` + StateSectorPreCommitInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) `perm:"read"` - StateVerifiedClientStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `perm:"read"` + StateVMCirculatingSupplyInternal func(p0 context.Context, p1 types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"` - StateVerifiedRegistryRootKey func(p0 context.Context, p1 types.TipSetKey) (address.Address, error) `perm:"read"` + StateVerifiedClientStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `perm:"read"` - StateVerifierStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `perm:"read"` + StateVerifiedRegistryRootKey func(p0 context.Context, p1 types.TipSetKey) (address.Address, error) `perm:"read"` - StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64) (*api.MsgLookup, error) `perm:"read"` + StateVerifierStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `perm:"read"` - StateWaitMsgLimited func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch) (*api.MsgLookup, error) `perm:"read"` + StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64) (*api.MsgLookup, error) `perm:"read"` - SyncCheckBad func(p0 context.Context, p1 cid.Cid) (string, error) `perm:"read"` + StateWaitMsgLimited func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch) (*api.MsgLookup, error) `perm:"read"` - SyncCheckpoint func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"` + SyncCheckBad func(p0 context.Context, p1 cid.Cid) (string, error) `perm:"read"` - SyncIncomingBlocks func(p0 context.Context) (<-chan *types.BlockHeader, error) `perm:"read"` + SyncCheckpoint func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"` - SyncMarkBad func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` + SyncIncomingBlocks func(p0 context.Context) (<-chan *types.BlockHeader, error) `perm:"read"` - SyncState func(p0 context.Context) (*api.SyncState, error) `perm:"read"` + SyncMarkBad func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` - SyncSubmitBlock func(p0 context.Context, p1 *types.BlockMsg) error `perm:"write"` + SyncState func(p0 context.Context) (*api.SyncState, error) `perm:"read"` - SyncUnmarkAllBad func(p0 context.Context) error `perm:"admin"` + SyncSubmitBlock func(p0 context.Context, p1 *types.BlockMsg) error `perm:"write"` - SyncUnmarkBad func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` + SyncUnmarkAllBad func(p0 context.Context) error `perm:"admin"` - SyncValidateTipset func(p0 context.Context, p1 types.TipSetKey) (bool, error) `perm:"read"` + SyncUnmarkBad func(p0 context.Context, p1 cid.Cid) error `perm:"admin"` - WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"read"` + SyncValidateTipset func(p0 context.Context, p1 types.TipSetKey) (bool, error) `perm:"read"` - WalletDefaultAddress func(p0 context.Context) (address.Address, error) `perm:"write"` + WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"read"` - WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"` + WalletDefaultAddress func(p0 context.Context) (address.Address, error) `perm:"write"` - WalletExport func(p0 context.Context, p1 address.Address) (*types.KeyInfo, error) `perm:"admin"` + WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"` - WalletHas func(p0 context.Context, p1 address.Address) (bool, error) `perm:"write"` + WalletExport func(p0 context.Context, p1 address.Address) (*types.KeyInfo, error) `perm:"admin"` - WalletImport func(p0 context.Context, p1 *types.KeyInfo) (address.Address, error) `perm:"admin"` + WalletHas func(p0 context.Context, p1 address.Address) (bool, error) `perm:"write"` - WalletList func(p0 context.Context) ([]address.Address, error) `perm:"write"` + WalletImport func(p0 context.Context, p1 *types.KeyInfo) (address.Address, error) `perm:"admin"` - WalletNew func(p0 context.Context, p1 types.KeyType) (address.Address, error) `perm:"write"` + WalletList func(p0 context.Context) ([]address.Address, error) `perm:"write"` - WalletSetDefault func(p0 context.Context, p1 address.Address) error `perm:"write"` + WalletNew func(p0 context.Context, p1 types.KeyType) (address.Address, error) `perm:"write"` - WalletSign func(p0 context.Context, p1 address.Address, p2 []byte) (*crypto.Signature, error) `perm:"sign"` + WalletSetDefault func(p0 context.Context, p1 address.Address) error `perm:"write"` - WalletSignMessage func(p0 context.Context, p1 address.Address, p2 *types.Message) (*types.SignedMessage, error) `perm:"sign"` + WalletSign func(p0 context.Context, p1 address.Address, p2 []byte) (*crypto.Signature, error) `perm:"sign"` - WalletValidateAddress func(p0 context.Context, p1 string) (address.Address, error) `perm:"read"` + WalletSignMessage func(p0 context.Context, p1 address.Address, p2 *types.Message) (*types.SignedMessage, error) `perm:"sign"` - WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"` - } + WalletValidateAddress func(p0 context.Context, p1 string) (address.Address, error) `perm:"read"` + + WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"` } type FullNodeStub struct { @@ -425,71 +427,73 @@ type FullNodeStub struct { } type GatewayStruct struct { - Internal struct { - ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*api.BlockMessages, error) `` + Internal GatewayMethods +} - ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `` +type GatewayMethods struct { + ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*api.BlockMessages, error) `` - ChainGetTipSet func(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) `` + ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `` - ChainGetTipSetByHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `` + ChainGetTipSet func(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) `` - ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) `` + ChainGetTipSetByHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `` - ChainHead func(p0 context.Context) (*types.TipSet, error) `` + ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) `` - ChainNotify func(p0 context.Context) (<-chan []*api.HeadChange, error) `` + ChainHead func(p0 context.Context) (*types.TipSet, error) `` - ChainPutObj func(p0 context.Context, p1 blocks.Block) error `` + ChainNotify func(p0 context.Context) (<-chan []*api.HeadChange, error) `` - ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `` + ChainPutObj func(p0 context.Context, p1 blocks.Block) error `` - GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *api.MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `` + ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `` - MpoolPush func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `` + GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *api.MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `` - MsigGetAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `` + MpoolPush func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `` - MsigGetPending func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*api.MsigTransaction, error) `` + MsigGetAvailableBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) `` - MsigGetVested func(p0 context.Context, p1 address.Address, p2 types.TipSetKey, p3 types.TipSetKey) (types.BigInt, error) `` + MsigGetPending func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*api.MsigTransaction, error) `` - StateAccountKey func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `` + MsigGetVested func(p0 context.Context, p1 address.Address, p2 types.TipSetKey, p3 types.TipSetKey) (types.BigInt, error) `` - StateDealProviderCollateralBounds func(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (api.DealCollateralBounds, error) `` + StateAccountKey func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `` - StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) `` + StateDealProviderCollateralBounds func(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (api.DealCollateralBounds, error) `` - StateGetReceipt func(p0 context.Context, p1 cid.Cid, p2 types.TipSetKey) (*types.MessageReceipt, error) `` + StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) `` - StateListMiners func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `` + StateGetReceipt func(p0 context.Context, p1 cid.Cid, p2 types.TipSetKey) (*types.MessageReceipt, error) `` - StateLookupID func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `` + StateListMiners func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `` - StateMarketBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MarketBalance, error) `` + StateLookupID func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `` - StateMarketStorageDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*api.MarketDeal, error) `` + StateMarketBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MarketBalance, error) `` - StateMinerInfo func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MinerInfo, error) `` + StateMarketStorageDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*api.MarketDeal, error) `` - StateMinerPower func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*api.MinerPower, error) `` + StateMinerInfo func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (api.MinerInfo, error) `` - StateMinerProvingDeadline func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*dline.Info, error) `` + StateMinerPower func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*api.MinerPower, error) `` - StateNetworkVersion func(p0 context.Context, p1 types.TipSetKey) (abinetwork.Version, error) `` + StateMinerProvingDeadline func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*dline.Info, error) `` - StateSearchMsg func(p0 context.Context, p1 cid.Cid) (*api.MsgLookup, error) `` + StateNetworkVersion func(p0 context.Context, p1 types.TipSetKey) (abinetwork.Version, error) `` - StateSectorGetInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorOnChainInfo, error) `` + StateSearchMsg func(p0 context.Context, p1 cid.Cid) (*api.MsgLookup, error) `` - StateVerifiedClientStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `` + StateSectorGetInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorOnChainInfo, error) `` - StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64) (*api.MsgLookup, error) `` + StateVerifiedClientStatus func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) `` - Version func(p0 context.Context) (api.APIVersion, error) `` + StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64) (*api.MsgLookup, error) `` - WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `` - } + Version func(p0 context.Context) (api.APIVersion, error) `` + + WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) `` } type GatewayStub struct { diff --git a/api/v0api/v0mocks/mock_full.go b/api/v0api/v0mocks/mock_full.go index 2b815c4ca..619f19d35 100644 --- a/api/v0api/v0mocks/mock_full.go +++ b/api/v0api/v0mocks/mock_full.go @@ -11,8 +11,8 @@ import ( gomock "github.com/golang/mock/gomock" uuid "github.com/google/uuid" - blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" metrics "github.com/libp2p/go-libp2p/core/metrics" network0 "github.com/libp2p/go-libp2p/core/network" peer "github.com/libp2p/go-libp2p/core/peer" @@ -2249,10 +2249,10 @@ func (mr *MockFullNodeMockRecorder) StateCall(arg0, arg1, arg2 interface{}) *gom } // StateChangedActors mocks base method. -func (m *MockFullNode) StateChangedActors(arg0 context.Context, arg1, arg2 cid.Cid) (map[string]types.Actor, error) { +func (m *MockFullNode) StateChangedActors(arg0 context.Context, arg1, arg2 cid.Cid) (map[string]types.ActorV5, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateChangedActors", arg0, arg1, arg2) - ret0, _ := ret[0].(map[string]types.Actor) + ret0, _ := ret[0].(map[string]types.ActorV5) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -2324,10 +2324,10 @@ func (mr *MockFullNodeMockRecorder) StateDecodeParams(arg0, arg1, arg2, arg3, ar } // StateGetActor mocks base method. -func (m *MockFullNode) StateGetActor(arg0 context.Context, arg1 address.Address, arg2 types.TipSetKey) (*types.Actor, error) { +func (m *MockFullNode) StateGetActor(arg0 context.Context, arg1 address.Address, arg2 types.TipSetKey) (*types.ActorV5, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateGetActor", arg0, arg1, arg2) - ret0, _ := ret[0].(*types.Actor) + ret0, _ := ret[0].(*types.ActorV5) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/api/version.go b/api/version.go index 3b50a9502..9c2113578 100644 --- a/api/version.go +++ b/api/version.go @@ -58,7 +58,7 @@ var ( FullAPIVersion1 = newVer(2, 3, 0) MinerAPIVersion0 = newVer(1, 5, 0) - WorkerAPIVersion0 = newVer(1, 6, 0) + WorkerAPIVersion0 = newVer(1, 7, 0) ) //nolint:varcheck,deadcode diff --git a/blockstore/api.go b/blockstore/api.go index 090f53e5a..251deb13a 100644 --- a/blockstore/api.go +++ b/blockstore/api.go @@ -3,8 +3,8 @@ package blockstore import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" ) diff --git a/blockstore/autobatch.go b/blockstore/autobatch.go index d41d521ef..3cb8eafa6 100644 --- a/blockstore/autobatch.go +++ b/blockstore/autobatch.go @@ -5,9 +5,9 @@ import ( "sync" "time" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + block "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" ) diff --git a/blockstore/badger/blockstore.go b/blockstore/badger/blockstore.go index 050ed6d3b..da4f9f67d 100644 --- a/blockstore/badger/blockstore.go +++ b/blockstore/badger/blockstore.go @@ -13,9 +13,9 @@ import ( "github.com/dgraph-io/badger/v2" "github.com/dgraph-io/badger/v2/options" "github.com/dgraph-io/badger/v2/pb" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" logger "github.com/ipfs/go-log/v2" pool "github.com/libp2p/go-buffer-pool" "github.com/multiformats/go-base32" diff --git a/blockstore/badger/blockstore_test.go b/blockstore/badger/blockstore_test.go index a14515796..fc81be43e 100644 --- a/blockstore/badger/blockstore_test.go +++ b/blockstore/badger/blockstore_test.go @@ -10,8 +10,8 @@ import ( "strings" "testing" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" diff --git a/blockstore/badger/blockstore_test_suite.go b/blockstore/badger/blockstore_test_suite.go index 7db155901..877eb6e6b 100644 --- a/blockstore/badger/blockstore_test_suite.go +++ b/blockstore/badger/blockstore_test_suite.go @@ -9,10 +9,10 @@ import ( "strings" "testing" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" u "github.com/ipfs/go-ipfs-util" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/stretchr/testify/require" "github.com/filecoin-project/lotus/blockstore" diff --git a/blockstore/buffered.go b/blockstore/buffered.go index dbee095a2..e089ed561 100644 --- a/blockstore/buffered.go +++ b/blockstore/buffered.go @@ -4,9 +4,9 @@ import ( "context" "os" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + block "github.com/ipfs/go-libipfs/blocks" ) // buflog is a logger for the buffered blockstore. It is subscoped from the diff --git a/blockstore/discard.go b/blockstore/discard.go index a8e6cfec7..7f1a76a22 100644 --- a/blockstore/discard.go +++ b/blockstore/discard.go @@ -4,8 +4,8 @@ import ( "context" "io" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" ) var _ Blockstore = (*discardstore)(nil) diff --git a/blockstore/fallback.go b/blockstore/fallback.go index de948b346..9fab960f5 100644 --- a/blockstore/fallback.go +++ b/blockstore/fallback.go @@ -5,9 +5,9 @@ import ( "sync" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" ) diff --git a/blockstore/idstore.go b/blockstore/idstore.go index 23b85146a..a0ecec5f0 100644 --- a/blockstore/idstore.go +++ b/blockstore/idstore.go @@ -4,8 +4,8 @@ import ( "context" "io" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" mh "github.com/multiformats/go-multihash" "golang.org/x/xerrors" ) diff --git a/blockstore/ipfs.go b/blockstore/ipfs.go index 41c2b8710..756314f2d 100644 --- a/blockstore/ipfs.go +++ b/blockstore/ipfs.go @@ -5,9 +5,9 @@ import ( "context" "io/ioutil" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" httpapi "github.com/ipfs/go-ipfs-http-client" + blocks "github.com/ipfs/go-libipfs/blocks" iface "github.com/ipfs/interface-go-ipfs-core" "github.com/ipfs/interface-go-ipfs-core/options" "github.com/ipfs/interface-go-ipfs-core/path" diff --git a/blockstore/mem.go b/blockstore/mem.go index 7cfefafd7..05da287c5 100644 --- a/blockstore/mem.go +++ b/blockstore/mem.go @@ -3,9 +3,9 @@ package blockstore import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" ) // NewMemory returns a temporary memory-backed blockstore. diff --git a/blockstore/mem_test.go b/blockstore/mem_test.go index 4d4a77624..6a5e0d2d1 100644 --- a/blockstore/mem_test.go +++ b/blockstore/mem_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" mh "github.com/multiformats/go-multihash" "github.com/stretchr/testify/require" ) diff --git a/blockstore/net.go b/blockstore/net.go index 77da764a5..a6b008af2 100644 --- a/blockstore/net.go +++ b/blockstore/net.go @@ -8,9 +8,9 @@ import ( "sync" "sync/atomic" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-msgio" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" diff --git a/blockstore/net_serve.go b/blockstore/net_serve.go index 2540c845e..b58d2a5fd 100644 --- a/blockstore/net_serve.go +++ b/blockstore/net_serve.go @@ -5,9 +5,9 @@ import ( "context" "encoding/binary" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + block "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-msgio" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" diff --git a/blockstore/net_test.go b/blockstore/net_test.go index d8c33818e..6c3060a98 100644 --- a/blockstore/net_test.go +++ b/blockstore/net_test.go @@ -6,8 +6,8 @@ import ( "io" "testing" - block "github.com/ipfs/go-block-format" ipld "github.com/ipfs/go-ipld-format" + block "github.com/ipfs/go-libipfs/blocks" "github.com/libp2p/go-msgio" "github.com/stretchr/testify/require" ) diff --git a/blockstore/splitstore/debug.go b/blockstore/splitstore/debug.go index f059ae4ce..c870a44e1 100644 --- a/blockstore/splitstore/debug.go +++ b/blockstore/splitstore/debug.go @@ -12,8 +12,8 @@ import ( "sync" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "go.uber.org/multierr" "golang.org/x/xerrors" ) diff --git a/blockstore/splitstore/splitstore.go b/blockstore/splitstore/splitstore.go index dee6e784c..0afb15c11 100644 --- a/blockstore/splitstore/splitstore.go +++ b/blockstore/splitstore/splitstore.go @@ -8,10 +8,10 @@ import ( "sync/atomic" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" dstore "github.com/ipfs/go-datastore" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" "go.opencensus.io/stats" "go.uber.org/multierr" diff --git a/blockstore/splitstore/splitstore_compact.go b/blockstore/splitstore/splitstore_compact.go index 1c4c903ff..0422736f0 100644 --- a/blockstore/splitstore/splitstore_compact.go +++ b/blockstore/splitstore/splitstore_compact.go @@ -10,9 +10,9 @@ import ( "sync/atomic" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" cbg "github.com/whyrusleeping/cbor-gen" "go.opencensus.io/stats" "golang.org/x/sync/errgroup" @@ -905,6 +905,10 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp walkCnt := new(int64) scanCnt := new(int64) + tsRef := func(blkCids []cid.Cid) (cid.Cid, error) { + return types.NewTipSetKey(blkCids...).Cid() + } + stopWalk := func(_ cid.Cid) error { return errStopWalk } walkBlock := func(c cid.Cid) error { @@ -926,11 +930,19 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp err = s.view(c, func(data []byte) error { return hdr.UnmarshalCBOR(bytes.NewBuffer(data)) }) - if err != nil { return xerrors.Errorf("error unmarshaling block header (cid: %s): %w", c, err) } + // tipset CID references are retained + pRef, err := tsRef(hdr.Parents) + if err != nil { + return xerrors.Errorf("error computing cid reference to parent tipset") + } + if err := s.walkObjectIncomplete(pRef, visitor, fHot, stopWalk); err != nil { + return xerrors.Errorf("error walking parent tipset cid reference") + } + // message are retained if within the inclMsgs boundary if hdr.Height >= inclMsgs && hdr.Height > 0 { if inclMsgs < inclState { @@ -981,6 +993,15 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp return nil } + // retain ref to chain head + hRef, err := tsRef(ts.Cids()) + if err != nil { + return xerrors.Errorf("error computing cid reference to parent tipset") + } + if err := s.walkObjectIncomplete(hRef, visitor, fHot, stopWalk); err != nil { + return xerrors.Errorf("error walking parent tipset cid reference") + } + for len(toWalk) > 0 { // walking can take a while, so check this with every opportunity if err := s.checkClosing(); err != nil { diff --git a/blockstore/splitstore/splitstore_expose.go b/blockstore/splitstore/splitstore_expose.go index ff9bf1f71..d092fbb9b 100644 --- a/blockstore/splitstore/splitstore_expose.go +++ b/blockstore/splitstore/splitstore_expose.go @@ -4,9 +4,9 @@ import ( "context" "errors" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" bstore "github.com/filecoin-project/lotus/blockstore" ) diff --git a/blockstore/splitstore/splitstore_reify.go b/blockstore/splitstore/splitstore_reify.go index 9db480b8c..aa14f090a 100644 --- a/blockstore/splitstore/splitstore_reify.go +++ b/blockstore/splitstore/splitstore_reify.go @@ -5,8 +5,8 @@ import ( "runtime" "sync/atomic" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" ) diff --git a/blockstore/splitstore/splitstore_test.go b/blockstore/splitstore/splitstore_test.go index 750a2efed..c97a9d01c 100644 --- a/blockstore/splitstore/splitstore_test.go +++ b/blockstore/splitstore/splitstore_test.go @@ -11,11 +11,11 @@ import ( "testing" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-datastore/sync" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" mh "github.com/multiformats/go-multihash" diff --git a/blockstore/splitstore/splitstore_warmup.go b/blockstore/splitstore/splitstore_warmup.go index e387263da..23bbad7ca 100644 --- a/blockstore/splitstore/splitstore_warmup.go +++ b/blockstore/splitstore/splitstore_warmup.go @@ -5,9 +5,9 @@ import ( "sync/atomic" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" diff --git a/blockstore/sync.go b/blockstore/sync.go index 1b4ad8297..4f97027ae 100644 --- a/blockstore/sync.go +++ b/blockstore/sync.go @@ -4,8 +4,8 @@ import ( "context" "sync" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" ) // NewMemorySync returns a thread-safe in-memory blockstore. diff --git a/blockstore/timed.go b/blockstore/timed.go index 38f4e51f3..dda2e1958 100644 --- a/blockstore/timed.go +++ b/blockstore/timed.go @@ -6,9 +6,9 @@ import ( "sync" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/raulk/clock" "go.uber.org/multierr" ) diff --git a/blockstore/timed_test.go b/blockstore/timed_test.go index 931f14507..fb3aa00c9 100644 --- a/blockstore/timed_test.go +++ b/blockstore/timed_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/raulk/clock" "github.com/stretchr/testify/require" ) diff --git a/blockstore/union.go b/blockstore/union.go index 71e785f1a..3372cd20c 100644 --- a/blockstore/union.go +++ b/blockstore/union.go @@ -3,9 +3,9 @@ package blockstore import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" ) type unionBlockstore []Blockstore diff --git a/blockstore/union_test.go b/blockstore/union_test.go index 579489947..47aab852a 100644 --- a/blockstore/union_test.go +++ b/blockstore/union_test.go @@ -5,7 +5,7 @@ import ( "context" "testing" - blocks "github.com/ipfs/go-block-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/stretchr/testify/require" ) diff --git a/build/actors/pack.sh b/build/actors/pack.sh index c2060e67c..e594bb2da 100755 --- a/build/actors/pack.sh +++ b/build/actors/pack.sh @@ -52,4 +52,4 @@ popd echo "Generating metadata..." -make -C ../../ bundle-gen +make -C ../../ VERSION="$VERSION" RELEASE="$RELEASE" RELEASE_OVERRIDES="${RELEASE_OVERRIDES[*]}" bundle-gen diff --git a/build/actors/v10.tar.zst b/build/actors/v10.tar.zst new file mode 100644 index 000000000..9ac6453f8 Binary files /dev/null and b/build/actors/v10.tar.zst differ diff --git a/build/actors/v8.tar.zst b/build/actors/v8.tar.zst index c4eb857b9..88e0ac800 100644 Binary files a/build/actors/v8.tar.zst and b/build/actors/v8.tar.zst differ diff --git a/build/actors/v9.tar.zst b/build/actors/v9.tar.zst index 95b887312..f19c7db4c 100644 Binary files a/build/actors/v9.tar.zst and b/build/actors/v9.tar.zst differ diff --git a/build/bootstrap/butterflynet.pi b/build/bootstrap/butterflynet.pi index 556b5d14f..5b10e2bc4 100644 --- a/build/bootstrap/butterflynet.pi +++ b/build/bootstrap/butterflynet.pi @@ -1,2 +1,2 @@ -/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWKeDMuJbouvypr1nL2qRruhNVXzv4QiLsZRh6gnvLkc7p -/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWSsACNHLGoJbPqeitNY7tom19Nxq8x5ag36eTwmgcAeLo +/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWCa1wgMMBB9JjA2kYqaN1v5uh7xvcsc2gQJBHzPp7G57H +/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWD6fCvo1dyci6wsjTLyv7eJK73pCVz6RCQjbtPvbc8LYw diff --git a/build/builtin_actors.go b/build/builtin_actors.go index 4d283919e..50aecde40 100644 --- a/build/builtin_actors.go +++ b/build/builtin_actors.go @@ -95,10 +95,11 @@ func loadManifests(netw string) error { } type BuiltinActorsMetadata struct { - Network string - Version actorstypes.Version - ManifestCid cid.Cid - Actors map[string]cid.Cid + Network string + Version actorstypes.Version + ManifestCid cid.Cid + Actors map[string]cid.Cid + BundleGitTag string } // ReadEmbeddedBuiltinActorsMetadata reads the metadata from the embedded built-in actor bundles. diff --git a/build/builtin_actors_gen.go b/build/builtin_actors_gen.go index 1178573a6..2b28870ec 100644 --- a/build/builtin_actors_gen.go +++ b/build/builtin_actors_gen.go @@ -7,25 +7,32 @@ import ( ) var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMetadata{{ - Network: "butterflynet", - Version: 8, - ManifestCid: MustParseCid("bafy2bzacedvaarfyh6q3bk4dyzux46ednlace2ckxp5nbyn6mb3da2apqn6sk"), + Network: "butterflynet", + Version: 8, + + ManifestCid: MustParseCid("bafy2bzaceba5qgs4z3imhlxwds5vamahngatvuuglbv5yl3ftfiosj6ud5chs"), Actors: map[string]cid.Cid{ - "account": MustParseCid("bafk2bzaceavzeu4gqte7o33vr4htiaapiwpfq6p26tgdkqla2baqhmiqswfso"), - "cron": MustParseCid("bafk2bzacech35onpqxep4yox36k7sr4mj4bch54s3i4b3yyaustrbo5xwfbfs"), - "init": MustParseCid("bafk2bzaceahxin3sf5f6ude5j6we4yeqlg66s5qe4tu7lwp26jcg7yp2ns6hi"), - "multisig": MustParseCid("bafk2bzacectfmzjtniypgl4whm42sws5aupihqgfikwsr7p5yoq3bmqaogldi"), - "paymentchannel": MustParseCid("bafk2bzacecbwu54ce5mjgp2pqxyj6kpn2vlgiu5wv2lj2byjiegxnn3infd5i"), - "reward": MustParseCid("bafk2bzacecskkbhe6c4ud5jt62wg4w7j7shj6xdwoyic74s5y6pgywxxvnw72"), - "storagemarket": MustParseCid("bafk2bzacebycxcwwm7hwhuhpasaskil2kxaqb7tins7azdvvm72rorlciuysi"), - "storageminer": MustParseCid("bafk2bzacecgx3etor5m6lahpmjdwqnryutqe6naiurfhgsju72rd4nqssutbg"), - "storagepower": MustParseCid("bafk2bzaceayvy6xyp5cwtngm457c5hssvihidppgq3o7gy3dlmhgor3yzujoc"), - "system": MustParseCid("bafk2bzacec6xctjxybp7r3kkhase56o6jsaiua7ure5ttu2xfuojt4jhlsoa6"), - "verifiedregistry": MustParseCid("bafk2bzacec2hcqlqcfacylfcrhhliwkisvh4y3adwt47xkf2gdvodwu6ccepc"), + "account": MustParseCid("bafk2bzacebd5zetyjtragjwrv2nqktct6u2pmsi4eifbanovxohx3a7lszjxi"), + "cron": MustParseCid("bafk2bzacecrszortqkc7har77ssgajglymv6ftrqvmdko5h2yqqh5k2qospl2"), + "datacap": MustParseCid("bafk2bzacecapjnxnyw4talwqv5ajbtbkzmzqiosztj5cb3sortyp73ndjl76e"), + "eam": MustParseCid("bafk2bzacecflry2dyjqj6fhpovkbcbei377zabectznuxsf6bxggsve7bsxga"), + "ethaccount": MustParseCid("bafk2bzacedl4pmkfxkzoqajs6im3ranmopozsmxjcxsnk3kwvd3vv7mfwwrf4"), + "evm": MustParseCid("bafk2bzacebgzvmvwv7rsnnhp3zhqbiqkumvyrc7pazfovpptgpgtqkalrli74"), + "init": MustParseCid("bafk2bzacecbxp66q3ytjkg37nyv4rmzezbfaigvx4i5yhvqbm5gg4amjeaias"), + "multisig": MustParseCid("bafk2bzacecjltag3mn75dsnmrmopjow27buxqhabissowayqlmavrcfetqswc"), + "paymentchannel": MustParseCid("bafk2bzacednzxg263eqbl2imwz3uhujov63tjkffieyl4hl3dhrgxyhwep6hc"), + "placeholder": MustParseCid("bafk2bzaceaamp2a35vpfml4skap4dffklzae2urcm34mtwwce2lvhaons3a5y"), + "reward": MustParseCid("bafk2bzacectp23cxsbbdrr3uggnw7f263qll5wkkfzqhn5yq37ae2ehdjdzri"), + "storagemarket": MustParseCid("bafk2bzacea45ko3ezkpeujsniovncwnizc4wsxd7kyckskhs7gvzwthzb2mqe"), + "storageminer": MustParseCid("bafk2bzaced74qthwrl3gahcf7o3vrdrodbcqhlplh6fykbgy5sd2iyouhq44c"), + "storagepower": MustParseCid("bafk2bzaceduksv6wqthr5fgp7mx5prv6gzul2oozf3svrjbuggc4bgokdxgfy"), + "system": MustParseCid("bafk2bzacebe6j2ius6clbbr7dypsg54jzmn5xablzunph7ebedw6yhwla4cj2"), + "verifiedregistry": MustParseCid("bafk2bzacebu4joy25gneu2qv3qfm3ktakzalndjrbhekeqrqk3zhotv6nyy2g"), }, }, { - Network: "butterflynet", - Version: 9, + Network: "butterflynet", + Version: 9, + ManifestCid: MustParseCid("bafy2bzacec35by4erhcdgcsgzp7yb3j57utydlxxfc73m3k5pep67ehvvyv6i"), Actors: map[string]cid.Cid{ "account": MustParseCid("bafk2bzaceajsdln7v4chxqoukiw7lxw6aexg5qdsaex2hgelz2sbu24iblhzg"), @@ -42,8 +49,32 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet "verifiedregistry": MustParseCid("bafk2bzacecjkesz766626ab4svnzpq3jfs26a75vfktlfaku5fjdao2eyiqyq"), }, }, { - Network: "calibrationnet", - Version: 8, + Network: "butterflynet", + Version: 10, + BundleGitTag: "v10.0.0", + ManifestCid: MustParseCid("bafy2bzaceckjhsggacixv2d377zfdcnuio4hzkveprio3xnhm3gohi3zy3zco"), + Actors: map[string]cid.Cid{ + "account": MustParseCid("bafk2bzacedkt3uzgugcsdrcsyfvizcpyr5eshltmienbyhjne2t7t3ktkihny"), + "cron": MustParseCid("bafk2bzacecrehknegmfnhmhwy2g43cw52mvl7ptfpp44syus4iph7az7uveuq"), + "datacap": MustParseCid("bafk2bzaced4krgbpj4sywcc453l3pygqr4qocc6nxylhztsm4duvkgfwd7vws"), + "eam": MustParseCid("bafk2bzacebn5lyg5pfhjpdlf3r7lnah4x33bhp5afftdgbr4kbpuioytr4bhe"), + "ethaccount": MustParseCid("bafk2bzaceaxyu24a2tbiacfr4p367xjtptrbang4qrh3fx65cojyrzolwyi4u"), + "evm": MustParseCid("bafk2bzacea5bqaubqeuqmpguxrem2pgocjr43wcfi5e3jpw2e3b4o6tcvs746"), + "init": MustParseCid("bafk2bzaceaufptkdg2gc4eq4ijqxtqp7wxwifusxb6kxay3vdz3wr5epqjbho"), + "multisig": MustParseCid("bafk2bzacedp3c26ccw3l7fci4xhedxhqeqevkubuf5okuslq7o7rcqwqfahci"), + "paymentchannel": MustParseCid("bafk2bzacedlmiqvbutz4ebx2mezy3pqj72x2yt4gwea7sf4dv4a4s7xidelok"), + "placeholder": MustParseCid("bafk2bzacedfvut2myeleyq67fljcrw4kkmn5pb5dpyozovj7jpoez5irnc3ro"), + "reward": MustParseCid("bafk2bzacecrzxiowkhzpgz4rl2pdldzwmmnctuq5zzntqjkgyhyfllo3afb5s"), + "storagemarket": MustParseCid("bafk2bzacebh2q3ofolirt5q2jpx367dfv22aecevsmybba3yhnxfs3foe6c5q"), + "storageminer": MustParseCid("bafk2bzaceavop4j7iwneew6h7p667gvx37baloxilxetwkhsrr26jme6yye5o"), + "storagepower": MustParseCid("bafk2bzacecfblbat4w7jkxx7kjst33lowyb7s6apdnl7fsnpmy5c3jfq5kvye"), + "system": MustParseCid("bafk2bzacebojf25kc5yo7gskdbdgg5f52oppej2jp6nknzlvrww4ue5vkddd2"), + "verifiedregistry": MustParseCid("bafk2bzaceavue3zekq4wmvttck2vgxlcensrsgh5niu5qhna2owejycorftcc"), + }, +}, { + Network: "calibrationnet", + Version: 8, + ManifestCid: MustParseCid("bafy2bzacedrdn6z3z7xz7lx4wll3tlgktirhllzqxb766dxpaqp3ukxsjfsba"), Actors: map[string]cid.Cid{ "account": MustParseCid("bafk2bzacecruossn66xqbeutqx5r4k2kjzgd43frmwd4qkw6haez44ubvvpxo"), @@ -59,8 +90,9 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet "verifiedregistry": MustParseCid("bafk2bzaceaihibfu625lbtzdp3tcftscshrmbgghgrc7kzqhxn4455pycpdkm"), }, }, { - Network: "calibrationnet", - Version: 9, + Network: "calibrationnet", + Version: 9, + ManifestCid: MustParseCid("bafy2bzacedbedgynklc4dgpyxippkxmba2mgtw7ecntoneclsvvl4klqwuyyy"), Actors: map[string]cid.Cid{ "account": MustParseCid("bafk2bzaceavfgpiw6whqigmskk74z4blm22nwjfnzxb4unlqz2e4wg3c5ujpw"), @@ -77,43 +109,101 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet "verifiedregistry": MustParseCid("bafk2bzacebh7dj6j7yi5vadh7lgqjtq42qi2uq4n6zy2g5vjeathacwn2tscu"), }, }, { - Network: "caterpillarnet", - Version: 8, - ManifestCid: MustParseCid("bafy2bzacecsmunz6fzhg53276cixadn6ybhcnzkgbw3la5hf342tfxsdoet26"), + Network: "calibrationnet", + Version: 10, + BundleGitTag: "v10.0.0-rc.1", + ManifestCid: MustParseCid("bafy2bzaced25ta3j6ygs34roprilbtb3f6mxifyfnm7z7ndquaruxzdq3y7lo"), Actors: map[string]cid.Cid{ - "account": MustParseCid("bafk2bzaced6yatl4y2nmqmx2h3btk3np6oelyw2yt57elsb2nfmm33fadzt2g"), - "cron": MustParseCid("bafk2bzacebrujytq4u7g62jbz52gio5k2s6rhruty7nt4eqq7ygitzxuee5zi"), - "init": MustParseCid("bafk2bzacedajw5ptnwfdidv6m4rvd4c2m7dve4lhfbawygl5idkalcxbiiudu"), - "multisig": MustParseCid("bafk2bzaceb3kh5hjh6eebb5236xp7crn2owyyo7irap6sy4ns76uc7om6pxuy"), - "paymentchannel": MustParseCid("bafk2bzacedl5am53e4mtxpzligcycxvmkolfkhfiuavww2dq3ukgaqwowj7vw"), - "reward": MustParseCid("bafk2bzacecbswf242j43cymj3wh7nszawwlofv6z6z4qipb5d32hpxdhxywng"), - "storagemarket": MustParseCid("bafk2bzaceca5ersmg3zxf2cztgktq33bmfjuiqjcjlktwj52xyrpujbdsqvek"), - "storageminer": MustParseCid("bafk2bzacedg2fqaq5udfp3h6cxhywm27dgagxtselfgkyyyunqq362eaxpdm4"), - "storagepower": MustParseCid("bafk2bzaceb3dm2i2q323e6iozo3r6pyded645vvlpf537kga2a3hu5x7abgl4"), - "system": MustParseCid("bafk2bzacebu47th3xerlngqavlipb6cfu2utljkxxzgadc3totogto2tmx2jc"), - "verifiedregistry": MustParseCid("bafk2bzaceci3niq3rmbcmepgn27zvlgci6d5t4dvthx3pbmmx3wcu5elova6i"), + "account": MustParseCid("bafk2bzacebhfuz3sv7duvk653544xsxhdn4lsmy7ol7k6gdgancyctvmd7lnq"), + "cron": MustParseCid("bafk2bzacecw2yjb6ysieffa7lk7xd32b3n4ssowvafolt7eq52lp6lk4lkhji"), + "datacap": MustParseCid("bafk2bzaceaot6tv6p4cat3cg5fknq22htosw3p5rwyijmdsraatwqyc4qyero"), + "eam": MustParseCid("bafk2bzacec5untyj6cefdsfm47wckozw6wt6svqqh5dzh63nu4f6dvf26fkco"), + "ethaccount": MustParseCid("bafk2bzacebiyrhz32xwxi6xql67aaq5nrzeelzas472kuwjqmdmgwotpkj35e"), + "evm": MustParseCid("bafk2bzaceblpgzid4qjfavuiht6uwvq2lznshklk2qmf5akm3dzx2fczdqdxc"), + "init": MustParseCid("bafk2bzacedhxbcglnonzruxf2jpczara73eh735wf2kznatx2u4gsuhgqwffq"), + "multisig": MustParseCid("bafk2bzacebv5gdlte2pyovmz6s37me6x2rixaa6a33w6lgqdohmycl23snvwm"), + "paymentchannel": MustParseCid("bafk2bzacea7ngq44gedftjlar3j3ql3dmd7e7xkkb6squgxinfncybfmppmlc"), + "placeholder": MustParseCid("bafk2bzacedfvut2myeleyq67fljcrw4kkmn5pb5dpyozovj7jpoez5irnc3ro"), + "reward": MustParseCid("bafk2bzacea3yo22x4dsh4axioshrdp42eoeugef3tqtmtwz5untyvth7uc73o"), + "storagemarket": MustParseCid("bafk2bzacecclsfboql3iraf3e66pzuh3h7qp3vgmfurqz26qh5g5nrexjgknc"), + "storageminer": MustParseCid("bafk2bzacedu4chbl36rilas45py4vhqtuj6o7aa5stlvnwef3kshgwcsmha6y"), + "storagepower": MustParseCid("bafk2bzacedu3c67spbf2dmwo77ymkjel6i2o5gpzyksgu2iuwu2xvcnxgfdjg"), + "system": MustParseCid("bafk2bzacea4mtukm5zazygkdbgdf26cpnwwif5n2no7s6tknpxlwy6fpq3mug"), + "verifiedregistry": MustParseCid("bafk2bzacec67wuchq64k7kgrujguukjvdlsl24pgighqdx5vgjhyk6bycrwnc"), }, }, { - Network: "caterpillarnet", - Version: 9, - ManifestCid: MustParseCid("bafy2bzacedo6tmei6rzjaaddh2yffe5xgr6w4smnadofjhomc3saiv3ubplqe"), + Network: "caterpillarnet", + Version: 8, + + ManifestCid: MustParseCid("bafy2bzacebsdvrxmdajiyxq2mxxxppvg2zwvqjzz3pgbsxwh6pvdcjofpmnxw"), Actors: map[string]cid.Cid{ - "account": MustParseCid("bafk2bzacebb32htqlwcwiotyvtbeehfmluu2ubjnepo57gelelwitudrstwba"), - "cron": MustParseCid("bafk2bzaceatvkww7soy4a6onu6xhe7pzkdzkqw46ywuu56yv3ncl76xpotzqu"), - "datacap": MustParseCid("bafk2bzaced57nk7i7w6qmbosy4gd6atme6yppesdgjllou6nppbti5yw6glcg"), - "init": MustParseCid("bafk2bzacedtoputbtz573ytg4yo5wbbg7fbhrzplux4uknxrb2jarifcuxxou"), - "multisig": MustParseCid("bafk2bzacec22z3xz45mbwgtliwkj7ngc43bervnt557c6dqsg6aesatpd5isy"), - "paymentchannel": MustParseCid("bafk2bzacedym7xnaxr2igfq72rttj2adqyqqfxk3j4qovp2bcwqk5paoe4t7e"), - "reward": MustParseCid("bafk2bzacedemsmbmbtk5toprmm6jivjq3wkxumavc65vpvm6ngspgjfkth7z6"), - "storagemarket": MustParseCid("bafk2bzacecb53mmklf4rbv263dvufqj3nsf7mi6zk2tjlgwmzbr633kw3ds3w"), - "storageminer": MustParseCid("bafk2bzacea3wljpn2ixgnd4lovr6yckiwd652ytcrz5amgj47lg6drjhgggqa"), - "storagepower": MustParseCid("bafk2bzaceakvohgvovpeldb6hjfg7readxo37a5h4qauis4nz6pte7mcll6c2"), - "system": MustParseCid("bafk2bzacecisuqj2ln7ep72xaejvs2lrgh2logc7retxxpd3qvobymwyz7bxo"), - "verifiedregistry": MustParseCid("bafk2bzacebyjosiripwqyf56yhjfs5hg26mch7totsqth4rgpt5j32hqg6ric"), + "account": MustParseCid("bafk2bzacedfms6w3ghqtljpgsfuiqa6ztjx7kcuin6myjezj6rypj3zjbqms6"), + "cron": MustParseCid("bafk2bzaceaganmlpozvy4jywigs46pfrtdmhjjey6uyhpurplqbasojsislba"), + "datacap": MustParseCid("bafk2bzacebafqqe3wv5ytkfwmqzbmchgem66pw6yq6rl7w6vlhqsbkxnisswq"), + "eam": MustParseCid("bafk2bzaceaeayeksiivw4y3gdqtigbgfntyvwc3q7v2ivb5kx7u55pn4q5lt6"), + "ethaccount": MustParseCid("bafk2bzaceburkmtd63nmzxpux5rcxsbqr6x5didl2ce7al32g4tqrvo4pjz2i"), + "evm": MustParseCid("bafk2bzacea7tp4lop7ivhay3ozitkmxxurk74v4zse42ant47rh2uw5z3tq5e"), + "init": MustParseCid("bafk2bzaced23r54kwuebl7t6mdantbby5qpfduxwxfryeliof2enyqzhokix6"), + "multisig": MustParseCid("bafk2bzacebcn3rib6j6jvclys7dkf62hco45ssgamczkrtzt6xyewd6gt3mtu"), + "paymentchannel": MustParseCid("bafk2bzacecvas4leo44pqdguj22nnwqoqdgwajzrpm5d6ltkehc37ni6p6doq"), + "placeholder": MustParseCid("bafk2bzaceaamp2a35vpfml4skap4dffklzae2urcm34mtwwce2lvhaons3a5y"), + "reward": MustParseCid("bafk2bzacebiizh4ohvv6p4uxjusoygex4wxcgvudqmdl2fsh6ft6s2zt4tz6q"), + "storagemarket": MustParseCid("bafk2bzacedhkidshm7w2sqlw7izvaieyhkvmyhfsem6t6qfnkh7dnwqe56po2"), + "storageminer": MustParseCid("bafk2bzacedcmsibwfwhkp3sabmbyjmhqibyhjf3wwst7u5bkb2k6xpun3xevg"), + "storagepower": MustParseCid("bafk2bzacecrgnpypxnxzgglhlitaallfee3dl4ejy3y63knl7llnwba4ycf7i"), + "system": MustParseCid("bafk2bzacecl7gizbe52xj6sfm5glubkhrdblmzuwlid6lxrwr5zhcmv4dl2ew"), + "verifiedregistry": MustParseCid("bafk2bzacebzndvdqtdck2y35smcxezldgh6nm6rbkj3g3fmiknsgg2uah235y"), }, }, { - Network: "devnet", - Version: 8, + Network: "caterpillarnet", + Version: 9, + + ManifestCid: MustParseCid("bafy2bzacebsdvrxmdajiyxq2mxxxppvg2zwvqjzz3pgbsxwh6pvdcjofpmnxw"), + Actors: map[string]cid.Cid{ + "account": MustParseCid("bafk2bzacedfms6w3ghqtljpgsfuiqa6ztjx7kcuin6myjezj6rypj3zjbqms6"), + "cron": MustParseCid("bafk2bzaceaganmlpozvy4jywigs46pfrtdmhjjey6uyhpurplqbasojsislba"), + "datacap": MustParseCid("bafk2bzacebafqqe3wv5ytkfwmqzbmchgem66pw6yq6rl7w6vlhqsbkxnisswq"), + "eam": MustParseCid("bafk2bzaceaeayeksiivw4y3gdqtigbgfntyvwc3q7v2ivb5kx7u55pn4q5lt6"), + "ethaccount": MustParseCid("bafk2bzaceburkmtd63nmzxpux5rcxsbqr6x5didl2ce7al32g4tqrvo4pjz2i"), + "evm": MustParseCid("bafk2bzacea7tp4lop7ivhay3ozitkmxxurk74v4zse42ant47rh2uw5z3tq5e"), + "init": MustParseCid("bafk2bzaced23r54kwuebl7t6mdantbby5qpfduxwxfryeliof2enyqzhokix6"), + "multisig": MustParseCid("bafk2bzacebcn3rib6j6jvclys7dkf62hco45ssgamczkrtzt6xyewd6gt3mtu"), + "paymentchannel": MustParseCid("bafk2bzacecvas4leo44pqdguj22nnwqoqdgwajzrpm5d6ltkehc37ni6p6doq"), + "placeholder": MustParseCid("bafk2bzaceaamp2a35vpfml4skap4dffklzae2urcm34mtwwce2lvhaons3a5y"), + "reward": MustParseCid("bafk2bzacebiizh4ohvv6p4uxjusoygex4wxcgvudqmdl2fsh6ft6s2zt4tz6q"), + "storagemarket": MustParseCid("bafk2bzacedhkidshm7w2sqlw7izvaieyhkvmyhfsem6t6qfnkh7dnwqe56po2"), + "storageminer": MustParseCid("bafk2bzacedcmsibwfwhkp3sabmbyjmhqibyhjf3wwst7u5bkb2k6xpun3xevg"), + "storagepower": MustParseCid("bafk2bzacecrgnpypxnxzgglhlitaallfee3dl4ejy3y63knl7llnwba4ycf7i"), + "system": MustParseCid("bafk2bzacecl7gizbe52xj6sfm5glubkhrdblmzuwlid6lxrwr5zhcmv4dl2ew"), + "verifiedregistry": MustParseCid("bafk2bzacebzndvdqtdck2y35smcxezldgh6nm6rbkj3g3fmiknsgg2uah235y"), + }, +}, { + Network: "caterpillarnet", + Version: 10, + BundleGitTag: "v10.0.0", + ManifestCid: MustParseCid("bafy2bzaceajftd7jawqnwf4kzkotksrwy6ag7mu2apkvypzrrmxboheuum5oi"), + Actors: map[string]cid.Cid{ + "account": MustParseCid("bafk2bzacecsbx4tovnr5x2ifcpqbpx33oht74mgtvmaauzrqcq2wnm7prr7ak"), + "cron": MustParseCid("bafk2bzacecpzfajba6m4v4ty342jw6lcu6n63bwtldmzko733wpd2q5jzfdvu"), + "datacap": MustParseCid("bafk2bzaceaa5zplkxvguwvnecfen62buhli5rraa3ga74b33a3sbscanzx4ok"), + "eam": MustParseCid("bafk2bzaceaffoa3eqmj7h53lwjatfqrjw63l3czk3vthyjz6oyhgwka3xwp6g"), + "ethaccount": MustParseCid("bafk2bzaceb7suh5m4xagoq6ap5v5x7vrhex2coq6gu6d54jteblm36cxhk5b2"), + "evm": MustParseCid("bafk2bzaceccmwmnb42pn7y7skbjwjur7b2eqxuw4lvm3he2xpvudjzluss4os"), + "init": MustParseCid("bafk2bzaceai72h4hxbgbp6gwm3m24uujscrj4bmbh6pxoerqtduijxt6dchfq"), + "multisig": MustParseCid("bafk2bzacebycdokda2gysqpnl3dwksgidujgsksf4n6qotjq4erj5zd7clkzy"), + "paymentchannel": MustParseCid("bafk2bzaceb5ucvftftiim6cxjusdpsmbht4x33kgexxgv5447gevk47h7jjqk"), + "placeholder": MustParseCid("bafk2bzacedfvut2myeleyq67fljcrw4kkmn5pb5dpyozovj7jpoez5irnc3ro"), + "reward": MustParseCid("bafk2bzaceajqygfkhamlzfsquqjgoy4p7pc2fruouqajapfucf22rbmtt5yf6"), + "storagemarket": MustParseCid("bafk2bzacednmzko2o5iv5kc6qxvpqfx5rq72krxzvna6cqoqem6flbfukglby"), + "storageminer": MustParseCid("bafk2bzacedayzz5qw7t7ykycf3a2hp666j5hb23a3mnmgp4xbbpvrx3h3ags4"), + "storagepower": MustParseCid("bafk2bzacedd3eiejzp35xuwjf3cvgd43b5ukqhelqmtgzqzqnt2wcy56pb744"), + "system": MustParseCid("bafk2bzacecfivztuulqqv4o5oyvvvrkblwix4hqt24pqru6ivnpioefhuhria"), + "verifiedregistry": MustParseCid("bafk2bzacecdhw6x7dfrxfysmn6tdbn2ny464omgqppxhjuawxauscidppd7pc"), + }, +}, { + Network: "devnet", + Version: 8, + ManifestCid: MustParseCid("bafy2bzacedq7tuibavyqxzkq4uybjj7ly22eu42mjkoehwn5d47xfunmtjm4k"), Actors: map[string]cid.Cid{ "account": MustParseCid("bafk2bzacea4tlgnp7m6tlldpz3termlwxlnyq24nwd4zdzv4r6nsjuaktuuzc"), @@ -129,8 +219,9 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet "verifiedregistry": MustParseCid("bafk2bzaceaajgtglewgitshgdi2nzrvq7eihjtyqj5yiamesqun2hujl3xev2"), }, }, { - Network: "devnet", - Version: 9, + Network: "devnet", + Version: 9, + ManifestCid: MustParseCid("bafy2bzacedozk3jh2j4nobqotkbofodq4chbrabioxbfrygpldgoxs3zwgggk"), Actors: map[string]cid.Cid{ "account": MustParseCid("bafk2bzaced5llqnqqhypolyuogz3h2wjomugqkrhyhocvly3aoib4c5xiush6"), @@ -147,8 +238,55 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet "verifiedregistry": MustParseCid("bafk2bzacednorhcy446agy7ecpmfms2u4aoa3mj2eqomffuoerbik5yavrxyi"), }, }, { - Network: "mainnet", - Version: 8, + Network: "devnet", + Version: 10, + BundleGitTag: "v10.0.0", + ManifestCid: MustParseCid("bafy2bzacebzz376j5kizfck56366kdz5aut6ktqrvqbi3efa2d4l2o2m653ts"), + Actors: map[string]cid.Cid{ + "account": MustParseCid("bafk2bzacedkj5dqs5xxamnlug2d5dyjl6askf7wlmvwzhmsrzcvogv7acqfe6"), + "cron": MustParseCid("bafk2bzaceabslrigld2vshng6sppbp3bsptjtttvbxctwqe5lkyl2efom2wu4"), + "datacap": MustParseCid("bafk2bzaceagg4qklzhhg5oj4shwqpoeykeyxus7xhj2abuot2tycdwsf2oaaa"), + "eam": MustParseCid("bafk2bzaceafttsbglcetxwtzqtdniittwczogkefgnxztgsp7mymcpvdlhdik"), + "ethaccount": MustParseCid("bafk2bzacedypn6tf3yrj4bavmscddygeima3puih37fbkxuhjhlrzbjh3dbo4"), + "evm": MustParseCid("bafk2bzacec5ywczgg73fnwi36nlxso3zduop3fwj3pq6ynn5zltrs4dpcwglg"), + "init": MustParseCid("bafk2bzacebkanlbkwwtniyz4fawevnkoyje67l5nflltmciplqiutekxzzfh4"), + "multisig": MustParseCid("bafk2bzacectxa2izvpaybmmpvearekrybxtglctwnexzzneyn6xrnrmectmpa"), + "paymentchannel": MustParseCid("bafk2bzacectov7vawkhsvq7aobyjq3oppamytq425wpkxejmq65vvcdm4bt2e"), + "placeholder": MustParseCid("bafk2bzacedfvut2myeleyq67fljcrw4kkmn5pb5dpyozovj7jpoez5irnc3ro"), + "reward": MustParseCid("bafk2bzacec3xpbrxw2rnpuve4mxfhny44lxbpbwmduy4ula4ohj2bp6wplpvc"), + "storagemarket": MustParseCid("bafk2bzacec5nexsejraoqraywka7zcacjoxgpdbopehdkhiwqwcyghtof4s3w"), + "storageminer": MustParseCid("bafk2bzacecw5xzj6z5b7qxx5xca5py4aoecmqj2pxb6nw673alufy22zckkyo"), + "storagepower": MustParseCid("bafk2bzaceckhnpxoaanjf474wxzkntlnzdofoy75ehyuydfjkuw4swhotws4y"), + "system": MustParseCid("bafk2bzaceairk5qz5hyzt4yyaxa356aszyifswiust5ilxizwxujcmtzvjzoa"), + "verifiedregistry": MustParseCid("bafk2bzaced2mkyqobpgna5jevosym3adv2bvraggigyz2jgn5cxymirxj4x3i"), + }, +}, { + Network: "hyperspace", + Version: 8, + + ManifestCid: MustParseCid("bafy2bzacedvffumcvf72f2btjqvece3kpcdorxq5tq76iwcmqbzvsiu526cqm"), + Actors: map[string]cid.Cid{ + "account": MustParseCid("bafk2bzacecim7uybic2qprbkjhowg7qkniv4zywj5h5g4u4ss72urco2akzuo"), + "cron": MustParseCid("bafk2bzaceahgq64awp4f7li3hdgimc4upqvdvltpmeywckvens33umcxt424a"), + "datacap": MustParseCid("bafk2bzacebkxn52ttooaslkwncijk3bgd3tm2zw7vijdhwvg2cxnxbrzmmq5e"), + "eam": MustParseCid("bafk2bzaceczhgub5anrnaf7ol65mu54gsgwcj6c6m3yhet7rhxm2l6kz4s4ru"), + "ethaccount": MustParseCid("bafk2bzacealn5enbxyxbfs7gbsjbyma2zk3bcr7okvflxhpr753d4eh6ixooa"), + "evm": MustParseCid("bafk2bzacedljkrmazyewawpnddrkzrt55556374dw2pm2hokgkompgzw4vx5y"), + "init": MustParseCid("bafk2bzacec55gyyaqjrw7zughywocgwcjvv6k5fijjpjw4xgckuqz6pjtff5a"), + "multisig": MustParseCid("bafk2bzaceblozbdzybdivvjdiid4jwm2jc6x5a66sunh2vvwsqba6wzqmr7i6"), + "paymentchannel": MustParseCid("bafk2bzacealcyke5a6n24efs6qe4iikynpk2twqssyugy7jcyf6p6shgw2iwa"), + "placeholder": MustParseCid("bafk2bzaceaamp2a35vpfml4skap4dffklzae2urcm34mtwwce2lvhaons3a5y"), + "reward": MustParseCid("bafk2bzacebafzaqhwsm3nmsfwcd6ngvx6ev6zlcpyfljqh4kb77vok6opban6"), + "storagemarket": MustParseCid("bafk2bzacecrjfg4p7fxznsdkoobs4po2ve3ywixrirrk6netgxh63qqaefamg"), + "storageminer": MustParseCid("bafk2bzaceb3ctd4atxwhdkmlg4i63zxo5aopknlj7l5kaiqr22xpcmico6vg4"), + "storagepower": MustParseCid("bafk2bzacecvcix3ugopvby2vah5wwiu5cqjedwzwkanmr34kdoc4f3o6p7nsq"), + "system": MustParseCid("bafk2bzacedo2hfopt6gy52goj7fot5qwzhtnysmgo7h25crq4clpugkerjabk"), + "verifiedregistry": MustParseCid("bafk2bzacea7rfkjrixaidksnmjehglmavyt56nyeu3sfxu2e3dcpf62oab6tw"), + }, +}, { + Network: "mainnet", + Version: 8, + ManifestCid: MustParseCid("bafy2bzacebogjbpiemi7npzxchgcjjki3tfxon4ims55obfyfleqntteljsea"), Actors: map[string]cid.Cid{ "account": MustParseCid("bafk2bzacedudbf7fc5va57t3tmo63snmt3en4iaidv4vo3qlyacbxaa6hlx6y"), @@ -164,8 +302,9 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet "verifiedregistry": MustParseCid("bafk2bzaceb3zbkjz3auizmoln2unmxep7dyfcmsre64vnqfhdyh7rkqfoxlw4"), }, }, { - Network: "mainnet", - Version: 9, + Network: "mainnet", + Version: 9, + ManifestCid: MustParseCid("bafy2bzaceb6j6666h36xnhksu3ww4kxb6e25niayfgkdnifaqi6m6ooc66i6i"), Actors: map[string]cid.Cid{ "account": MustParseCid("bafk2bzacect2p7urje3pylrrrjy3tngn6yaih4gtzauuatf2jllk3ksgfiw2y"), @@ -182,8 +321,32 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet "verifiedregistry": MustParseCid("bafk2bzacecf3yodlyudzukumehbuabgqljyhjt5ifiv4vetcfohnvsxzynwga"), }, }, { - Network: "testing", - Version: 8, + Network: "mainnet", + Version: 10, + BundleGitTag: "v10.0.0", + ManifestCid: MustParseCid("bafy2bzacecsuyf7mmvrhkx2evng5gnz5canlnz2fdlzu2lvcgptiq2pzuovos"), + Actors: map[string]cid.Cid{ + "account": MustParseCid("bafk2bzaceampw4romta75hyz5p4cqriypmpbgnkxncgxgqn6zptv5lsp2w2bo"), + "cron": MustParseCid("bafk2bzacedcbtsifegiu432m5tysjzkxkmoczxscb6hqpmrr6img7xzdbbs2g"), + "datacap": MustParseCid("bafk2bzacealj5uk7wixhvk7l5tnredtelralwnceafqq34nb2lbylhtuyo64u"), + "eam": MustParseCid("bafk2bzacedrpm5gbleh4xkyo2jvs7p5g6f34soa6dpv7ashcdgy676snsum6g"), + "ethaccount": MustParseCid("bafk2bzaceaqoc5zakbhjxn3jljc4lxnthllzunhdor7sxhwgmskvc6drqc3fa"), + "evm": MustParseCid("bafk2bzaceahmzdxhqsm7cu2mexusjp6frm7r4kdesvti3etv5evfqboos2j4g"), + "init": MustParseCid("bafk2bzaced2f5rhir3hbpqbz5ght7ohv2kgj42g5ykxrypuo2opxsup3ykwl6"), + "multisig": MustParseCid("bafk2bzaceduf3hayh63jnl4z2knxv7cnrdenoubni22fxersc4octlwpxpmy4"), + "paymentchannel": MustParseCid("bafk2bzaceartlg4mrbwgzcwric6mtvyawpbgx2xclo2vj27nna57nxynf3pgc"), + "placeholder": MustParseCid("bafk2bzacedfvut2myeleyq67fljcrw4kkmn5pb5dpyozovj7jpoez5irnc3ro"), + "reward": MustParseCid("bafk2bzacebnhtaejfjtzymyfmbdrfmo7vgj3zsof6zlucbmkhrvcuotw5dxpq"), + "storagemarket": MustParseCid("bafk2bzaceclejwjtpu2dhw3qbx6ow7b4pmhwa7ocrbbiqwp36sq5yeg6jz2bc"), + "storageminer": MustParseCid("bafk2bzaced4h7noksockro7glnssz2jnmo2rpzd7dvnmfs4p24zx3h6gtx47s"), + "storagepower": MustParseCid("bafk2bzacec4ay4crzo73ypmh7o3fjendhbqrxake46bprabw67fvwjz5q6ixq"), + "system": MustParseCid("bafk2bzacedakk5nofebyup4m7nvx6djksfwhnxzrfuq4oyemhpl4lllaikr64"), + "verifiedregistry": MustParseCid("bafk2bzacedfel6edzqpe5oujno7fog4i526go4dtcs6vwrdtbpy2xq6htvcg6"), + }, +}, { + Network: "testing", + Version: 8, + ManifestCid: MustParseCid("bafy2bzacedkjpqx27wgsvfxzuxfvixuxtbpt2y6yo6igcasez6gqiowron776"), Actors: map[string]cid.Cid{ "account": MustParseCid("bafk2bzacebmfbtdj5vruje5auacrhhprcjdd6uclhukb7je7t2f6ozfcgqlu2"), @@ -199,8 +362,9 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet "verifiedregistry": MustParseCid("bafk2bzacectzxvtoselhnzsair5nv6k5vokvegnht6z2lfee4p3xexo4kg4m6"), }, }, { - Network: "testing", - Version: 9, + Network: "testing", + Version: 9, + ManifestCid: MustParseCid("bafy2bzacecnnrmekqw2xvud46g3vo6x26cogh3ydgljqajlxqxzzbuxsjlwjm"), Actors: map[string]cid.Cid{ "account": MustParseCid("bafk2bzaceaiebfiuu76zoywzltelio2zuvsavirka27ur6kspn7scvcl5cuiy"), @@ -217,8 +381,32 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet "verifiedregistry": MustParseCid("bafk2bzaceatmqip2o3ausbntvdhj7yemu6hb3b5yqv6hm42gylbbmz7geocpm"), }, }, { - Network: "testing-fake-proofs", - Version: 8, + Network: "testing", + Version: 10, + BundleGitTag: "v10.0.0", + ManifestCid: MustParseCid("bafy2bzacebsp3bkxwsijenqeimhvhtg52d6o76hn6qhzxveqfq7d5hdd5l2ee"), + Actors: map[string]cid.Cid{ + "account": MustParseCid("bafk2bzaceazxb6p2xg6caivmie6k2bvutyesngwyvhwv4eemwu7ia4vnqkcuy"), + "cron": MustParseCid("bafk2bzaceax6ym73boyl5zdpbcr6zmbajzylmcdvlapz5zcqgzcshakz44jbq"), + "datacap": MustParseCid("bafk2bzacea63x3v6lvtb4ast5uq3nhrpokvylymvezyr5xyjl6vtlfwkuw6qo"), + "eam": MustParseCid("bafk2bzacebhualcn7fofyqr6lhrel32ud23hcwzeenfqu3rrn5nmt6gugqgo6"), + "ethaccount": MustParseCid("bafk2bzacecgft7e3v4kbpb3tlt5s6hng74ptu3ggcdi4wmt5p4vr6qkmkw2zc"), + "evm": MustParseCid("bafk2bzaceaoqvbqetgicqpvwvcnpjx5aa74kwlhq3u7mwv4yseszxkimwz5pk"), + "init": MustParseCid("bafk2bzaceapmoyg2qppzle24t25ncyycn2uwhnw6crqkqlokkbc7w4mn74wko"), + "multisig": MustParseCid("bafk2bzacecn3dlepgaps3h6iwlq65dx6zyrbfi4pmgdqxphb5idubb6ibflwe"), + "paymentchannel": MustParseCid("bafk2bzaceaanxurr2k3ueolwcnminmdfp3tyxtntqg5fou37smeulb5dxqjzk"), + "placeholder": MustParseCid("bafk2bzacedfvut2myeleyq67fljcrw4kkmn5pb5dpyozovj7jpoez5irnc3ro"), + "reward": MustParseCid("bafk2bzacedujdvwk4omjexdnmh2qrkqbw27v4c2g3krajhtzyfzart36bimum"), + "storagemarket": MustParseCid("bafk2bzacecdbjjxvdtltobiu7thwyyr2puunoz3q4vyfnhhxl2sbp4ovwq37s"), + "storageminer": MustParseCid("bafk2bzacebo5q7jrf4qjrhtotwt5ouzlygvml4bzofs2egdnbxyfmuo7tro6c"), + "storagepower": MustParseCid("bafk2bzacebt2ipqnorxbzncwjadkulip6blzksmwd4mmyrfjsmjyf55itra2k"), + "system": MustParseCid("bafk2bzacecf2jimdz7knhngs64ximfz3eaud6s3kiunmkybgrkupdjyo2dw7o"), + "verifiedregistry": MustParseCid("bafk2bzacecdmek2htsgcyoyl35glakyab66cojqo2y335njnm7krleb6yfbps"), + }, +}, { + Network: "testing-fake-proofs", + Version: 8, + ManifestCid: MustParseCid("bafy2bzacecd3lb5v6tzjylnhnrhexslssyaozy6hogzgpkhztoe76exbrgrug"), Actors: map[string]cid.Cid{ "account": MustParseCid("bafk2bzacebmfbtdj5vruje5auacrhhprcjdd6uclhukb7je7t2f6ozfcgqlu2"), @@ -234,8 +422,9 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet "verifiedregistry": MustParseCid("bafk2bzacectzxvtoselhnzsair5nv6k5vokvegnht6z2lfee4p3xexo4kg4m6"), }, }, { - Network: "testing-fake-proofs", - Version: 9, + Network: "testing-fake-proofs", + Version: 9, + ManifestCid: MustParseCid("bafy2bzacecql2gj2tri4fnbznmldue73qzt6zszvugw4exd64mwb52zrhv7k2"), Actors: map[string]cid.Cid{ "account": MustParseCid("bafk2bzaceaiebfiuu76zoywzltelio2zuvsavirka27ur6kspn7scvcl5cuiy"), @@ -251,4 +440,27 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet "system": MustParseCid("bafk2bzacedo4pu3iwx2gu72hinsstpiokhl5iicnb3rumzffsnhy7zhmnxhyy"), "verifiedregistry": MustParseCid("bafk2bzaceatmqip2o3ausbntvdhj7yemu6hb3b5yqv6hm42gylbbmz7geocpm"), }, +}, { + Network: "testing-fake-proofs", + Version: 10, + BundleGitTag: "v10.0.0", + ManifestCid: MustParseCid("bafy2bzacedwap2uuii4luljckrnb4vkur2unb6fyinn7xjie6xlva2wmlygj2"), + Actors: map[string]cid.Cid{ + "account": MustParseCid("bafk2bzaceazxb6p2xg6caivmie6k2bvutyesngwyvhwv4eemwu7ia4vnqkcuy"), + "cron": MustParseCid("bafk2bzaceax6ym73boyl5zdpbcr6zmbajzylmcdvlapz5zcqgzcshakz44jbq"), + "datacap": MustParseCid("bafk2bzacea63x3v6lvtb4ast5uq3nhrpokvylymvezyr5xyjl6vtlfwkuw6qo"), + "eam": MustParseCid("bafk2bzacebhualcn7fofyqr6lhrel32ud23hcwzeenfqu3rrn5nmt6gugqgo6"), + "ethaccount": MustParseCid("bafk2bzacecgft7e3v4kbpb3tlt5s6hng74ptu3ggcdi4wmt5p4vr6qkmkw2zc"), + "evm": MustParseCid("bafk2bzaceaoqvbqetgicqpvwvcnpjx5aa74kwlhq3u7mwv4yseszxkimwz5pk"), + "init": MustParseCid("bafk2bzaceapmoyg2qppzle24t25ncyycn2uwhnw6crqkqlokkbc7w4mn74wko"), + "multisig": MustParseCid("bafk2bzacecn3dlepgaps3h6iwlq65dx6zyrbfi4pmgdqxphb5idubb6ibflwe"), + "paymentchannel": MustParseCid("bafk2bzaceaanxurr2k3ueolwcnminmdfp3tyxtntqg5fou37smeulb5dxqjzk"), + "placeholder": MustParseCid("bafk2bzacedfvut2myeleyq67fljcrw4kkmn5pb5dpyozovj7jpoez5irnc3ro"), + "reward": MustParseCid("bafk2bzacedujdvwk4omjexdnmh2qrkqbw27v4c2g3krajhtzyfzart36bimum"), + "storagemarket": MustParseCid("bafk2bzacecdbjjxvdtltobiu7thwyyr2puunoz3q4vyfnhhxl2sbp4ovwq37s"), + "storageminer": MustParseCid("bafk2bzacedc5klueery4fn2voso4u76rgo54uctsculesdbxxbeh6rgp2q4te"), + "storagepower": MustParseCid("bafk2bzacecuz2h2renlfio4xkyrvvro7nwidf7utpjy3oizk2xuszoz3gmea6"), + "system": MustParseCid("bafk2bzacecf2jimdz7knhngs64ximfz3eaud6s3kiunmkybgrkupdjyo2dw7o"), + "verifiedregistry": MustParseCid("bafk2bzacecdmek2htsgcyoyl35glakyab66cojqo2y335njnm7krleb6yfbps"), + }, }} diff --git a/build/builtin_actors_test.go b/build/builtin_actors_test.go index 384193fee..bb133bdab 100644 --- a/build/builtin_actors_test.go +++ b/build/builtin_actors_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" @@ -16,7 +17,13 @@ func TestEmbeddedMetadata(t *testing.T) { metadata, err := build.ReadEmbeddedBuiltinActorsMetadata() require.NoError(t, err) - require.Equal(t, metadata, build.EmbeddedBuiltinActorsMetadata) + for i, v1 := range metadata { + v2 := build.EmbeddedBuiltinActorsMetadata[i] + require.Equal(t, v1.Network, v2.Network) + require.Equal(t, v1.Version, v2.Version) + require.Equal(t, v1.ManifestCid, v2.ManifestCid) + require.Equal(t, v1.Actors, v2.Actors) + } } // Test that we're registering the manifest correctly. @@ -26,7 +33,7 @@ func TestRegistration(t *testing.T) { require.True(t, found) require.True(t, manifestCid.Defined()) - for _, key := range actors.GetBuiltinActorsKeys(av) { + for _, key := range manifest.GetBuiltinActorsKeys(av) { actorCid, found := actors.GetActorCodeID(av, key) require.True(t, found) name, version, found := actors.GetActorMetaByCode(actorCid) diff --git a/build/drand.go b/build/drand.go index 3b976ac92..3027d930b 100644 --- a/build/drand.go +++ b/build/drand.go @@ -69,6 +69,10 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{ ChainInfoJSON: `{"public_key":"8cda589f88914aa728fd183f383980b35789ce81b274e5daee1f338b77d02566ef4d3fb0098af1f844f10f9c803c1827","period":25,"genesis_time":1595348225,"hash":"e73b7dc3c4f6a236378220c0dd6aa110eb16eed26c11259606e07ee122838d4f","groupHash":"567d4785122a5a3e75a9bc9911d7ea807dd85ff76b78dc4ff06b075712898607"}`, }, DrandIncentinet: { + Servers: []string{ + "https://dev1.drand.sh", + "https://dev2.drand.sh", + }, ChainInfoJSON: `{"public_key":"8cad0c72c606ab27d36ee06de1d5b2db1faf92e447025ca37575ab3a8aac2eaae83192f846fc9e158bc738423753d000","period":30,"genesis_time":1595873820,"hash":"80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039","groupHash":"d9406aaed487f7af71851b4399448e311f2328923d454e971536c05398ce2d9b"}`, }, } diff --git a/build/genesis/butterflynet.car b/build/genesis/butterflynet.car index 71a1c684e..589e5ab75 100644 Binary files a/build/genesis/butterflynet.car and b/build/genesis/butterflynet.car differ diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 9d24212d2..2bdf6336a 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index 876ae6cea..4f93653ad 100644 Binary files a/build/openrpc/gateway.json.gz and b/build/openrpc/gateway.json.gz differ diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 404a39214..3106db222 100644 Binary files a/build/openrpc/miner.json.gz and b/build/openrpc/miner.json.gz differ diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index 787ad29fb..c5c61341b 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/build/params_2k.go b/build/params_2k.go index 4c612d3ca..962b2f9ba 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -21,8 +21,9 @@ const GenesisFile = "" var NetworkBundle = "devnet" var BundleOverrides map[actorstypes.Version]string +var ActorDebugging = true -const GenesisNetworkVersion = network.Version16 +const GenesisNetworkVersion = network.Version17 var UpgradeBreezeHeight = abi.ChainEpoch(-1) @@ -56,7 +57,9 @@ var UpgradeOhSnapHeight = abi.ChainEpoch(-18) var UpgradeSkyrHeight = abi.ChainEpoch(-19) -var UpgradeSharkHeight = abi.ChainEpoch(100) +var UpgradeSharkHeight = abi.ChainEpoch(-20) + +var UpgradeHyggeHeight = abi.ChainEpoch(30) var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, @@ -110,6 +113,7 @@ func init() { UpgradeOhSnapHeight = getUpgradeHeight("LOTUS_OHSNAP_HEIGHT", UpgradeOhSnapHeight) UpgradeSkyrHeight = getUpgradeHeight("LOTUS_SKYR_HEIGHT", UpgradeSkyrHeight) UpgradeSharkHeight = getUpgradeHeight("LOTUS_SHARK_HEIGHT", UpgradeSharkHeight) + UpgradeHyggeHeight = getUpgradeHeight("LOTUS_HYGGE_HEIGHT", UpgradeHyggeHeight) BuildType |= Build2k @@ -130,4 +134,8 @@ const InteractivePoRepConfidence = 6 const BootstrapPeerThreshold = 1 +// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint. +// As per https://github.com/ethereum-lists/chains +const Eip155ChainId = 31415926 + var WhitelistedBlock = cid.Undef diff --git a/build/params_butterfly.go b/build/params_butterfly.go index 6f0a64598..b00381b44 100644 --- a/build/params_butterfly.go +++ b/build/params_butterfly.go @@ -19,10 +19,11 @@ var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, } -const GenesisNetworkVersion = network.Version16 +const GenesisNetworkVersion = network.Version17 var NetworkBundle = "butterflynet" var BundleOverrides map[actorstypes.Version]string +var ActorDebugging = false const BootstrappersFile = "butterflynet.pi" const GenesisFile = "butterflynet.car" @@ -49,7 +50,8 @@ const UpgradeHyperdriveHeight = -16 const UpgradeChocolateHeight = -17 const UpgradeOhSnapHeight = -18 const UpgradeSkyrHeight = -19 -const UpgradeSharkHeight = abi.ChainEpoch(600) +const UpgradeSharkHeight = abi.ChainEpoch(-20) +const UpgradeHyggeHeight = abi.ChainEpoch(600) var SupportedProofTypes = []abi.RegisteredSealProof{ abi.RegisteredSealProof_StackedDrg512MiBV1, @@ -80,4 +82,8 @@ const PropagationDelaySecs = uint64(6) // BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start const BootstrapPeerThreshold = 2 +// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint. +// As per https://github.com/ethereum-lists/chains +const Eip155ChainId = 3141592 + var WhitelistedBlock = cid.Undef diff --git a/build/params_calibnet.go b/build/params_calibnet.go index f1aacc506..32923f7a8 100644 --- a/build/params_calibnet.go +++ b/build/params_calibnet.go @@ -26,6 +26,7 @@ const GenesisNetworkVersion = network.Version0 var NetworkBundle = "calibrationnet" var BundleOverrides map[actorstypes.Version]string +var ActorDebugging = false const BootstrappersFile = "calibnet.pi" const GenesisFile = "calibnet.car" @@ -69,6 +70,9 @@ const UpgradeSkyrHeight = 510 const UpgradeSharkHeight = 16800 // 6 days after genesis +// 2023-02-21T16:30:00Z +const UpgradeHyggeHeight = 322354 + var SupportedProofTypes = []abi.RegisteredSealProof{ abi.RegisteredSealProof_StackedDrg32GiBV1, abi.RegisteredSealProof_StackedDrg64GiBV1, @@ -113,4 +117,8 @@ var PropagationDelaySecs = uint64(10) // BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start const BootstrapPeerThreshold = 4 +// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint. +// As per https://github.com/ethereum-lists/chains +const Eip155ChainId = 314159 + var WhitelistedBlock = cid.Undef diff --git a/build/params_interop.go b/build/params_interop.go index dbc619e1b..4d94de049 100644 --- a/build/params_interop.go +++ b/build/params_interop.go @@ -20,6 +20,7 @@ import ( var NetworkBundle = "caterpillarnet" var BundleOverrides map[actorstypes.Version]string +var ActorDebugging = false const BootstrappersFile = "interopnet.pi" const GenesisFile = "interopnet.car" @@ -49,7 +50,9 @@ var UpgradeChocolateHeight = abi.ChainEpoch(-17) var UpgradeOhSnapHeight = abi.ChainEpoch(-18) var UpgradeSkyrHeight = abi.ChainEpoch(-19) -const UpgradeSharkHeight = abi.ChainEpoch(99999999999999) +const UpgradeSharkHeight = abi.ChainEpoch(-20) + +const UpgradeHyggeHeight = abi.ChainEpoch(99999999999999) var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, @@ -104,6 +107,7 @@ func init() { UpgradeOhSnapHeight = getUpgradeHeight("LOTUS_OHSNAP_HEIGHT", UpgradeOhSnapHeight) UpgradeSkyrHeight = getUpgradeHeight("LOTUS_SKYR_HEIGHT", UpgradeSkyrHeight) UpgradeSharkHeight = getUpgradeHeight("LOTUS_SHARK_HEIGHT", UpgradeSharkHeight) + UpgradeHyggeHeight = getUpgradeHeight("LOTUS_HYGGE_HEIGHT", UpgradeHyggeHeight) BuildType |= BuildInteropnet SetAddressNetwork(address.Testnet) @@ -118,4 +122,9 @@ const PropagationDelaySecs = uint64(6) // BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start const BootstrapPeerThreshold = 2 +// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint. +// As per https://github.com/ethereum-lists/chains +// TODO same as butterfly for now, as we didn't submit an assignment for interopnet. +const Eip155ChainId = 3141592 + var WhitelistedBlock = cid.Undef diff --git a/build/params_mainnet.go b/build/params_mainnet.go index 875d6abbd..453cdafaf 100644 --- a/build/params_mainnet.go +++ b/build/params_mainnet.go @@ -25,6 +25,9 @@ var NetworkBundle = "mainnet" // NOTE: DO NOT change this unless you REALLY know what you're doing. This is consensus critical. var BundleOverrides map[actorstypes.Version]string +// NOTE: DO NOT change this unless you REALLY know what you're doing. This is consensus critical. +const ActorDebugging = false + const GenesisNetworkVersion = network.Version0 const BootstrappersFile = "mainnet.pi" @@ -56,6 +59,7 @@ const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 60) const UpgradeOrangeHeight = 336458 // 2020-12-22T02:00:00Z +// var because of wdpost_test.go var UpgradeClausHeight = abi.ChainEpoch(343200) // 2021-03-04T00:00:30Z @@ -80,14 +84,16 @@ const UpgradeOhSnapHeight = 1594680 const UpgradeSkyrHeight = 1960320 // 2022-11-30T14:00:00Z -var UpgradeSharkHeight = abi.ChainEpoch(2383680) +const UpgradeSharkHeight = 2383680 + +// 2023-03-14T15:14:00Z +var UpgradeHyggeHeight = abi.ChainEpoch(2683348) var SupportedProofTypes = []abi.RegisteredSealProof{ abi.RegisteredSealProof_StackedDrg32GiBV1, abi.RegisteredSealProof_StackedDrg64GiBV1, } var ConsensusMinerMinPower = abi.NewStoragePower(10 << 40) -var MinVerifiedDealSize = abi.NewStoragePower(1 << 20) var PreCommitChallengeDelay = abi.ChainEpoch(150) var PropagationDelaySecs = uint64(10) @@ -96,8 +102,8 @@ func init() { SetAddressNetwork(address.Mainnet) } - if os.Getenv("LOTUS_DISABLE_SHARK") == "1" { - UpgradeSharkHeight = math.MaxInt64 + if os.Getenv("LOTUS_DISABLE_HYGGE") == "1" { + UpgradeHyggeHeight = math.MaxInt64 } // NOTE: DO NOT change this unless you REALLY know what you're doing. This is not consensus critical, however, @@ -125,5 +131,9 @@ const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds) // BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start const BootstrapPeerThreshold = 4 +// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint. +// As per https://github.com/ethereum-lists/chains +const Eip155ChainId = 314 + // we skip checks on message validity in this block to sidestep the zero-bls signature var WhitelistedBlock = MustParseCid("bafy2bzaceapyg2uyzk7vueh3xccxkuwbz3nxewjyguoxvhx77malc2lzn2ybi") diff --git a/build/params_shared_vals.go b/build/params_shared_vals.go index 645560d36..be6640d6f 100644 --- a/build/params_shared_vals.go +++ b/build/params_shared_vals.go @@ -33,7 +33,7 @@ const TestNetworkVersion = network.Version{{.latestNetworkVersion}} /* inline-gen start */ -const TestNetworkVersion = network.Version17 +const TestNetworkVersion = network.Version18 /* inline-gen end */ diff --git a/build/params_testground.go b/build/params_testground.go index dcdee888d..17ea5a59b 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -42,9 +42,6 @@ var ( AllowableClockDriftSecs = uint64(1) - Finality = policy.ChainFinality - ForkLengthThreshold = Finality - SlashablePowerDelay = 20 InteractivePoRepConfidence = 6 @@ -108,6 +105,7 @@ var ( UpgradeOhSnapHeight abi.ChainEpoch = -17 UpgradeSkyrHeight abi.ChainEpoch = -18 UpgradeSharkHeight abi.ChainEpoch = -19 + UpgradeHyggeHeight abi.ChainEpoch = -20 DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, @@ -116,6 +114,7 @@ var ( GenesisNetworkVersion = network.Version0 NetworkBundle = "devnet" BundleOverrides map[actorstypes.Version]string + ActorDebugging = true NewestNetworkVersion = network.Version16 ActorUpgradeNetworkVersion = network.Version16 @@ -128,4 +127,11 @@ var ( GenesisFile = "" ) +const Finality = policy.ChainFinality +const ForkLengthThreshold = Finality + const BootstrapPeerThreshold = 1 + +// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint. +// As per https://github.com/ethereum-lists/chains +const Eip155ChainId = 31415926 diff --git a/build/version.go b/build/version.go index 99fe6b53d..e5a1435f1 100644 --- a/build/version.go +++ b/build/version.go @@ -37,7 +37,7 @@ func BuildTypeString() string { } // BuildVersion is the local build version -const BuildVersion = "1.19.0" +const BuildVersion = "1.20.0" func UserVersion() string { if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" { diff --git a/chain/actors/actor_cids.go b/chain/actors/actor_cids.go index 042426801..ad9ae4909 100644 --- a/chain/actors/actor_cids.go +++ b/chain/actors/actor_cids.go @@ -5,6 +5,7 @@ import ( "golang.org/x/xerrors" actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" @@ -28,7 +29,7 @@ func GetActorCodeID(av actorstypes.Version, name string) (cid.Cid, bool) { // Actors V7 and lower switch name { - case AccountKey: + case manifest.AccountKey: switch av { case actorstypes.Version0: @@ -53,7 +54,7 @@ func GetActorCodeID(av actorstypes.Version, name string) (cid.Cid, bool) { return builtin7.AccountActorCodeID, true } - case CronKey: + case manifest.CronKey: switch av { case actorstypes.Version0: @@ -78,7 +79,7 @@ func GetActorCodeID(av actorstypes.Version, name string) (cid.Cid, bool) { return builtin7.CronActorCodeID, true } - case InitKey: + case manifest.InitKey: switch av { case actorstypes.Version0: @@ -103,7 +104,7 @@ func GetActorCodeID(av actorstypes.Version, name string) (cid.Cid, bool) { return builtin7.InitActorCodeID, true } - case MarketKey: + case manifest.MarketKey: switch av { case actorstypes.Version0: @@ -128,7 +129,7 @@ func GetActorCodeID(av actorstypes.Version, name string) (cid.Cid, bool) { return builtin7.StorageMarketActorCodeID, true } - case MinerKey: + case manifest.MinerKey: switch av { case actorstypes.Version0: @@ -153,7 +154,7 @@ func GetActorCodeID(av actorstypes.Version, name string) (cid.Cid, bool) { return builtin7.StorageMinerActorCodeID, true } - case MultisigKey: + case manifest.MultisigKey: switch av { case actorstypes.Version0: @@ -178,7 +179,7 @@ func GetActorCodeID(av actorstypes.Version, name string) (cid.Cid, bool) { return builtin7.MultisigActorCodeID, true } - case PaychKey: + case manifest.PaychKey: switch av { case actorstypes.Version0: @@ -203,7 +204,7 @@ func GetActorCodeID(av actorstypes.Version, name string) (cid.Cid, bool) { return builtin7.PaymentChannelActorCodeID, true } - case PowerKey: + case manifest.PowerKey: switch av { case actorstypes.Version0: @@ -228,7 +229,7 @@ func GetActorCodeID(av actorstypes.Version, name string) (cid.Cid, bool) { return builtin7.StoragePowerActorCodeID, true } - case RewardKey: + case manifest.RewardKey: switch av { case actorstypes.Version0: @@ -253,7 +254,7 @@ func GetActorCodeID(av actorstypes.Version, name string) (cid.Cid, bool) { return builtin7.RewardActorCodeID, true } - case SystemKey: + case manifest.SystemKey: switch av { case actorstypes.Version0: @@ -278,7 +279,7 @@ func GetActorCodeID(av actorstypes.Version, name string) (cid.Cid, bool) { return builtin7.SystemActorCodeID, true } - case VerifregKey: + case manifest.VerifregKey: switch av { case actorstypes.Version0: @@ -314,7 +315,7 @@ func GetActorCodeIDs(av actorstypes.Version) (map[string]cid.Cid, error) { return cids, nil } - actorsKeys := GetBuiltinActorsKeys(av) + actorsKeys := manifest.GetBuiltinActorsKeys(av) synthCids := make(map[string]cid.Cid) for _, key := range actorsKeys { diff --git a/chain/actors/agen/main.go b/chain/actors/agen/main.go index fe47d7bfd..b9f3a22a4 100644 --- a/chain/actors/agen/main.go +++ b/chain/actors/agen/main.go @@ -28,6 +28,7 @@ var actors = map[string][]int{ "reward": lotusactors.Versions, "verifreg": lotusactors.Versions, "datacap": lotusactors.Versions[8:], + "evm": lotusactors.Versions[9:], } func main() { diff --git a/chain/actors/builtin/account/account.go b/chain/actors/builtin/account/account.go index f8c65a9b9..4542ad767 100644 --- a/chain/actors/builtin/account/account.go +++ b/chain/actors/builtin/account/account.go @@ -1,12 +1,14 @@ package account import ( + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" actorstypes "github.com/filecoin-project/go-state-types/actors" - builtin9 "github.com/filecoin-project/go-state-types/builtin" + builtin10 "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" @@ -20,11 +22,11 @@ import ( "github.com/filecoin-project/lotus/chain/types" ) -var Methods = builtin9.MethodsAccount +var Methods = builtin10.MethodsAccount func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.AccountKey { + if name != manifest.AccountKey { return nil, xerrors.Errorf("actor code is not account: %s", name) } @@ -36,6 +38,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -97,6 +102,9 @@ func MakeState(store adt.Store, av actorstypes.Version, addr address.Address) (S case actorstypes.Version9: return make9(store, addr) + case actorstypes.Version10: + return make10(store, addr) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -104,6 +112,25 @@ func MakeState(store adt.Store, av actorstypes.Version, addr address.Address) (S type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + PubkeyAddress() (address.Address, error) GetState() interface{} } + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state0{}).Code(), + (&state2{}).Code(), + (&state3{}).Code(), + (&state4{}).Code(), + (&state5{}).Code(), + (&state6{}).Code(), + (&state7{}).Code(), + (&state8{}).Code(), + (&state9{}).Code(), + (&state10{}).Code(), + } +} diff --git a/chain/actors/builtin/account/actor.go.template b/chain/actors/builtin/account/actor.go.template index 07b4cc94b..2db38eff6 100644 --- a/chain/actors/builtin/account/actor.go.template +++ b/chain/actors/builtin/account/actor.go.template @@ -1,6 +1,7 @@ package account import ( + "github.com/ipfs/go-cid" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/lotus/chain/actors" "golang.org/x/xerrors" @@ -10,6 +11,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/go-state-types/manifest" {{range .versions}} {{if (le . 7)}} @@ -23,7 +25,7 @@ var Methods = builtin{{.latestVersion}}.MethodsAccount func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.AccountKey { + if name != manifest.AccountKey { return nil, xerrors.Errorf("actor code is not account: %s", name) } @@ -62,6 +64,17 @@ func MakeState(store adt.Store, av actorstypes.Version, addr address.Address) (S type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + PubkeyAddress() (address.Address, error) GetState() interface{} } + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } +} diff --git a/chain/actors/builtin/account/state.go.template b/chain/actors/builtin/account/state.go.template index 93e7dc0db..55a56de8c 100644 --- a/chain/actors/builtin/account/state.go.template +++ b/chain/actors/builtin/account/state.go.template @@ -1,10 +1,15 @@ package account import ( + "fmt" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-address" "github.com/ipfs/go-cid" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/go-state-types/manifest" {{if (le .v 7)}} account{{.v}} "github.com/filecoin-project/specs-actors{{.import}}actors/builtin/account" @@ -41,4 +46,21 @@ func (s *state{{.v}}) PubkeyAddress() (address.Address, error) { func (s *state{{.v}}) GetState() interface{} { return &s.State +} + +func (s *state{{.v}}) ActorKey() string { + return manifest.AccountKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code } \ No newline at end of file diff --git a/chain/actors/builtin/account/v0.go b/chain/actors/builtin/account/v0.go index 314bd4b29..a41ee3879 100644 --- a/chain/actors/builtin/account/v0.go +++ b/chain/actors/builtin/account/v0.go @@ -1,11 +1,16 @@ package account import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" account0 "github.com/filecoin-project/specs-actors/actors/builtin/account" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -38,3 +43,20 @@ func (s *state0) PubkeyAddress() (address.Address, error) { func (s *state0) GetState() interface{} { return &s.State } + +func (s *state0) ActorKey() string { + return manifest.AccountKey +} + +func (s *state0) ActorVersion() actorstypes.Version { + return actorstypes.Version0 +} + +func (s *state0) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/account/v10.go b/chain/actors/builtin/account/v10.go new file mode 100644 index 000000000..ff87c4212 --- /dev/null +++ b/chain/actors/builtin/account/v10.go @@ -0,0 +1,62 @@ +package account + +import ( + "fmt" + + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" + account10 "github.com/filecoin-project/go-state-types/builtin/v10/account" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store, addr address.Address) (State, error) { + out := state10{store: store} + out.State = account10.State{Address: addr} + return &out, nil +} + +type state10 struct { + account10.State + store adt.Store +} + +func (s *state10) PubkeyAddress() (address.Address, error) { + return s.Address, nil +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +func (s *state10) ActorKey() string { + return manifest.AccountKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/account/v2.go b/chain/actors/builtin/account/v2.go index 605065424..db0af77e2 100644 --- a/chain/actors/builtin/account/v2.go +++ b/chain/actors/builtin/account/v2.go @@ -1,11 +1,16 @@ package account import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" account2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/account" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -38,3 +43,20 @@ func (s *state2) PubkeyAddress() (address.Address, error) { func (s *state2) GetState() interface{} { return &s.State } + +func (s *state2) ActorKey() string { + return manifest.AccountKey +} + +func (s *state2) ActorVersion() actorstypes.Version { + return actorstypes.Version2 +} + +func (s *state2) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/account/v3.go b/chain/actors/builtin/account/v3.go index d070476ea..9e6c71ad0 100644 --- a/chain/actors/builtin/account/v3.go +++ b/chain/actors/builtin/account/v3.go @@ -1,11 +1,16 @@ package account import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" account3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/account" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -38,3 +43,20 @@ func (s *state3) PubkeyAddress() (address.Address, error) { func (s *state3) GetState() interface{} { return &s.State } + +func (s *state3) ActorKey() string { + return manifest.AccountKey +} + +func (s *state3) ActorVersion() actorstypes.Version { + return actorstypes.Version3 +} + +func (s *state3) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/account/v4.go b/chain/actors/builtin/account/v4.go index f4d9f7a06..907896312 100644 --- a/chain/actors/builtin/account/v4.go +++ b/chain/actors/builtin/account/v4.go @@ -1,11 +1,16 @@ package account import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" account4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/account" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -38,3 +43,20 @@ func (s *state4) PubkeyAddress() (address.Address, error) { func (s *state4) GetState() interface{} { return &s.State } + +func (s *state4) ActorKey() string { + return manifest.AccountKey +} + +func (s *state4) ActorVersion() actorstypes.Version { + return actorstypes.Version4 +} + +func (s *state4) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/account/v5.go b/chain/actors/builtin/account/v5.go index 5e01ce152..8514ab325 100644 --- a/chain/actors/builtin/account/v5.go +++ b/chain/actors/builtin/account/v5.go @@ -1,11 +1,16 @@ package account import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" account5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/account" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -38,3 +43,20 @@ func (s *state5) PubkeyAddress() (address.Address, error) { func (s *state5) GetState() interface{} { return &s.State } + +func (s *state5) ActorKey() string { + return manifest.AccountKey +} + +func (s *state5) ActorVersion() actorstypes.Version { + return actorstypes.Version5 +} + +func (s *state5) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/account/v6.go b/chain/actors/builtin/account/v6.go index 85135dcda..16369f38c 100644 --- a/chain/actors/builtin/account/v6.go +++ b/chain/actors/builtin/account/v6.go @@ -1,11 +1,16 @@ package account import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" account6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/account" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -38,3 +43,20 @@ func (s *state6) PubkeyAddress() (address.Address, error) { func (s *state6) GetState() interface{} { return &s.State } + +func (s *state6) ActorKey() string { + return manifest.AccountKey +} + +func (s *state6) ActorVersion() actorstypes.Version { + return actorstypes.Version6 +} + +func (s *state6) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/account/v7.go b/chain/actors/builtin/account/v7.go index 4ae979b82..cd420da92 100644 --- a/chain/actors/builtin/account/v7.go +++ b/chain/actors/builtin/account/v7.go @@ -1,11 +1,16 @@ package account import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" account7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/account" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -38,3 +43,20 @@ func (s *state7) PubkeyAddress() (address.Address, error) { func (s *state7) GetState() interface{} { return &s.State } + +func (s *state7) ActorKey() string { + return manifest.AccountKey +} + +func (s *state7) ActorVersion() actorstypes.Version { + return actorstypes.Version7 +} + +func (s *state7) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/account/v8.go b/chain/actors/builtin/account/v8.go index 211deea33..13b478de8 100644 --- a/chain/actors/builtin/account/v8.go +++ b/chain/actors/builtin/account/v8.go @@ -1,11 +1,16 @@ package account import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" account8 "github.com/filecoin-project/go-state-types/builtin/v8/account" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -38,3 +43,20 @@ func (s *state8) PubkeyAddress() (address.Address, error) { func (s *state8) GetState() interface{} { return &s.State } + +func (s *state8) ActorKey() string { + return manifest.AccountKey +} + +func (s *state8) ActorVersion() actorstypes.Version { + return actorstypes.Version8 +} + +func (s *state8) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/account/v9.go b/chain/actors/builtin/account/v9.go index 7e172b33c..fc1fc4d14 100644 --- a/chain/actors/builtin/account/v9.go +++ b/chain/actors/builtin/account/v9.go @@ -1,11 +1,16 @@ package account import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" account9 "github.com/filecoin-project/go-state-types/builtin/v9/account" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -38,3 +43,20 @@ func (s *state9) PubkeyAddress() (address.Address, error) { func (s *state9) GetState() interface{} { return &s.State } + +func (s *state9) ActorKey() string { + return manifest.AccountKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/builtin.go b/chain/actors/builtin/builtin.go index 82e80365a..414a11e72 100644 --- a/chain/actors/builtin/builtin.go +++ b/chain/actors/builtin/builtin.go @@ -10,6 +10,7 @@ import ( "github.com/filecoin-project/go-state-types/builtin" smoothingtypes "github.com/filecoin-project/go-state-types/builtin/v8/util/smoothing" minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/go-state-types/proof" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" @@ -25,6 +26,7 @@ import ( var SystemActorAddr = builtin.SystemActorAddr var BurntFundsActorAddr = builtin.BurntFundsActorAddr var CronActorAddr = builtin.CronActorAddr +var EthereumAddressManagerActorAddr = builtin.EthereumAddressManagerActorAddr var SaftAddress = makeAddress("t0122") var ReserveAddress = makeAddress("t090") var RootVerifierAddress = makeAddress("t080") @@ -165,7 +167,7 @@ func IsAccountActor(c cid.Cid) bool { func IsStorageMinerActor(c cid.Cid) bool { name, _, ok := actors.GetActorMetaByCode(c) if ok { - return name == actors.MinerKey + return name == manifest.MinerKey } if c == builtin0.StorageMinerActorCodeID { @@ -202,7 +204,7 @@ func IsStorageMinerActor(c cid.Cid) bool { func IsMultisigActor(c cid.Cid) bool { name, _, ok := actors.GetActorMetaByCode(c) if ok { - return name == actors.MultisigKey + return name == manifest.MultisigKey } if c == builtin0.MultisigActorCodeID { @@ -273,6 +275,33 @@ func IsPaymentChannelActor(c cid.Cid) bool { return false } +func IsPlaceholderActor(c cid.Cid) bool { + name, _, ok := actors.GetActorMetaByCode(c) + if ok { + return name == manifest.PlaceholderKey + } + + return false +} + +func IsEvmActor(c cid.Cid) bool { + name, _, ok := actors.GetActorMetaByCode(c) + if ok { + return name == manifest.EvmKey + } + + return false +} + +func IsEthAccountActor(c cid.Cid) bool { + name, _, ok := actors.GetActorMetaByCode(c) + if ok { + return name == manifest.EthAccountKey + } + + return false +} + func makeAddress(addr string) address.Address { ret, err := address.NewFromString(addr) if err != nil { diff --git a/chain/actors/builtin/builtin.go.template b/chain/actors/builtin/builtin.go.template index 825f6cc07..3b737c47e 100644 --- a/chain/actors/builtin/builtin.go.template +++ b/chain/actors/builtin/builtin.go.template @@ -15,6 +15,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/proof" "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/lotus/chain/actors" @@ -25,6 +26,7 @@ import ( var SystemActorAddr = builtin.SystemActorAddr var BurntFundsActorAddr = builtin.BurntFundsActorAddr var CronActorAddr = builtin.CronActorAddr +var EthereumAddressManagerActorAddr = builtin.EthereumAddressManagerActorAddr var SaftAddress = makeAddress("t0122") var ReserveAddress = makeAddress("t090") var RootVerifierAddress = makeAddress("t080") @@ -107,7 +109,7 @@ func IsAccountActor(c cid.Cid) bool { func IsStorageMinerActor(c cid.Cid) bool { name, _, ok := actors.GetActorMetaByCode(c) if ok { - return name == actors.MinerKey + return name == manifest.MinerKey } {{range .versions}} @@ -123,7 +125,7 @@ func IsStorageMinerActor(c cid.Cid) bool { func IsMultisigActor(c cid.Cid) bool { name, _, ok := actors.GetActorMetaByCode(c) if ok { - return name == actors.MultisigKey + return name == manifest.MultisigKey } {{range .versions}} @@ -152,6 +154,33 @@ func IsPaymentChannelActor(c cid.Cid) bool { return false } +func IsPlaceholderActor(c cid.Cid) bool { + name, _, ok := actors.GetActorMetaByCode(c) + if ok { + return name == manifest.PlaceholderKey + } + + return false +} + +func IsEvmActor(c cid.Cid) bool { + name, _, ok := actors.GetActorMetaByCode(c) + if ok { + return name == manifest.EvmKey + } + + return false +} + +func IsEthAccountActor(c cid.Cid) bool { + name, _, ok := actors.GetActorMetaByCode(c) + if ok { + return name == manifest.EthAccountKey + } + + return false +} + func makeAddress(addr string) address.Address { ret, err := address.NewFromString(addr) if err != nil { diff --git a/chain/actors/builtin/cron/actor.go.template b/chain/actors/builtin/cron/actor.go.template index 67c781fb2..7e01483d2 100644 --- a/chain/actors/builtin/cron/actor.go.template +++ b/chain/actors/builtin/cron/actor.go.template @@ -1,11 +1,13 @@ package cron import ( + "github.com/ipfs/go-cid" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/go-state-types/manifest" {{range .versions}} {{if (le . 7)}} @@ -17,7 +19,7 @@ import ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.CronKey { + if name != manifest.CronKey { return nil, xerrors.Errorf("actor code is not cron: %s", name) } @@ -60,5 +62,16 @@ var ( type State interface { + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + GetState() interface{} } + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } +} diff --git a/chain/actors/builtin/cron/cron.go b/chain/actors/builtin/cron/cron.go index 29f795476..43b8c0eaa 100644 --- a/chain/actors/builtin/cron/cron.go +++ b/chain/actors/builtin/cron/cron.go @@ -1,10 +1,12 @@ package cron import ( + "github.com/ipfs/go-cid" "golang.org/x/xerrors" actorstypes "github.com/filecoin-project/go-state-types/actors" - builtin9 "github.com/filecoin-project/go-state-types/builtin" + builtin10 "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/manifest" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" @@ -20,7 +22,7 @@ import ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.CronKey { + if name != manifest.CronKey { return nil, xerrors.Errorf("actor code is not cron: %s", name) } @@ -32,6 +34,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -93,15 +98,37 @@ func MakeState(store adt.Store, av actorstypes.Version) (State, error) { case actorstypes.Version9: return make9(store) + case actorstypes.Version10: + return make10(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } var ( - Address = builtin9.CronActorAddr - Methods = builtin9.MethodsCron + Address = builtin10.CronActorAddr + Methods = builtin10.MethodsCron ) type State interface { + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + GetState() interface{} } + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state0{}).Code(), + (&state2{}).Code(), + (&state3{}).Code(), + (&state4{}).Code(), + (&state5{}).Code(), + (&state6{}).Code(), + (&state7{}).Code(), + (&state8{}).Code(), + (&state9{}).Code(), + (&state10{}).Code(), + } +} diff --git a/chain/actors/builtin/cron/state.go.template b/chain/actors/builtin/cron/state.go.template index 13cdc46c9..ca82d8be8 100644 --- a/chain/actors/builtin/cron/state.go.template +++ b/chain/actors/builtin/cron/state.go.template @@ -1,9 +1,13 @@ package cron import ( + "fmt" "github.com/ipfs/go-cid" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" {{if (le .v 7)}} cron{{.v}} "github.com/filecoin-project/specs-actors{{.import}}actors/builtin/cron" @@ -36,4 +40,21 @@ type state{{.v}} struct { func (s *state{{.v}}) GetState() interface{} { return &s.State -} \ No newline at end of file +} + +func (s *state{{.v}}) ActorKey() string { + return manifest.CronKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/cron/v0.go b/chain/actors/builtin/cron/v0.go index baa81aac3..6dce524f6 100644 --- a/chain/actors/builtin/cron/v0.go +++ b/chain/actors/builtin/cron/v0.go @@ -1,10 +1,15 @@ package cron import ( + "fmt" + "github.com/ipfs/go-cid" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" cron0 "github.com/filecoin-project/specs-actors/actors/builtin/cron" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -33,3 +38,20 @@ type state0 struct { func (s *state0) GetState() interface{} { return &s.State } + +func (s *state0) ActorKey() string { + return manifest.CronKey +} + +func (s *state0) ActorVersion() actorstypes.Version { + return actorstypes.Version0 +} + +func (s *state0) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/cron/v10.go b/chain/actors/builtin/cron/v10.go new file mode 100644 index 000000000..2d20e2401 --- /dev/null +++ b/chain/actors/builtin/cron/v10.go @@ -0,0 +1,57 @@ +package cron + +import ( + "fmt" + + "github.com/ipfs/go-cid" + + actorstypes "github.com/filecoin-project/go-state-types/actors" + cron10 "github.com/filecoin-project/go-state-types/builtin/v10/cron" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store) (State, error) { + out := state10{store: store} + out.State = *cron10.ConstructState(cron10.BuiltInEntries()) + return &out, nil +} + +type state10 struct { + cron10.State + store adt.Store +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +func (s *state10) ActorKey() string { + return manifest.CronKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/cron/v2.go b/chain/actors/builtin/cron/v2.go index d6ee35935..97b3ffbe0 100644 --- a/chain/actors/builtin/cron/v2.go +++ b/chain/actors/builtin/cron/v2.go @@ -1,10 +1,15 @@ package cron import ( + "fmt" + "github.com/ipfs/go-cid" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" cron2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/cron" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -33,3 +38,20 @@ type state2 struct { func (s *state2) GetState() interface{} { return &s.State } + +func (s *state2) ActorKey() string { + return manifest.CronKey +} + +func (s *state2) ActorVersion() actorstypes.Version { + return actorstypes.Version2 +} + +func (s *state2) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/cron/v3.go b/chain/actors/builtin/cron/v3.go index 356d385cd..4c0d4f1d9 100644 --- a/chain/actors/builtin/cron/v3.go +++ b/chain/actors/builtin/cron/v3.go @@ -1,10 +1,15 @@ package cron import ( + "fmt" + "github.com/ipfs/go-cid" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" cron3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/cron" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -33,3 +38,20 @@ type state3 struct { func (s *state3) GetState() interface{} { return &s.State } + +func (s *state3) ActorKey() string { + return manifest.CronKey +} + +func (s *state3) ActorVersion() actorstypes.Version { + return actorstypes.Version3 +} + +func (s *state3) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/cron/v4.go b/chain/actors/builtin/cron/v4.go index 3db3c95aa..a222f0d93 100644 --- a/chain/actors/builtin/cron/v4.go +++ b/chain/actors/builtin/cron/v4.go @@ -1,10 +1,15 @@ package cron import ( + "fmt" + "github.com/ipfs/go-cid" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" cron4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/cron" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -33,3 +38,20 @@ type state4 struct { func (s *state4) GetState() interface{} { return &s.State } + +func (s *state4) ActorKey() string { + return manifest.CronKey +} + +func (s *state4) ActorVersion() actorstypes.Version { + return actorstypes.Version4 +} + +func (s *state4) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/cron/v5.go b/chain/actors/builtin/cron/v5.go index 5d99af1fd..2487cbbc6 100644 --- a/chain/actors/builtin/cron/v5.go +++ b/chain/actors/builtin/cron/v5.go @@ -1,10 +1,15 @@ package cron import ( + "fmt" + "github.com/ipfs/go-cid" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" cron5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/cron" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -33,3 +38,20 @@ type state5 struct { func (s *state5) GetState() interface{} { return &s.State } + +func (s *state5) ActorKey() string { + return manifest.CronKey +} + +func (s *state5) ActorVersion() actorstypes.Version { + return actorstypes.Version5 +} + +func (s *state5) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/cron/v6.go b/chain/actors/builtin/cron/v6.go index c86cd6c42..673e7588a 100644 --- a/chain/actors/builtin/cron/v6.go +++ b/chain/actors/builtin/cron/v6.go @@ -1,10 +1,15 @@ package cron import ( + "fmt" + "github.com/ipfs/go-cid" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" cron6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/cron" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -33,3 +38,20 @@ type state6 struct { func (s *state6) GetState() interface{} { return &s.State } + +func (s *state6) ActorKey() string { + return manifest.CronKey +} + +func (s *state6) ActorVersion() actorstypes.Version { + return actorstypes.Version6 +} + +func (s *state6) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/cron/v7.go b/chain/actors/builtin/cron/v7.go index db9f8f9e2..cd71bd418 100644 --- a/chain/actors/builtin/cron/v7.go +++ b/chain/actors/builtin/cron/v7.go @@ -1,10 +1,15 @@ package cron import ( + "fmt" + "github.com/ipfs/go-cid" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" cron7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/cron" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -33,3 +38,20 @@ type state7 struct { func (s *state7) GetState() interface{} { return &s.State } + +func (s *state7) ActorKey() string { + return manifest.CronKey +} + +func (s *state7) ActorVersion() actorstypes.Version { + return actorstypes.Version7 +} + +func (s *state7) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/cron/v8.go b/chain/actors/builtin/cron/v8.go index 00567acf9..904de5496 100644 --- a/chain/actors/builtin/cron/v8.go +++ b/chain/actors/builtin/cron/v8.go @@ -1,10 +1,15 @@ package cron import ( + "fmt" + "github.com/ipfs/go-cid" + actorstypes "github.com/filecoin-project/go-state-types/actors" cron8 "github.com/filecoin-project/go-state-types/builtin/v8/cron" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -33,3 +38,20 @@ type state8 struct { func (s *state8) GetState() interface{} { return &s.State } + +func (s *state8) ActorKey() string { + return manifest.CronKey +} + +func (s *state8) ActorVersion() actorstypes.Version { + return actorstypes.Version8 +} + +func (s *state8) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/cron/v9.go b/chain/actors/builtin/cron/v9.go index 312a33b68..201348b6c 100644 --- a/chain/actors/builtin/cron/v9.go +++ b/chain/actors/builtin/cron/v9.go @@ -1,10 +1,15 @@ package cron import ( + "fmt" + "github.com/ipfs/go-cid" + actorstypes "github.com/filecoin-project/go-state-types/actors" cron9 "github.com/filecoin-project/go-state-types/builtin/v9/cron" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -33,3 +38,20 @@ type state9 struct { func (s *state9) GetState() interface{} { return &s.State } + +func (s *state9) ActorKey() string { + return manifest.CronKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/datacap/actor.go.template b/chain/actors/builtin/datacap/actor.go.template index 9a3f2bdb8..7bf4fbef2 100644 --- a/chain/actors/builtin/datacap/actor.go.template +++ b/chain/actors/builtin/datacap/actor.go.template @@ -3,6 +3,8 @@ package datacap import ( "golang.org/x/xerrors" + "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" @@ -12,6 +14,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/go-state-types/manifest" ) var ( @@ -21,7 +24,7 @@ var ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.DatacapKey { + if name != manifest.DatacapKey { return nil, xerrors.Errorf("actor code is not datacap: %s", name) } @@ -41,17 +44,27 @@ func MakeState(store adt.Store, av actorstypes.Version, governor address.Address {{range .versions}} case actorstypes.Version{{.}}: return make{{.}}(store, governor, bitwidth) - - default: return nil, xerrors.Errorf("datacap actor only valid for actors v9 and above, got %d", av) {{end}} + default: return nil, xerrors.Errorf("datacap actor only valid for actors v9 and above, got %d", av) } } type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + ForEachClient(func(addr address.Address, dcap abi.StoragePower) error) error VerifiedClientDataCap(address.Address) (bool, abi.StoragePower, error) Governor() (address.Address, error) GetState() interface{} } + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } +} diff --git a/chain/actors/builtin/datacap/datacap.go b/chain/actors/builtin/datacap/datacap.go index 3915c01e5..c12c77230 100644 --- a/chain/actors/builtin/datacap/datacap.go +++ b/chain/actors/builtin/datacap/datacap.go @@ -1,13 +1,15 @@ package datacap import ( + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" - builtin9 "github.com/filecoin-project/go-state-types/builtin" + builtin10 "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" @@ -15,13 +17,13 @@ import ( ) var ( - Address = builtin9.DatacapActorAddr - Methods = builtin9.MethodsDatacap + Address = builtin10.DatacapActorAddr + Methods = builtin10.MethodsDatacap ) func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.DatacapKey { + if name != manifest.DatacapKey { return nil, xerrors.Errorf("actor code is not datacap: %s", name) } @@ -30,6 +32,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -42,17 +47,30 @@ func MakeState(store adt.Store, av actorstypes.Version, governor address.Address case actorstypes.Version9: return make9(store, governor, bitwidth) + case actorstypes.Version10: + return make10(store, governor, bitwidth) + default: return nil, xerrors.Errorf("datacap actor only valid for actors v9 and above, got %d", av) - } } type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + ForEachClient(func(addr address.Address, dcap abi.StoragePower) error) error VerifiedClientDataCap(address.Address) (bool, abi.StoragePower, error) Governor() (address.Address, error) GetState() interface{} } + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state9{}).Code(), + (&state10{}).Code(), + } +} diff --git a/chain/actors/builtin/datacap/state.go.template b/chain/actors/builtin/datacap/state.go.template index 297f9f79f..de0ccb4be 100644 --- a/chain/actors/builtin/datacap/state.go.template +++ b/chain/actors/builtin/datacap/state.go.template @@ -1,15 +1,18 @@ package datacap import ( + "fmt" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" + actorstypes "github.com/filecoin-project/go-state-types/actors" datacap{{.v}} "github.com/filecoin-project/go-state-types/builtin{{.import}}datacap" adt{{.v}} "github.com/filecoin-project/go-state-types/builtin{{.import}}util/adt" + "github.com/filecoin-project/go-state-types/manifest" ) var _ State = (*state{{.v}})(nil) @@ -59,3 +62,20 @@ func (s *state{{.v}}) verifiedClients() (adt.Map, error) { func (s *state{{.v}}) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) { return getDataCap(s.store, actors.Version{{.v}}, s.verifiedClients, addr) } + +func (s *state{{.v}}) ActorKey() string { + return manifest.DatacapKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/datacap/util.go b/chain/actors/builtin/datacap/util.go index e1442055a..03e941d6e 100644 --- a/chain/actors/builtin/datacap/util.go +++ b/chain/actors/builtin/datacap/util.go @@ -54,6 +54,9 @@ func forEachClient(store adt.Store, ver actors.Version, root rootFunc, cb func(a } a, err := address.NewIDAddress(id) + if err != nil { + return xerrors.Errorf("creating ID address from actor ID: %w", err) + } return cb(a, big.Div(dcap, verifreg.DataCapGranularity)) }) diff --git a/chain/actors/builtin/datacap/v10.go b/chain/actors/builtin/datacap/v10.go new file mode 100644 index 000000000..25eec4ea8 --- /dev/null +++ b/chain/actors/builtin/datacap/v10.go @@ -0,0 +1,82 @@ +package datacap + +import ( + "fmt" + + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + datacap10 "github.com/filecoin-project/go-state-types/builtin/v10/datacap" + adt10 "github.com/filecoin-project/go-state-types/builtin/v10/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store, governor address.Address, bitwidth uint64) (State, error) { + out := state10{store: store} + s, err := datacap10.ConstructState(store, governor, bitwidth) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state10 struct { + datacap10.State + store adt.Store +} + +func (s *state10) Governor() (address.Address, error) { + return s.State.Governor, nil +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +func (s *state10) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachClient(s.store, actors.Version10, s.verifiedClients, cb) +} + +func (s *state10) verifiedClients() (adt.Map, error) { + return adt10.AsMap(s.store, s.Token.Balances, int(s.Token.HamtBitWidth)) +} + +func (s *state10) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, actors.Version10, s.verifiedClients, addr) +} + +func (s *state10) ActorKey() string { + return manifest.DatacapKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/datacap/v9.go b/chain/actors/builtin/datacap/v9.go index a6e4bbcd6..1d239fb95 100644 --- a/chain/actors/builtin/datacap/v9.go +++ b/chain/actors/builtin/datacap/v9.go @@ -1,12 +1,16 @@ package datacap import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" datacap9 "github.com/filecoin-project/go-state-types/builtin/v9/datacap" adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" @@ -59,3 +63,20 @@ func (s *state9) verifiedClients() (adt.Map, error) { func (s *state9) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) { return getDataCap(s.store, actors.Version9, s.verifiedClients, addr) } + +func (s *state9) ActorKey() string { + return manifest.DatacapKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/evm/actor.go.template b/chain/actors/builtin/evm/actor.go.template new file mode 100644 index 000000000..62da06867 --- /dev/null +++ b/chain/actors/builtin/evm/actor.go.template @@ -0,0 +1,57 @@ +package evm + +import ( + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/cbor" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/go-state-types/manifest" + + builtin{{.latestVersion}} "github.com/filecoin-project/go-state-types/builtin" +) + +var Methods = builtin{{.latestVersion}}.MethodsEVM + +func Load(store adt.Store, act *types.Actor) (State, error) { + if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { + if name != manifest.EvmKey { + return nil, xerrors.Errorf("actor code is not evm: %s", name) + } + + switch av { + {{range .versions}} + case actorstypes.Version{{.}}: + return load{{.}}(store, act.Head) + {{end}} + } + } + + return nil, xerrors.Errorf("unknown actor code %s", act.Code) +} + +func MakeState(store adt.Store, av actorstypes.Version, bytecode cid.Cid) (State, error) { + switch av { +{{range .versions}} + case actorstypes.Version{{.}}: + return make{{.}}(store, bytecode) +{{end}} + default: return nil, xerrors.Errorf("evm actor only valid for actors v10 and above, got %d", av) + } +} + +type State interface { + cbor.Marshaler + + Nonce() (uint64, error) + IsAlive() (bool, error) + GetState() interface{} + + GetBytecode() ([]byte, error) + GetBytecodeCID() (cid.Cid, error) + GetBytecodeHash() ([32]byte, error) +} diff --git a/chain/actors/builtin/evm/evm.go b/chain/actors/builtin/evm/evm.go new file mode 100644 index 000000000..f214cdc13 --- /dev/null +++ b/chain/actors/builtin/evm/evm.go @@ -0,0 +1,57 @@ +package evm + +import ( + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + actorstypes "github.com/filecoin-project/go-state-types/actors" + builtin10 "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" +) + +var Methods = builtin10.MethodsEVM + +func Load(store adt.Store, act *types.Actor) (State, error) { + if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { + if name != manifest.EvmKey { + return nil, xerrors.Errorf("actor code is not evm: %s", name) + } + + switch av { + + case actorstypes.Version10: + return load10(store, act.Head) + + } + } + + return nil, xerrors.Errorf("unknown actor code %s", act.Code) +} + +func MakeState(store adt.Store, av actorstypes.Version, bytecode cid.Cid) (State, error) { + switch av { + + case actorstypes.Version10: + return make10(store, bytecode) + + default: + return nil, xerrors.Errorf("evm actor only valid for actors v10 and above, got %d", av) + } +} + +type State interface { + cbor.Marshaler + + Nonce() (uint64, error) + IsAlive() (bool, error) + GetState() interface{} + + GetBytecode() ([]byte, error) + GetBytecodeCID() (cid.Cid, error) + GetBytecodeHash() ([32]byte, error) +} diff --git a/chain/actors/builtin/evm/state.go.template b/chain/actors/builtin/evm/state.go.template new file mode 100644 index 000000000..f193733d1 --- /dev/null +++ b/chain/actors/builtin/evm/state.go.template @@ -0,0 +1,73 @@ +package evm + +import ( + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/go-state-types/abi" + + evm{{.v}} "github.com/filecoin-project/go-state-types/builtin{{.import}}evm" +) + +var _ State = (*state{{.v}})(nil) + +func load{{.v}}(store adt.Store, root cid.Cid) (State, error) { + out := state{{.v}}{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make{{.v}}(store adt.Store, bytecode cid.Cid) (State, error) { + out := state{{.v}}{store: store} + s, err := evm{{.v}}.ConstructState(store, bytecode) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state{{.v}} struct { + evm{{.v}}.State + store adt.Store +} + +func (s *state{{.v}}) Nonce() (uint64, error) { + return s.State.Nonce, nil +} + +func (s *state{{.v}}) IsAlive() (bool, error) { + return s.State.Tombstone == nil, nil +} + +func (s *state{{.v}}) GetState() interface{} { + return &s.State +} + +func (s *state{{.v}}) GetBytecodeCID() (cid.Cid, error) { + return s.State.Bytecode, nil +} + +func (s *state{{.v}}) GetBytecodeHash() ([32]byte, error) { + return s.State.BytecodeHash, nil +} + +func (s *state{{.v}}) GetBytecode() ([]byte, error) { + bc, err := s.GetBytecodeCID() + if err != nil { + return nil, err + } + + var byteCode abi.CborBytesTransparent + if err := s.store.Get(s.store.Context(), bc, &byteCode); err != nil { + return nil, err + } + + return byteCode, nil +} diff --git a/chain/actors/builtin/evm/v10.go b/chain/actors/builtin/evm/v10.go new file mode 100644 index 000000000..d467aa187 --- /dev/null +++ b/chain/actors/builtin/evm/v10.go @@ -0,0 +1,72 @@ +package evm + +import ( + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/go-state-types/abi" + evm10 "github.com/filecoin-project/go-state-types/builtin/v10/evm" + + "github.com/filecoin-project/lotus/chain/actors/adt" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store, bytecode cid.Cid) (State, error) { + out := state10{store: store} + s, err := evm10.ConstructState(store, bytecode) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state10 struct { + evm10.State + store adt.Store +} + +func (s *state10) Nonce() (uint64, error) { + return s.State.Nonce, nil +} + +func (s *state10) IsAlive() (bool, error) { + return s.State.Tombstone == nil, nil +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +func (s *state10) GetBytecodeCID() (cid.Cid, error) { + return s.State.Bytecode, nil +} + +func (s *state10) GetBytecodeHash() ([32]byte, error) { + return s.State.BytecodeHash, nil +} + +func (s *state10) GetBytecode() ([]byte, error) { + bc, err := s.GetBytecodeCID() + if err != nil { + return nil, err + } + + var byteCode abi.CborBytesTransparent + if err := s.store.Get(s.store.Context(), bc, &byteCode); err != nil { + return nil, err + } + + return byteCode, nil +} diff --git a/chain/actors/builtin/init/actor.go.template b/chain/actors/builtin/init/actor.go.template index 43bb70c4c..1d19ebb40 100644 --- a/chain/actors/builtin/init/actor.go.template +++ b/chain/actors/builtin/init/actor.go.template @@ -13,6 +13,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/go-state-types/manifest" {{range .versions}} {{if (le . 7)}} builtin{{.}} "github.com/filecoin-project/specs-actors{{import .}}actors/builtin" @@ -28,7 +29,7 @@ var ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.InitKey { + if name != manifest.InitKey { return nil, xerrors.Errorf("actor code is not init: %s", name) } @@ -67,6 +68,10 @@ func MakeState(store adt.Store, av actorstypes.Version, networkName string) (Sta type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + ResolveAddress(address address.Address) (address.Address, bool, error) MapAddressToNewID(address address.Address) (address.Address, error) NetworkName() (dtypes.NetworkName, error) @@ -87,6 +92,16 @@ type State interface { // Sets the address map for the init actor. This should only be used for testing. SetAddressMap(mcid cid.Cid) error - AddressMap() (adt.Map, error) GetState() interface{} + + AddressMap() (adt.Map, error) + AddressMapBitWidth() int + AddressMapHashFunction() func(input []byte) []byte +} + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } } diff --git a/chain/actors/builtin/init/init.go b/chain/actors/builtin/init/init.go index 8a5550697..c38629d2d 100644 --- a/chain/actors/builtin/init/init.go +++ b/chain/actors/builtin/init/init.go @@ -7,8 +7,9 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" - builtin9 "github.com/filecoin-project/go-state-types/builtin" + builtin10 "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" @@ -24,13 +25,13 @@ import ( ) var ( - Address = builtin9.InitActorAddr - Methods = builtin9.MethodsInit + Address = builtin10.InitActorAddr + Methods = builtin10.MethodsInit ) func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.InitKey { + if name != manifest.InitKey { return nil, xerrors.Errorf("actor code is not init: %s", name) } @@ -42,6 +43,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -103,6 +107,9 @@ func MakeState(store adt.Store, av actorstypes.Version, networkName string) (Sta case actorstypes.Version9: return make9(store, networkName) + case actorstypes.Version10: + return make10(store, networkName) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -110,6 +117,10 @@ func MakeState(store adt.Store, av actorstypes.Version, networkName string) (Sta type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + ResolveAddress(address address.Address) (address.Address, bool, error) MapAddressToNewID(address address.Address) (address.Address, error) NetworkName() (dtypes.NetworkName, error) @@ -130,6 +141,24 @@ type State interface { // Sets the address map for the init actor. This should only be used for testing. SetAddressMap(mcid cid.Cid) error - AddressMap() (adt.Map, error) GetState() interface{} + + AddressMap() (adt.Map, error) + AddressMapBitWidth() int + AddressMapHashFunction() func(input []byte) []byte +} + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state0{}).Code(), + (&state2{}).Code(), + (&state3{}).Code(), + (&state4{}).Code(), + (&state5{}).Code(), + (&state6{}).Code(), + (&state7{}).Code(), + (&state8{}).Code(), + (&state9{}).Code(), + (&state10{}).Code(), + } } diff --git a/chain/actors/builtin/init/state.go.template b/chain/actors/builtin/init/state.go.template index 0e56f5da4..52e223a85 100644 --- a/chain/actors/builtin/init/state.go.template +++ b/chain/actors/builtin/init/state.go.template @@ -1,14 +1,20 @@ package init import ( + "crypto/sha256" + "fmt" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/go-state-types/manifest" {{if (le .v 7)}} {{if (ge .v 3)}} @@ -119,10 +125,42 @@ func (s *state{{.v}}) SetAddressMap(mcid cid.Cid) error { return nil } +func (s *state{{.v}}) GetState() interface{} { + return &s.State +} + func (s *state{{.v}}) AddressMap() (adt.Map, error) { return adt{{.v}}.AsMap(s.store, s.State.AddressMap{{if (ge .v 3)}}, builtin{{.v}}.DefaultHamtBitwidth{{end}}) } -func (s *state{{.v}}) GetState() interface{} { - return &s.State -} \ No newline at end of file +func (s *state{{.v}}) AddressMapBitWidth() int { + {{- if (ge .v 3)}} + return builtin{{.v}}.DefaultHamtBitwidth + {{- else}} + return 5 + {{- end}} +} + +func (s *state{{.v}}) AddressMapHashFunction() func(input []byte) []byte { + return func(input []byte) []byte { + res := sha256.Sum256(input) + return res[:] + } +} + +func (s *state{{.v}}) ActorKey() string { + return manifest.InitKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/init/v0.go b/chain/actors/builtin/init/v0.go index 2f6b213c0..7e48dda9e 100644 --- a/chain/actors/builtin/init/v0.go +++ b/chain/actors/builtin/init/v0.go @@ -1,15 +1,21 @@ package init import ( + "crypto/sha256" + "fmt" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -103,10 +109,38 @@ func (s *state0) SetAddressMap(mcid cid.Cid) error { return nil } +func (s *state0) GetState() interface{} { + return &s.State +} + func (s *state0) AddressMap() (adt.Map, error) { return adt0.AsMap(s.store, s.State.AddressMap) } -func (s *state0) GetState() interface{} { - return &s.State +func (s *state0) AddressMapBitWidth() int { + return 5 +} + +func (s *state0) AddressMapHashFunction() func(input []byte) []byte { + return func(input []byte) []byte { + res := sha256.Sum256(input) + return res[:] + } +} + +func (s *state0) ActorKey() string { + return manifest.InitKey +} + +func (s *state0) ActorVersion() actorstypes.Version { + return actorstypes.Version0 +} + +func (s *state0) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code } diff --git a/chain/actors/builtin/init/v10.go b/chain/actors/builtin/init/v10.go new file mode 100644 index 000000000..dd8c778dd --- /dev/null +++ b/chain/actors/builtin/init/v10.go @@ -0,0 +1,147 @@ +package init + +import ( + "crypto/sha256" + "fmt" + + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + builtin10 "github.com/filecoin-project/go-state-types/builtin" + init10 "github.com/filecoin-project/go-state-types/builtin/v10/init" + adt10 "github.com/filecoin-project/go-state-types/builtin/v10/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/node/modules/dtypes" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store, networkName string) (State, error) { + out := state10{store: store} + + s, err := init10.ConstructState(store, networkName) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state10 struct { + init10.State + store adt.Store +} + +func (s *state10) ResolveAddress(address address.Address) (address.Address, bool, error) { + return s.State.ResolveAddress(s.store, address) +} + +func (s *state10) MapAddressToNewID(address address.Address) (address.Address, error) { + return s.State.MapAddressToNewID(s.store, address) +} + +func (s *state10) ForEachActor(cb func(id abi.ActorID, address address.Address) error) error { + addrs, err := adt10.AsMap(s.store, s.State.AddressMap, builtin10.DefaultHamtBitwidth) + if err != nil { + return err + } + var actorID cbg.CborInt + return addrs.ForEach(&actorID, func(key string) error { + addr, err := address.NewFromBytes([]byte(key)) + if err != nil { + return err + } + return cb(abi.ActorID(actorID), addr) + }) +} + +func (s *state10) NetworkName() (dtypes.NetworkName, error) { + return dtypes.NetworkName(s.State.NetworkName), nil +} + +func (s *state10) SetNetworkName(name string) error { + s.State.NetworkName = name + return nil +} + +func (s *state10) SetNextID(id abi.ActorID) error { + s.State.NextID = id + return nil +} + +func (s *state10) Remove(addrs ...address.Address) (err error) { + m, err := adt10.AsMap(s.store, s.State.AddressMap, builtin10.DefaultHamtBitwidth) + if err != nil { + return err + } + for _, addr := range addrs { + if err = m.Delete(abi.AddrKey(addr)); err != nil { + return xerrors.Errorf("failed to delete entry for address: %s; err: %w", addr, err) + } + } + amr, err := m.Root() + if err != nil { + return xerrors.Errorf("failed to get address map root: %w", err) + } + s.State.AddressMap = amr + return nil +} + +func (s *state10) SetAddressMap(mcid cid.Cid) error { + s.State.AddressMap = mcid + return nil +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +func (s *state10) AddressMap() (adt.Map, error) { + return adt10.AsMap(s.store, s.State.AddressMap, builtin10.DefaultHamtBitwidth) +} + +func (s *state10) AddressMapBitWidth() int { + return builtin10.DefaultHamtBitwidth +} + +func (s *state10) AddressMapHashFunction() func(input []byte) []byte { + return func(input []byte) []byte { + res := sha256.Sum256(input) + return res[:] + } +} + +func (s *state10) ActorKey() string { + return manifest.InitKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/init/v2.go b/chain/actors/builtin/init/v2.go index d780a1fe9..c107bd52d 100644 --- a/chain/actors/builtin/init/v2.go +++ b/chain/actors/builtin/init/v2.go @@ -1,15 +1,21 @@ package init import ( + "crypto/sha256" + "fmt" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -103,10 +109,38 @@ func (s *state2) SetAddressMap(mcid cid.Cid) error { return nil } +func (s *state2) GetState() interface{} { + return &s.State +} + func (s *state2) AddressMap() (adt.Map, error) { return adt2.AsMap(s.store, s.State.AddressMap) } -func (s *state2) GetState() interface{} { - return &s.State +func (s *state2) AddressMapBitWidth() int { + return 5 +} + +func (s *state2) AddressMapHashFunction() func(input []byte) []byte { + return func(input []byte) []byte { + res := sha256.Sum256(input) + return res[:] + } +} + +func (s *state2) ActorKey() string { + return manifest.InitKey +} + +func (s *state2) ActorVersion() actorstypes.Version { + return actorstypes.Version2 +} + +func (s *state2) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code } diff --git a/chain/actors/builtin/init/v3.go b/chain/actors/builtin/init/v3.go index b2f713b1f..0be11f976 100644 --- a/chain/actors/builtin/init/v3.go +++ b/chain/actors/builtin/init/v3.go @@ -1,16 +1,22 @@ package init import ( + "crypto/sha256" + "fmt" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" init3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/init" adt3 "github.com/filecoin-project/specs-actors/v3/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -104,10 +110,38 @@ func (s *state3) SetAddressMap(mcid cid.Cid) error { return nil } +func (s *state3) GetState() interface{} { + return &s.State +} + func (s *state3) AddressMap() (adt.Map, error) { return adt3.AsMap(s.store, s.State.AddressMap, builtin3.DefaultHamtBitwidth) } -func (s *state3) GetState() interface{} { - return &s.State +func (s *state3) AddressMapBitWidth() int { + return builtin3.DefaultHamtBitwidth +} + +func (s *state3) AddressMapHashFunction() func(input []byte) []byte { + return func(input []byte) []byte { + res := sha256.Sum256(input) + return res[:] + } +} + +func (s *state3) ActorKey() string { + return manifest.InitKey +} + +func (s *state3) ActorVersion() actorstypes.Version { + return actorstypes.Version3 +} + +func (s *state3) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code } diff --git a/chain/actors/builtin/init/v4.go b/chain/actors/builtin/init/v4.go index 9de02816f..5ca6bc1c8 100644 --- a/chain/actors/builtin/init/v4.go +++ b/chain/actors/builtin/init/v4.go @@ -1,16 +1,22 @@ package init import ( + "crypto/sha256" + "fmt" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" init4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/init" adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -104,10 +110,38 @@ func (s *state4) SetAddressMap(mcid cid.Cid) error { return nil } +func (s *state4) GetState() interface{} { + return &s.State +} + func (s *state4) AddressMap() (adt.Map, error) { return adt4.AsMap(s.store, s.State.AddressMap, builtin4.DefaultHamtBitwidth) } -func (s *state4) GetState() interface{} { - return &s.State +func (s *state4) AddressMapBitWidth() int { + return builtin4.DefaultHamtBitwidth +} + +func (s *state4) AddressMapHashFunction() func(input []byte) []byte { + return func(input []byte) []byte { + res := sha256.Sum256(input) + return res[:] + } +} + +func (s *state4) ActorKey() string { + return manifest.InitKey +} + +func (s *state4) ActorVersion() actorstypes.Version { + return actorstypes.Version4 +} + +func (s *state4) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code } diff --git a/chain/actors/builtin/init/v5.go b/chain/actors/builtin/init/v5.go index f9c59f83a..f6450789d 100644 --- a/chain/actors/builtin/init/v5.go +++ b/chain/actors/builtin/init/v5.go @@ -1,16 +1,22 @@ package init import ( + "crypto/sha256" + "fmt" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" init5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/init" adt5 "github.com/filecoin-project/specs-actors/v5/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -104,10 +110,38 @@ func (s *state5) SetAddressMap(mcid cid.Cid) error { return nil } +func (s *state5) GetState() interface{} { + return &s.State +} + func (s *state5) AddressMap() (adt.Map, error) { return adt5.AsMap(s.store, s.State.AddressMap, builtin5.DefaultHamtBitwidth) } -func (s *state5) GetState() interface{} { - return &s.State +func (s *state5) AddressMapBitWidth() int { + return builtin5.DefaultHamtBitwidth +} + +func (s *state5) AddressMapHashFunction() func(input []byte) []byte { + return func(input []byte) []byte { + res := sha256.Sum256(input) + return res[:] + } +} + +func (s *state5) ActorKey() string { + return manifest.InitKey +} + +func (s *state5) ActorVersion() actorstypes.Version { + return actorstypes.Version5 +} + +func (s *state5) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code } diff --git a/chain/actors/builtin/init/v6.go b/chain/actors/builtin/init/v6.go index 494b6aaa0..4d2267aa1 100644 --- a/chain/actors/builtin/init/v6.go +++ b/chain/actors/builtin/init/v6.go @@ -1,16 +1,22 @@ package init import ( + "crypto/sha256" + "fmt" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" init6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/init" adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -104,10 +110,38 @@ func (s *state6) SetAddressMap(mcid cid.Cid) error { return nil } +func (s *state6) GetState() interface{} { + return &s.State +} + func (s *state6) AddressMap() (adt.Map, error) { return adt6.AsMap(s.store, s.State.AddressMap, builtin6.DefaultHamtBitwidth) } -func (s *state6) GetState() interface{} { - return &s.State +func (s *state6) AddressMapBitWidth() int { + return builtin6.DefaultHamtBitwidth +} + +func (s *state6) AddressMapHashFunction() func(input []byte) []byte { + return func(input []byte) []byte { + res := sha256.Sum256(input) + return res[:] + } +} + +func (s *state6) ActorKey() string { + return manifest.InitKey +} + +func (s *state6) ActorVersion() actorstypes.Version { + return actorstypes.Version6 +} + +func (s *state6) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code } diff --git a/chain/actors/builtin/init/v7.go b/chain/actors/builtin/init/v7.go index bc378a141..052faf985 100644 --- a/chain/actors/builtin/init/v7.go +++ b/chain/actors/builtin/init/v7.go @@ -1,16 +1,22 @@ package init import ( + "crypto/sha256" + "fmt" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" init7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/init" adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -104,10 +110,38 @@ func (s *state7) SetAddressMap(mcid cid.Cid) error { return nil } +func (s *state7) GetState() interface{} { + return &s.State +} + func (s *state7) AddressMap() (adt.Map, error) { return adt7.AsMap(s.store, s.State.AddressMap, builtin7.DefaultHamtBitwidth) } -func (s *state7) GetState() interface{} { - return &s.State +func (s *state7) AddressMapBitWidth() int { + return builtin7.DefaultHamtBitwidth +} + +func (s *state7) AddressMapHashFunction() func(input []byte) []byte { + return func(input []byte) []byte { + res := sha256.Sum256(input) + return res[:] + } +} + +func (s *state7) ActorKey() string { + return manifest.InitKey +} + +func (s *state7) ActorVersion() actorstypes.Version { + return actorstypes.Version7 +} + +func (s *state7) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code } diff --git a/chain/actors/builtin/init/v8.go b/chain/actors/builtin/init/v8.go index 63b058e57..c7c7860d3 100644 --- a/chain/actors/builtin/init/v8.go +++ b/chain/actors/builtin/init/v8.go @@ -1,16 +1,22 @@ package init import ( + "crypto/sha256" + "fmt" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" builtin8 "github.com/filecoin-project/go-state-types/builtin" init8 "github.com/filecoin-project/go-state-types/builtin/v8/init" adt8 "github.com/filecoin-project/go-state-types/builtin/v8/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -104,10 +110,38 @@ func (s *state8) SetAddressMap(mcid cid.Cid) error { return nil } +func (s *state8) GetState() interface{} { + return &s.State +} + func (s *state8) AddressMap() (adt.Map, error) { return adt8.AsMap(s.store, s.State.AddressMap, builtin8.DefaultHamtBitwidth) } -func (s *state8) GetState() interface{} { - return &s.State +func (s *state8) AddressMapBitWidth() int { + return builtin8.DefaultHamtBitwidth +} + +func (s *state8) AddressMapHashFunction() func(input []byte) []byte { + return func(input []byte) []byte { + res := sha256.Sum256(input) + return res[:] + } +} + +func (s *state8) ActorKey() string { + return manifest.InitKey +} + +func (s *state8) ActorVersion() actorstypes.Version { + return actorstypes.Version8 +} + +func (s *state8) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code } diff --git a/chain/actors/builtin/init/v9.go b/chain/actors/builtin/init/v9.go index 6153b4f73..a221a4a7c 100644 --- a/chain/actors/builtin/init/v9.go +++ b/chain/actors/builtin/init/v9.go @@ -1,16 +1,22 @@ package init import ( + "crypto/sha256" + "fmt" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" builtin9 "github.com/filecoin-project/go-state-types/builtin" init9 "github.com/filecoin-project/go-state-types/builtin/v9/init" adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -104,10 +110,38 @@ func (s *state9) SetAddressMap(mcid cid.Cid) error { return nil } +func (s *state9) GetState() interface{} { + return &s.State +} + func (s *state9) AddressMap() (adt.Map, error) { return adt9.AsMap(s.store, s.State.AddressMap, builtin9.DefaultHamtBitwidth) } -func (s *state9) GetState() interface{} { - return &s.State +func (s *state9) AddressMapBitWidth() int { + return builtin9.DefaultHamtBitwidth +} + +func (s *state9) AddressMapHashFunction() func(input []byte) []byte { + return func(input []byte) []byte { + res := sha256.Sum256(input) + return res[:] + } +} + +func (s *state9) ActorKey() string { + return manifest.InitKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code } diff --git a/chain/actors/builtin/market/actor.go.template b/chain/actors/builtin/market/actor.go.template index fa0622ff0..a84c04ab9 100644 --- a/chain/actors/builtin/market/actor.go.template +++ b/chain/actors/builtin/market/actor.go.template @@ -1,6 +1,7 @@ package market import ( + "github.com/ipfs/go-cid" actorstypes "github.com/filecoin-project/go-state-types/actors" "unicode/utf8" @@ -12,6 +13,7 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/cbor" cbg "github.com/whyrusleeping/cbor-gen" + "github.com/filecoin-project/go-state-types/manifest" markettypes "github.com/filecoin-project/go-state-types/builtin/v9/market" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" @@ -35,7 +37,7 @@ var ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.MarketKey { + if name != manifest.MarketKey { return nil, xerrors.Errorf("actor code is not market: %s", name) } @@ -73,6 +75,11 @@ func MakeState(store adt.Store, av actorstypes.Version) (State, error) { type State interface { cbor.Marshaler + + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + BalancesChanged(State) (bool, error) EscrowTable() (BalanceTable, error) LockedTable() (BalanceTable, error) @@ -200,3 +207,10 @@ func labelFromGoString(s string) (markettypes.DealLabel, error) { return markettypes.NewLabelFromBytes([]byte(s)) } } + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } +} diff --git a/chain/actors/builtin/market/market.go b/chain/actors/builtin/market/market.go index 0e095d282..fc057549d 100644 --- a/chain/actors/builtin/market/market.go +++ b/chain/actors/builtin/market/market.go @@ -3,6 +3,7 @@ package market import ( "unicode/utf8" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" @@ -14,6 +15,7 @@ import ( markettypes "github.com/filecoin-project/go-state-types/builtin/v9/market" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/go-state-types/network" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" @@ -35,7 +37,7 @@ var ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.MarketKey { + if name != manifest.MarketKey { return nil, xerrors.Errorf("actor code is not market: %s", name) } @@ -47,6 +49,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -108,12 +113,20 @@ func MakeState(store adt.Store, av actorstypes.Version) (State, error) { case actorstypes.Version9: return make9(store) + case actorstypes.Version10: + return make10(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } type State interface { cbor.Marshaler + + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + BalancesChanged(State) (bool, error) EscrowTable() (BalanceTable, error) LockedTable() (BalanceTable, error) @@ -192,6 +205,9 @@ func DecodePublishStorageDealsReturn(b []byte, nv network.Version) (PublishStora case actorstypes.Version9: return decodePublishStorageDealsReturn9(b) + case actorstypes.Version10: + return decodePublishStorageDealsReturn10(b) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -264,3 +280,18 @@ func labelFromGoString(s string) (markettypes.DealLabel, error) { return markettypes.NewLabelFromBytes([]byte(s)) } } + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state0{}).Code(), + (&state2{}).Code(), + (&state3{}).Code(), + (&state4{}).Code(), + (&state5{}).Code(), + (&state6{}).Code(), + (&state7{}).Code(), + (&state8{}).Code(), + (&state9{}).Code(), + (&state10{}).Code(), + } +} diff --git a/chain/actors/builtin/market/state.go.template b/chain/actors/builtin/market/state.go.template index 50abdeb6b..bbaa5c775 100644 --- a/chain/actors/builtin/market/state.go.template +++ b/chain/actors/builtin/market/state.go.template @@ -1,6 +1,7 @@ package market import ( + "fmt" "bytes" "github.com/filecoin-project/go-address" @@ -14,9 +15,12 @@ import ( {{end}} + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" {{if (le .v 7)}} market{{.v}} "github.com/filecoin-project/specs-actors{{.import}}actors/builtin/market" @@ -205,16 +209,17 @@ func (s *dealStates{{.v}}) array() adt.Array { } func fromV{{.v}}DealState(v{{.v}} market{{.v}}.DealState) DealState { - {{if (le .v 8)}} - return DealState{ + ret := DealState{ SectorStartEpoch: v{{.v}}.SectorStartEpoch, LastUpdatedEpoch: v{{.v}}.LastUpdatedEpoch, SlashEpoch: v{{.v}}.SlashEpoch, VerifiedClaim: 0, } - {{else}} - return (DealState)(v{{.v}}) + {{if (ge .v 9)}} + ret.VerifiedClaim = verifregtypes.AllocationId(v{{.v}}.VerifiedClaim) {{end}} + + return ret } type dealProposals{{.v}} struct { @@ -370,7 +375,7 @@ func (s *state{{.v}}) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifreg {{if (le .v 8)}} return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") {{else}} - allocations, err := adt9.AsMap(s.store, s.PendingDealAllocationIds, builtin.DefaultHamtBitwidth) + allocations, err := adt{{.v}}.AsMap(s.store, s.PendingDealAllocationIds, builtin.DefaultHamtBitwidth) if err != nil { return verifregtypes.NoAllocationID, xerrors.Errorf("failed to load allocation id for %d: %w", dealId, err) } @@ -387,3 +392,21 @@ func (s *state{{.v}}) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifreg return verifregtypes.AllocationId(allocationId), nil {{end}} } + + +func (s *state{{.v}}) ActorKey() string { + return manifest.MarketKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/market/v0.go b/chain/actors/builtin/market/v0.go index aa68049bb..c0a628b47 100644 --- a/chain/actors/builtin/market/v0.go +++ b/chain/actors/builtin/market/v0.go @@ -2,6 +2,7 @@ package market import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -9,10 +10,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" ) @@ -184,14 +188,14 @@ func (s *dealStates0) array() adt.Array { } func fromV0DealState(v0 market0.DealState) DealState { - - return DealState{ + ret := DealState{ SectorStartEpoch: v0.SectorStartEpoch, LastUpdatedEpoch: v0.LastUpdatedEpoch, SlashEpoch: v0.SlashEpoch, VerifiedClaim: 0, } + return ret } type dealProposals0 struct { @@ -307,3 +311,20 @@ func (s *state0) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } + +func (s *state0) ActorKey() string { + return manifest.MarketKey +} + +func (s *state0) ActorVersion() actorstypes.Version { + return actorstypes.Version0 +} + +func (s *state0) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/market/v10.go b/chain/actors/builtin/market/v10.go new file mode 100644 index 000000000..aaa0ee0f1 --- /dev/null +++ b/chain/actors/builtin/market/v10.go @@ -0,0 +1,377 @@ +package market + +import ( + "bytes" + "fmt" + + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" + rlepluslazy "github.com/filecoin-project/go-bitfield/rle" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/builtin" + market10 "github.com/filecoin-project/go-state-types/builtin/v10/market" + adt10 "github.com/filecoin-project/go-state-types/builtin/v10/util/adt" + markettypes "github.com/filecoin-project/go-state-types/builtin/v9/market" + verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store) (State, error) { + out := state10{store: store} + + s, err := market10.ConstructState(store) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state10 struct { + market10.State + store adt.Store +} + +func (s *state10) TotalLocked() (abi.TokenAmount, error) { + fml := types.BigAdd(s.TotalClientLockedCollateral, s.TotalProviderLockedCollateral) + fml = types.BigAdd(fml, s.TotalClientStorageFee) + return fml, nil +} + +func (s *state10) BalancesChanged(otherState State) (bool, error) { + otherState10, ok := otherState.(*state10) + if !ok { + // there's no way to compare different versions of the state, so let's + // just say that means the state of balances has changed + return true, nil + } + return !s.State.EscrowTable.Equals(otherState10.State.EscrowTable) || !s.State.LockedTable.Equals(otherState10.State.LockedTable), nil +} + +func (s *state10) StatesChanged(otherState State) (bool, error) { + otherState10, ok := otherState.(*state10) + if !ok { + // there's no way to compare different versions of the state, so let's + // just say that means the state of balances has changed + return true, nil + } + return !s.State.States.Equals(otherState10.State.States), nil +} + +func (s *state10) States() (DealStates, error) { + stateArray, err := adt10.AsArray(s.store, s.State.States, market10.StatesAmtBitwidth) + if err != nil { + return nil, err + } + return &dealStates10{stateArray}, nil +} + +func (s *state10) ProposalsChanged(otherState State) (bool, error) { + otherState10, ok := otherState.(*state10) + if !ok { + // there's no way to compare different versions of the state, so let's + // just say that means the state of balances has changed + return true, nil + } + return !s.State.Proposals.Equals(otherState10.State.Proposals), nil +} + +func (s *state10) Proposals() (DealProposals, error) { + proposalArray, err := adt10.AsArray(s.store, s.State.Proposals, market10.ProposalsAmtBitwidth) + if err != nil { + return nil, err + } + return &dealProposals10{proposalArray}, nil +} + +func (s *state10) EscrowTable() (BalanceTable, error) { + bt, err := adt10.AsBalanceTable(s.store, s.State.EscrowTable) + if err != nil { + return nil, err + } + return &balanceTable10{bt}, nil +} + +func (s *state10) LockedTable() (BalanceTable, error) { + bt, err := adt10.AsBalanceTable(s.store, s.State.LockedTable) + if err != nil { + return nil, err + } + return &balanceTable10{bt}, nil +} + +func (s *state10) VerifyDealsForActivation( + minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch, +) (weight, verifiedWeight abi.DealWeight, err error) { + w, vw, _, err := market10.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch) + return w, vw, err +} + +func (s *state10) NextID() (abi.DealID, error) { + return s.State.NextID, nil +} + +type balanceTable10 struct { + *adt10.BalanceTable +} + +func (bt *balanceTable10) ForEach(cb func(address.Address, abi.TokenAmount) error) error { + asMap := (*adt10.Map)(bt.BalanceTable) + var ta abi.TokenAmount + return asMap.ForEach(&ta, func(key string) error { + a, err := address.NewFromBytes([]byte(key)) + if err != nil { + return err + } + return cb(a, ta) + }) +} + +type dealStates10 struct { + adt.Array +} + +func (s *dealStates10) Get(dealID abi.DealID) (*DealState, bool, error) { + var deal10 market10.DealState + found, err := s.Array.Get(uint64(dealID), &deal10) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + deal := fromV10DealState(deal10) + return &deal, true, nil +} + +func (s *dealStates10) ForEach(cb func(dealID abi.DealID, ds DealState) error) error { + var ds10 market10.DealState + return s.Array.ForEach(&ds10, func(idx int64) error { + return cb(abi.DealID(idx), fromV10DealState(ds10)) + }) +} + +func (s *dealStates10) decode(val *cbg.Deferred) (*DealState, error) { + var ds10 market10.DealState + if err := ds10.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + ds := fromV10DealState(ds10) + return &ds, nil +} + +func (s *dealStates10) array() adt.Array { + return s.Array +} + +func fromV10DealState(v10 market10.DealState) DealState { + ret := DealState{ + SectorStartEpoch: v10.SectorStartEpoch, + LastUpdatedEpoch: v10.LastUpdatedEpoch, + SlashEpoch: v10.SlashEpoch, + VerifiedClaim: 0, + } + + ret.VerifiedClaim = verifregtypes.AllocationId(v10.VerifiedClaim) + + return ret +} + +type dealProposals10 struct { + adt.Array +} + +func (s *dealProposals10) Get(dealID abi.DealID) (*DealProposal, bool, error) { + var proposal10 market10.DealProposal + found, err := s.Array.Get(uint64(dealID), &proposal10) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + + proposal, err := fromV10DealProposal(proposal10) + if err != nil { + return nil, true, xerrors.Errorf("decoding proposal: %w", err) + } + + return &proposal, true, nil +} + +func (s *dealProposals10) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error { + var dp10 market10.DealProposal + return s.Array.ForEach(&dp10, func(idx int64) error { + dp, err := fromV10DealProposal(dp10) + if err != nil { + return xerrors.Errorf("decoding proposal: %w", err) + } + + return cb(abi.DealID(idx), dp) + }) +} + +func (s *dealProposals10) decode(val *cbg.Deferred) (*DealProposal, error) { + var dp10 market10.DealProposal + if err := dp10.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + + dp, err := fromV10DealProposal(dp10) + if err != nil { + return nil, err + } + + return &dp, nil +} + +func (s *dealProposals10) array() adt.Array { + return s.Array +} + +func fromV10DealProposal(v10 market10.DealProposal) (DealProposal, error) { + + label, err := fromV10Label(v10.Label) + + if err != nil { + return DealProposal{}, xerrors.Errorf("error setting deal label: %w", err) + } + + return DealProposal{ + PieceCID: v10.PieceCID, + PieceSize: v10.PieceSize, + VerifiedDeal: v10.VerifiedDeal, + Client: v10.Client, + Provider: v10.Provider, + + Label: label, + + StartEpoch: v10.StartEpoch, + EndEpoch: v10.EndEpoch, + StoragePricePerEpoch: v10.StoragePricePerEpoch, + + ProviderCollateral: v10.ProviderCollateral, + ClientCollateral: v10.ClientCollateral, + }, nil +} + +func fromV10Label(v10 market10.DealLabel) (DealLabel, error) { + if v10.IsString() { + str, err := v10.ToString() + if err != nil { + return markettypes.EmptyDealLabel, xerrors.Errorf("failed to convert string label to string: %w", err) + } + return markettypes.NewLabelFromString(str) + } + + bs, err := v10.ToBytes() + if err != nil { + return markettypes.EmptyDealLabel, xerrors.Errorf("failed to convert bytes label to bytes: %w", err) + } + return markettypes.NewLabelFromBytes(bs) +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +var _ PublishStorageDealsReturn = (*publishStorageDealsReturn10)(nil) + +func decodePublishStorageDealsReturn10(b []byte) (PublishStorageDealsReturn, error) { + var retval market10.PublishStorageDealsReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil { + return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err) + } + + return &publishStorageDealsReturn10{retval}, nil +} + +type publishStorageDealsReturn10 struct { + market10.PublishStorageDealsReturn +} + +func (r *publishStorageDealsReturn10) IsDealValid(index uint64) (bool, int, error) { + + set, err := r.ValidDeals.IsSet(index) + if err != nil || !set { + return false, -1, err + } + maskBf, err := bitfield.NewFromIter(&rlepluslazy.RunSliceIterator{ + Runs: []rlepluslazy.Run{rlepluslazy.Run{Val: true, Len: index}}}) + if err != nil { + return false, -1, err + } + before, err := bitfield.IntersectBitField(maskBf, r.ValidDeals) + if err != nil { + return false, -1, err + } + outIdx, err := before.Count() + if err != nil { + return false, -1, err + } + return set, int(outIdx), nil + +} + +func (r *publishStorageDealsReturn10) DealIDs() ([]abi.DealID, error) { + return r.IDs, nil +} + +func (s *state10) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes.AllocationId, error) { + + allocations, err := adt10.AsMap(s.store, s.PendingDealAllocationIds, builtin.DefaultHamtBitwidth) + if err != nil { + return verifregtypes.NoAllocationID, xerrors.Errorf("failed to load allocation id for %d: %w", dealId, err) + } + + var allocationId cbg.CborInt + found, err := allocations.Get(abi.UIntKey(uint64(dealId)), &allocationId) + if err != nil { + return verifregtypes.NoAllocationID, xerrors.Errorf("failed to load allocation id for %d: %w", dealId, err) + } + if !found { + return verifregtypes.NoAllocationID, nil + } + + return verifregtypes.AllocationId(allocationId), nil + +} + +func (s *state10) ActorKey() string { + return manifest.MarketKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/market/v2.go b/chain/actors/builtin/market/v2.go index 777a17cd0..89ffdde8f 100644 --- a/chain/actors/builtin/market/v2.go +++ b/chain/actors/builtin/market/v2.go @@ -2,6 +2,7 @@ package market import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -9,10 +10,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" ) @@ -184,14 +188,14 @@ func (s *dealStates2) array() adt.Array { } func fromV2DealState(v2 market2.DealState) DealState { - - return DealState{ + ret := DealState{ SectorStartEpoch: v2.SectorStartEpoch, LastUpdatedEpoch: v2.LastUpdatedEpoch, SlashEpoch: v2.SlashEpoch, VerifiedClaim: 0, } + return ret } type dealProposals2 struct { @@ -307,3 +311,20 @@ func (s *state2) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } + +func (s *state2) ActorKey() string { + return manifest.MarketKey +} + +func (s *state2) ActorVersion() actorstypes.Version { + return actorstypes.Version2 +} + +func (s *state2) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/market/v3.go b/chain/actors/builtin/market/v3.go index 5ca09fdfb..f4d073ed8 100644 --- a/chain/actors/builtin/market/v3.go +++ b/chain/actors/builtin/market/v3.go @@ -2,6 +2,7 @@ package market import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -9,10 +10,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" market3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/market" adt3 "github.com/filecoin-project/specs-actors/v3/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" ) @@ -179,14 +183,14 @@ func (s *dealStates3) array() adt.Array { } func fromV3DealState(v3 market3.DealState) DealState { - - return DealState{ + ret := DealState{ SectorStartEpoch: v3.SectorStartEpoch, LastUpdatedEpoch: v3.LastUpdatedEpoch, SlashEpoch: v3.SlashEpoch, VerifiedClaim: 0, } + return ret } type dealProposals3 struct { @@ -302,3 +306,20 @@ func (s *state3) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } + +func (s *state3) ActorKey() string { + return manifest.MarketKey +} + +func (s *state3) ActorVersion() actorstypes.Version { + return actorstypes.Version3 +} + +func (s *state3) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/market/v4.go b/chain/actors/builtin/market/v4.go index 23422ec31..422a30cbb 100644 --- a/chain/actors/builtin/market/v4.go +++ b/chain/actors/builtin/market/v4.go @@ -2,6 +2,7 @@ package market import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -9,10 +10,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" market4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/market" adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" ) @@ -179,14 +183,14 @@ func (s *dealStates4) array() adt.Array { } func fromV4DealState(v4 market4.DealState) DealState { - - return DealState{ + ret := DealState{ SectorStartEpoch: v4.SectorStartEpoch, LastUpdatedEpoch: v4.LastUpdatedEpoch, SlashEpoch: v4.SlashEpoch, VerifiedClaim: 0, } + return ret } type dealProposals4 struct { @@ -302,3 +306,20 @@ func (s *state4) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } + +func (s *state4) ActorKey() string { + return manifest.MarketKey +} + +func (s *state4) ActorVersion() actorstypes.Version { + return actorstypes.Version4 +} + +func (s *state4) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/market/v5.go b/chain/actors/builtin/market/v5.go index 8e8833c37..b30decb03 100644 --- a/chain/actors/builtin/market/v5.go +++ b/chain/actors/builtin/market/v5.go @@ -2,6 +2,7 @@ package market import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -9,10 +10,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" market5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/market" adt5 "github.com/filecoin-project/specs-actors/v5/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" ) @@ -179,14 +183,14 @@ func (s *dealStates5) array() adt.Array { } func fromV5DealState(v5 market5.DealState) DealState { - - return DealState{ + ret := DealState{ SectorStartEpoch: v5.SectorStartEpoch, LastUpdatedEpoch: v5.LastUpdatedEpoch, SlashEpoch: v5.SlashEpoch, VerifiedClaim: 0, } + return ret } type dealProposals5 struct { @@ -302,3 +306,20 @@ func (s *state5) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } + +func (s *state5) ActorKey() string { + return manifest.MarketKey +} + +func (s *state5) ActorVersion() actorstypes.Version { + return actorstypes.Version5 +} + +func (s *state5) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/market/v6.go b/chain/actors/builtin/market/v6.go index d86f73108..377b278ae 100644 --- a/chain/actors/builtin/market/v6.go +++ b/chain/actors/builtin/market/v6.go @@ -2,6 +2,7 @@ package market import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,10 +12,13 @@ import ( "github.com/filecoin-project/go-bitfield" rlepluslazy "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" market6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/market" adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" ) @@ -181,14 +185,14 @@ func (s *dealStates6) array() adt.Array { } func fromV6DealState(v6 market6.DealState) DealState { - - return DealState{ + ret := DealState{ SectorStartEpoch: v6.SectorStartEpoch, LastUpdatedEpoch: v6.LastUpdatedEpoch, SlashEpoch: v6.SlashEpoch, VerifiedClaim: 0, } + return ret } type dealProposals6 struct { @@ -320,3 +324,20 @@ func (s *state6) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } + +func (s *state6) ActorKey() string { + return manifest.MarketKey +} + +func (s *state6) ActorVersion() actorstypes.Version { + return actorstypes.Version6 +} + +func (s *state6) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/market/v7.go b/chain/actors/builtin/market/v7.go index 5f6547e3f..cd4607cbe 100644 --- a/chain/actors/builtin/market/v7.go +++ b/chain/actors/builtin/market/v7.go @@ -2,6 +2,7 @@ package market import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,10 +12,13 @@ import ( "github.com/filecoin-project/go-bitfield" rlepluslazy "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" market7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/market" adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" ) @@ -181,14 +185,14 @@ func (s *dealStates7) array() adt.Array { } func fromV7DealState(v7 market7.DealState) DealState { - - return DealState{ + ret := DealState{ SectorStartEpoch: v7.SectorStartEpoch, LastUpdatedEpoch: v7.LastUpdatedEpoch, SlashEpoch: v7.SlashEpoch, VerifiedClaim: 0, } + return ret } type dealProposals7 struct { @@ -320,3 +324,20 @@ func (s *state7) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } + +func (s *state7) ActorKey() string { + return manifest.MarketKey +} + +func (s *state7) ActorVersion() actorstypes.Version { + return actorstypes.Version7 +} + +func (s *state7) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/market/v8.go b/chain/actors/builtin/market/v8.go index 5f3b690bb..5cce06d3a 100644 --- a/chain/actors/builtin/market/v8.go +++ b/chain/actors/builtin/market/v8.go @@ -2,6 +2,7 @@ package market import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,11 +12,14 @@ import ( "github.com/filecoin-project/go-bitfield" rlepluslazy "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" market8 "github.com/filecoin-project/go-state-types/builtin/v8/market" adt8 "github.com/filecoin-project/go-state-types/builtin/v8/util/adt" markettypes "github.com/filecoin-project/go-state-types/builtin/v9/market" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" ) @@ -182,14 +186,14 @@ func (s *dealStates8) array() adt.Array { } func fromV8DealState(v8 market8.DealState) DealState { - - return DealState{ + ret := DealState{ SectorStartEpoch: v8.SectorStartEpoch, LastUpdatedEpoch: v8.LastUpdatedEpoch, SlashEpoch: v8.SlashEpoch, VerifiedClaim: 0, } + return ret } type dealProposals8 struct { @@ -337,3 +341,20 @@ func (s *state8) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes return verifregtypes.NoAllocationID, xerrors.Errorf("unsupported before actors v9") } + +func (s *state8) ActorKey() string { + return manifest.MarketKey +} + +func (s *state8) ActorVersion() actorstypes.Version { + return actorstypes.Version8 +} + +func (s *state8) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/market/v9.go b/chain/actors/builtin/market/v9.go index 9fed45ae8..095c20850 100644 --- a/chain/actors/builtin/market/v9.go +++ b/chain/actors/builtin/market/v9.go @@ -2,6 +2,7 @@ package market import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,12 +12,15 @@ import ( "github.com/filecoin-project/go-bitfield" rlepluslazy "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/builtin" market9 "github.com/filecoin-project/go-state-types/builtin/v9/market" markettypes "github.com/filecoin-project/go-state-types/builtin/v9/market" adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" ) @@ -183,9 +187,16 @@ func (s *dealStates9) array() adt.Array { } func fromV9DealState(v9 market9.DealState) DealState { + ret := DealState{ + SectorStartEpoch: v9.SectorStartEpoch, + LastUpdatedEpoch: v9.LastUpdatedEpoch, + SlashEpoch: v9.SlashEpoch, + VerifiedClaim: 0, + } - return (DealState)(v9) + ret.VerifiedClaim = verifregtypes.AllocationId(v9.VerifiedClaim) + return ret } type dealProposals9 struct { @@ -347,3 +358,20 @@ func (s *state9) GetAllocationIdForPendingDeal(dealId abi.DealID) (verifregtypes return verifregtypes.AllocationId(allocationId), nil } + +func (s *state9) ActorKey() string { + return manifest.MarketKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/miner/actor.go.template b/chain/actors/builtin/miner/actor.go.template index 751ab698f..abbcbfeb6 100644 --- a/chain/actors/builtin/miner/actor.go.template +++ b/chain/actors/builtin/miner/actor.go.template @@ -1,6 +1,7 @@ package miner import ( + "github.com/ipfs/go-cid" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/network" @@ -16,7 +17,8 @@ import ( "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" - miner{{.latestVersion}} "github.com/filecoin-project/go-state-types/builtin{{import .latestVersion}}miner" + minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" + "github.com/filecoin-project/go-state-types/manifest" {{range .versions}} {{if (le . 7)}} @@ -27,7 +29,7 @@ import ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.MinerKey { + if name != manifest.MinerKey { return nil, xerrors.Errorf("actor code is not miner: %s", name) } @@ -66,6 +68,10 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + // Total available balance to spend. AvailableBalance(abi.TokenAmount) (abi.TokenAmount, error) // Funds that will vest by the given epoch. @@ -74,11 +80,12 @@ type State interface { LockedFunds() (LockedFunds, error) FeeDebt() (abi.TokenAmount, error) + // Returns nil, nil if sector is not found GetSector(abi.SectorNumber) (*SectorOnChainInfo, error) FindSector(abi.SectorNumber) (*SectorLocation, error) GetSectorExpiration(abi.SectorNumber) (*SectorExpiration, error) - GetPrecommittedSector(abi.SectorNumber) (*miner{{.latestVersion}}.SectorPreCommitOnChainInfo, error) - ForEachPrecommittedSector(func(miner{{.latestVersion}}.SectorPreCommitOnChainInfo) error) error + GetPrecommittedSector(abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) + ForEachPrecommittedSector(func(SectorPreCommitOnChainInfo) error) error LoadSectors(sectorNos *bitfield.BitField) ([]*SectorOnChainInfo, error) NumLiveSectors() (uint64, error) IsAllocated(abi.SectorNumber) (bool, error) @@ -107,7 +114,7 @@ type State interface { sectors() (adt.Array, error) decodeSectorOnChainInfo(*cbg.Deferred) (SectorOnChainInfo, error) precommits() (adt.Map, error) - decodeSectorPreCommitOnChainInfo(*cbg.Deferred) (miner{{.latestVersion}}.SectorPreCommitOnChainInfo, error) + decodeSectorPreCommitOnChainInfo(*cbg.Deferred) (SectorPreCommitOnChainInfo, error) GetState() interface{} } @@ -145,7 +152,7 @@ type Partition interface { UnprovenSectors() (bitfield.BitField, error) } -type SectorOnChainInfo = miner{{.latestVersion}}.SectorOnChainInfo +type SectorOnChainInfo = minertypes.SectorOnChainInfo func PreferredSealProofTypeFromWindowPoStType(nver network.Version, proof abi.RegisteredPoStProof) (abi.RegisteredSealProof, error) { // We added support for the new proofs in network version 7, and removed support for the old @@ -200,9 +207,12 @@ func WinningPoStProofTypeFromWindowPoStProofType(nver network.Version, proof abi } } -type MinerInfo = miner{{.latestVersion}}.MinerInfo -type WorkerKeyChange = miner{{.latestVersion}}.WorkerKeyChange -type SectorPreCommitOnChainInfo = miner{{.latestVersion}}.SectorPreCommitOnChainInfo +type MinerInfo = minertypes.MinerInfo +type BeneficiaryTerm = minertypes.BeneficiaryTerm +type PendingBeneficiaryChange = minertypes.PendingBeneficiaryChange +type WorkerKeyChange = minertypes.WorkerKeyChange +type SectorPreCommitOnChainInfo = minertypes.SectorPreCommitOnChainInfo +type SectorPreCommitInfo = minertypes.SectorPreCommitInfo type WindowPostVerifyInfo = proof.WindowPoStVerifyInfo type SectorExpiration struct { @@ -230,8 +240,8 @@ type SectorExtensions struct { } type PreCommitChanges struct { - Added []miner{{.latestVersion}}.SectorPreCommitOnChainInfo - Removed []miner{{.latestVersion}}.SectorPreCommitOnChainInfo + Added []SectorPreCommitOnChainInfo + Removed []SectorPreCommitOnChainInfo } type LockedFunds struct { @@ -243,3 +253,10 @@ type LockedFunds struct { func (lf LockedFunds) TotalLockedFunds() abi.TokenAmount { return big.Add(lf.VestingFunds, big.Add(lf.InitialPledgeRequirement, lf.PreCommitDeposits)) } + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } +} diff --git a/chain/actors/builtin/miner/miner.go b/chain/actors/builtin/miner/miner.go index c3db4cb0e..1931af3d3 100644 --- a/chain/actors/builtin/miner/miner.go +++ b/chain/actors/builtin/miner/miner.go @@ -1,6 +1,7 @@ package miner import ( + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" @@ -8,9 +9,10 @@ import ( "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" - miner9 "github.com/filecoin-project/go-state-types/builtin/v9/miner" + minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-state-types/proof" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" @@ -28,7 +30,7 @@ import ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.MinerKey { + if name != manifest.MinerKey { return nil, xerrors.Errorf("actor code is not miner: %s", name) } @@ -40,6 +42,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -101,6 +106,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version9: return make9(store) + case actors.Version10: + return make10(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -108,6 +116,10 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + // Total available balance to spend. AvailableBalance(abi.TokenAmount) (abi.TokenAmount, error) // Funds that will vest by the given epoch. @@ -116,11 +128,12 @@ type State interface { LockedFunds() (LockedFunds, error) FeeDebt() (abi.TokenAmount, error) + // Returns nil, nil if sector is not found GetSector(abi.SectorNumber) (*SectorOnChainInfo, error) FindSector(abi.SectorNumber) (*SectorLocation, error) GetSectorExpiration(abi.SectorNumber) (*SectorExpiration, error) - GetPrecommittedSector(abi.SectorNumber) (*miner9.SectorPreCommitOnChainInfo, error) - ForEachPrecommittedSector(func(miner9.SectorPreCommitOnChainInfo) error) error + GetPrecommittedSector(abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) + ForEachPrecommittedSector(func(SectorPreCommitOnChainInfo) error) error LoadSectors(sectorNos *bitfield.BitField) ([]*SectorOnChainInfo, error) NumLiveSectors() (uint64, error) IsAllocated(abi.SectorNumber) (bool, error) @@ -149,7 +162,7 @@ type State interface { sectors() (adt.Array, error) decodeSectorOnChainInfo(*cbg.Deferred) (SectorOnChainInfo, error) precommits() (adt.Map, error) - decodeSectorPreCommitOnChainInfo(*cbg.Deferred) (miner9.SectorPreCommitOnChainInfo, error) + decodeSectorPreCommitOnChainInfo(*cbg.Deferred) (SectorPreCommitOnChainInfo, error) GetState() interface{} } @@ -187,7 +200,7 @@ type Partition interface { UnprovenSectors() (bitfield.BitField, error) } -type SectorOnChainInfo = miner9.SectorOnChainInfo +type SectorOnChainInfo = minertypes.SectorOnChainInfo func PreferredSealProofTypeFromWindowPoStType(nver network.Version, proof abi.RegisteredPoStProof) (abi.RegisteredSealProof, error) { // We added support for the new proofs in network version 7, and removed support for the old @@ -242,9 +255,12 @@ func WinningPoStProofTypeFromWindowPoStProofType(nver network.Version, proof abi } } -type MinerInfo = miner9.MinerInfo -type WorkerKeyChange = miner9.WorkerKeyChange -type SectorPreCommitOnChainInfo = miner9.SectorPreCommitOnChainInfo +type MinerInfo = minertypes.MinerInfo +type BeneficiaryTerm = minertypes.BeneficiaryTerm +type PendingBeneficiaryChange = minertypes.PendingBeneficiaryChange +type WorkerKeyChange = minertypes.WorkerKeyChange +type SectorPreCommitOnChainInfo = minertypes.SectorPreCommitOnChainInfo +type SectorPreCommitInfo = minertypes.SectorPreCommitInfo type WindowPostVerifyInfo = proof.WindowPoStVerifyInfo type SectorExpiration struct { @@ -272,8 +288,8 @@ type SectorExtensions struct { } type PreCommitChanges struct { - Added []miner9.SectorPreCommitOnChainInfo - Removed []miner9.SectorPreCommitOnChainInfo + Added []SectorPreCommitOnChainInfo + Removed []SectorPreCommitOnChainInfo } type LockedFunds struct { @@ -285,3 +301,18 @@ type LockedFunds struct { func (lf LockedFunds) TotalLockedFunds() abi.TokenAmount { return big.Add(lf.VestingFunds, big.Add(lf.InitialPledgeRequirement, lf.PreCommitDeposits)) } + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state0{}).Code(), + (&state2{}).Code(), + (&state3{}).Code(), + (&state4{}).Code(), + (&state5{}).Code(), + (&state6{}).Code(), + (&state7{}).Code(), + (&state8{}).Code(), + (&state9{}).Code(), + (&state10{}).Code(), + } +} diff --git a/chain/actors/builtin/miner/state.go.template b/chain/actors/builtin/miner/state.go.template index 16c9c75e7..b322b2283 100644 --- a/chain/actors/builtin/miner/state.go.template +++ b/chain/actors/builtin/miner/state.go.template @@ -1,6 +1,7 @@ package miner import ( + "fmt" "bytes" "errors" {{if (le .v 1)}} @@ -15,7 +16,9 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/actors/adt" - minertypes "github.com/filecoin-project/go-state-types/builtin/v{{.latestVersion}}/miner" + "github.com/filecoin-project/lotus/chain/actors" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" {{if (le .v 7)}} {{if (ge .v 3)}} @@ -98,6 +101,7 @@ func (s *state{{.v}}) PreCommitDeposits() (abi.TokenAmount, error) { return s.State.PreCommitDeposits, nil } +// Returns nil, nil if sector is not found func (s *state{{.v}}) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { info, ok, err := s.State.GetSector(s.store, num) if !ok || err != nil { @@ -215,7 +219,7 @@ func (s *state{{.v}}) GetSectorExpiration(num abi.SectorNumber) (*SectorExpirati return &out, nil } -func (s *state{{.v}}) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state{{.v}}) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { info, ok, err := s.State.GetPrecommittedSector(s.store, num) if !ok || err != nil { return nil, err @@ -226,7 +230,7 @@ func (s *state{{.v}}) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.S return &ret, nil } -func (s *state{{.v}}) ForEachPrecommittedSector(cb func(minertypes.SectorPreCommitOnChainInfo) error) error { +func (s *state{{.v}}) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { {{if (ge .v 3) -}} precommitted, err := adt{{.v}}.AsMap(s.store, s.State.PreCommittedSectors, builtin{{.v}}.DefaultHamtBitwidth) {{- else -}} @@ -414,9 +418,10 @@ func (s *state{{.v}}) Info() (MinerInfo, error) { WindowPoStPartitionSectors: info.WindowPoStPartitionSectors, ConsensusFaultElapsed: {{if (ge .v 2)}}info.ConsensusFaultElapsed{{else}}-1{{end}}, {{if (ge .v 9)}} - Beneficiary: info.Beneficiary, - BeneficiaryTerm: info.BeneficiaryTerm, - PendingBeneficiaryTerm: info.PendingBeneficiaryTerm,{{end}} + Beneficiary: info.Beneficiary, + BeneficiaryTerm: BeneficiaryTerm(info.BeneficiaryTerm), + PendingBeneficiaryTerm: (*PendingBeneficiaryChange)(info.PendingBeneficiaryTerm), + {{end}} } return mi, nil @@ -448,11 +453,11 @@ func (s *state{{.v}}) precommits() (adt.Map, error) { return adt{{.v}}.AsMap(s.store, s.PreCommittedSectors{{if (ge .v 3)}}, builtin{{.v}}.DefaultHamtBitwidth{{end}}) } -func (s *state{{.v}}) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state{{.v}}) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { var sp miner{{.v}}.SectorPreCommitOnChainInfo err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, err + return SectorPreCommitOnChainInfo{}, err } return fromV{{.v}}SectorPreCommitOnChainInfo(sp), nil @@ -583,9 +588,9 @@ func fromV{{.v}}SectorOnChainInfo(v{{.v}} miner{{.v}}.SectorOnChainInfo) SectorO return info } -func fromV{{.v}}SectorPreCommitOnChainInfo(v{{.v}} miner{{.v}}.SectorPreCommitOnChainInfo) minertypes.SectorPreCommitOnChainInfo { - {{if (le .v 8)}}return minertypes.SectorPreCommitOnChainInfo{ - Info: minertypes.SectorPreCommitInfo{ +func fromV{{.v}}SectorPreCommitOnChainInfo(v{{.v}} miner{{.v}}.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + ret := SectorPreCommitOnChainInfo{ + Info: SectorPreCommitInfo{ SealProof: v{{.v}}.Info.SealProof, SectorNumber: v{{.v}}.Info.SectorNumber, SealedCID: v{{.v}}.Info.SealedCID, @@ -596,9 +601,32 @@ func fromV{{.v}}SectorPreCommitOnChainInfo(v{{.v}} miner{{.v}}.SectorPreCommitOn }, PreCommitDeposit: v{{.v}}.PreCommitDeposit, PreCommitEpoch: v{{.v}}.PreCommitEpoch, - }{{else}}return v{{.v}}{{end}} + } + + {{if (ge .v 9)}} + ret.Info.UnsealedCid = v{{.v}}.Info.UnsealedCid + {{end}} + + return ret } func (s *state{{.v}}) GetState() interface{} { return &s.State } + +func (s *state{{.v}}) ActorKey() string { + return manifest.MinerKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/miner/v0.go b/chain/actors/builtin/miner/v0.go index e815806bd..7d5eaf8e0 100644 --- a/chain/actors/builtin/miner/v0.go +++ b/chain/actors/builtin/miner/v0.go @@ -3,6 +3,7 @@ package miner import ( "bytes" "errors" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,12 +12,14 @@ import ( "github.com/filecoin-project/go-bitfield" rle "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" - minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -88,6 +91,7 @@ func (s *state0) PreCommitDeposits() (abi.TokenAmount, error) { return s.State.PreCommitDeposits, nil } +// Returns nil, nil if sector is not found func (s *state0) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { info, ok, err := s.State.GetSector(s.store, num) if !ok || err != nil { @@ -195,7 +199,7 @@ func (s *state0) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e return &out, nil } -func (s *state0) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state0) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { info, ok, err := s.State.GetPrecommittedSector(s.store, num) if !ok || err != nil { return nil, err @@ -206,7 +210,7 @@ func (s *state0) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.Sector return &ret, nil } -func (s *state0) ForEachPrecommittedSector(cb func(minertypes.SectorPreCommitOnChainInfo) error) error { +func (s *state0) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { precommitted, err := adt0.AsMap(s.store, s.State.PreCommittedSectors) if err != nil { return err @@ -419,11 +423,11 @@ func (s *state0) precommits() (adt.Map, error) { return adt0.AsMap(s.store, s.PreCommittedSectors) } -func (s *state0) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state0) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { var sp miner0.SectorPreCommitOnChainInfo err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, err + return SectorPreCommitOnChainInfo{}, err } return fromV0SectorPreCommitOnChainInfo(sp), nil @@ -509,9 +513,9 @@ func fromV0SectorOnChainInfo(v0 miner0.SectorOnChainInfo) SectorOnChainInfo { return info } -func fromV0SectorPreCommitOnChainInfo(v0 miner0.SectorPreCommitOnChainInfo) minertypes.SectorPreCommitOnChainInfo { - return minertypes.SectorPreCommitOnChainInfo{ - Info: minertypes.SectorPreCommitInfo{ +func fromV0SectorPreCommitOnChainInfo(v0 miner0.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + ret := SectorPreCommitOnChainInfo{ + Info: SectorPreCommitInfo{ SealProof: v0.Info.SealProof, SectorNumber: v0.Info.SectorNumber, SealedCID: v0.Info.SealedCID, @@ -523,8 +527,27 @@ func fromV0SectorPreCommitOnChainInfo(v0 miner0.SectorPreCommitOnChainInfo) mine PreCommitDeposit: v0.PreCommitDeposit, PreCommitEpoch: v0.PreCommitEpoch, } + + return ret } func (s *state0) GetState() interface{} { return &s.State } + +func (s *state0) ActorKey() string { + return manifest.MinerKey +} + +func (s *state0) ActorVersion() actorstypes.Version { + return actorstypes.Version0 +} + +func (s *state0) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/miner/v10.go b/chain/actors/builtin/miner/v10.go new file mode 100644 index 000000000..4d47ba396 --- /dev/null +++ b/chain/actors/builtin/miner/v10.go @@ -0,0 +1,591 @@ +package miner + +import ( + "bytes" + "errors" + "fmt" + + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-bitfield" + rle "github.com/filecoin-project/go-bitfield/rle" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + builtin10 "github.com/filecoin-project/go-state-types/builtin" + miner10 "github.com/filecoin-project/go-state-types/builtin/v10/miner" + adt10 "github.com/filecoin-project/go-state-types/builtin/v10/util/adt" + "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store) (State, error) { + out := state10{store: store} + out.State = miner10.State{} + return &out, nil +} + +type state10 struct { + miner10.State + store adt.Store +} + +type deadline10 struct { + miner10.Deadline + store adt.Store +} + +type partition10 struct { + miner10.Partition + store adt.Store +} + +func (s *state10) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) { + defer func() { + if r := recover(); r != nil { + err = xerrors.Errorf("failed to get available balance: %w", r) + available = abi.NewTokenAmount(0) + } + }() + // this panics if the miner doesnt have enough funds to cover their locked pledge + available, err = s.GetAvailableBalance(bal) + return available, err +} + +func (s *state10) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.CheckVestedFunds(s.store, epoch) +} + +func (s *state10) LockedFunds() (LockedFunds, error) { + return LockedFunds{ + VestingFunds: s.State.LockedFunds, + InitialPledgeRequirement: s.State.InitialPledge, + PreCommitDeposits: s.State.PreCommitDeposits, + }, nil +} + +func (s *state10) FeeDebt() (abi.TokenAmount, error) { + return s.State.FeeDebt, nil +} + +func (s *state10) InitialPledge() (abi.TokenAmount, error) { + return s.State.InitialPledge, nil +} + +func (s *state10) PreCommitDeposits() (abi.TokenAmount, error) { + return s.State.PreCommitDeposits, nil +} + +// Returns nil, nil if sector is not found +func (s *state10) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { + info, ok, err := s.State.GetSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV10SectorOnChainInfo(*info) + return &ret, nil +} + +func (s *state10) FindSector(num abi.SectorNumber) (*SectorLocation, error) { + dlIdx, partIdx, err := s.State.FindSector(s.store, num) + if err != nil { + return nil, err + } + return &SectorLocation{ + Deadline: dlIdx, + Partition: partIdx, + }, nil +} + +func (s *state10) NumLiveSectors() (uint64, error) { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return 0, err + } + var total uint64 + if err := dls.ForEach(s.store, func(dlIdx uint64, dl *miner10.Deadline) error { + total += dl.LiveSectors + return nil + }); err != nil { + return 0, err + } + return total, nil +} + +// GetSectorExpiration returns the effective expiration of the given sector. +// +// If the sector does not expire early, the Early expiration field is 0. +func (s *state10) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, error) { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return nil, err + } + // NOTE: this can be optimized significantly. + // 1. If the sector is non-faulty, it will expire on-time (can be + // learned from the sector info). + // 2. If it's faulty, it will expire early within the first 42 entries + // of the expiration queue. + + stopErr := errors.New("stop") + out := SectorExpiration{} + err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner10.Deadline) error { + partitions, err := dl.PartitionsArray(s.store) + if err != nil { + return err + } + quant := s.State.QuantSpecForDeadline(dlIdx) + var part miner10.Partition + return partitions.ForEach(&part, func(partIdx int64) error { + if found, err := part.Sectors.IsSet(uint64(num)); err != nil { + return err + } else if !found { + return nil + } + if found, err := part.Terminated.IsSet(uint64(num)); err != nil { + return err + } else if found { + // already terminated + return stopErr + } + + q, err := miner10.LoadExpirationQueue(s.store, part.ExpirationsEpochs, quant, miner10.PartitionExpirationAmtBitwidth) + if err != nil { + return err + } + var exp miner10.ExpirationSet + return q.ForEach(&exp, func(epoch int64) error { + if early, err := exp.EarlySectors.IsSet(uint64(num)); err != nil { + return err + } else if early { + out.Early = abi.ChainEpoch(epoch) + return nil + } + if onTime, err := exp.OnTimeSectors.IsSet(uint64(num)); err != nil { + return err + } else if onTime { + out.OnTime = abi.ChainEpoch(epoch) + return stopErr + } + return nil + }) + }) + }) + if err == stopErr { + err = nil + } + if err != nil { + return nil, err + } + if out.Early == 0 && out.OnTime == 0 { + return nil, xerrors.Errorf("failed to find sector %d", num) + } + return &out, nil +} + +func (s *state10) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { + info, ok, err := s.State.GetPrecommittedSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV10SectorPreCommitOnChainInfo(*info) + + return &ret, nil +} + +func (s *state10) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { + precommitted, err := adt10.AsMap(s.store, s.State.PreCommittedSectors, builtin10.DefaultHamtBitwidth) + if err != nil { + return err + } + + var info miner10.SectorPreCommitOnChainInfo + if err := precommitted.ForEach(&info, func(_ string) error { + return cb(fromV10SectorPreCommitOnChainInfo(info)) + }); err != nil { + return err + } + + return nil +} + +func (s *state10) LoadSectors(snos *bitfield.BitField) ([]*SectorOnChainInfo, error) { + sectors, err := miner10.LoadSectors(s.store, s.State.Sectors) + if err != nil { + return nil, err + } + + // If no sector numbers are specified, load all. + if snos == nil { + infos := make([]*SectorOnChainInfo, 0, sectors.Length()) + var info10 miner10.SectorOnChainInfo + if err := sectors.ForEach(&info10, func(_ int64) error { + info := fromV10SectorOnChainInfo(info10) + infos = append(infos, &info) + return nil + }); err != nil { + return nil, err + } + return infos, nil + } + + // Otherwise, load selected. + infos10, err := sectors.Load(*snos) + if err != nil { + return nil, err + } + infos := make([]*SectorOnChainInfo, len(infos10)) + for i, info10 := range infos10 { + info := fromV10SectorOnChainInfo(*info10) + infos[i] = &info + } + return infos, nil +} + +func (s *state10) loadAllocatedSectorNumbers() (bitfield.BitField, error) { + var allocatedSectors bitfield.BitField + err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors) + return allocatedSectors, err +} + +func (s *state10) IsAllocated(num abi.SectorNumber) (bool, error) { + allocatedSectors, err := s.loadAllocatedSectorNumbers() + if err != nil { + return false, err + } + + return allocatedSectors.IsSet(uint64(num)) +} + +func (s *state10) GetProvingPeriodStart() (abi.ChainEpoch, error) { + return s.State.ProvingPeriodStart, nil +} + +func (s *state10) UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, error) { + allocatedSectors, err := s.loadAllocatedSectorNumbers() + if err != nil { + return nil, err + } + + allocatedRuns, err := allocatedSectors.RunIterator() + if err != nil { + return nil, err + } + + unallocatedRuns, err := rle.Subtract( + &rle.RunSliceIterator{Runs: []rle.Run{{Val: true, Len: abi.MaxSectorNumber}}}, + allocatedRuns, + ) + if err != nil { + return nil, err + } + + iter, err := rle.BitsFromRuns(unallocatedRuns) + if err != nil { + return nil, err + } + + sectors := make([]abi.SectorNumber, 0, count) + for iter.HasNext() && len(sectors) < count { + nextNo, err := iter.Next() + if err != nil { + return nil, err + } + sectors = append(sectors, abi.SectorNumber(nextNo)) + } + + return sectors, nil +} + +func (s *state10) GetAllocatedSectors() (*bitfield.BitField, error) { + var allocatedSectors bitfield.BitField + if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil { + return nil, err + } + + return &allocatedSectors, nil +} + +func (s *state10) LoadDeadline(idx uint64) (Deadline, error) { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return nil, err + } + dl, err := dls.LoadDeadline(s.store, idx) + if err != nil { + return nil, err + } + return &deadline10{*dl, s.store}, nil +} + +func (s *state10) ForEachDeadline(cb func(uint64, Deadline) error) error { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return err + } + return dls.ForEach(s.store, func(i uint64, dl *miner10.Deadline) error { + return cb(i, &deadline10{*dl, s.store}) + }) +} + +func (s *state10) NumDeadlines() (uint64, error) { + return miner10.WPoStPeriodDeadlines, nil +} + +func (s *state10) DeadlinesChanged(other State) (bool, error) { + other10, ok := other.(*state10) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return !s.State.Deadlines.Equals(other10.Deadlines), nil +} + +func (s *state10) MinerInfoChanged(other State) (bool, error) { + other0, ok := other.(*state10) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.Info.Equals(other0.State.Info), nil +} + +func (s *state10) Info() (MinerInfo, error) { + info, err := s.State.GetInfo(s.store) + if err != nil { + return MinerInfo{}, err + } + + mi := MinerInfo{ + Owner: info.Owner, + Worker: info.Worker, + ControlAddresses: info.ControlAddresses, + + PendingWorkerKey: (*WorkerKeyChange)(info.PendingWorkerKey), + + PeerId: info.PeerId, + Multiaddrs: info.Multiaddrs, + WindowPoStProofType: info.WindowPoStProofType, + SectorSize: info.SectorSize, + WindowPoStPartitionSectors: info.WindowPoStPartitionSectors, + ConsensusFaultElapsed: info.ConsensusFaultElapsed, + + Beneficiary: info.Beneficiary, + BeneficiaryTerm: BeneficiaryTerm(info.BeneficiaryTerm), + PendingBeneficiaryTerm: (*PendingBeneficiaryChange)(info.PendingBeneficiaryTerm), + } + + return mi, nil +} + +func (s *state10) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) { + return s.State.RecordedDeadlineInfo(epoch), nil +} + +func (s *state10) DeadlineCronActive() (bool, error) { + return s.State.DeadlineCronActive, nil +} + +func (s *state10) sectors() (adt.Array, error) { + return adt10.AsArray(s.store, s.Sectors, miner10.SectorsAmtBitwidth) +} + +func (s *state10) decodeSectorOnChainInfo(val *cbg.Deferred) (SectorOnChainInfo, error) { + var si miner10.SectorOnChainInfo + err := si.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorOnChainInfo{}, err + } + + return fromV10SectorOnChainInfo(si), nil +} + +func (s *state10) precommits() (adt.Map, error) { + return adt10.AsMap(s.store, s.PreCommittedSectors, builtin10.DefaultHamtBitwidth) +} + +func (s *state10) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { + var sp miner10.SectorPreCommitOnChainInfo + err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorPreCommitOnChainInfo{}, err + } + + return fromV10SectorPreCommitOnChainInfo(sp), nil +} + +func (s *state10) EraseAllUnproven() error { + + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return err + } + + err = dls.ForEach(s.store, func(dindx uint64, dl *miner10.Deadline) error { + ps, err := dl.PartitionsArray(s.store) + if err != nil { + return err + } + + var part miner10.Partition + err = ps.ForEach(&part, func(pindx int64) error { + _ = part.ActivateUnproven() + err = ps.Set(uint64(pindx), &part) + return nil + }) + + if err != nil { + return err + } + + dl.Partitions, err = ps.Root() + if err != nil { + return err + } + + return dls.UpdateDeadline(s.store, dindx, dl) + }) + if err != nil { + return err + } + + return s.State.SaveDeadlines(s.store, dls) + +} + +func (d *deadline10) LoadPartition(idx uint64) (Partition, error) { + p, err := d.Deadline.LoadPartition(d.store, idx) + if err != nil { + return nil, err + } + return &partition10{*p, d.store}, nil +} + +func (d *deadline10) ForEachPartition(cb func(uint64, Partition) error) error { + ps, err := d.Deadline.PartitionsArray(d.store) + if err != nil { + return err + } + var part miner10.Partition + return ps.ForEach(&part, func(i int64) error { + return cb(uint64(i), &partition10{part, d.store}) + }) +} + +func (d *deadline10) PartitionsChanged(other Deadline) (bool, error) { + other10, ok := other.(*deadline10) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return !d.Deadline.Partitions.Equals(other10.Deadline.Partitions), nil +} + +func (d *deadline10) PartitionsPoSted() (bitfield.BitField, error) { + return d.Deadline.PartitionsPoSted, nil +} + +func (d *deadline10) DisputableProofCount() (uint64, error) { + + ops, err := d.OptimisticProofsSnapshotArray(d.store) + if err != nil { + return 0, err + } + + return ops.Length(), nil + +} + +func (p *partition10) AllSectors() (bitfield.BitField, error) { + return p.Partition.Sectors, nil +} + +func (p *partition10) FaultySectors() (bitfield.BitField, error) { + return p.Partition.Faults, nil +} + +func (p *partition10) RecoveringSectors() (bitfield.BitField, error) { + return p.Partition.Recoveries, nil +} + +func (p *partition10) UnprovenSectors() (bitfield.BitField, error) { + return p.Partition.Unproven, nil +} + +func fromV10SectorOnChainInfo(v10 miner10.SectorOnChainInfo) SectorOnChainInfo { + info := SectorOnChainInfo{ + SectorNumber: v10.SectorNumber, + SealProof: v10.SealProof, + SealedCID: v10.SealedCID, + DealIDs: v10.DealIDs, + Activation: v10.Activation, + Expiration: v10.Expiration, + DealWeight: v10.DealWeight, + VerifiedDealWeight: v10.VerifiedDealWeight, + InitialPledge: v10.InitialPledge, + ExpectedDayReward: v10.ExpectedDayReward, + ExpectedStoragePledge: v10.ExpectedStoragePledge, + + SectorKeyCID: v10.SectorKeyCID, + } + return info +} + +func fromV10SectorPreCommitOnChainInfo(v10 miner10.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + ret := SectorPreCommitOnChainInfo{ + Info: SectorPreCommitInfo{ + SealProof: v10.Info.SealProof, + SectorNumber: v10.Info.SectorNumber, + SealedCID: v10.Info.SealedCID, + SealRandEpoch: v10.Info.SealRandEpoch, + DealIDs: v10.Info.DealIDs, + Expiration: v10.Info.Expiration, + UnsealedCid: nil, + }, + PreCommitDeposit: v10.PreCommitDeposit, + PreCommitEpoch: v10.PreCommitEpoch, + } + + ret.Info.UnsealedCid = v10.Info.UnsealedCid + + return ret +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +func (s *state10) ActorKey() string { + return manifest.MinerKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/miner/v2.go b/chain/actors/builtin/miner/v2.go index 3501e81f1..14341ae38 100644 --- a/chain/actors/builtin/miner/v2.go +++ b/chain/actors/builtin/miner/v2.go @@ -3,6 +3,7 @@ package miner import ( "bytes" "errors" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,11 +12,13 @@ import ( "github.com/filecoin-project/go-bitfield" rle "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" - minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -87,6 +90,7 @@ func (s *state2) PreCommitDeposits() (abi.TokenAmount, error) { return s.State.PreCommitDeposits, nil } +// Returns nil, nil if sector is not found func (s *state2) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { info, ok, err := s.State.GetSector(s.store, num) if !ok || err != nil { @@ -194,7 +198,7 @@ func (s *state2) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e return &out, nil } -func (s *state2) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state2) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { info, ok, err := s.State.GetPrecommittedSector(s.store, num) if !ok || err != nil { return nil, err @@ -205,7 +209,7 @@ func (s *state2) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.Sector return &ret, nil } -func (s *state2) ForEachPrecommittedSector(cb func(minertypes.SectorPreCommitOnChainInfo) error) error { +func (s *state2) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { precommitted, err := adt2.AsMap(s.store, s.State.PreCommittedSectors) if err != nil { return err @@ -418,11 +422,11 @@ func (s *state2) precommits() (adt.Map, error) { return adt2.AsMap(s.store, s.PreCommittedSectors) } -func (s *state2) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state2) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { var sp miner2.SectorPreCommitOnChainInfo err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, err + return SectorPreCommitOnChainInfo{}, err } return fromV2SectorPreCommitOnChainInfo(sp), nil @@ -540,9 +544,9 @@ func fromV2SectorOnChainInfo(v2 miner2.SectorOnChainInfo) SectorOnChainInfo { return info } -func fromV2SectorPreCommitOnChainInfo(v2 miner2.SectorPreCommitOnChainInfo) minertypes.SectorPreCommitOnChainInfo { - return minertypes.SectorPreCommitOnChainInfo{ - Info: minertypes.SectorPreCommitInfo{ +func fromV2SectorPreCommitOnChainInfo(v2 miner2.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + ret := SectorPreCommitOnChainInfo{ + Info: SectorPreCommitInfo{ SealProof: v2.Info.SealProof, SectorNumber: v2.Info.SectorNumber, SealedCID: v2.Info.SealedCID, @@ -554,8 +558,27 @@ func fromV2SectorPreCommitOnChainInfo(v2 miner2.SectorPreCommitOnChainInfo) mine PreCommitDeposit: v2.PreCommitDeposit, PreCommitEpoch: v2.PreCommitEpoch, } + + return ret } func (s *state2) GetState() interface{} { return &s.State } + +func (s *state2) ActorKey() string { + return manifest.MinerKey +} + +func (s *state2) ActorVersion() actorstypes.Version { + return actorstypes.Version2 +} + +func (s *state2) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/miner/v3.go b/chain/actors/builtin/miner/v3.go index 5d2d3ef61..52808da8c 100644 --- a/chain/actors/builtin/miner/v3.go +++ b/chain/actors/builtin/miner/v3.go @@ -3,6 +3,7 @@ package miner import ( "bytes" "errors" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,12 +12,14 @@ import ( "github.com/filecoin-project/go-bitfield" rle "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" - minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" miner3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/miner" adt3 "github.com/filecoin-project/specs-actors/v3/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -88,6 +91,7 @@ func (s *state3) PreCommitDeposits() (abi.TokenAmount, error) { return s.State.PreCommitDeposits, nil } +// Returns nil, nil if sector is not found func (s *state3) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { info, ok, err := s.State.GetSector(s.store, num) if !ok || err != nil { @@ -195,7 +199,7 @@ func (s *state3) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e return &out, nil } -func (s *state3) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state3) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { info, ok, err := s.State.GetPrecommittedSector(s.store, num) if !ok || err != nil { return nil, err @@ -206,7 +210,7 @@ func (s *state3) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.Sector return &ret, nil } -func (s *state3) ForEachPrecommittedSector(cb func(minertypes.SectorPreCommitOnChainInfo) error) error { +func (s *state3) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { precommitted, err := adt3.AsMap(s.store, s.State.PreCommittedSectors, builtin3.DefaultHamtBitwidth) if err != nil { return err @@ -414,11 +418,11 @@ func (s *state3) precommits() (adt.Map, error) { return adt3.AsMap(s.store, s.PreCommittedSectors, builtin3.DefaultHamtBitwidth) } -func (s *state3) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state3) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { var sp miner3.SectorPreCommitOnChainInfo err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, err + return SectorPreCommitOnChainInfo{}, err } return fromV3SectorPreCommitOnChainInfo(sp), nil @@ -540,9 +544,9 @@ func fromV3SectorOnChainInfo(v3 miner3.SectorOnChainInfo) SectorOnChainInfo { return info } -func fromV3SectorPreCommitOnChainInfo(v3 miner3.SectorPreCommitOnChainInfo) minertypes.SectorPreCommitOnChainInfo { - return minertypes.SectorPreCommitOnChainInfo{ - Info: minertypes.SectorPreCommitInfo{ +func fromV3SectorPreCommitOnChainInfo(v3 miner3.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + ret := SectorPreCommitOnChainInfo{ + Info: SectorPreCommitInfo{ SealProof: v3.Info.SealProof, SectorNumber: v3.Info.SectorNumber, SealedCID: v3.Info.SealedCID, @@ -554,8 +558,27 @@ func fromV3SectorPreCommitOnChainInfo(v3 miner3.SectorPreCommitOnChainInfo) mine PreCommitDeposit: v3.PreCommitDeposit, PreCommitEpoch: v3.PreCommitEpoch, } + + return ret } func (s *state3) GetState() interface{} { return &s.State } + +func (s *state3) ActorKey() string { + return manifest.MinerKey +} + +func (s *state3) ActorVersion() actorstypes.Version { + return actorstypes.Version3 +} + +func (s *state3) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/miner/v4.go b/chain/actors/builtin/miner/v4.go index db36c3875..5980ef769 100644 --- a/chain/actors/builtin/miner/v4.go +++ b/chain/actors/builtin/miner/v4.go @@ -3,6 +3,7 @@ package miner import ( "bytes" "errors" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,12 +12,14 @@ import ( "github.com/filecoin-project/go-bitfield" rle "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" - minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" miner4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -88,6 +91,7 @@ func (s *state4) PreCommitDeposits() (abi.TokenAmount, error) { return s.State.PreCommitDeposits, nil } +// Returns nil, nil if sector is not found func (s *state4) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { info, ok, err := s.State.GetSector(s.store, num) if !ok || err != nil { @@ -195,7 +199,7 @@ func (s *state4) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e return &out, nil } -func (s *state4) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state4) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { info, ok, err := s.State.GetPrecommittedSector(s.store, num) if !ok || err != nil { return nil, err @@ -206,7 +210,7 @@ func (s *state4) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.Sector return &ret, nil } -func (s *state4) ForEachPrecommittedSector(cb func(minertypes.SectorPreCommitOnChainInfo) error) error { +func (s *state4) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { precommitted, err := adt4.AsMap(s.store, s.State.PreCommittedSectors, builtin4.DefaultHamtBitwidth) if err != nil { return err @@ -414,11 +418,11 @@ func (s *state4) precommits() (adt.Map, error) { return adt4.AsMap(s.store, s.PreCommittedSectors, builtin4.DefaultHamtBitwidth) } -func (s *state4) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state4) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { var sp miner4.SectorPreCommitOnChainInfo err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, err + return SectorPreCommitOnChainInfo{}, err } return fromV4SectorPreCommitOnChainInfo(sp), nil @@ -540,9 +544,9 @@ func fromV4SectorOnChainInfo(v4 miner4.SectorOnChainInfo) SectorOnChainInfo { return info } -func fromV4SectorPreCommitOnChainInfo(v4 miner4.SectorPreCommitOnChainInfo) minertypes.SectorPreCommitOnChainInfo { - return minertypes.SectorPreCommitOnChainInfo{ - Info: minertypes.SectorPreCommitInfo{ +func fromV4SectorPreCommitOnChainInfo(v4 miner4.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + ret := SectorPreCommitOnChainInfo{ + Info: SectorPreCommitInfo{ SealProof: v4.Info.SealProof, SectorNumber: v4.Info.SectorNumber, SealedCID: v4.Info.SealedCID, @@ -554,8 +558,27 @@ func fromV4SectorPreCommitOnChainInfo(v4 miner4.SectorPreCommitOnChainInfo) mine PreCommitDeposit: v4.PreCommitDeposit, PreCommitEpoch: v4.PreCommitEpoch, } + + return ret } func (s *state4) GetState() interface{} { return &s.State } + +func (s *state4) ActorKey() string { + return manifest.MinerKey +} + +func (s *state4) ActorVersion() actorstypes.Version { + return actorstypes.Version4 +} + +func (s *state4) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/miner/v5.go b/chain/actors/builtin/miner/v5.go index 8ff6432d2..886300ea3 100644 --- a/chain/actors/builtin/miner/v5.go +++ b/chain/actors/builtin/miner/v5.go @@ -3,6 +3,7 @@ package miner import ( "bytes" "errors" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,12 +12,14 @@ import ( "github.com/filecoin-project/go-bitfield" rle "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" - minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner" adt5 "github.com/filecoin-project/specs-actors/v5/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -88,6 +91,7 @@ func (s *state5) PreCommitDeposits() (abi.TokenAmount, error) { return s.State.PreCommitDeposits, nil } +// Returns nil, nil if sector is not found func (s *state5) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { info, ok, err := s.State.GetSector(s.store, num) if !ok || err != nil { @@ -195,7 +199,7 @@ func (s *state5) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e return &out, nil } -func (s *state5) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state5) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { info, ok, err := s.State.GetPrecommittedSector(s.store, num) if !ok || err != nil { return nil, err @@ -206,7 +210,7 @@ func (s *state5) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.Sector return &ret, nil } -func (s *state5) ForEachPrecommittedSector(cb func(minertypes.SectorPreCommitOnChainInfo) error) error { +func (s *state5) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { precommitted, err := adt5.AsMap(s.store, s.State.PreCommittedSectors, builtin5.DefaultHamtBitwidth) if err != nil { return err @@ -414,11 +418,11 @@ func (s *state5) precommits() (adt.Map, error) { return adt5.AsMap(s.store, s.PreCommittedSectors, builtin5.DefaultHamtBitwidth) } -func (s *state5) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state5) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { var sp miner5.SectorPreCommitOnChainInfo err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, err + return SectorPreCommitOnChainInfo{}, err } return fromV5SectorPreCommitOnChainInfo(sp), nil @@ -540,9 +544,9 @@ func fromV5SectorOnChainInfo(v5 miner5.SectorOnChainInfo) SectorOnChainInfo { return info } -func fromV5SectorPreCommitOnChainInfo(v5 miner5.SectorPreCommitOnChainInfo) minertypes.SectorPreCommitOnChainInfo { - return minertypes.SectorPreCommitOnChainInfo{ - Info: minertypes.SectorPreCommitInfo{ +func fromV5SectorPreCommitOnChainInfo(v5 miner5.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + ret := SectorPreCommitOnChainInfo{ + Info: SectorPreCommitInfo{ SealProof: v5.Info.SealProof, SectorNumber: v5.Info.SectorNumber, SealedCID: v5.Info.SealedCID, @@ -554,8 +558,27 @@ func fromV5SectorPreCommitOnChainInfo(v5 miner5.SectorPreCommitOnChainInfo) mine PreCommitDeposit: v5.PreCommitDeposit, PreCommitEpoch: v5.PreCommitEpoch, } + + return ret } func (s *state5) GetState() interface{} { return &s.State } + +func (s *state5) ActorKey() string { + return manifest.MinerKey +} + +func (s *state5) ActorVersion() actorstypes.Version { + return actorstypes.Version5 +} + +func (s *state5) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/miner/v6.go b/chain/actors/builtin/miner/v6.go index f11d4d062..4737b0ee2 100644 --- a/chain/actors/builtin/miner/v6.go +++ b/chain/actors/builtin/miner/v6.go @@ -3,6 +3,7 @@ package miner import ( "bytes" "errors" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,12 +12,14 @@ import ( "github.com/filecoin-project/go-bitfield" rle "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" - minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -88,6 +91,7 @@ func (s *state6) PreCommitDeposits() (abi.TokenAmount, error) { return s.State.PreCommitDeposits, nil } +// Returns nil, nil if sector is not found func (s *state6) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { info, ok, err := s.State.GetSector(s.store, num) if !ok || err != nil { @@ -195,7 +199,7 @@ func (s *state6) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e return &out, nil } -func (s *state6) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state6) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { info, ok, err := s.State.GetPrecommittedSector(s.store, num) if !ok || err != nil { return nil, err @@ -206,7 +210,7 @@ func (s *state6) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.Sector return &ret, nil } -func (s *state6) ForEachPrecommittedSector(cb func(minertypes.SectorPreCommitOnChainInfo) error) error { +func (s *state6) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { precommitted, err := adt6.AsMap(s.store, s.State.PreCommittedSectors, builtin6.DefaultHamtBitwidth) if err != nil { return err @@ -414,11 +418,11 @@ func (s *state6) precommits() (adt.Map, error) { return adt6.AsMap(s.store, s.PreCommittedSectors, builtin6.DefaultHamtBitwidth) } -func (s *state6) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state6) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { var sp miner6.SectorPreCommitOnChainInfo err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, err + return SectorPreCommitOnChainInfo{}, err } return fromV6SectorPreCommitOnChainInfo(sp), nil @@ -540,9 +544,9 @@ func fromV6SectorOnChainInfo(v6 miner6.SectorOnChainInfo) SectorOnChainInfo { return info } -func fromV6SectorPreCommitOnChainInfo(v6 miner6.SectorPreCommitOnChainInfo) minertypes.SectorPreCommitOnChainInfo { - return minertypes.SectorPreCommitOnChainInfo{ - Info: minertypes.SectorPreCommitInfo{ +func fromV6SectorPreCommitOnChainInfo(v6 miner6.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + ret := SectorPreCommitOnChainInfo{ + Info: SectorPreCommitInfo{ SealProof: v6.Info.SealProof, SectorNumber: v6.Info.SectorNumber, SealedCID: v6.Info.SealedCID, @@ -554,8 +558,27 @@ func fromV6SectorPreCommitOnChainInfo(v6 miner6.SectorPreCommitOnChainInfo) mine PreCommitDeposit: v6.PreCommitDeposit, PreCommitEpoch: v6.PreCommitEpoch, } + + return ret } func (s *state6) GetState() interface{} { return &s.State } + +func (s *state6) ActorKey() string { + return manifest.MinerKey +} + +func (s *state6) ActorVersion() actorstypes.Version { + return actorstypes.Version6 +} + +func (s *state6) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/miner/v7.go b/chain/actors/builtin/miner/v7.go index f7893cef3..72803eb75 100644 --- a/chain/actors/builtin/miner/v7.go +++ b/chain/actors/builtin/miner/v7.go @@ -3,6 +3,7 @@ package miner import ( "bytes" "errors" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,12 +12,14 @@ import ( "github.com/filecoin-project/go-bitfield" rle "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" - minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" miner7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/miner" adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -88,6 +91,7 @@ func (s *state7) PreCommitDeposits() (abi.TokenAmount, error) { return s.State.PreCommitDeposits, nil } +// Returns nil, nil if sector is not found func (s *state7) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { info, ok, err := s.State.GetSector(s.store, num) if !ok || err != nil { @@ -194,7 +198,7 @@ func (s *state7) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e return &out, nil } -func (s *state7) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state7) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { info, ok, err := s.State.GetPrecommittedSector(s.store, num) if !ok || err != nil { return nil, err @@ -205,7 +209,7 @@ func (s *state7) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.Sector return &ret, nil } -func (s *state7) ForEachPrecommittedSector(cb func(minertypes.SectorPreCommitOnChainInfo) error) error { +func (s *state7) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { precommitted, err := adt7.AsMap(s.store, s.State.PreCommittedSectors, builtin7.DefaultHamtBitwidth) if err != nil { return err @@ -413,11 +417,11 @@ func (s *state7) precommits() (adt.Map, error) { return adt7.AsMap(s.store, s.PreCommittedSectors, builtin7.DefaultHamtBitwidth) } -func (s *state7) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state7) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { var sp miner7.SectorPreCommitOnChainInfo err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, err + return SectorPreCommitOnChainInfo{}, err } return fromV7SectorPreCommitOnChainInfo(sp), nil @@ -541,9 +545,9 @@ func fromV7SectorOnChainInfo(v7 miner7.SectorOnChainInfo) SectorOnChainInfo { return info } -func fromV7SectorPreCommitOnChainInfo(v7 miner7.SectorPreCommitOnChainInfo) minertypes.SectorPreCommitOnChainInfo { - return minertypes.SectorPreCommitOnChainInfo{ - Info: minertypes.SectorPreCommitInfo{ +func fromV7SectorPreCommitOnChainInfo(v7 miner7.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + ret := SectorPreCommitOnChainInfo{ + Info: SectorPreCommitInfo{ SealProof: v7.Info.SealProof, SectorNumber: v7.Info.SectorNumber, SealedCID: v7.Info.SealedCID, @@ -555,8 +559,27 @@ func fromV7SectorPreCommitOnChainInfo(v7 miner7.SectorPreCommitOnChainInfo) mine PreCommitDeposit: v7.PreCommitDeposit, PreCommitEpoch: v7.PreCommitEpoch, } + + return ret } func (s *state7) GetState() interface{} { return &s.State } + +func (s *state7) ActorKey() string { + return manifest.MinerKey +} + +func (s *state7) ActorVersion() actorstypes.Version { + return actorstypes.Version7 +} + +func (s *state7) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/miner/v8.go b/chain/actors/builtin/miner/v8.go index 0d53cc664..3e3739591 100644 --- a/chain/actors/builtin/miner/v8.go +++ b/chain/actors/builtin/miner/v8.go @@ -3,6 +3,7 @@ package miner import ( "bytes" "errors" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,12 +12,14 @@ import ( "github.com/filecoin-project/go-bitfield" rle "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" builtin8 "github.com/filecoin-project/go-state-types/builtin" miner8 "github.com/filecoin-project/go-state-types/builtin/v8/miner" adt8 "github.com/filecoin-project/go-state-types/builtin/v8/util/adt" - minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -88,6 +91,7 @@ func (s *state8) PreCommitDeposits() (abi.TokenAmount, error) { return s.State.PreCommitDeposits, nil } +// Returns nil, nil if sector is not found func (s *state8) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { info, ok, err := s.State.GetSector(s.store, num) if !ok || err != nil { @@ -194,7 +198,7 @@ func (s *state8) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e return &out, nil } -func (s *state8) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state8) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { info, ok, err := s.State.GetPrecommittedSector(s.store, num) if !ok || err != nil { return nil, err @@ -205,7 +209,7 @@ func (s *state8) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.Sector return &ret, nil } -func (s *state8) ForEachPrecommittedSector(cb func(minertypes.SectorPreCommitOnChainInfo) error) error { +func (s *state8) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { precommitted, err := adt8.AsMap(s.store, s.State.PreCommittedSectors, builtin8.DefaultHamtBitwidth) if err != nil { return err @@ -413,11 +417,11 @@ func (s *state8) precommits() (adt.Map, error) { return adt8.AsMap(s.store, s.PreCommittedSectors, builtin8.DefaultHamtBitwidth) } -func (s *state8) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state8) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { var sp miner8.SectorPreCommitOnChainInfo err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, err + return SectorPreCommitOnChainInfo{}, err } return fromV8SectorPreCommitOnChainInfo(sp), nil @@ -541,9 +545,9 @@ func fromV8SectorOnChainInfo(v8 miner8.SectorOnChainInfo) SectorOnChainInfo { return info } -func fromV8SectorPreCommitOnChainInfo(v8 miner8.SectorPreCommitOnChainInfo) minertypes.SectorPreCommitOnChainInfo { - return minertypes.SectorPreCommitOnChainInfo{ - Info: minertypes.SectorPreCommitInfo{ +func fromV8SectorPreCommitOnChainInfo(v8 miner8.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + ret := SectorPreCommitOnChainInfo{ + Info: SectorPreCommitInfo{ SealProof: v8.Info.SealProof, SectorNumber: v8.Info.SectorNumber, SealedCID: v8.Info.SealedCID, @@ -555,8 +559,27 @@ func fromV8SectorPreCommitOnChainInfo(v8 miner8.SectorPreCommitOnChainInfo) mine PreCommitDeposit: v8.PreCommitDeposit, PreCommitEpoch: v8.PreCommitEpoch, } + + return ret } func (s *state8) GetState() interface{} { return &s.State } + +func (s *state8) ActorKey() string { + return manifest.MinerKey +} + +func (s *state8) ActorVersion() actorstypes.Version { + return actorstypes.Version8 +} + +func (s *state8) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/miner/v9.go b/chain/actors/builtin/miner/v9.go index 32b8d008b..72d9dbd59 100644 --- a/chain/actors/builtin/miner/v9.go +++ b/chain/actors/builtin/miner/v9.go @@ -3,6 +3,7 @@ package miner import ( "bytes" "errors" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -11,12 +12,14 @@ import ( "github.com/filecoin-project/go-bitfield" rle "github.com/filecoin-project/go-bitfield/rle" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" builtin9 "github.com/filecoin-project/go-state-types/builtin" miner9 "github.com/filecoin-project/go-state-types/builtin/v9/miner" - minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -88,6 +91,7 @@ func (s *state9) PreCommitDeposits() (abi.TokenAmount, error) { return s.State.PreCommitDeposits, nil } +// Returns nil, nil if sector is not found func (s *state9) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { info, ok, err := s.State.GetSector(s.store, num) if !ok || err != nil { @@ -194,7 +198,7 @@ func (s *state9) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e return &out, nil } -func (s *state9) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state9) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { info, ok, err := s.State.GetPrecommittedSector(s.store, num) if !ok || err != nil { return nil, err @@ -205,7 +209,7 @@ func (s *state9) GetPrecommittedSector(num abi.SectorNumber) (*minertypes.Sector return &ret, nil } -func (s *state9) ForEachPrecommittedSector(cb func(minertypes.SectorPreCommitOnChainInfo) error) error { +func (s *state9) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { precommitted, err := adt9.AsMap(s.store, s.State.PreCommittedSectors, builtin9.DefaultHamtBitwidth) if err != nil { return err @@ -384,8 +388,8 @@ func (s *state9) Info() (MinerInfo, error) { ConsensusFaultElapsed: info.ConsensusFaultElapsed, Beneficiary: info.Beneficiary, - BeneficiaryTerm: info.BeneficiaryTerm, - PendingBeneficiaryTerm: info.PendingBeneficiaryTerm, + BeneficiaryTerm: BeneficiaryTerm(info.BeneficiaryTerm), + PendingBeneficiaryTerm: (*PendingBeneficiaryChange)(info.PendingBeneficiaryTerm), } return mi, nil @@ -417,11 +421,11 @@ func (s *state9) precommits() (adt.Map, error) { return adt9.AsMap(s.store, s.PreCommittedSectors, builtin9.DefaultHamtBitwidth) } -func (s *state9) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (minertypes.SectorPreCommitOnChainInfo, error) { +func (s *state9) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { var sp miner9.SectorPreCommitOnChainInfo err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, err + return SectorPreCommitOnChainInfo{}, err } return fromV9SectorPreCommitOnChainInfo(sp), nil @@ -545,10 +549,43 @@ func fromV9SectorOnChainInfo(v9 miner9.SectorOnChainInfo) SectorOnChainInfo { return info } -func fromV9SectorPreCommitOnChainInfo(v9 miner9.SectorPreCommitOnChainInfo) minertypes.SectorPreCommitOnChainInfo { - return v9 +func fromV9SectorPreCommitOnChainInfo(v9 miner9.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + ret := SectorPreCommitOnChainInfo{ + Info: SectorPreCommitInfo{ + SealProof: v9.Info.SealProof, + SectorNumber: v9.Info.SectorNumber, + SealedCID: v9.Info.SealedCID, + SealRandEpoch: v9.Info.SealRandEpoch, + DealIDs: v9.Info.DealIDs, + Expiration: v9.Info.Expiration, + UnsealedCid: nil, + }, + PreCommitDeposit: v9.PreCommitDeposit, + PreCommitEpoch: v9.PreCommitEpoch, + } + + ret.Info.UnsealedCid = v9.Info.UnsealedCid + + return ret } func (s *state9) GetState() interface{} { return &s.State } + +func (s *state9) ActorKey() string { + return manifest.MinerKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/multisig/actor.go.template b/chain/actors/builtin/multisig/actor.go.template index a02a986aa..9bb69a048 100644 --- a/chain/actors/builtin/multisig/actor.go.template +++ b/chain/actors/builtin/multisig/actor.go.template @@ -2,6 +2,7 @@ package multisig import ( actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/ipfs/go-cid" "fmt" "github.com/minio/blake2b-simd" @@ -20,6 +21,7 @@ import ( {{end}} builtintypes "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" @@ -28,7 +30,7 @@ import ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.MultisigKey { + if name != manifest.MultisigKey { return nil, xerrors.Errorf("actor code is not multisig: %s", name) } @@ -67,6 +69,10 @@ func MakeState(store adt.Store, av actorstypes.Version, signers []address.Addres type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + LockedBalance(epoch abi.ChainEpoch) (abi.TokenAmount, error) StartEpoch() (abi.ChainEpoch, error) UnlockDuration() (abi.ChainEpoch, error) @@ -141,3 +147,10 @@ func txnParams(id uint64, data *ProposalHashData) ([]byte, error) { return actors.SerializeParams(¶ms) } + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } +} diff --git a/chain/actors/builtin/multisig/message.go.template b/chain/actors/builtin/multisig/message.go.template index 1e1559968..b5bc6924f 100644 --- a/chain/actors/builtin/multisig/message.go.template +++ b/chain/actors/builtin/multisig/message.go.template @@ -14,6 +14,7 @@ import ( actorstypes "github.com/filecoin-project/go-state-types/actors" multisig{{.v}} "github.com/filecoin-project/go-state-types/builtin{{.import}}multisig" init{{.latestVersion}} "github.com/filecoin-project/go-state-types/builtin/v{{.latestVersion}}/init" + "github.com/filecoin-project/go-state-types/manifest" {{end}} builtintypes "github.com/filecoin-project/go-state-types/builtin" @@ -68,7 +69,7 @@ func (m message{{.v}}) Create( ConstructorParams: enc, } {{else}} - code, ok := actors.GetActorCodeID(actorstypes.Version{{.v}}, actors.MultisigKey) + code, ok := actors.GetActorCodeID(actorstypes.Version{{.v}}, manifest.MultisigKey) if !ok { return nil, xerrors.Errorf("failed to get multisig code ID") } diff --git a/chain/actors/builtin/multisig/message10.go b/chain/actors/builtin/multisig/message10.go new file mode 100644 index 000000000..87ee759bd --- /dev/null +++ b/chain/actors/builtin/multisig/message10.go @@ -0,0 +1,77 @@ +package multisig + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + builtintypes "github.com/filecoin-project/go-state-types/builtin" + init10 "github.com/filecoin-project/go-state-types/builtin/v10/init" + multisig10 "github.com/filecoin-project/go-state-types/builtin/v10/multisig" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/types" +) + +type message10 struct{ message0 } + +func (m message10) Create( + signers []address.Address, threshold uint64, + unlockStart, unlockDuration abi.ChainEpoch, + initialAmount abi.TokenAmount, +) (*types.Message, error) { + + lenAddrs := uint64(len(signers)) + + if lenAddrs < threshold { + return nil, xerrors.Errorf("cannot require signing of more addresses than provided for multisig") + } + + if threshold == 0 { + threshold = lenAddrs + } + + if m.from == address.Undef { + return nil, xerrors.Errorf("must provide source address") + } + + // Set up constructor parameters for multisig + msigParams := &multisig10.ConstructorParams{ + Signers: signers, + NumApprovalsThreshold: threshold, + UnlockDuration: unlockDuration, + StartEpoch: unlockStart, + } + + enc, actErr := actors.SerializeParams(msigParams) + if actErr != nil { + return nil, actErr + } + + code, ok := actors.GetActorCodeID(actorstypes.Version10, manifest.MultisigKey) + if !ok { + return nil, xerrors.Errorf("failed to get multisig code ID") + } + + // new actors are created by invoking 'exec' on the init actor with the constructor params + execParams := &init10.ExecParams{ + CodeCID: code, + ConstructorParams: enc, + } + + enc, actErr = actors.SerializeParams(execParams) + if actErr != nil { + return nil, actErr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Method: builtintypes.MethodsInit.Exec, + Params: enc, + Value: initialAmount, + }, nil +} diff --git a/chain/actors/builtin/multisig/message8.go b/chain/actors/builtin/multisig/message8.go index f627a695f..4131a1b76 100644 --- a/chain/actors/builtin/multisig/message8.go +++ b/chain/actors/builtin/multisig/message8.go @@ -7,8 +7,9 @@ import ( "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" builtintypes "github.com/filecoin-project/go-state-types/builtin" + init10 "github.com/filecoin-project/go-state-types/builtin/v10/init" multisig8 "github.com/filecoin-project/go-state-types/builtin/v8/multisig" - init9 "github.com/filecoin-project/go-state-types/builtin/v9/init" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/lotus/chain/actors" init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" @@ -50,13 +51,13 @@ func (m message8) Create( return nil, actErr } - code, ok := actors.GetActorCodeID(actorstypes.Version8, actors.MultisigKey) + code, ok := actors.GetActorCodeID(actorstypes.Version8, manifest.MultisigKey) if !ok { return nil, xerrors.Errorf("failed to get multisig code ID") } // new actors are created by invoking 'exec' on the init actor with the constructor params - execParams := &init9.ExecParams{ + execParams := &init10.ExecParams{ CodeCID: code, ConstructorParams: enc, } diff --git a/chain/actors/builtin/multisig/message9.go b/chain/actors/builtin/multisig/message9.go index 62f6ff558..f9c8c3103 100644 --- a/chain/actors/builtin/multisig/message9.go +++ b/chain/actors/builtin/multisig/message9.go @@ -7,8 +7,9 @@ import ( "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" builtintypes "github.com/filecoin-project/go-state-types/builtin" - init9 "github.com/filecoin-project/go-state-types/builtin/v9/init" + init10 "github.com/filecoin-project/go-state-types/builtin/v10/init" multisig9 "github.com/filecoin-project/go-state-types/builtin/v9/multisig" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/lotus/chain/actors" init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" @@ -50,13 +51,13 @@ func (m message9) Create( return nil, actErr } - code, ok := actors.GetActorCodeID(actorstypes.Version9, actors.MultisigKey) + code, ok := actors.GetActorCodeID(actorstypes.Version9, manifest.MultisigKey) if !ok { return nil, xerrors.Errorf("failed to get multisig code ID") } // new actors are created by invoking 'exec' on the init actor with the constructor params - execParams := &init9.ExecParams{ + execParams := &init10.ExecParams{ CodeCID: code, ConstructorParams: enc, } diff --git a/chain/actors/builtin/multisig/multisig.go b/chain/actors/builtin/multisig/multisig.go index 6c0d449df..4abdf7bbb 100644 --- a/chain/actors/builtin/multisig/multisig.go +++ b/chain/actors/builtin/multisig/multisig.go @@ -3,6 +3,7 @@ package multisig import ( "fmt" + "github.com/ipfs/go-cid" "github.com/minio/blake2b-simd" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" @@ -11,8 +12,9 @@ import ( "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" builtintypes "github.com/filecoin-project/go-state-types/builtin" - msig9 "github.com/filecoin-project/go-state-types/builtin/v9/multisig" + msig10 "github.com/filecoin-project/go-state-types/builtin/v10/multisig" "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" @@ -28,7 +30,7 @@ import ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.MultisigKey { + if name != manifest.MultisigKey { return nil, xerrors.Errorf("actor code is not multisig: %s", name) } @@ -40,6 +42,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -101,6 +106,9 @@ func MakeState(store adt.Store, av actorstypes.Version, signers []address.Addres case actorstypes.Version9: return make9(store, signers, threshold, startEpoch, unlockDuration, initialBalance) + case actorstypes.Version10: + return make10(store, signers, threshold, startEpoch, unlockDuration, initialBalance) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -108,6 +116,10 @@ func MakeState(store adt.Store, av actorstypes.Version, signers []address.Addres type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + LockedBalance(epoch abi.ChainEpoch) (abi.TokenAmount, error) StartEpoch() (abi.ChainEpoch, error) UnlockDuration() (abi.ChainEpoch, error) @@ -123,7 +135,7 @@ type State interface { GetState() interface{} } -type Transaction = msig9.Transaction +type Transaction = msig10.Transaction var Methods = builtintypes.MethodsMultisig @@ -156,6 +168,9 @@ func Message(version actorstypes.Version, from address.Address) MessageBuilder { case actorstypes.Version9: return message9{message0{from}} + + case actorstypes.Version10: + return message10{message0{from}} default: panic(fmt.Sprintf("unsupported actors version: %d", version)) } @@ -179,13 +194,13 @@ type MessageBuilder interface { } // this type is the same between v0 and v2 -type ProposalHashData = msig9.ProposalHashData -type ProposeReturn = msig9.ProposeReturn -type ProposeParams = msig9.ProposeParams -type ApproveReturn = msig9.ApproveReturn +type ProposalHashData = msig10.ProposalHashData +type ProposeReturn = msig10.ProposeReturn +type ProposeParams = msig10.ProposeParams +type ApproveReturn = msig10.ApproveReturn func txnParams(id uint64, data *ProposalHashData) ([]byte, error) { - params := msig9.TxnIDParams{ID: msig9.TxnID(id)} + params := msig10.TxnIDParams{ID: msig10.TxnID(id)} if data != nil { if data.Requester.Protocol() != address.ID { return nil, xerrors.Errorf("proposer address must be an ID address, was %s", data.Requester) @@ -206,3 +221,18 @@ func txnParams(id uint64, data *ProposalHashData) ([]byte, error) { return actors.SerializeParams(¶ms) } + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state0{}).Code(), + (&state2{}).Code(), + (&state3{}).Code(), + (&state4{}).Code(), + (&state5{}).Code(), + (&state6{}).Code(), + (&state7{}).Code(), + (&state8{}).Code(), + (&state9{}).Code(), + (&state10{}).Code(), + } +} diff --git a/chain/actors/builtin/multisig/state.go.template b/chain/actors/builtin/multisig/state.go.template index e375becc3..5d04b94be 100644 --- a/chain/actors/builtin/multisig/state.go.template +++ b/chain/actors/builtin/multisig/state.go.template @@ -1,9 +1,11 @@ package multisig import ( + "fmt" "bytes" "encoding/binary" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" @@ -12,6 +14,8 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/go-state-types/manifest" {{if (le .v 7)}} {{if (ge .v 3)}} @@ -131,3 +135,20 @@ func (s *state{{.v}}) decodeTransaction(val *cbg.Deferred) (Transaction, error) func (s *state{{.v}}) GetState() interface{} { return &s.State } + +func (s *state{{.v}}) ActorKey() string { + return manifest.MultisigKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/multisig/v0.go b/chain/actors/builtin/multisig/v0.go index 9f4d09dc1..86bfdaaf3 100644 --- a/chain/actors/builtin/multisig/v0.go +++ b/chain/actors/builtin/multisig/v0.go @@ -3,6 +3,7 @@ package multisig import ( "bytes" "encoding/binary" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -10,9 +11,12 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -114,3 +118,20 @@ func (s *state0) decodeTransaction(val *cbg.Deferred) (Transaction, error) { func (s *state0) GetState() interface{} { return &s.State } + +func (s *state0) ActorKey() string { + return manifest.MultisigKey +} + +func (s *state0) ActorVersion() actorstypes.Version { + return actorstypes.Version0 +} + +func (s *state0) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/multisig/v10.go b/chain/actors/builtin/multisig/v10.go new file mode 100644 index 000000000..d87fc5807 --- /dev/null +++ b/chain/actors/builtin/multisig/v10.go @@ -0,0 +1,138 @@ +package multisig + +import ( + "bytes" + "encoding/binary" + "fmt" + + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + builtin10 "github.com/filecoin-project/go-state-types/builtin" + msig10 "github.com/filecoin-project/go-state-types/builtin/v10/multisig" + adt10 "github.com/filecoin-project/go-state-types/builtin/v10/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store, signers []address.Address, threshold uint64, startEpoch abi.ChainEpoch, unlockDuration abi.ChainEpoch, initialBalance abi.TokenAmount) (State, error) { + out := state10{store: store} + out.State = msig10.State{} + out.State.Signers = signers + out.State.NumApprovalsThreshold = threshold + out.State.StartEpoch = startEpoch + out.State.UnlockDuration = unlockDuration + out.State.InitialBalance = initialBalance + + em, err := adt10.StoreEmptyMap(store, builtin10.DefaultHamtBitwidth) + if err != nil { + return nil, err + } + + out.State.PendingTxns = em + + return &out, nil +} + +type state10 struct { + msig10.State + store adt.Store +} + +func (s *state10) LockedBalance(currEpoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.State.AmountLocked(currEpoch - s.State.StartEpoch), nil +} + +func (s *state10) StartEpoch() (abi.ChainEpoch, error) { + return s.State.StartEpoch, nil +} + +func (s *state10) UnlockDuration() (abi.ChainEpoch, error) { + return s.State.UnlockDuration, nil +} + +func (s *state10) InitialBalance() (abi.TokenAmount, error) { + return s.State.InitialBalance, nil +} + +func (s *state10) Threshold() (uint64, error) { + return s.State.NumApprovalsThreshold, nil +} + +func (s *state10) Signers() ([]address.Address, error) { + return s.State.Signers, nil +} + +func (s *state10) ForEachPendingTxn(cb func(id int64, txn Transaction) error) error { + arr, err := adt10.AsMap(s.store, s.State.PendingTxns, builtin10.DefaultHamtBitwidth) + if err != nil { + return err + } + var out msig10.Transaction + return arr.ForEach(&out, func(key string) error { + txid, n := binary.Varint([]byte(key)) + if n <= 0 { + return xerrors.Errorf("invalid pending transaction key: %v", key) + } + return cb(txid, (Transaction)(out)) //nolint:unconvert + }) +} + +func (s *state10) PendingTxnChanged(other State) (bool, error) { + other10, ok := other.(*state10) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.PendingTxns.Equals(other10.PendingTxns), nil +} + +func (s *state10) transactions() (adt.Map, error) { + return adt10.AsMap(s.store, s.PendingTxns, builtin10.DefaultHamtBitwidth) +} + +func (s *state10) decodeTransaction(val *cbg.Deferred) (Transaction, error) { + var tx msig10.Transaction + if err := tx.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return Transaction{}, err + } + return Transaction(tx), nil +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +func (s *state10) ActorKey() string { + return manifest.MultisigKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/multisig/v2.go b/chain/actors/builtin/multisig/v2.go index 14e895680..77330d513 100644 --- a/chain/actors/builtin/multisig/v2.go +++ b/chain/actors/builtin/multisig/v2.go @@ -3,6 +3,7 @@ package multisig import ( "bytes" "encoding/binary" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -10,9 +11,12 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" msig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig" adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -114,3 +118,20 @@ func (s *state2) decodeTransaction(val *cbg.Deferred) (Transaction, error) { func (s *state2) GetState() interface{} { return &s.State } + +func (s *state2) ActorKey() string { + return manifest.MultisigKey +} + +func (s *state2) ActorVersion() actorstypes.Version { + return actorstypes.Version2 +} + +func (s *state2) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/multisig/v3.go b/chain/actors/builtin/multisig/v3.go index 5cde148c1..e8659093f 100644 --- a/chain/actors/builtin/multisig/v3.go +++ b/chain/actors/builtin/multisig/v3.go @@ -3,6 +3,7 @@ package multisig import ( "bytes" "encoding/binary" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -10,10 +11,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" msig3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/multisig" adt3 "github.com/filecoin-project/specs-actors/v3/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -115,3 +119,20 @@ func (s *state3) decodeTransaction(val *cbg.Deferred) (Transaction, error) { func (s *state3) GetState() interface{} { return &s.State } + +func (s *state3) ActorKey() string { + return manifest.MultisigKey +} + +func (s *state3) ActorVersion() actorstypes.Version { + return actorstypes.Version3 +} + +func (s *state3) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/multisig/v4.go b/chain/actors/builtin/multisig/v4.go index 87936661d..ddaac5470 100644 --- a/chain/actors/builtin/multisig/v4.go +++ b/chain/actors/builtin/multisig/v4.go @@ -3,6 +3,7 @@ package multisig import ( "bytes" "encoding/binary" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -10,10 +11,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" msig4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/multisig" adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -115,3 +119,20 @@ func (s *state4) decodeTransaction(val *cbg.Deferred) (Transaction, error) { func (s *state4) GetState() interface{} { return &s.State } + +func (s *state4) ActorKey() string { + return manifest.MultisigKey +} + +func (s *state4) ActorVersion() actorstypes.Version { + return actorstypes.Version4 +} + +func (s *state4) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/multisig/v5.go b/chain/actors/builtin/multisig/v5.go index d50638ca5..50474d5fd 100644 --- a/chain/actors/builtin/multisig/v5.go +++ b/chain/actors/builtin/multisig/v5.go @@ -3,6 +3,7 @@ package multisig import ( "bytes" "encoding/binary" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -10,10 +11,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" msig5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/multisig" adt5 "github.com/filecoin-project/specs-actors/v5/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -115,3 +119,20 @@ func (s *state5) decodeTransaction(val *cbg.Deferred) (Transaction, error) { func (s *state5) GetState() interface{} { return &s.State } + +func (s *state5) ActorKey() string { + return manifest.MultisigKey +} + +func (s *state5) ActorVersion() actorstypes.Version { + return actorstypes.Version5 +} + +func (s *state5) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/multisig/v6.go b/chain/actors/builtin/multisig/v6.go index 9246eeaa9..c51404dc4 100644 --- a/chain/actors/builtin/multisig/v6.go +++ b/chain/actors/builtin/multisig/v6.go @@ -3,6 +3,7 @@ package multisig import ( "bytes" "encoding/binary" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -10,10 +11,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" msig6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/multisig" adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -115,3 +119,20 @@ func (s *state6) decodeTransaction(val *cbg.Deferred) (Transaction, error) { func (s *state6) GetState() interface{} { return &s.State } + +func (s *state6) ActorKey() string { + return manifest.MultisigKey +} + +func (s *state6) ActorVersion() actorstypes.Version { + return actorstypes.Version6 +} + +func (s *state6) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/multisig/v7.go b/chain/actors/builtin/multisig/v7.go index a6b630179..9ddce167a 100644 --- a/chain/actors/builtin/multisig/v7.go +++ b/chain/actors/builtin/multisig/v7.go @@ -3,6 +3,7 @@ package multisig import ( "bytes" "encoding/binary" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -10,10 +11,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" msig7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/multisig" adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -115,3 +119,20 @@ func (s *state7) decodeTransaction(val *cbg.Deferred) (Transaction, error) { func (s *state7) GetState() interface{} { return &s.State } + +func (s *state7) ActorKey() string { + return manifest.MultisigKey +} + +func (s *state7) ActorVersion() actorstypes.Version { + return actorstypes.Version7 +} + +func (s *state7) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/multisig/v8.go b/chain/actors/builtin/multisig/v8.go index 6311583b3..b28ec5684 100644 --- a/chain/actors/builtin/multisig/v8.go +++ b/chain/actors/builtin/multisig/v8.go @@ -3,6 +3,7 @@ package multisig import ( "bytes" "encoding/binary" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -10,10 +11,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" builtin8 "github.com/filecoin-project/go-state-types/builtin" msig8 "github.com/filecoin-project/go-state-types/builtin/v8/multisig" adt8 "github.com/filecoin-project/go-state-types/builtin/v8/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -115,3 +119,20 @@ func (s *state8) decodeTransaction(val *cbg.Deferred) (Transaction, error) { func (s *state8) GetState() interface{} { return &s.State } + +func (s *state8) ActorKey() string { + return manifest.MultisigKey +} + +func (s *state8) ActorVersion() actorstypes.Version { + return actorstypes.Version8 +} + +func (s *state8) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/multisig/v9.go b/chain/actors/builtin/multisig/v9.go index ef9a48f28..faa3b7d37 100644 --- a/chain/actors/builtin/multisig/v9.go +++ b/chain/actors/builtin/multisig/v9.go @@ -3,6 +3,7 @@ package multisig import ( "bytes" "encoding/binary" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -10,10 +11,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" builtin9 "github.com/filecoin-project/go-state-types/builtin" msig9 "github.com/filecoin-project/go-state-types/builtin/v9/multisig" adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -115,3 +119,20 @@ func (s *state9) decodeTransaction(val *cbg.Deferred) (Transaction, error) { func (s *state9) GetState() interface{} { return &s.State } + +func (s *state9) ActorKey() string { + return manifest.MultisigKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/paych/actor.go.template b/chain/actors/builtin/paych/actor.go.template index 1308d4ea4..e19ac5e29 100644 --- a/chain/actors/builtin/paych/actor.go.template +++ b/chain/actors/builtin/paych/actor.go.template @@ -1,7 +1,9 @@ package paych import ( + "github.com/ipfs/go-cid" actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/ipfs/go-cid" "encoding/base64" "fmt" @@ -12,6 +14,7 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/cbor" ipldcbor "github.com/ipfs/go-ipld-cbor" + "github.com/filecoin-project/go-state-types/manifest" paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" paychtypes "github.com/filecoin-project/go-state-types/builtin/v8/paych" @@ -29,7 +32,7 @@ import ( // Load returns an abstract copy of payment channel state, irregardless of actor version func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.PaychKey { + if name != manifest.PaychKey { return nil, xerrors.Errorf("actor code is not paych: %s", name) } @@ -59,6 +62,11 @@ func Load(store adt.Store, act *types.Actor) (State, error) { // versions type State interface { cbor.Marshaler + + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + // Channel owner, who has funded the actor From() (address.Address, error) // Recipient of payouts from channel @@ -132,4 +140,11 @@ func toV0SignedVoucher(sv paychtypes.SignedVoucher) paych0.SignedVoucher { Merges: nil, Signature: sv.Signature, } -} \ No newline at end of file +} + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } +} diff --git a/chain/actors/builtin/paych/message10.go b/chain/actors/builtin/paych/message10.go new file mode 100644 index 000000000..03daa7bcf --- /dev/null +++ b/chain/actors/builtin/paych/message10.go @@ -0,0 +1,109 @@ +package paych + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + builtin10 "github.com/filecoin-project/go-state-types/builtin" + init10 "github.com/filecoin-project/go-state-types/builtin/v10/init" + paych10 "github.com/filecoin-project/go-state-types/builtin/v10/paych" + paychtypes "github.com/filecoin-project/go-state-types/builtin/v8/paych" + + "github.com/filecoin-project/lotus/chain/actors" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/types" +) + +type message10 struct{ from address.Address } + +func (m message10) Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error) { + + actorCodeID, ok := actors.GetActorCodeID(actorstypes.Version10, "paymentchannel") + if !ok { + return nil, xerrors.Errorf("error getting actor paymentchannel code id for actor version %d", 10) + } + + params, aerr := actors.SerializeParams(&paych10.ConstructorParams{From: m.from, To: to}) + if aerr != nil { + return nil, aerr + } + enc, aerr := actors.SerializeParams(&init10.ExecParams{ + CodeCID: actorCodeID, + ConstructorParams: params, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Value: initialAmount, + Method: builtin10.MethodsInit.Exec, + Params: enc, + }, nil +} + +func (m message10) Update(paych address.Address, sv *paychtypes.SignedVoucher, secret []byte) (*types.Message, error) { + params, aerr := actors.SerializeParams(&paych10.UpdateChannelStateParams{ + + Sv: toV10SignedVoucher(*sv), + + Secret: secret, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin10.MethodsPaych.UpdateChannelState, + Params: params, + }, nil +} + +func toV10SignedVoucher(sv paychtypes.SignedVoucher) paych10.SignedVoucher { + merges := make([]paych10.Merge, len(sv.Merges)) + for i := range sv.Merges { + merges[i] = paych10.Merge{ + Lane: sv.Merges[i].Lane, + Nonce: sv.Merges[i].Nonce, + } + } + + return paych10.SignedVoucher{ + ChannelAddr: sv.ChannelAddr, + TimeLockMin: sv.TimeLockMin, + TimeLockMax: sv.TimeLockMax, + SecretHash: sv.SecretHash, + Extra: (*paych10.ModVerifyParams)(sv.Extra), + Lane: sv.Lane, + Nonce: sv.Nonce, + Amount: sv.Amount, + MinSettleHeight: sv.MinSettleHeight, + Merges: merges, + Signature: sv.Signature, + } +} + +func (m message10) Settle(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin10.MethodsPaych.Settle, + }, nil +} + +func (m message10) Collect(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin10.MethodsPaych.Collect, + }, nil +} diff --git a/chain/actors/builtin/paych/mock/mock.go b/chain/actors/builtin/paych/mock/mock.go index 729db5924..3b8881319 100644 --- a/chain/actors/builtin/paych/mock/mock.go +++ b/chain/actors/builtin/paych/mock/mock.go @@ -3,9 +3,13 @@ package mock import ( "io" + "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/lotus/chain/actors/builtin/paych" ) @@ -18,6 +22,18 @@ type mockState struct { lanes map[uint64]paych.LaneState } +func (ms *mockState) Code() cid.Cid { + panic("paych mock does not have CID") +} + +func (ms *mockState) ActorKey() string { + return manifest.PaychKey +} + +func (ms *mockState) ActorVersion() actorstypes.Version { + panic("paych mock is unversioned") +} + func (ms *mockState) GetState() interface{} { panic("implement me") } diff --git a/chain/actors/builtin/paych/paych.go b/chain/actors/builtin/paych/paych.go index e0a13fd21..0e6a3ca07 100644 --- a/chain/actors/builtin/paych/paych.go +++ b/chain/actors/builtin/paych/paych.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "fmt" + "github.com/ipfs/go-cid" ipldcbor "github.com/ipfs/go-ipld-cbor" "golang.org/x/xerrors" @@ -13,6 +14,7 @@ import ( "github.com/filecoin-project/go-state-types/big" paychtypes "github.com/filecoin-project/go-state-types/builtin/v8/paych" "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" @@ -30,7 +32,7 @@ import ( // Load returns an abstract copy of payment channel state, irregardless of actor version func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.PaychKey { + if name != manifest.PaychKey { return nil, xerrors.Errorf("actor code is not paych: %s", name) } @@ -42,6 +44,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -77,6 +82,11 @@ func Load(store adt.Store, act *types.Actor) (State, error) { // versions type State interface { cbor.Marshaler + + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + // Channel owner, who has funded the actor From() (address.Address, error) // Recipient of payouts from channel @@ -148,6 +158,9 @@ func Message(version actorstypes.Version, from address.Address) MessageBuilder { case actorstypes.Version9: return message9{from} + case actorstypes.Version10: + return message10{from} + default: panic(fmt.Sprintf("unsupported actors version: %d", version)) } @@ -175,3 +188,18 @@ func toV0SignedVoucher(sv paychtypes.SignedVoucher) paych0.SignedVoucher { Signature: sv.Signature, } } + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state0{}).Code(), + (&state2{}).Code(), + (&state3{}).Code(), + (&state4{}).Code(), + (&state5{}).Code(), + (&state6{}).Code(), + (&state7{}).Code(), + (&state8{}).Code(), + (&state9{}).Code(), + (&state10{}).Code(), + } +} diff --git a/chain/actors/builtin/paych/state.go.template b/chain/actors/builtin/paych/state.go.template index c3954ce81..0b0f9f9a1 100644 --- a/chain/actors/builtin/paych/state.go.template +++ b/chain/actors/builtin/paych/state.go.template @@ -1,6 +1,8 @@ package paych import ( + "fmt" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" @@ -8,6 +10,8 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/go-state-types/manifest" {{if (le .v 7)}} paych{{.v}} "github.com/filecoin-project/specs-actors{{.import}}actors/builtin/paych" @@ -117,3 +121,20 @@ func (ls *laneState{{.v}}) Redeemed() (big.Int, error) { func (ls *laneState{{.v}}) Nonce() (uint64, error) { return ls.LaneState.Nonce, nil } + +func (s *state{{.v}}) ActorKey() string { + return manifest.PaychKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/paych/v0.go b/chain/actors/builtin/paych/v0.go index 727525c50..facc7f656 100644 --- a/chain/actors/builtin/paych/v0.go +++ b/chain/actors/builtin/paych/v0.go @@ -1,14 +1,19 @@ package paych import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -111,3 +116,20 @@ func (ls *laneState0) Redeemed() (big.Int, error) { func (ls *laneState0) Nonce() (uint64, error) { return ls.LaneState.Nonce, nil } + +func (s *state0) ActorKey() string { + return manifest.PaychKey +} + +func (s *state0) ActorVersion() actorstypes.Version { + return actorstypes.Version0 +} + +func (s *state0) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/paych/v10.go b/chain/actors/builtin/paych/v10.go new file mode 100644 index 000000000..edc6c96b6 --- /dev/null +++ b/chain/actors/builtin/paych/v10.go @@ -0,0 +1,135 @@ +package paych + +import ( + "fmt" + + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/big" + paych10 "github.com/filecoin-project/go-state-types/builtin/v10/paych" + adt10 "github.com/filecoin-project/go-state-types/builtin/v10/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store) (State, error) { + out := state10{store: store} + out.State = paych10.State{} + return &out, nil +} + +type state10 struct { + paych10.State + store adt.Store + lsAmt *adt10.Array +} + +// Channel owner, who has funded the actor +func (s *state10) From() (address.Address, error) { + return s.State.From, nil +} + +// Recipient of payouts from channel +func (s *state10) To() (address.Address, error) { + return s.State.To, nil +} + +// Height at which the channel can be `Collected` +func (s *state10) SettlingAt() (abi.ChainEpoch, error) { + return s.State.SettlingAt, nil +} + +// Amount successfully redeemed through the payment channel, paid out on `Collect()` +func (s *state10) ToSend() (abi.TokenAmount, error) { + return s.State.ToSend, nil +} + +func (s *state10) getOrLoadLsAmt() (*adt10.Array, error) { + if s.lsAmt != nil { + return s.lsAmt, nil + } + + // Get the lane state from the chain + lsamt, err := adt10.AsArray(s.store, s.State.LaneStates, paych10.LaneStatesAmtBitwidth) + if err != nil { + return nil, err + } + + s.lsAmt = lsamt + return lsamt, nil +} + +// Get total number of lanes +func (s *state10) LaneCount() (uint64, error) { + lsamt, err := s.getOrLoadLsAmt() + if err != nil { + return 0, err + } + return lsamt.Length(), nil +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +// Iterate lane states +func (s *state10) ForEachLaneState(cb func(idx uint64, dl LaneState) error) error { + // Get the lane state from the chain + lsamt, err := s.getOrLoadLsAmt() + if err != nil { + return err + } + + // Note: we use a map instead of an array to store laneStates because the + // client sets the lane ID (the index) and potentially they could use a + // very large index. + var ls paych10.LaneState + return lsamt.ForEach(&ls, func(i int64) error { + return cb(uint64(i), &laneState10{ls}) + }) +} + +type laneState10 struct { + paych10.LaneState +} + +func (ls *laneState10) Redeemed() (big.Int, error) { + return ls.LaneState.Redeemed, nil +} + +func (ls *laneState10) Nonce() (uint64, error) { + return ls.LaneState.Nonce, nil +} + +func (s *state10) ActorKey() string { + return manifest.PaychKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/paych/v2.go b/chain/actors/builtin/paych/v2.go index 5852c9a64..63a3cc75e 100644 --- a/chain/actors/builtin/paych/v2.go +++ b/chain/actors/builtin/paych/v2.go @@ -1,14 +1,19 @@ package paych import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" paych2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/paych" adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -111,3 +116,20 @@ func (ls *laneState2) Redeemed() (big.Int, error) { func (ls *laneState2) Nonce() (uint64, error) { return ls.LaneState.Nonce, nil } + +func (s *state2) ActorKey() string { + return manifest.PaychKey +} + +func (s *state2) ActorVersion() actorstypes.Version { + return actorstypes.Version2 +} + +func (s *state2) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/paych/v3.go b/chain/actors/builtin/paych/v3.go index 5297e9d10..c672c0027 100644 --- a/chain/actors/builtin/paych/v3.go +++ b/chain/actors/builtin/paych/v3.go @@ -1,14 +1,19 @@ package paych import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" paych3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/paych" adt3 "github.com/filecoin-project/specs-actors/v3/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -111,3 +116,20 @@ func (ls *laneState3) Redeemed() (big.Int, error) { func (ls *laneState3) Nonce() (uint64, error) { return ls.LaneState.Nonce, nil } + +func (s *state3) ActorKey() string { + return manifest.PaychKey +} + +func (s *state3) ActorVersion() actorstypes.Version { + return actorstypes.Version3 +} + +func (s *state3) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/paych/v4.go b/chain/actors/builtin/paych/v4.go index be10061bf..842e52093 100644 --- a/chain/actors/builtin/paych/v4.go +++ b/chain/actors/builtin/paych/v4.go @@ -1,14 +1,19 @@ package paych import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" paych4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/paych" adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -111,3 +116,20 @@ func (ls *laneState4) Redeemed() (big.Int, error) { func (ls *laneState4) Nonce() (uint64, error) { return ls.LaneState.Nonce, nil } + +func (s *state4) ActorKey() string { + return manifest.PaychKey +} + +func (s *state4) ActorVersion() actorstypes.Version { + return actorstypes.Version4 +} + +func (s *state4) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/paych/v5.go b/chain/actors/builtin/paych/v5.go index 37a917273..8f53fe43f 100644 --- a/chain/actors/builtin/paych/v5.go +++ b/chain/actors/builtin/paych/v5.go @@ -1,14 +1,19 @@ package paych import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" paych5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/paych" adt5 "github.com/filecoin-project/specs-actors/v5/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -111,3 +116,20 @@ func (ls *laneState5) Redeemed() (big.Int, error) { func (ls *laneState5) Nonce() (uint64, error) { return ls.LaneState.Nonce, nil } + +func (s *state5) ActorKey() string { + return manifest.PaychKey +} + +func (s *state5) ActorVersion() actorstypes.Version { + return actorstypes.Version5 +} + +func (s *state5) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/paych/v6.go b/chain/actors/builtin/paych/v6.go index 36676d9de..0a8a93896 100644 --- a/chain/actors/builtin/paych/v6.go +++ b/chain/actors/builtin/paych/v6.go @@ -1,14 +1,19 @@ package paych import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" paych6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/paych" adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -111,3 +116,20 @@ func (ls *laneState6) Redeemed() (big.Int, error) { func (ls *laneState6) Nonce() (uint64, error) { return ls.LaneState.Nonce, nil } + +func (s *state6) ActorKey() string { + return manifest.PaychKey +} + +func (s *state6) ActorVersion() actorstypes.Version { + return actorstypes.Version6 +} + +func (s *state6) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/paych/v7.go b/chain/actors/builtin/paych/v7.go index 88b6f2b84..ce0dcba0a 100644 --- a/chain/actors/builtin/paych/v7.go +++ b/chain/actors/builtin/paych/v7.go @@ -1,14 +1,19 @@ package paych import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" paych7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/paych" adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -111,3 +116,20 @@ func (ls *laneState7) Redeemed() (big.Int, error) { func (ls *laneState7) Nonce() (uint64, error) { return ls.LaneState.Nonce, nil } + +func (s *state7) ActorKey() string { + return manifest.PaychKey +} + +func (s *state7) ActorVersion() actorstypes.Version { + return actorstypes.Version7 +} + +func (s *state7) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/paych/v8.go b/chain/actors/builtin/paych/v8.go index 1961e69ec..51067e87b 100644 --- a/chain/actors/builtin/paych/v8.go +++ b/chain/actors/builtin/paych/v8.go @@ -1,14 +1,19 @@ package paych import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" paych8 "github.com/filecoin-project/go-state-types/builtin/v8/paych" adt8 "github.com/filecoin-project/go-state-types/builtin/v8/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -111,3 +116,20 @@ func (ls *laneState8) Redeemed() (big.Int, error) { func (ls *laneState8) Nonce() (uint64, error) { return ls.LaneState.Nonce, nil } + +func (s *state8) ActorKey() string { + return manifest.PaychKey +} + +func (s *state8) ActorVersion() actorstypes.Version { + return actorstypes.Version8 +} + +func (s *state8) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/paych/v9.go b/chain/actors/builtin/paych/v9.go index 443fe74ea..8a69e16d4 100644 --- a/chain/actors/builtin/paych/v9.go +++ b/chain/actors/builtin/paych/v9.go @@ -1,14 +1,19 @@ package paych import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" paych9 "github.com/filecoin-project/go-state-types/builtin/v9/paych" adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -111,3 +116,20 @@ func (ls *laneState9) Redeemed() (big.Int, error) { func (ls *laneState9) Nonce() (uint64, error) { return ls.LaneState.Nonce, nil } + +func (s *state9) ActorKey() string { + return manifest.PaychKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/power/actor.go.template b/chain/actors/builtin/power/actor.go.template index 93fe70370..ed2d3fa77 100644 --- a/chain/actors/builtin/power/actor.go.template +++ b/chain/actors/builtin/power/actor.go.template @@ -1,6 +1,7 @@ package power import ( + "github.com/ipfs/go-cid" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/big" @@ -14,6 +15,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/go-state-types/manifest" {{range .versions}} {{if (le . 7)}} @@ -30,7 +32,7 @@ var ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.PowerKey { + if name != manifest.PowerKey { return nil, xerrors.Errorf("actor code is not power: %s", name) } @@ -69,6 +71,10 @@ func MakeState(store adt.Store, av actorstypes.Version) (State, error) { type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + TotalLocked() (abi.TokenAmount, error) TotalPower() (Claim, error) TotalCommitted() (Claim, error) @@ -109,3 +115,10 @@ func AddClaims(a Claim, b Claim) Claim { QualityAdjPower: big.Add(a.QualityAdjPower, b.QualityAdjPower), } } + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } +} diff --git a/chain/actors/builtin/power/power.go b/chain/actors/builtin/power/power.go index dc008f1f1..6dca61435 100644 --- a/chain/actors/builtin/power/power.go +++ b/chain/actors/builtin/power/power.go @@ -1,6 +1,7 @@ package power import ( + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" @@ -8,8 +9,9 @@ import ( "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" - builtin9 "github.com/filecoin-project/go-state-types/builtin" + builtin10 "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" @@ -25,13 +27,13 @@ import ( ) var ( - Address = builtin9.StoragePowerActorAddr - Methods = builtin9.MethodsPower + Address = builtin10.StoragePowerActorAddr + Methods = builtin10.MethodsPower ) func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.PowerKey { + if name != manifest.PowerKey { return nil, xerrors.Errorf("actor code is not power: %s", name) } @@ -43,6 +45,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -104,6 +109,9 @@ func MakeState(store adt.Store, av actorstypes.Version) (State, error) { case actorstypes.Version9: return make9(store) + case actorstypes.Version10: + return make10(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -111,6 +119,10 @@ func MakeState(store adt.Store, av actorstypes.Version) (State, error) { type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + TotalLocked() (abi.TokenAmount, error) TotalPower() (Claim, error) TotalCommitted() (Claim, error) @@ -151,3 +163,18 @@ func AddClaims(a Claim, b Claim) Claim { QualityAdjPower: big.Add(a.QualityAdjPower, b.QualityAdjPower), } } + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state0{}).Code(), + (&state2{}).Code(), + (&state3{}).Code(), + (&state4{}).Code(), + (&state5{}).Code(), + (&state6{}).Code(), + (&state7{}).Code(), + (&state8{}).Code(), + (&state9{}).Code(), + (&state10{}).Code(), + } +} diff --git a/chain/actors/builtin/power/state.go.template b/chain/actors/builtin/power/state.go.template index 08362d2db..d37a8b98a 100644 --- a/chain/actors/builtin/power/state.go.template +++ b/chain/actors/builtin/power/state.go.template @@ -1,6 +1,8 @@ package power import ( + "fmt" + actorstypes "github.com/filecoin-project/go-state-types/actors" "bytes" "github.com/filecoin-project/go-address" @@ -8,8 +10,10 @@ import ( "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/go-state-types/manifest" {{if (le .v 7)}} {{if (ge .v 3)}} @@ -205,3 +209,20 @@ func fromV{{.v}}Claim(v{{.v}} power{{.v}}.Claim) Claim { QualityAdjPower: v{{.v}}.QualityAdjPower, } } + +func (s *state{{.v}}) ActorKey() string { + return manifest.PowerKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/power/v0.go b/chain/actors/builtin/power/v0.go index 5ae42b4df..4cf550616 100644 --- a/chain/actors/builtin/power/v0.go +++ b/chain/actors/builtin/power/v0.go @@ -2,15 +2,19 @@ package power import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -188,3 +192,20 @@ func fromV0Claim(v0 power0.Claim) Claim { QualityAdjPower: v0.QualityAdjPower, } } + +func (s *state0) ActorKey() string { + return manifest.PowerKey +} + +func (s *state0) ActorVersion() actorstypes.Version { + return actorstypes.Version0 +} + +func (s *state0) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/power/v10.go b/chain/actors/builtin/power/v10.go new file mode 100644 index 000000000..dd7a9decf --- /dev/null +++ b/chain/actors/builtin/power/v10.go @@ -0,0 +1,207 @@ +package power + +import ( + "bytes" + "fmt" + + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + builtin10 "github.com/filecoin-project/go-state-types/builtin" + power10 "github.com/filecoin-project/go-state-types/builtin/v10/power" + adt10 "github.com/filecoin-project/go-state-types/builtin/v10/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store) (State, error) { + out := state10{store: store} + + s, err := power10.ConstructState(store) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state10 struct { + power10.State + store adt.Store +} + +func (s *state10) TotalLocked() (abi.TokenAmount, error) { + return s.TotalPledgeCollateral, nil +} + +func (s *state10) TotalPower() (Claim, error) { + return Claim{ + RawBytePower: s.TotalRawBytePower, + QualityAdjPower: s.TotalQualityAdjPower, + }, nil +} + +// Committed power to the network. Includes miners below the minimum threshold. +func (s *state10) TotalCommitted() (Claim, error) { + return Claim{ + RawBytePower: s.TotalBytesCommitted, + QualityAdjPower: s.TotalQABytesCommitted, + }, nil +} + +func (s *state10) MinerPower(addr address.Address) (Claim, bool, error) { + claims, err := s.claims() + if err != nil { + return Claim{}, false, err + } + var claim power10.Claim + ok, err := claims.Get(abi.AddrKey(addr), &claim) + if err != nil { + return Claim{}, false, err + } + return Claim{ + RawBytePower: claim.RawBytePower, + QualityAdjPower: claim.QualityAdjPower, + }, ok, nil +} + +func (s *state10) MinerNominalPowerMeetsConsensusMinimum(a address.Address) (bool, error) { + return s.State.MinerNominalPowerMeetsConsensusMinimum(s.store, a) +} + +func (s *state10) TotalPowerSmoothed() (builtin.FilterEstimate, error) { + return builtin.FilterEstimate(s.State.ThisEpochQAPowerSmoothed), nil +} + +func (s *state10) MinerCounts() (uint64, uint64, error) { + return uint64(s.State.MinerAboveMinPowerCount), uint64(s.State.MinerCount), nil +} + +func (s *state10) ListAllMiners() ([]address.Address, error) { + claims, err := s.claims() + if err != nil { + return nil, err + } + + var miners []address.Address + err = claims.ForEach(nil, func(k string) error { + a, err := address.NewFromBytes([]byte(k)) + if err != nil { + return err + } + miners = append(miners, a) + return nil + }) + if err != nil { + return nil, err + } + + return miners, nil +} + +func (s *state10) ForEachClaim(cb func(miner address.Address, claim Claim) error) error { + claims, err := s.claims() + if err != nil { + return err + } + + var claim power10.Claim + return claims.ForEach(&claim, func(k string) error { + a, err := address.NewFromBytes([]byte(k)) + if err != nil { + return err + } + return cb(a, Claim{ + RawBytePower: claim.RawBytePower, + QualityAdjPower: claim.QualityAdjPower, + }) + }) +} + +func (s *state10) ClaimsChanged(other State) (bool, error) { + other10, ok := other.(*state10) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.Claims.Equals(other10.State.Claims), nil +} + +func (s *state10) SetTotalQualityAdjPower(p abi.StoragePower) error { + s.State.TotalQualityAdjPower = p + return nil +} + +func (s *state10) SetTotalRawBytePower(p abi.StoragePower) error { + s.State.TotalRawBytePower = p + return nil +} + +func (s *state10) SetThisEpochQualityAdjPower(p abi.StoragePower) error { + s.State.ThisEpochQualityAdjPower = p + return nil +} + +func (s *state10) SetThisEpochRawBytePower(p abi.StoragePower) error { + s.State.ThisEpochRawBytePower = p + return nil +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +func (s *state10) claims() (adt.Map, error) { + return adt10.AsMap(s.store, s.Claims, builtin10.DefaultHamtBitwidth) +} + +func (s *state10) decodeClaim(val *cbg.Deferred) (Claim, error) { + var ci power10.Claim + if err := ci.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return Claim{}, err + } + return fromV10Claim(ci), nil +} + +func fromV10Claim(v10 power10.Claim) Claim { + return Claim{ + RawBytePower: v10.RawBytePower, + QualityAdjPower: v10.QualityAdjPower, + } +} + +func (s *state10) ActorKey() string { + return manifest.PowerKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/power/v2.go b/chain/actors/builtin/power/v2.go index 485819e3e..bac0fa179 100644 --- a/chain/actors/builtin/power/v2.go +++ b/chain/actors/builtin/power/v2.go @@ -2,15 +2,19 @@ package power import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" power2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/power" adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -188,3 +192,20 @@ func fromV2Claim(v2 power2.Claim) Claim { QualityAdjPower: v2.QualityAdjPower, } } + +func (s *state2) ActorKey() string { + return manifest.PowerKey +} + +func (s *state2) ActorVersion() actorstypes.Version { + return actorstypes.Version2 +} + +func (s *state2) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/power/v3.go b/chain/actors/builtin/power/v3.go index e33ee2bb5..bdb66e384 100644 --- a/chain/actors/builtin/power/v3.go +++ b/chain/actors/builtin/power/v3.go @@ -2,16 +2,20 @@ package power import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" power3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/power" adt3 "github.com/filecoin-project/specs-actors/v3/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -184,3 +188,20 @@ func fromV3Claim(v3 power3.Claim) Claim { QualityAdjPower: v3.QualityAdjPower, } } + +func (s *state3) ActorKey() string { + return manifest.PowerKey +} + +func (s *state3) ActorVersion() actorstypes.Version { + return actorstypes.Version3 +} + +func (s *state3) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/power/v4.go b/chain/actors/builtin/power/v4.go index e5c446f07..b2dc95347 100644 --- a/chain/actors/builtin/power/v4.go +++ b/chain/actors/builtin/power/v4.go @@ -2,16 +2,20 @@ package power import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" power4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/power" adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -184,3 +188,20 @@ func fromV4Claim(v4 power4.Claim) Claim { QualityAdjPower: v4.QualityAdjPower, } } + +func (s *state4) ActorKey() string { + return manifest.PowerKey +} + +func (s *state4) ActorVersion() actorstypes.Version { + return actorstypes.Version4 +} + +func (s *state4) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/power/v5.go b/chain/actors/builtin/power/v5.go index aaf248058..3a3adaf32 100644 --- a/chain/actors/builtin/power/v5.go +++ b/chain/actors/builtin/power/v5.go @@ -2,16 +2,20 @@ package power import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" power5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/power" adt5 "github.com/filecoin-project/specs-actors/v5/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -184,3 +188,20 @@ func fromV5Claim(v5 power5.Claim) Claim { QualityAdjPower: v5.QualityAdjPower, } } + +func (s *state5) ActorKey() string { + return manifest.PowerKey +} + +func (s *state5) ActorVersion() actorstypes.Version { + return actorstypes.Version5 +} + +func (s *state5) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/power/v6.go b/chain/actors/builtin/power/v6.go index 072def6e2..7e8eb3654 100644 --- a/chain/actors/builtin/power/v6.go +++ b/chain/actors/builtin/power/v6.go @@ -2,16 +2,20 @@ package power import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" power6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/power" adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -184,3 +188,20 @@ func fromV6Claim(v6 power6.Claim) Claim { QualityAdjPower: v6.QualityAdjPower, } } + +func (s *state6) ActorKey() string { + return manifest.PowerKey +} + +func (s *state6) ActorVersion() actorstypes.Version { + return actorstypes.Version6 +} + +func (s *state6) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/power/v7.go b/chain/actors/builtin/power/v7.go index 0c60b03a0..893c58667 100644 --- a/chain/actors/builtin/power/v7.go +++ b/chain/actors/builtin/power/v7.go @@ -2,16 +2,20 @@ package power import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" power7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/power" adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -184,3 +188,20 @@ func fromV7Claim(v7 power7.Claim) Claim { QualityAdjPower: v7.QualityAdjPower, } } + +func (s *state7) ActorKey() string { + return manifest.PowerKey +} + +func (s *state7) ActorVersion() actorstypes.Version { + return actorstypes.Version7 +} + +func (s *state7) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/power/v8.go b/chain/actors/builtin/power/v8.go index c23da6904..b15fe4355 100644 --- a/chain/actors/builtin/power/v8.go +++ b/chain/actors/builtin/power/v8.go @@ -2,16 +2,20 @@ package power import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" builtin8 "github.com/filecoin-project/go-state-types/builtin" power8 "github.com/filecoin-project/go-state-types/builtin/v8/power" adt8 "github.com/filecoin-project/go-state-types/builtin/v8/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -184,3 +188,20 @@ func fromV8Claim(v8 power8.Claim) Claim { QualityAdjPower: v8.QualityAdjPower, } } + +func (s *state8) ActorKey() string { + return manifest.PowerKey +} + +func (s *state8) ActorVersion() actorstypes.Version { + return actorstypes.Version8 +} + +func (s *state8) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/power/v9.go b/chain/actors/builtin/power/v9.go index 7614b7c2e..126fbbfbf 100644 --- a/chain/actors/builtin/power/v9.go +++ b/chain/actors/builtin/power/v9.go @@ -2,16 +2,20 @@ package power import ( "bytes" + "fmt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" builtin9 "github.com/filecoin-project/go-state-types/builtin" power9 "github.com/filecoin-project/go-state-types/builtin/v9/power" adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -184,3 +188,20 @@ func fromV9Claim(v9 power9.Claim) Claim { QualityAdjPower: v9.QualityAdjPower, } } + +func (s *state9) ActorKey() string { + return manifest.PowerKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/registry.go b/chain/actors/builtin/registry.go index 622bf4185..4ce48098d 100644 --- a/chain/actors/builtin/registry.go +++ b/chain/actors/builtin/registry.go @@ -7,8 +7,25 @@ import ( "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/builtin" + account10 "github.com/filecoin-project/go-state-types/builtin/v10/account" + cron10 "github.com/filecoin-project/go-state-types/builtin/v10/cron" + datacap10 "github.com/filecoin-project/go-state-types/builtin/v10/datacap" + eam10 "github.com/filecoin-project/go-state-types/builtin/v10/eam" + ethaccount10 "github.com/filecoin-project/go-state-types/builtin/v10/ethaccount" + evm10 "github.com/filecoin-project/go-state-types/builtin/v10/evm" + _init10 "github.com/filecoin-project/go-state-types/builtin/v10/init" + market10 "github.com/filecoin-project/go-state-types/builtin/v10/market" + miner10 "github.com/filecoin-project/go-state-types/builtin/v10/miner" + multisig10 "github.com/filecoin-project/go-state-types/builtin/v10/multisig" + paych10 "github.com/filecoin-project/go-state-types/builtin/v10/paych" + placeholder10 "github.com/filecoin-project/go-state-types/builtin/v10/placeholder" + power10 "github.com/filecoin-project/go-state-types/builtin/v10/power" + reward10 "github.com/filecoin-project/go-state-types/builtin/v10/reward" + system10 "github.com/filecoin-project/go-state-types/builtin/v10/system" + verifreg10 "github.com/filecoin-project/go-state-types/builtin/v10/verifreg" account8 "github.com/filecoin-project/go-state-types/builtin/v8/account" cron8 "github.com/filecoin-project/go-state-types/builtin/v8/cron" _init8 "github.com/filecoin-project/go-state-types/builtin/v8/init" @@ -33,6 +50,7 @@ import ( system9 "github.com/filecoin-project/go-state-types/builtin/v9/system" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" rtt "github.com/filecoin-project/go-state-types/rt" "github.com/filecoin-project/lotus/chain/actors" @@ -41,14 +59,14 @@ import ( type RegistryEntry struct { state cbor.Er code cid.Cid - methods map[uint64]builtin.MethodMeta + methods map[abi.MethodNum]builtin.MethodMeta } func (r RegistryEntry) State() cbor.Er { return r.state } -func (r RegistryEntry) Exports() map[uint64]builtin.MethodMeta { +func (r RegistryEntry) Exports() map[abi.MethodNum]builtin.MethodMeta { return r.methods } @@ -60,10 +78,10 @@ func MakeRegistryLegacy(actors []rtt.VMActor) []RegistryEntry { registry := make([]RegistryEntry, 0) for _, actor := range actors { - methodMap := make(map[uint64]builtin.MethodMeta) + methodMap := make(map[abi.MethodNum]builtin.MethodMeta) for methodNum, method := range actor.Exports() { if method != nil { - methodMap[uint64(methodNum)] = makeMethodMeta(method) + methodMap[abi.MethodNum(methodNum)] = makeMethodMeta(method) } } registry = append(registry, RegistryEntry{ @@ -106,67 +124,67 @@ func MakeRegistry(av actorstypes.Version) []RegistryEntry { case actorstypes.Version8: for key, codeID := range codeIDs { switch key { - case actors.AccountKey: + case manifest.AccountKey: registry = append(registry, RegistryEntry{ code: codeID, methods: account8.Methods, state: new(account8.State), }) - case actors.CronKey: + case manifest.CronKey: registry = append(registry, RegistryEntry{ code: codeID, methods: cron8.Methods, state: new(cron8.State), }) - case actors.InitKey: + case manifest.InitKey: registry = append(registry, RegistryEntry{ code: codeID, methods: _init8.Methods, state: new(_init8.State), }) - case actors.MarketKey: + case manifest.MarketKey: registry = append(registry, RegistryEntry{ code: codeID, methods: market8.Methods, state: new(market8.State), }) - case actors.MinerKey: + case manifest.MinerKey: registry = append(registry, RegistryEntry{ code: codeID, methods: miner8.Methods, state: new(miner8.State), }) - case actors.MultisigKey: + case manifest.MultisigKey: registry = append(registry, RegistryEntry{ code: codeID, methods: multisig8.Methods, state: new(multisig8.State), }) - case actors.PaychKey: + case manifest.PaychKey: registry = append(registry, RegistryEntry{ code: codeID, methods: paych8.Methods, state: new(paych8.State), }) - case actors.PowerKey: + case manifest.PowerKey: registry = append(registry, RegistryEntry{ code: codeID, methods: power8.Methods, state: new(power8.State), }) - case actors.RewardKey: + case manifest.RewardKey: registry = append(registry, RegistryEntry{ code: codeID, methods: reward8.Methods, state: new(reward8.State), }) - case actors.SystemKey: + case manifest.SystemKey: registry = append(registry, RegistryEntry{ code: codeID, methods: system8.Methods, state: new(system8.State), }) - case actors.VerifregKey: + case manifest.VerifregKey: registry = append(registry, RegistryEntry{ code: codeID, methods: verifreg8.Methods, @@ -179,78 +197,183 @@ func MakeRegistry(av actorstypes.Version) []RegistryEntry { case actorstypes.Version9: for key, codeID := range codeIDs { switch key { - case actors.AccountKey: + case manifest.AccountKey: registry = append(registry, RegistryEntry{ code: codeID, methods: account9.Methods, state: new(account9.State), }) - case actors.CronKey: + case manifest.CronKey: registry = append(registry, RegistryEntry{ code: codeID, methods: cron9.Methods, state: new(cron9.State), }) - case actors.InitKey: + case manifest.InitKey: registry = append(registry, RegistryEntry{ code: codeID, methods: _init9.Methods, state: new(_init9.State), }) - case actors.MarketKey: + case manifest.MarketKey: registry = append(registry, RegistryEntry{ code: codeID, methods: market9.Methods, state: new(market9.State), }) - case actors.MinerKey: + case manifest.MinerKey: registry = append(registry, RegistryEntry{ code: codeID, methods: miner9.Methods, state: new(miner9.State), }) - case actors.MultisigKey: + case manifest.MultisigKey: registry = append(registry, RegistryEntry{ code: codeID, methods: multisig9.Methods, state: new(multisig9.State), }) - case actors.PaychKey: + case manifest.PaychKey: registry = append(registry, RegistryEntry{ code: codeID, methods: paych9.Methods, state: new(paych9.State), }) - case actors.PowerKey: + case manifest.PowerKey: registry = append(registry, RegistryEntry{ code: codeID, methods: power9.Methods, state: new(power9.State), }) - case actors.RewardKey: + case manifest.RewardKey: registry = append(registry, RegistryEntry{ code: codeID, methods: reward9.Methods, state: new(reward9.State), }) - case actors.SystemKey: + case manifest.SystemKey: registry = append(registry, RegistryEntry{ code: codeID, methods: system9.Methods, state: new(system9.State), }) - case actors.VerifregKey: + case manifest.VerifregKey: registry = append(registry, RegistryEntry{ code: codeID, methods: verifreg9.Methods, state: new(verifreg9.State), }) - case actors.DatacapKey: + case manifest.DatacapKey: registry = append(registry, RegistryEntry{ code: codeID, methods: datacap9.Methods, state: new(datacap9.State), }) + + } + } + + case actorstypes.Version10: + for key, codeID := range codeIDs { + switch key { + case manifest.AccountKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: account10.Methods, + state: new(account10.State), + }) + case manifest.CronKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: cron10.Methods, + state: new(cron10.State), + }) + case manifest.InitKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: _init10.Methods, + state: new(_init10.State), + }) + case manifest.MarketKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: market10.Methods, + state: new(market10.State), + }) + case manifest.MinerKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: miner10.Methods, + state: new(miner10.State), + }) + case manifest.MultisigKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: multisig10.Methods, + state: new(multisig10.State), + }) + case manifest.PaychKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: paych10.Methods, + state: new(paych10.State), + }) + case manifest.PowerKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: power10.Methods, + state: new(power10.State), + }) + case manifest.RewardKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: reward10.Methods, + state: new(reward10.State), + }) + case manifest.SystemKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: system10.Methods, + state: new(system10.State), + }) + case manifest.VerifregKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: verifreg10.Methods, + state: new(verifreg10.State), + }) + case manifest.DatacapKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: datacap10.Methods, + state: new(datacap10.State), + }) + + case manifest.EvmKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: evm10.Methods, + state: new(evm10.State), + }) + case manifest.EamKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: eam10.Methods, + state: nil, + }) + case manifest.PlaceholderKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: placeholder10.Methods, + state: nil, + }) + case manifest.EthAccountKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: ethaccount10.Methods, + state: nil, + }) + } } diff --git a/chain/actors/builtin/registry.go.template b/chain/actors/builtin/registry.go.template index 39211c476..a63b00917 100644 --- a/chain/actors/builtin/registry.go.template +++ b/chain/actors/builtin/registry.go.template @@ -25,23 +25,31 @@ import ( {{if (ge . 9)}} datacap{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/datacap" {{end}} + {{if (ge . 10)}} + evm{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/evm" + eam{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/eam" + placeholder{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/placeholder" + ethaccount{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/ethaccount" + {{end}} {{end}} "github.com/filecoin-project/go-state-types/cbor" rtt "github.com/filecoin-project/go-state-types/rt" "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/manifest" ) type RegistryEntry struct { state cbor.Er code cid.Cid - methods map[uint64]builtin.MethodMeta + methods map[abi.MethodNum]builtin.MethodMeta } func (r RegistryEntry) State() cbor.Er { return r.state } -func (r RegistryEntry) Exports() map[uint64]builtin.MethodMeta { +func (r RegistryEntry) Exports() map[abi.MethodNum]builtin.MethodMeta { return r.methods } @@ -53,10 +61,10 @@ func MakeRegistryLegacy(actors []rtt.VMActor) []RegistryEntry { registry := make([]RegistryEntry, 0) for _, actor := range actors { - methodMap := make(map[uint64]builtin.MethodMeta) + methodMap := make(map[abi.MethodNum]builtin.MethodMeta) for methodNum, method := range actor.Exports() { if method != nil { - methodMap[uint64(methodNum)] = makeMethodMeta(method) + methodMap[abi.MethodNum(methodNum)] = makeMethodMeta(method) } } registry = append(registry, RegistryEntry{ @@ -100,78 +108,104 @@ func MakeRegistry(av actorstypes.Version) []RegistryEntry { case actorstypes.Version{{.}}: for key, codeID := range codeIDs { switch key { - case actors.AccountKey: + case manifest.AccountKey: registry = append(registry, RegistryEntry{ code: codeID, methods: account{{.}}.Methods, state: new(account{{.}}.State), }) - case actors.CronKey: + case manifest.CronKey: registry = append(registry, RegistryEntry{ code: codeID, methods: cron{{.}}.Methods, state: new(cron{{.}}.State), }) - case actors.InitKey: + case manifest.InitKey: registry = append(registry, RegistryEntry{ code: codeID, methods: _init{{.}}.Methods, state: new(_init{{.}}.State), }) - case actors.MarketKey: + case manifest.MarketKey: registry = append(registry, RegistryEntry{ code: codeID, methods: market{{.}}.Methods, state: new(market{{.}}.State), }) - case actors.MinerKey: + case manifest.MinerKey: registry = append(registry, RegistryEntry{ code: codeID, methods: miner{{.}}.Methods, state: new(miner{{.}}.State), }) - case actors.MultisigKey: + case manifest.MultisigKey: registry = append(registry, RegistryEntry{ code: codeID, methods: multisig{{.}}.Methods, state: new(multisig{{.}}.State), }) - case actors.PaychKey: + case manifest.PaychKey: registry = append(registry, RegistryEntry{ code: codeID, methods: paych{{.}}.Methods, state: new(paych{{.}}.State), }) - case actors.PowerKey: + case manifest.PowerKey: registry = append(registry, RegistryEntry{ code: codeID, methods: power{{.}}.Methods, state: new(power{{.}}.State), }) - case actors.RewardKey: + case manifest.RewardKey: registry = append(registry, RegistryEntry{ code: codeID, methods: reward{{.}}.Methods, state: new(reward{{.}}.State), }) - case actors.SystemKey: + case manifest.SystemKey: registry = append(registry, RegistryEntry{ code: codeID, methods: system{{.}}.Methods, state: new(system{{.}}.State), }) - case actors.VerifregKey: + case manifest.VerifregKey: registry = append(registry, RegistryEntry{ code: codeID, methods: verifreg{{.}}.Methods, state: new(verifreg{{.}}.State), }) - {{if (ge . 9)}}case actors.DatacapKey: + {{if (ge . 9)}}case manifest.DatacapKey: registry = append(registry, RegistryEntry{ code: codeID, methods: datacap{{.}}.Methods, state: new(datacap{{.}}.State), }){{end}} + {{if (ge . 10)}} + case manifest.EvmKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: evm{{.}}.Methods, + state: new(evm{{.}}.State), + }) + case manifest.EamKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: eam{{.}}.Methods, + state: nil, + }) + case manifest.PlaceholderKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: placeholder{{.}}.Methods, + state: nil, + }) + case manifest.EthAccountKey: + registry = append(registry, RegistryEntry{ + code: codeID, + methods: ethaccount{{.}}.Methods, + state: nil, + }) + {{end}} } } {{end}} diff --git a/chain/actors/builtin/reward/actor.go.template b/chain/actors/builtin/reward/actor.go.template index 165f9efdf..81bf91ac3 100644 --- a/chain/actors/builtin/reward/actor.go.template +++ b/chain/actors/builtin/reward/actor.go.template @@ -1,6 +1,7 @@ package reward import ( + "github.com/ipfs/go-cid" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/abi" reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" @@ -18,6 +19,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/go-state-types/manifest" ) var ( @@ -27,7 +29,7 @@ var ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.RewardKey { + if name != manifest.RewardKey { return nil, xerrors.Errorf("actor code is not reward: %s", name) } @@ -66,6 +68,10 @@ func MakeState(store adt.Store, av actorstypes.Version, currRealizedPower abi.St type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + ThisEpochBaselinePower() (abi.StoragePower, error) ThisEpochReward() (abi.StoragePower, error) ThisEpochRewardSmoothed() (builtin.FilterEstimate, error) @@ -84,3 +90,10 @@ type State interface { } type AwardBlockRewardParams = reward0.AwardBlockRewardParams + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } +} diff --git a/chain/actors/builtin/reward/reward.go b/chain/actors/builtin/reward/reward.go index 6902b258e..01462d680 100644 --- a/chain/actors/builtin/reward/reward.go +++ b/chain/actors/builtin/reward/reward.go @@ -1,12 +1,14 @@ package reward import ( + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" - builtin9 "github.com/filecoin-project/go-state-types/builtin" + builtin10 "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" @@ -23,13 +25,13 @@ import ( ) var ( - Address = builtin9.RewardActorAddr - Methods = builtin9.MethodsReward + Address = builtin10.RewardActorAddr + Methods = builtin10.MethodsReward ) func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.RewardKey { + if name != manifest.RewardKey { return nil, xerrors.Errorf("actor code is not reward: %s", name) } @@ -41,6 +43,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -102,6 +107,9 @@ func MakeState(store adt.Store, av actorstypes.Version, currRealizedPower abi.St case actorstypes.Version9: return make9(store, currRealizedPower) + case actorstypes.Version10: + return make10(store, currRealizedPower) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -109,6 +117,10 @@ func MakeState(store adt.Store, av actorstypes.Version, currRealizedPower abi.St type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + ThisEpochBaselinePower() (abi.StoragePower, error) ThisEpochReward() (abi.StoragePower, error) ThisEpochRewardSmoothed() (builtin.FilterEstimate, error) @@ -127,3 +139,18 @@ type State interface { } type AwardBlockRewardParams = reward0.AwardBlockRewardParams + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state0{}).Code(), + (&state2{}).Code(), + (&state3{}).Code(), + (&state4{}).Code(), + (&state5{}).Code(), + (&state6{}).Code(), + (&state7{}).Code(), + (&state8{}).Code(), + (&state9{}).Code(), + (&state10{}).Code(), + } +} diff --git a/chain/actors/builtin/reward/state.go.template b/chain/actors/builtin/reward/state.go.template index dac3d82a4..28ddb80f0 100644 --- a/chain/actors/builtin/reward/state.go.template +++ b/chain/actors/builtin/reward/state.go.template @@ -1,11 +1,15 @@ package reward import ( + "fmt" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/go-state-types/manifest" {{if (le .v 7)}} miner{{.v}} "github.com/filecoin-project/specs-actors{{.import}}actors/builtin/miner" @@ -117,3 +121,20 @@ func (s *state{{.v}}) PreCommitDepositForPower(networkQAPower builtin.FilterEsti func (s *state{{.v}}) GetState() interface{} { return &s.State } + +func (s *state{{.v}}) ActorKey() string { + return manifest.RewardKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/reward/v0.go b/chain/actors/builtin/reward/v0.go index 12bdee054..66736f9e0 100644 --- a/chain/actors/builtin/reward/v0.go +++ b/chain/actors/builtin/reward/v0.go @@ -1,13 +1,18 @@ package reward import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -93,3 +98,20 @@ func (s *state0) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, func (s *state0) GetState() interface{} { return &s.State } + +func (s *state0) ActorKey() string { + return manifest.RewardKey +} + +func (s *state0) ActorVersion() actorstypes.Version { + return actorstypes.Version0 +} + +func (s *state0) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/reward/v10.go b/chain/actors/builtin/reward/v10.go new file mode 100644 index 000000000..3ffe9a267 --- /dev/null +++ b/chain/actors/builtin/reward/v10.go @@ -0,0 +1,120 @@ +package reward + +import ( + "fmt" + + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + miner10 "github.com/filecoin-project/go-state-types/builtin/v10/miner" + reward10 "github.com/filecoin-project/go-state-types/builtin/v10/reward" + smoothing10 "github.com/filecoin-project/go-state-types/builtin/v10/util/smoothing" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store, currRealizedPower abi.StoragePower) (State, error) { + out := state10{store: store} + out.State = *reward10.ConstructState(currRealizedPower) + return &out, nil +} + +type state10 struct { + reward10.State + store adt.Store +} + +func (s *state10) ThisEpochReward() (abi.TokenAmount, error) { + return s.State.ThisEpochReward, nil +} + +func (s *state10) ThisEpochRewardSmoothed() (builtin.FilterEstimate, error) { + + return builtin.FilterEstimate{ + PositionEstimate: s.State.ThisEpochRewardSmoothed.PositionEstimate, + VelocityEstimate: s.State.ThisEpochRewardSmoothed.VelocityEstimate, + }, nil + +} + +func (s *state10) ThisEpochBaselinePower() (abi.StoragePower, error) { + return s.State.ThisEpochBaselinePower, nil +} + +func (s *state10) TotalStoragePowerReward() (abi.TokenAmount, error) { + return s.State.TotalStoragePowerReward, nil +} + +func (s *state10) EffectiveBaselinePower() (abi.StoragePower, error) { + return s.State.EffectiveBaselinePower, nil +} + +func (s *state10) EffectiveNetworkTime() (abi.ChainEpoch, error) { + return s.State.EffectiveNetworkTime, nil +} + +func (s *state10) CumsumBaseline() (reward10.Spacetime, error) { + return s.State.CumsumBaseline, nil +} + +func (s *state10) CumsumRealized() (reward10.Spacetime, error) { + return s.State.CumsumRealized, nil +} + +func (s *state10) InitialPledgeForPower(qaPower abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) { + return miner10.InitialPledgeForPower( + qaPower, + s.State.ThisEpochBaselinePower, + s.State.ThisEpochRewardSmoothed, + smoothing10.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + circSupply, + ), nil +} + +func (s *state10) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) { + return miner10.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed, + smoothing10.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + sectorWeight), nil +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +func (s *state10) ActorKey() string { + return manifest.RewardKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/reward/v2.go b/chain/actors/builtin/reward/v2.go index ed2481635..6d640f2e9 100644 --- a/chain/actors/builtin/reward/v2.go +++ b/chain/actors/builtin/reward/v2.go @@ -1,13 +1,18 @@ package reward import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" reward2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/reward" smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -96,3 +101,20 @@ func (s *state2) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, func (s *state2) GetState() interface{} { return &s.State } + +func (s *state2) ActorKey() string { + return manifest.RewardKey +} + +func (s *state2) ActorVersion() actorstypes.Version { + return actorstypes.Version2 +} + +func (s *state2) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/reward/v3.go b/chain/actors/builtin/reward/v3.go index d9f4bf369..fe8e555c9 100644 --- a/chain/actors/builtin/reward/v3.go +++ b/chain/actors/builtin/reward/v3.go @@ -1,13 +1,18 @@ package reward import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" miner3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/miner" reward3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/reward" smoothing3 "github.com/filecoin-project/specs-actors/v3/actors/util/smoothing" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -96,3 +101,20 @@ func (s *state3) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, func (s *state3) GetState() interface{} { return &s.State } + +func (s *state3) ActorKey() string { + return manifest.RewardKey +} + +func (s *state3) ActorVersion() actorstypes.Version { + return actorstypes.Version3 +} + +func (s *state3) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/reward/v4.go b/chain/actors/builtin/reward/v4.go index 160c72ce7..f0decd392 100644 --- a/chain/actors/builtin/reward/v4.go +++ b/chain/actors/builtin/reward/v4.go @@ -1,13 +1,18 @@ package reward import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" miner4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" reward4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/reward" smoothing4 "github.com/filecoin-project/specs-actors/v4/actors/util/smoothing" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -96,3 +101,20 @@ func (s *state4) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, func (s *state4) GetState() interface{} { return &s.State } + +func (s *state4) ActorKey() string { + return manifest.RewardKey +} + +func (s *state4) ActorVersion() actorstypes.Version { + return actorstypes.Version4 +} + +func (s *state4) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/reward/v5.go b/chain/actors/builtin/reward/v5.go index 838ec8f21..82be12c0a 100644 --- a/chain/actors/builtin/reward/v5.go +++ b/chain/actors/builtin/reward/v5.go @@ -1,13 +1,18 @@ package reward import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner" reward5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/reward" smoothing5 "github.com/filecoin-project/specs-actors/v5/actors/util/smoothing" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -96,3 +101,20 @@ func (s *state5) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, func (s *state5) GetState() interface{} { return &s.State } + +func (s *state5) ActorKey() string { + return manifest.RewardKey +} + +func (s *state5) ActorVersion() actorstypes.Version { + return actorstypes.Version5 +} + +func (s *state5) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/reward/v6.go b/chain/actors/builtin/reward/v6.go index e056b22f6..71884dada 100644 --- a/chain/actors/builtin/reward/v6.go +++ b/chain/actors/builtin/reward/v6.go @@ -1,13 +1,18 @@ package reward import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" reward6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/reward" smoothing6 "github.com/filecoin-project/specs-actors/v6/actors/util/smoothing" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -96,3 +101,20 @@ func (s *state6) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, func (s *state6) GetState() interface{} { return &s.State } + +func (s *state6) ActorKey() string { + return manifest.RewardKey +} + +func (s *state6) ActorVersion() actorstypes.Version { + return actorstypes.Version6 +} + +func (s *state6) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/reward/v7.go b/chain/actors/builtin/reward/v7.go index 5fedaa43c..bc39f3666 100644 --- a/chain/actors/builtin/reward/v7.go +++ b/chain/actors/builtin/reward/v7.go @@ -1,13 +1,18 @@ package reward import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" miner7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/miner" reward7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/reward" smoothing7 "github.com/filecoin-project/specs-actors/v7/actors/util/smoothing" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -96,3 +101,20 @@ func (s *state7) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, func (s *state7) GetState() interface{} { return &s.State } + +func (s *state7) ActorKey() string { + return manifest.RewardKey +} + +func (s *state7) ActorVersion() actorstypes.Version { + return actorstypes.Version7 +} + +func (s *state7) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/reward/v8.go b/chain/actors/builtin/reward/v8.go index ecc5a94ba..5f6b96d29 100644 --- a/chain/actors/builtin/reward/v8.go +++ b/chain/actors/builtin/reward/v8.go @@ -1,13 +1,18 @@ package reward import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" miner8 "github.com/filecoin-project/go-state-types/builtin/v8/miner" reward8 "github.com/filecoin-project/go-state-types/builtin/v8/reward" smoothing8 "github.com/filecoin-project/go-state-types/builtin/v8/util/smoothing" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -96,3 +101,20 @@ func (s *state8) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, func (s *state8) GetState() interface{} { return &s.State } + +func (s *state8) ActorKey() string { + return manifest.RewardKey +} + +func (s *state8) ActorVersion() actorstypes.Version { + return actorstypes.Version8 +} + +func (s *state8) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/reward/v9.go b/chain/actors/builtin/reward/v9.go index 04da532d2..6118e2b30 100644 --- a/chain/actors/builtin/reward/v9.go +++ b/chain/actors/builtin/reward/v9.go @@ -1,13 +1,18 @@ package reward import ( + "fmt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" miner9 "github.com/filecoin-project/go-state-types/builtin/v9/miner" reward9 "github.com/filecoin-project/go-state-types/builtin/v9/reward" smoothing9 "github.com/filecoin-project/go-state-types/builtin/v9/util/smoothing" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" ) @@ -96,3 +101,20 @@ func (s *state9) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, func (s *state9) GetState() interface{} { return &s.State } + +func (s *state9) ActorKey() string { + return manifest.RewardKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/system/actor.go.template b/chain/actors/builtin/system/actor.go.template index 0ef41e775..b725f0820 100644 --- a/chain/actors/builtin/system/actor.go.template +++ b/chain/actors/builtin/system/actor.go.template @@ -1,7 +1,9 @@ package system import ( + "github.com/ipfs/go-cid" actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" @@ -23,7 +25,7 @@ var ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.SystemKey { + if name != manifest.SystemKey { return nil, xerrors.Errorf("actor code is not system: %s", name) } @@ -60,7 +62,18 @@ func MakeState(store adt.Store, av actorstypes.Version, builtinActors cid.Cid) ( } type State interface { + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + GetState() interface{} GetBuiltinActors() cid.Cid SetBuiltinActors(cid.Cid) error } + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } +} diff --git a/chain/actors/builtin/system/state.go.template b/chain/actors/builtin/system/state.go.template index f8d9addf7..c6cab0583 100644 --- a/chain/actors/builtin/system/state.go.template +++ b/chain/actors/builtin/system/state.go.template @@ -1,9 +1,14 @@ package system import ( + "fmt" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/ipfs/go-cid" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors" {{if (le .v 7)}} system{{.v}} "github.com/filecoin-project/specs-actors{{.import}}actors/builtin/system" @@ -56,4 +61,21 @@ func (s *state{{.v}}) SetBuiltinActors(c cid.Cid) error { s.State.BuiltinActors = c return nil {{end}} -} \ No newline at end of file +} + +func (s *state{{.v}}) ActorKey() string { + return manifest.SystemKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/system/system.go b/chain/actors/builtin/system/system.go index 4c99d90eb..c7589efa1 100644 --- a/chain/actors/builtin/system/system.go +++ b/chain/actors/builtin/system/system.go @@ -5,7 +5,8 @@ import ( "golang.org/x/xerrors" actorstypes "github.com/filecoin-project/go-state-types/actors" - builtin9 "github.com/filecoin-project/go-state-types/builtin" + builtin10 "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/manifest" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" @@ -20,12 +21,12 @@ import ( ) var ( - Address = builtin9.SystemActorAddr + Address = builtin10.SystemActorAddr ) func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.SystemKey { + if name != manifest.SystemKey { return nil, xerrors.Errorf("actor code is not system: %s", name) } @@ -37,6 +38,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -98,12 +102,34 @@ func MakeState(store adt.Store, av actorstypes.Version, builtinActors cid.Cid) ( case actorstypes.Version9: return make9(store, builtinActors) + case actorstypes.Version10: + return make10(store, builtinActors) + } return nil, xerrors.Errorf("unknown actor version %d", av) } type State interface { + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + GetState() interface{} GetBuiltinActors() cid.Cid SetBuiltinActors(cid.Cid) error } + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state0{}).Code(), + (&state2{}).Code(), + (&state3{}).Code(), + (&state4{}).Code(), + (&state5{}).Code(), + (&state6{}).Code(), + (&state7{}).Code(), + (&state8{}).Code(), + (&state9{}).Code(), + (&state10{}).Code(), + } +} diff --git a/chain/actors/builtin/system/v0.go b/chain/actors/builtin/system/v0.go index 78e578896..d5f0f079e 100644 --- a/chain/actors/builtin/system/v0.go +++ b/chain/actors/builtin/system/v0.go @@ -1,11 +1,16 @@ package system import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" system0 "github.com/filecoin-project/specs-actors/actors/builtin/system" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -46,3 +51,20 @@ func (s *state0) SetBuiltinActors(c cid.Cid) error { return xerrors.New("cannot set manifest cid before v8") } + +func (s *state0) ActorKey() string { + return manifest.SystemKey +} + +func (s *state0) ActorVersion() actorstypes.Version { + return actorstypes.Version0 +} + +func (s *state0) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/system/v10.go b/chain/actors/builtin/system/v10.go new file mode 100644 index 000000000..2cdb39682 --- /dev/null +++ b/chain/actors/builtin/system/v10.go @@ -0,0 +1,72 @@ +package system + +import ( + "fmt" + + "github.com/ipfs/go-cid" + + actorstypes "github.com/filecoin-project/go-state-types/actors" + system10 "github.com/filecoin-project/go-state-types/builtin/v10/system" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store, builtinActors cid.Cid) (State, error) { + out := state10{store: store} + out.State = system10.State{ + BuiltinActors: builtinActors, + } + return &out, nil +} + +type state10 struct { + system10.State + store adt.Store +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +func (s *state10) GetBuiltinActors() cid.Cid { + + return s.State.BuiltinActors + +} + +func (s *state10) SetBuiltinActors(c cid.Cid) error { + + s.State.BuiltinActors = c + return nil + +} + +func (s *state10) ActorKey() string { + return manifest.SystemKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/system/v2.go b/chain/actors/builtin/system/v2.go index 21dfa5c78..b0c642054 100644 --- a/chain/actors/builtin/system/v2.go +++ b/chain/actors/builtin/system/v2.go @@ -1,11 +1,16 @@ package system import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" system2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/system" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -46,3 +51,20 @@ func (s *state2) SetBuiltinActors(c cid.Cid) error { return xerrors.New("cannot set manifest cid before v8") } + +func (s *state2) ActorKey() string { + return manifest.SystemKey +} + +func (s *state2) ActorVersion() actorstypes.Version { + return actorstypes.Version2 +} + +func (s *state2) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/system/v3.go b/chain/actors/builtin/system/v3.go index ccf8aa2c3..8334f780e 100644 --- a/chain/actors/builtin/system/v3.go +++ b/chain/actors/builtin/system/v3.go @@ -1,11 +1,16 @@ package system import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" system3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/system" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -46,3 +51,20 @@ func (s *state3) SetBuiltinActors(c cid.Cid) error { return xerrors.New("cannot set manifest cid before v8") } + +func (s *state3) ActorKey() string { + return manifest.SystemKey +} + +func (s *state3) ActorVersion() actorstypes.Version { + return actorstypes.Version3 +} + +func (s *state3) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/system/v4.go b/chain/actors/builtin/system/v4.go index bcb120be2..227104f37 100644 --- a/chain/actors/builtin/system/v4.go +++ b/chain/actors/builtin/system/v4.go @@ -1,11 +1,16 @@ package system import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" system4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/system" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -46,3 +51,20 @@ func (s *state4) SetBuiltinActors(c cid.Cid) error { return xerrors.New("cannot set manifest cid before v8") } + +func (s *state4) ActorKey() string { + return manifest.SystemKey +} + +func (s *state4) ActorVersion() actorstypes.Version { + return actorstypes.Version4 +} + +func (s *state4) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/system/v5.go b/chain/actors/builtin/system/v5.go index 182883398..bbfb70b51 100644 --- a/chain/actors/builtin/system/v5.go +++ b/chain/actors/builtin/system/v5.go @@ -1,11 +1,16 @@ package system import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" system5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/system" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -46,3 +51,20 @@ func (s *state5) SetBuiltinActors(c cid.Cid) error { return xerrors.New("cannot set manifest cid before v8") } + +func (s *state5) ActorKey() string { + return manifest.SystemKey +} + +func (s *state5) ActorVersion() actorstypes.Version { + return actorstypes.Version5 +} + +func (s *state5) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/system/v6.go b/chain/actors/builtin/system/v6.go index 9860ce373..2319b5929 100644 --- a/chain/actors/builtin/system/v6.go +++ b/chain/actors/builtin/system/v6.go @@ -1,11 +1,16 @@ package system import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" system6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/system" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -46,3 +51,20 @@ func (s *state6) SetBuiltinActors(c cid.Cid) error { return xerrors.New("cannot set manifest cid before v8") } + +func (s *state6) ActorKey() string { + return manifest.SystemKey +} + +func (s *state6) ActorVersion() actorstypes.Version { + return actorstypes.Version6 +} + +func (s *state6) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/system/v7.go b/chain/actors/builtin/system/v7.go index 5984b0b4d..0b10129e8 100644 --- a/chain/actors/builtin/system/v7.go +++ b/chain/actors/builtin/system/v7.go @@ -1,11 +1,16 @@ package system import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" system7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/system" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -46,3 +51,20 @@ func (s *state7) SetBuiltinActors(c cid.Cid) error { return xerrors.New("cannot set manifest cid before v8") } + +func (s *state7) ActorKey() string { + return manifest.SystemKey +} + +func (s *state7) ActorVersion() actorstypes.Version { + return actorstypes.Version7 +} + +func (s *state7) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/system/v8.go b/chain/actors/builtin/system/v8.go index 574df9c44..eca3b0c04 100644 --- a/chain/actors/builtin/system/v8.go +++ b/chain/actors/builtin/system/v8.go @@ -1,10 +1,15 @@ package system import ( + "fmt" + "github.com/ipfs/go-cid" + actorstypes "github.com/filecoin-project/go-state-types/actors" system8 "github.com/filecoin-project/go-state-types/builtin/v8/system" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -48,3 +53,20 @@ func (s *state8) SetBuiltinActors(c cid.Cid) error { return nil } + +func (s *state8) ActorKey() string { + return manifest.SystemKey +} + +func (s *state8) ActorVersion() actorstypes.Version { + return actorstypes.Version8 +} + +func (s *state8) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/system/v9.go b/chain/actors/builtin/system/v9.go index 40555a921..55e073efe 100644 --- a/chain/actors/builtin/system/v9.go +++ b/chain/actors/builtin/system/v9.go @@ -1,10 +1,15 @@ package system import ( + "fmt" + "github.com/ipfs/go-cid" + actorstypes "github.com/filecoin-project/go-state-types/actors" system9 "github.com/filecoin-project/go-state-types/builtin/v9/system" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" ) @@ -48,3 +53,20 @@ func (s *state9) SetBuiltinActors(c cid.Cid) error { return nil } + +func (s *state9) ActorKey() string { + return manifest.SystemKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/verifreg/actor.go.template b/chain/actors/builtin/verifreg/actor.go.template index 5c7715e3d..9f9efef92 100644 --- a/chain/actors/builtin/verifreg/actor.go.template +++ b/chain/actors/builtin/verifreg/actor.go.template @@ -1,7 +1,9 @@ package verifreg import ( + "github.com/ipfs/go-cid" actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" @@ -28,7 +30,7 @@ var ( func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.VerifregKey { + if name != manifest.VerifregKey { return nil, xerrors.Errorf("actor code is not verifreg: %s", name) } @@ -67,15 +69,31 @@ func MakeState(store adt.Store, av actorstypes.Version, rootKeyAddress address.A type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + RootKey() (address.Address, error) VerifiedClientDataCap(address.Address) (bool, abi.StoragePower, error) VerifierDataCap(address.Address) (bool, abi.StoragePower, error) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) ForEachVerifier(func(addr address.Address, dcap abi.StoragePower) error) error ForEachClient(func(addr address.Address, dcap abi.StoragePower) error) error - GetAllocation(clientIdAddr address.Address, allocationId verifregtypes.AllocationId) (*verifregtypes.Allocation, bool, error) - GetAllocations(clientIdAddr address.Address) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) - GetClaim(providerIdAddr address.Address, claimId verifregtypes.ClaimId) (*verifregtypes.Claim, bool, error) - GetClaims(providerIdAddr address.Address) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) + GetAllocation(clientIdAddr address.Address, allocationId AllocationId) (*Allocation, bool, error) + GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) + GetClaim(providerIdAddr address.Address, claimId ClaimId) (*Claim, bool, error) + GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) GetState() interface{} } + +func AllCodes() []cid.Cid { + return []cid.Cid{ {{range .versions}} + (&state{{.}}{}).Code(), + {{- end}} + } +} + +type Allocation = verifregtypes.Allocation +type AllocationId = verifregtypes.AllocationId +type Claim = verifregtypes.Claim +type ClaimId = verifregtypes.ClaimId \ No newline at end of file diff --git a/chain/actors/builtin/verifreg/state.go.template b/chain/actors/builtin/verifreg/state.go.template index cc3c2a781..526dff54e 100644 --- a/chain/actors/builtin/verifreg/state.go.template +++ b/chain/actors/builtin/verifreg/state.go.template @@ -1,6 +1,9 @@ package verifreg import ( + "fmt" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" @@ -22,6 +25,9 @@ import ( {{end}} {{if (ge .v 9)}} "github.com/filecoin-project/go-state-types/big" +{{if (gt .v 9)}} + verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" +{{end}} {{else}} verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" {{end}} @@ -116,34 +122,67 @@ func (s *state{{.v}}) GetState() interface{} { return &s.State } -func (s *state{{.v}}) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*verifreg9.Allocation, bool, error) { +func (s *state{{.v}}) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*Allocation, bool, error) { {{if (le .v 8)}} return nil, false, xerrors.Errorf("unsupported in actors v{{.v}}") {{else}} - return s.FindAllocation(s.store, clientIdAddr, allocationId) -{{end}} + alloc, ok, err := s.FindAllocation(s.store, clientIdAddr, verifreg{{.v}}.AllocationId(allocationId)) + return (*Allocation)(alloc), ok, err{{end}} } -func (s *state{{.v}}) GetAllocations(clientIdAddr address.Address) (map[verifreg9.AllocationId]verifreg9.Allocation, error) { +func (s *state{{.v}}) GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) { {{if (le .v 8)}} return nil, xerrors.Errorf("unsupported in actors v{{.v}}") {{else}} - return s.LoadAllocationsToMap(s.store, clientIdAddr) + v{{.v}}Map, err := s.LoadAllocationsToMap(s.store, clientIdAddr) + + retMap := make(map[AllocationId]Allocation, len(v{{.v}}Map)) + for k, v := range v{{.v}}Map { + retMap[AllocationId(k)] = Allocation(v) + } + + return retMap, err {{end}} } -func (s *state{{.v}}) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*verifreg9.Claim, bool, error) { +func (s *state{{.v}}) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*Claim, bool, error) { {{if (le .v 8)}} return nil, false, xerrors.Errorf("unsupported in actors v{{.v}}") {{else}} - return s.FindClaim(s.store, providerIdAddr, claimId) + claim, ok, err := s.FindClaim(s.store, providerIdAddr, verifreg{{.v}}.ClaimId(claimId)) + return (*Claim)(claim), ok, err {{end}} } -func (s *state{{.v}}) GetClaims(providerIdAddr address.Address) (map[verifreg9.ClaimId]verifreg9.Claim, error) { +func (s *state{{.v}}) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) { {{if (le .v 8)}} return nil, xerrors.Errorf("unsupported in actors v{{.v}}") {{else}} - return s.LoadClaimsToMap(s.store, providerIdAddr) + v{{.v}}Map, err := s.LoadClaimsToMap(s.store, providerIdAddr) + + retMap := make(map[ClaimId]Claim, len(v{{.v}}Map)) + for k, v := range v{{.v}}Map { + retMap[ClaimId(k)] = Claim(v) + } + + return retMap, err + {{end}} } + +func (s *state{{.v}}) ActorKey() string { + return manifest.VerifregKey +} + +func (s *state{{.v}}) ActorVersion() actorstypes.Version { + return actorstypes.Version{{.v}} +} + +func (s *state{{.v}}) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/verifreg/v0.go b/chain/actors/builtin/verifreg/v0.go index debe32125..8d97ebbc2 100644 --- a/chain/actors/builtin/verifreg/v0.go +++ b/chain/actors/builtin/verifreg/v0.go @@ -1,12 +1,16 @@ package verifreg import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" @@ -90,26 +94,43 @@ func (s *state0) GetState() interface{} { return &s.State } -func (s *state0) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*verifreg9.Allocation, bool, error) { +func (s *state0) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*Allocation, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v0") } -func (s *state0) GetAllocations(clientIdAddr address.Address) (map[verifreg9.AllocationId]verifreg9.Allocation, error) { +func (s *state0) GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) { return nil, xerrors.Errorf("unsupported in actors v0") } -func (s *state0) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*verifreg9.Claim, bool, error) { +func (s *state0) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*Claim, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v0") } -func (s *state0) GetClaims(providerIdAddr address.Address) (map[verifreg9.ClaimId]verifreg9.Claim, error) { +func (s *state0) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) { return nil, xerrors.Errorf("unsupported in actors v0") } + +func (s *state0) ActorKey() string { + return manifest.VerifregKey +} + +func (s *state0) ActorVersion() actorstypes.Version { + return actorstypes.Version0 +} + +func (s *state0) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/verifreg/v10.go b/chain/actors/builtin/verifreg/v10.go new file mode 100644 index 000000000..63b161da3 --- /dev/null +++ b/chain/actors/builtin/verifreg/v10.go @@ -0,0 +1,152 @@ +package verifreg + +import ( + "fmt" + + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/big" + builtin10 "github.com/filecoin-project/go-state-types/builtin" + adt10 "github.com/filecoin-project/go-state-types/builtin/v10/util/adt" + verifreg10 "github.com/filecoin-project/go-state-types/builtin/v10/verifreg" + verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" +) + +var _ State = (*state10)(nil) + +func load10(store adt.Store, root cid.Cid) (State, error) { + out := state10{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make10(store adt.Store, rootKeyAddress address.Address) (State, error) { + out := state10{store: store} + + s, err := verifreg10.ConstructState(store, rootKeyAddress) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state10 struct { + verifreg10.State + store adt.Store +} + +func (s *state10) RootKey() (address.Address, error) { + return s.State.RootKey, nil +} + +func (s *state10) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) { + + return false, big.Zero(), xerrors.Errorf("unsupported in actors v10") + +} + +func (s *state10) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, actors.Version10, s.verifiers, addr) +} + +func (s *state10) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version10, s.removeDataCapProposalIDs, verifier, client) +} + +func (s *state10) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachCap(s.store, actors.Version10, s.verifiers, cb) +} + +func (s *state10) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error { + + return xerrors.Errorf("unsupported in actors v10") + +} + +func (s *state10) verifiedClients() (adt.Map, error) { + + return nil, xerrors.Errorf("unsupported in actors v10") + +} + +func (s *state10) verifiers() (adt.Map, error) { + return adt10.AsMap(s.store, s.Verifiers, builtin10.DefaultHamtBitwidth) +} + +func (s *state10) removeDataCapProposalIDs() (adt.Map, error) { + return adt10.AsMap(s.store, s.RemoveDataCapProposalIDs, builtin10.DefaultHamtBitwidth) +} + +func (s *state10) GetState() interface{} { + return &s.State +} + +func (s *state10) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*Allocation, bool, error) { + + alloc, ok, err := s.FindAllocation(s.store, clientIdAddr, verifreg10.AllocationId(allocationId)) + return (*Allocation)(alloc), ok, err +} + +func (s *state10) GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) { + + v10Map, err := s.LoadAllocationsToMap(s.store, clientIdAddr) + + retMap := make(map[AllocationId]Allocation, len(v10Map)) + for k, v := range v10Map { + retMap[AllocationId(k)] = Allocation(v) + } + + return retMap, err + +} + +func (s *state10) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*Claim, bool, error) { + + claim, ok, err := s.FindClaim(s.store, providerIdAddr, verifreg10.ClaimId(claimId)) + return (*Claim)(claim), ok, err + +} + +func (s *state10) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) { + + v10Map, err := s.LoadClaimsToMap(s.store, providerIdAddr) + + retMap := make(map[ClaimId]Claim, len(v10Map)) + for k, v := range v10Map { + retMap[ClaimId(k)] = Claim(v) + } + + return retMap, err + +} + +func (s *state10) ActorKey() string { + return manifest.VerifregKey +} + +func (s *state10) ActorVersion() actorstypes.Version { + return actorstypes.Version10 +} + +func (s *state10) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/verifreg/v2.go b/chain/actors/builtin/verifreg/v2.go index a6f07eea2..61c175c7a 100644 --- a/chain/actors/builtin/verifreg/v2.go +++ b/chain/actors/builtin/verifreg/v2.go @@ -1,12 +1,16 @@ package verifreg import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" verifreg2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/verifreg" adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" @@ -90,26 +94,43 @@ func (s *state2) GetState() interface{} { return &s.State } -func (s *state2) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*verifreg9.Allocation, bool, error) { +func (s *state2) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*Allocation, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v2") } -func (s *state2) GetAllocations(clientIdAddr address.Address) (map[verifreg9.AllocationId]verifreg9.Allocation, error) { +func (s *state2) GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) { return nil, xerrors.Errorf("unsupported in actors v2") } -func (s *state2) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*verifreg9.Claim, bool, error) { +func (s *state2) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*Claim, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v2") } -func (s *state2) GetClaims(providerIdAddr address.Address) (map[verifreg9.ClaimId]verifreg9.Claim, error) { +func (s *state2) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) { return nil, xerrors.Errorf("unsupported in actors v2") } + +func (s *state2) ActorKey() string { + return manifest.VerifregKey +} + +func (s *state2) ActorVersion() actorstypes.Version { + return actorstypes.Version2 +} + +func (s *state2) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/verifreg/v3.go b/chain/actors/builtin/verifreg/v3.go index 11e56d8ae..5ba478500 100644 --- a/chain/actors/builtin/verifreg/v3.go +++ b/chain/actors/builtin/verifreg/v3.go @@ -1,12 +1,16 @@ package verifreg import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" verifreg3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/verifreg" adt3 "github.com/filecoin-project/specs-actors/v3/actors/util/adt" @@ -91,26 +95,43 @@ func (s *state3) GetState() interface{} { return &s.State } -func (s *state3) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*verifreg9.Allocation, bool, error) { +func (s *state3) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*Allocation, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v3") } -func (s *state3) GetAllocations(clientIdAddr address.Address) (map[verifreg9.AllocationId]verifreg9.Allocation, error) { +func (s *state3) GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) { return nil, xerrors.Errorf("unsupported in actors v3") } -func (s *state3) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*verifreg9.Claim, bool, error) { +func (s *state3) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*Claim, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v3") } -func (s *state3) GetClaims(providerIdAddr address.Address) (map[verifreg9.ClaimId]verifreg9.Claim, error) { +func (s *state3) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) { return nil, xerrors.Errorf("unsupported in actors v3") } + +func (s *state3) ActorKey() string { + return manifest.VerifregKey +} + +func (s *state3) ActorVersion() actorstypes.Version { + return actorstypes.Version3 +} + +func (s *state3) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/verifreg/v4.go b/chain/actors/builtin/verifreg/v4.go index da51e78b8..3ad739f68 100644 --- a/chain/actors/builtin/verifreg/v4.go +++ b/chain/actors/builtin/verifreg/v4.go @@ -1,12 +1,16 @@ package verifreg import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" verifreg4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/verifreg" adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" @@ -91,26 +95,43 @@ func (s *state4) GetState() interface{} { return &s.State } -func (s *state4) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*verifreg9.Allocation, bool, error) { +func (s *state4) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*Allocation, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v4") } -func (s *state4) GetAllocations(clientIdAddr address.Address) (map[verifreg9.AllocationId]verifreg9.Allocation, error) { +func (s *state4) GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) { return nil, xerrors.Errorf("unsupported in actors v4") } -func (s *state4) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*verifreg9.Claim, bool, error) { +func (s *state4) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*Claim, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v4") } -func (s *state4) GetClaims(providerIdAddr address.Address) (map[verifreg9.ClaimId]verifreg9.Claim, error) { +func (s *state4) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) { return nil, xerrors.Errorf("unsupported in actors v4") } + +func (s *state4) ActorKey() string { + return manifest.VerifregKey +} + +func (s *state4) ActorVersion() actorstypes.Version { + return actorstypes.Version4 +} + +func (s *state4) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/verifreg/v5.go b/chain/actors/builtin/verifreg/v5.go index 08f8ad706..1ffe06f3f 100644 --- a/chain/actors/builtin/verifreg/v5.go +++ b/chain/actors/builtin/verifreg/v5.go @@ -1,12 +1,16 @@ package verifreg import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" verifreg5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/verifreg" adt5 "github.com/filecoin-project/specs-actors/v5/actors/util/adt" @@ -91,26 +95,43 @@ func (s *state5) GetState() interface{} { return &s.State } -func (s *state5) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*verifreg9.Allocation, bool, error) { +func (s *state5) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*Allocation, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v5") } -func (s *state5) GetAllocations(clientIdAddr address.Address) (map[verifreg9.AllocationId]verifreg9.Allocation, error) { +func (s *state5) GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) { return nil, xerrors.Errorf("unsupported in actors v5") } -func (s *state5) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*verifreg9.Claim, bool, error) { +func (s *state5) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*Claim, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v5") } -func (s *state5) GetClaims(providerIdAddr address.Address) (map[verifreg9.ClaimId]verifreg9.Claim, error) { +func (s *state5) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) { return nil, xerrors.Errorf("unsupported in actors v5") } + +func (s *state5) ActorKey() string { + return manifest.VerifregKey +} + +func (s *state5) ActorVersion() actorstypes.Version { + return actorstypes.Version5 +} + +func (s *state5) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/verifreg/v6.go b/chain/actors/builtin/verifreg/v6.go index 8e6fc3603..9786838d1 100644 --- a/chain/actors/builtin/verifreg/v6.go +++ b/chain/actors/builtin/verifreg/v6.go @@ -1,12 +1,16 @@ package verifreg import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" verifreg6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/verifreg" adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" @@ -91,26 +95,43 @@ func (s *state6) GetState() interface{} { return &s.State } -func (s *state6) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*verifreg9.Allocation, bool, error) { +func (s *state6) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*Allocation, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v6") } -func (s *state6) GetAllocations(clientIdAddr address.Address) (map[verifreg9.AllocationId]verifreg9.Allocation, error) { +func (s *state6) GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) { return nil, xerrors.Errorf("unsupported in actors v6") } -func (s *state6) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*verifreg9.Claim, bool, error) { +func (s *state6) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*Claim, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v6") } -func (s *state6) GetClaims(providerIdAddr address.Address) (map[verifreg9.ClaimId]verifreg9.Claim, error) { +func (s *state6) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) { return nil, xerrors.Errorf("unsupported in actors v6") } + +func (s *state6) ActorKey() string { + return manifest.VerifregKey +} + +func (s *state6) ActorVersion() actorstypes.Version { + return actorstypes.Version6 +} + +func (s *state6) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/verifreg/v7.go b/chain/actors/builtin/verifreg/v7.go index c3b49a305..e63e27742 100644 --- a/chain/actors/builtin/verifreg/v7.go +++ b/chain/actors/builtin/verifreg/v7.go @@ -1,12 +1,16 @@ package verifreg import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" verifreg7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/verifreg" adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" @@ -90,26 +94,43 @@ func (s *state7) GetState() interface{} { return &s.State } -func (s *state7) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*verifreg9.Allocation, bool, error) { +func (s *state7) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*Allocation, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v7") } -func (s *state7) GetAllocations(clientIdAddr address.Address) (map[verifreg9.AllocationId]verifreg9.Allocation, error) { +func (s *state7) GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) { return nil, xerrors.Errorf("unsupported in actors v7") } -func (s *state7) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*verifreg9.Claim, bool, error) { +func (s *state7) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*Claim, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v7") } -func (s *state7) GetClaims(providerIdAddr address.Address) (map[verifreg9.ClaimId]verifreg9.Claim, error) { +func (s *state7) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) { return nil, xerrors.Errorf("unsupported in actors v7") } + +func (s *state7) ActorKey() string { + return manifest.VerifregKey +} + +func (s *state7) ActorVersion() actorstypes.Version { + return actorstypes.Version7 +} + +func (s *state7) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/verifreg/v8.go b/chain/actors/builtin/verifreg/v8.go index 36d219fa0..a1edeba34 100644 --- a/chain/actors/builtin/verifreg/v8.go +++ b/chain/actors/builtin/verifreg/v8.go @@ -1,15 +1,19 @@ package verifreg import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" builtin8 "github.com/filecoin-project/go-state-types/builtin" adt8 "github.com/filecoin-project/go-state-types/builtin/v8/util/adt" verifreg8 "github.com/filecoin-project/go-state-types/builtin/v8/verifreg" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" @@ -90,26 +94,43 @@ func (s *state8) GetState() interface{} { return &s.State } -func (s *state8) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*verifreg9.Allocation, bool, error) { +func (s *state8) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*Allocation, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v8") } -func (s *state8) GetAllocations(clientIdAddr address.Address) (map[verifreg9.AllocationId]verifreg9.Allocation, error) { +func (s *state8) GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) { return nil, xerrors.Errorf("unsupported in actors v8") } -func (s *state8) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*verifreg9.Claim, bool, error) { +func (s *state8) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*Claim, bool, error) { return nil, false, xerrors.Errorf("unsupported in actors v8") } -func (s *state8) GetClaims(providerIdAddr address.Address) (map[verifreg9.ClaimId]verifreg9.Claim, error) { +func (s *state8) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) { return nil, xerrors.Errorf("unsupported in actors v8") } + +func (s *state8) ActorKey() string { + return manifest.VerifregKey +} + +func (s *state8) ActorVersion() actorstypes.Version { + return actorstypes.Version8 +} + +func (s *state8) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code +} diff --git a/chain/actors/builtin/verifreg/v9.go b/chain/actors/builtin/verifreg/v9.go index 5c84c7041..bf6424ba7 100644 --- a/chain/actors/builtin/verifreg/v9.go +++ b/chain/actors/builtin/verifreg/v9.go @@ -1,15 +1,19 @@ package verifreg import ( + "fmt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" builtin9 "github.com/filecoin-project/go-state-types/builtin" adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" @@ -90,26 +94,58 @@ func (s *state9) GetState() interface{} { return &s.State } -func (s *state9) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*verifreg9.Allocation, bool, error) { +func (s *state9) GetAllocation(clientIdAddr address.Address, allocationId verifreg9.AllocationId) (*Allocation, bool, error) { - return s.FindAllocation(s.store, clientIdAddr, allocationId) + alloc, ok, err := s.FindAllocation(s.store, clientIdAddr, verifreg9.AllocationId(allocationId)) + return (*Allocation)(alloc), ok, err +} + +func (s *state9) GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) { + + v9Map, err := s.LoadAllocationsToMap(s.store, clientIdAddr) + + retMap := make(map[AllocationId]Allocation, len(v9Map)) + for k, v := range v9Map { + retMap[AllocationId(k)] = Allocation(v) + } + + return retMap, err } -func (s *state9) GetAllocations(clientIdAddr address.Address) (map[verifreg9.AllocationId]verifreg9.Allocation, error) { +func (s *state9) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*Claim, bool, error) { - return s.LoadAllocationsToMap(s.store, clientIdAddr) + claim, ok, err := s.FindClaim(s.store, providerIdAddr, verifreg9.ClaimId(claimId)) + return (*Claim)(claim), ok, err } -func (s *state9) GetClaim(providerIdAddr address.Address, claimId verifreg9.ClaimId) (*verifreg9.Claim, bool, error) { +func (s *state9) GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) { - return s.FindClaim(s.store, providerIdAddr, claimId) + v9Map, err := s.LoadClaimsToMap(s.store, providerIdAddr) + + retMap := make(map[ClaimId]Claim, len(v9Map)) + for k, v := range v9Map { + retMap[ClaimId(k)] = Claim(v) + } + + return retMap, err } -func (s *state9) GetClaims(providerIdAddr address.Address) (map[verifreg9.ClaimId]verifreg9.Claim, error) { - - return s.LoadClaimsToMap(s.store, providerIdAddr) - +func (s *state9) ActorKey() string { + return manifest.VerifregKey +} + +func (s *state9) ActorVersion() actorstypes.Version { + return actorstypes.Version9 +} + +func (s *state9) Code() cid.Cid { + code, ok := actors.GetActorCodeID(s.ActorVersion(), s.ActorKey()) + if !ok { + panic(fmt.Errorf("didn't find actor %v code id for actor version %d", s.ActorKey(), s.ActorVersion())) + } + + return code } diff --git a/chain/actors/builtin/verifreg/verifreg.go b/chain/actors/builtin/verifreg/verifreg.go index 300307dbb..1380a9207 100644 --- a/chain/actors/builtin/verifreg/verifreg.go +++ b/chain/actors/builtin/verifreg/verifreg.go @@ -1,14 +1,16 @@ package verifreg import ( + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" - builtin9 "github.com/filecoin-project/go-state-types/builtin" + builtin10 "github.com/filecoin-project/go-state-types/builtin" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" @@ -23,13 +25,13 @@ import ( ) var ( - Address = builtin9.VerifiedRegistryActorAddr - Methods = builtin9.MethodsVerifiedRegistry + Address = builtin10.VerifiedRegistryActorAddr + Methods = builtin10.MethodsVerifiedRegistry ) func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { - if name != actors.VerifregKey { + if name != manifest.VerifregKey { return nil, xerrors.Errorf("actor code is not verifreg: %s", name) } @@ -41,6 +43,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case actorstypes.Version9: return load9(store, act.Head) + case actorstypes.Version10: + return load10(store, act.Head) + } } @@ -102,6 +107,9 @@ func MakeState(store adt.Store, av actorstypes.Version, rootKeyAddress address.A case actorstypes.Version9: return make9(store, rootKeyAddress) + case actorstypes.Version10: + return make10(store, rootKeyAddress) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -109,15 +117,39 @@ func MakeState(store adt.Store, av actorstypes.Version, rootKeyAddress address.A type State interface { cbor.Marshaler + Code() cid.Cid + ActorKey() string + ActorVersion() actorstypes.Version + RootKey() (address.Address, error) VerifiedClientDataCap(address.Address) (bool, abi.StoragePower, error) VerifierDataCap(address.Address) (bool, abi.StoragePower, error) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) ForEachVerifier(func(addr address.Address, dcap abi.StoragePower) error) error ForEachClient(func(addr address.Address, dcap abi.StoragePower) error) error - GetAllocation(clientIdAddr address.Address, allocationId verifregtypes.AllocationId) (*verifregtypes.Allocation, bool, error) - GetAllocations(clientIdAddr address.Address) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) - GetClaim(providerIdAddr address.Address, claimId verifregtypes.ClaimId) (*verifregtypes.Claim, bool, error) - GetClaims(providerIdAddr address.Address) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) + GetAllocation(clientIdAddr address.Address, allocationId AllocationId) (*Allocation, bool, error) + GetAllocations(clientIdAddr address.Address) (map[AllocationId]Allocation, error) + GetClaim(providerIdAddr address.Address, claimId ClaimId) (*Claim, bool, error) + GetClaims(providerIdAddr address.Address) (map[ClaimId]Claim, error) GetState() interface{} } + +func AllCodes() []cid.Cid { + return []cid.Cid{ + (&state0{}).Code(), + (&state2{}).Code(), + (&state3{}).Code(), + (&state4{}).Code(), + (&state5{}).Code(), + (&state6{}).Code(), + (&state7{}).Code(), + (&state8{}).Code(), + (&state9{}).Code(), + (&state10{}).Code(), + } +} + +type Allocation = verifregtypes.Allocation +type AllocationId = verifregtypes.AllocationId +type Claim = verifregtypes.Claim +type ClaimId = verifregtypes.ClaimId diff --git a/chain/actors/manifest.go b/chain/actors/manifest.go index fdf274748..f58768ca2 100644 --- a/chain/actors/manifest.go +++ b/chain/actors/manifest.go @@ -15,44 +15,9 @@ import ( "github.com/filecoin-project/lotus/chain/actors/adt" ) -var manifestCids map[actorstypes.Version]cid.Cid = make(map[actorstypes.Version]cid.Cid) -var manifests map[actorstypes.Version]map[string]cid.Cid = make(map[actorstypes.Version]map[string]cid.Cid) -var actorMeta map[cid.Cid]actorEntry = make(map[cid.Cid]actorEntry) - -const ( - AccountKey = "account" - CronKey = "cron" - InitKey = "init" - MarketKey = "storagemarket" - MinerKey = "storageminer" - MultisigKey = "multisig" - PaychKey = "paymentchannel" - PowerKey = "storagepower" - RewardKey = "reward" - SystemKey = "system" - VerifregKey = "verifiedregistry" - DatacapKey = "datacap" -) - -func GetBuiltinActorsKeys(av actorstypes.Version) []string { - keys := []string{ - AccountKey, - CronKey, - InitKey, - MarketKey, - MinerKey, - MultisigKey, - PaychKey, - PowerKey, - RewardKey, - SystemKey, - VerifregKey, - } - if av >= 9 { - keys = append(keys, DatacapKey) - } - return keys -} +var manifestCids = make(map[actorstypes.Version]cid.Cid) +var manifests = make(map[actorstypes.Version]map[string]cid.Cid) +var actorMeta = make(map[cid.Cid]actorEntry) var ( manifestMx sync.RWMutex diff --git a/chain/actors/policy/policy.go b/chain/actors/policy/policy.go index eaeb326c7..eff7ba899 100644 --- a/chain/actors/policy/policy.go +++ b/chain/actors/policy/policy.go @@ -6,14 +6,18 @@ import ( "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + builtin10 "github.com/filecoin-project/go-state-types/builtin" builtin8 "github.com/filecoin-project/go-state-types/builtin" builtin9 "github.com/filecoin-project/go-state-types/builtin" + market10 "github.com/filecoin-project/go-state-types/builtin/v10/market" + miner10 "github.com/filecoin-project/go-state-types/builtin/v10/miner" + paych10 "github.com/filecoin-project/go-state-types/builtin/v10/paych" + verifreg10 "github.com/filecoin-project/go-state-types/builtin/v10/verifreg" market8 "github.com/filecoin-project/go-state-types/builtin/v8/market" miner8 "github.com/filecoin-project/go-state-types/builtin/v8/miner" verifreg8 "github.com/filecoin-project/go-state-types/builtin/v8/verifreg" market9 "github.com/filecoin-project/go-state-types/builtin/v9/market" miner9 "github.com/filecoin-project/go-state-types/builtin/v9/miner" - paych9 "github.com/filecoin-project/go-state-types/builtin/v9/paych" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" "github.com/filecoin-project/go-state-types/network" market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" @@ -47,10 +51,10 @@ import ( ) const ( - ChainFinality = miner9.ChainFinality + ChainFinality = miner10.ChainFinality SealRandomnessLookback = ChainFinality - PaychSettleDelay = paych9.SettleDelay - MaxPreCommitRandomnessLookback = builtin9.EpochsInDay + SealRandomnessLookback + PaychSettleDelay = paych10.SettleDelay + MaxPreCommitRandomnessLookback = builtin10.EpochsInDay + SealRandomnessLookback ) // SetSupportedProofTypes sets supported proof types, across all actor versions. @@ -159,11 +163,13 @@ func SetPreCommitChallengeDelay(delay abi.ChainEpoch) { miner9.PreCommitChallengeDelay = delay + miner10.PreCommitChallengeDelay = delay + } // TODO: this function shouldn't really exist. Instead, the API should expose the precommit delay. func GetPreCommitChallengeDelay() abi.ChainEpoch { - return miner9.PreCommitChallengeDelay + return miner10.PreCommitChallengeDelay } // SetConsensusMinerMinPower sets the minimum power of an individual miner must @@ -205,6 +211,10 @@ func SetConsensusMinerMinPower(p abi.StoragePower) { policy.ConsensusMinerMinPower = p } + for _, policy := range builtin10.PoStProofPolicies { + policy.ConsensusMinerMinPower = p + } + } // SetMinVerifiedDealSize sets the minimum size of a verified deal. This should @@ -229,6 +239,8 @@ func SetMinVerifiedDealSize(size abi.StoragePower) { verifreg9.MinVerifiedDealSize = size + verifreg10.MinVerifiedDealSize = size + } func GetMaxProveCommitDuration(ver actorstypes.Version, t abi.RegisteredSealProof) (abi.ChainEpoch, error) { @@ -270,6 +282,10 @@ func GetMaxProveCommitDuration(ver actorstypes.Version, t abi.RegisteredSealProo return miner9.MaxProveCommitDuration[t], nil + case actorstypes.Version10: + + return miner10.MaxProveCommitDuration[t], nil + default: return 0, xerrors.Errorf("unsupported actors version") } @@ -320,6 +336,11 @@ func SetProviderCollateralSupplyTarget(num, denom big.Int) { Denominator: denom, } + market10.ProviderCollateralSupplyTarget = builtin10.BigFrac{ + Numerator: num, + Denominator: denom, + } + } func DealProviderCollateralBounds( @@ -378,13 +399,18 @@ func DealProviderCollateralBounds( min, max := market9.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil) return min, max, nil + case actorstypes.Version10: + + min, max := market10.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil) + return min, max, nil + default: return big.Zero(), big.Zero(), xerrors.Errorf("unsupported actors version") } } func DealDurationBounds(pieceSize abi.PaddedPieceSize) (min, max abi.ChainEpoch) { - return market9.DealDurationBounds(pieceSize) + return market10.DealDurationBounds(pieceSize) } // Sets the challenge window and scales the proving period to match (such that @@ -446,6 +472,13 @@ func SetWPoStChallengeWindow(period abi.ChainEpoch) { // scale it if we're scaling the challenge period. miner9.WPoStDisputeWindow = period * 30 + miner10.WPoStChallengeWindow = period + miner10.WPoStProvingPeriod = period * abi.ChainEpoch(miner10.WPoStPeriodDeadlines) + + // by default, this is 2x finality which is 30 periods. + // scale it if we're scaling the challenge period. + miner10.WPoStDisputeWindow = period * 30 + } func GetWinningPoStSectorSetLookback(nwVer network.Version) abi.ChainEpoch { @@ -458,15 +491,15 @@ func GetWinningPoStSectorSetLookback(nwVer network.Version) abi.ChainEpoch { } func GetMaxSectorExpirationExtension() abi.ChainEpoch { - return miner9.MaxSectorExpirationExtension + return miner10.MaxSectorExpirationExtension } func GetMinSectorExpiration() abi.ChainEpoch { - return miner9.MinSectorExpiration + return miner10.MinSectorExpiration } func GetMaxPoStPartitions(nv network.Version, p abi.RegisteredPoStProof) (int, error) { - sectorsPerPart, err := builtin9.PoStProofWindowPoStPartitionSectors(p) + sectorsPerPart, err := builtin10.PoStProofWindowPoStPartitionSectors(p) if err != nil { return 0, err } @@ -486,7 +519,7 @@ func GetSectorMaxLifetime(proof abi.RegisteredSealProof, nwVer network.Version) return builtin4.SealProofPoliciesV0[proof].SectorMaxLifetime } - return builtin9.SealProofPoliciesV11[proof].SectorMaxLifetime + return builtin10.SealProofPoliciesV11[proof].SectorMaxLifetime } func GetAddressedSectorsMax(nwVer network.Version) (int, error) { @@ -523,6 +556,9 @@ func GetAddressedSectorsMax(nwVer network.Version) (int, error) { case actorstypes.Version9: return miner9.AddressedSectorsMax, nil + case actorstypes.Version10: + return miner10.AddressedSectorsMax, nil + default: return 0, xerrors.Errorf("unsupported network version") } @@ -572,6 +608,10 @@ func GetDeclarationsMax(nwVer network.Version) (int, error) { return miner9.DeclarationsMax, nil + case actorstypes.Version10: + + return miner10.DeclarationsMax, nil + default: return 0, xerrors.Errorf("unsupported network version") } @@ -620,6 +660,10 @@ func AggregateProveCommitNetworkFee(nwVer network.Version, aggregateSize int, ba return miner9.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil + case actorstypes.Version10: + + return miner10.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil + default: return big.Zero(), xerrors.Errorf("unsupported network version") } @@ -668,6 +712,10 @@ func AggregatePreCommitNetworkFee(nwVer network.Version, aggregateSize int, base return miner9.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil + case actorstypes.Version10: + + return miner10.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil + default: return big.Zero(), xerrors.Errorf("unsupported network version") } diff --git a/chain/actors/version.go b/chain/actors/version.go index b9f4c2034..34e9a88bf 100644 --- a/chain/actors/version.go +++ b/chain/actors/version.go @@ -14,20 +14,21 @@ const ({{range .actorVersions}} /* inline-gen start */ -var LatestVersion = 9 +var LatestVersion = 10 -var Versions = []int{0, 2, 3, 4, 5, 6, 7, 8, 9} +var Versions = []int{0, 2, 3, 4, 5, 6, 7, 8, 9, 10} const ( - Version0 Version = 0 - Version2 Version = 2 - Version3 Version = 3 - Version4 Version = 4 - Version5 Version = 5 - Version6 Version = 6 - Version7 Version = 7 - Version8 Version = 8 - Version9 Version = 9 + Version0 Version = 0 + Version2 Version = 2 + Version3 Version = 3 + Version4 Version = 4 + Version5 Version = 5 + Version6 Version = 6 + Version7 Version = 7 + Version8 Version = 8 + Version9 Version = 9 + Version10 Version = 10 ) /* inline-gen end */ diff --git a/chain/beacon/drand/drand.go b/chain/beacon/drand/drand.go index 5b6cc45bd..181fa3046 100644 --- a/chain/beacon/drand/drand.go +++ b/chain/beacon/drand/drand.go @@ -107,7 +107,7 @@ func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub, config dtypes client, err := dclient.Wrap(clients, opts...) if err != nil { - return nil, xerrors.Errorf("creating drand client") + return nil, xerrors.Errorf("creating drand client: %w", err) } lc, err := lru.New(1024) diff --git a/chain/consensus/filcns/compute_state.go b/chain/consensus/filcns/compute_state.go index 6b5405543..13dbc2069 100644 --- a/chain/consensus/filcns/compute_state.go +++ b/chain/consensus/filcns/compute_state.go @@ -5,11 +5,13 @@ import ( "sync/atomic" "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" "go.opencensus.io/stats" "go.opencensus.io/trace" "golang.org/x/xerrors" + amt4 "github.com/filecoin-project/go-amt-ipld/v4" "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" @@ -48,6 +50,7 @@ func NewActorRegistry() *vm.ActorRegistry { inv.Register(actorstypes.Version7, vm.ActorsVersionPredicate(actorstypes.Version7), builtin.MakeRegistryLegacy(exported7.BuiltinActors())) inv.Register(actorstypes.Version8, vm.ActorsVersionPredicate(actorstypes.Version8), builtin.MakeRegistry(actorstypes.Version8)) inv.Register(actorstypes.Version9, vm.ActorsVersionPredicate(actorstypes.Version9), builtin.MakeRegistry(actorstypes.Version9)) + inv.Register(actorstypes.Version10, vm.ActorsVersionPredicate(actorstypes.Version10), builtin.MakeRegistry(actorstypes.Version10)) return inv } @@ -88,10 +91,11 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context, }() ctx = blockstore.WithHotView(ctx) - makeVmWithBaseStateAndEpoch := func(base cid.Cid, e abi.ChainEpoch) (vm.Interface, error) { + makeVm := func(base cid.Cid, e abi.ChainEpoch, timestamp uint64) (vm.Interface, error) { vmopt := &vm.VMOpts{ StateBase: base, Epoch: e, + Timestamp: timestamp, Rand: r, Bstore: sm.ChainStore().StateBlockstore(), Actors: NewActorRegistry(), @@ -100,7 +104,9 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context, NetworkVersion: sm.GetNetworkVersion(ctx, e), BaseFee: baseFee, LookbackState: stmgr.LookbackStateGetterForTipset(sm, ts), + TipSetGetter: stmgr.TipSetGetterForTipset(sm.ChainStore(), ts), Tracing: vmTracing, + ReturnEvents: sm.ChainStore().IsStoringEvents(), } return sm.VMConstructor()(ctx, vmopt) @@ -135,10 +141,22 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context, return nil } + // May get filled with the genesis block header if there are null rounds + // for which to backfill cron execution. + var genesis *types.BlockHeader + + // There were null rounds in between the current epoch and the parent epoch. for i := parentEpoch; i < epoch; i++ { var err error if i > parentEpoch { - vmCron, err := makeVmWithBaseStateAndEpoch(pstate, i) + if genesis == nil { + if genesis, err = sm.ChainStore().GetGenesis(ctx); err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("failed to get genesis when backfilling null rounds: %w", err) + } + } + + ts := genesis.Timestamp + build.BlockDelaySecs*(uint64(i)) + vmCron, err := makeVm(pstate, i, ts) if err != nil { return cid.Undef, cid.Undef, xerrors.Errorf("making cron vm: %w", err) } @@ -165,13 +183,18 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context, partDone() partDone = metrics.Timer(ctx, metrics.VMApplyMessages) - vmi, err := makeVmWithBaseStateAndEpoch(pstate, epoch) + vmi, err := makeVm(pstate, epoch, ts.MinTimestamp()) if err != nil { return cid.Undef, cid.Undef, xerrors.Errorf("making vm: %w", err) } - var receipts []cbg.CBORMarshaler - processedMsgs := make(map[cid.Cid]struct{}) + var ( + receipts []*types.MessageReceipt + storingEvents = sm.ChainStore().IsStoringEvents() + events [][]types.Event + processedMsgs = make(map[cid.Cid]struct{}) + ) + for _, b := range bms { penalty := types.NewInt(0) gasReward := big.Zero() @@ -190,6 +213,11 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context, gasReward = big.Add(gasReward, r.GasCosts.MinerTip) penalty = big.Add(penalty, r.GasCosts.MinerPenalty) + if storingEvents { + // Appends nil when no events are returned to preserve positional alignment. + events = append(events, r.Events) + } + if em != nil { if err := em.MessageApplied(ctx, ts, cm.Cid(), m, r, false); err != nil { return cid.Undef, cid.Undef, err @@ -255,6 +283,23 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context, return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err) } + // Slice will be empty if not storing events. + for i, evs := range events { + if len(evs) == 0 { + continue + } + switch root, err := t.StoreEventsAMT(ctx, sm.ChainStore(), evs); { + case err != nil: + return cid.Undef, cid.Undef, xerrors.Errorf("failed to store events amt: %w", err) + case i >= len(receipts): + return cid.Undef, cid.Undef, xerrors.Errorf("assertion failed: receipt and events array lengths inconsistent") + case receipts[i].EventsRoot == nil: + return cid.Undef, cid.Undef, xerrors.Errorf("assertion failed: VM returned events with no events root") + case root != *receipts[i].EventsRoot: + return cid.Undef, cid.Undef, xerrors.Errorf("assertion failed: returned events AMT root does not match derived") + } + } + st, err := vmi.Flush(ctx) if err != nil { return cid.Undef, cid.Undef, xerrors.Errorf("vm flush failed: %w", err) @@ -313,4 +358,13 @@ func (t *TipSetExecutor) ExecuteTipSet(ctx context.Context, return t.ApplyBlocks(ctx, sm, parentEpoch, pstate, fbmsgs, blks[0].Height, r, em, vmTracing, baseFee, ts) } +func (t *TipSetExecutor) StoreEventsAMT(ctx context.Context, cs *store.ChainStore, events []types.Event) (cid.Cid, error) { + cst := cbor.NewCborStore(cs.ChainBlockstore()) + objs := make([]cbg.CBORMarshaler, len(events)) + for i := 0; i < len(events); i++ { + objs[i] = &events[i] + } + return amt4.FromArray(ctx, cst, objs, amt4.UseTreeBitWidth(types.EventAMTBitwidth)) +} + var _ stmgr.Executor = &TipSetExecutor{} diff --git a/chain/consensus/filcns/filecoin.go b/chain/consensus/filcns/filecoin.go index de3cf7cf7..2cd680746 100644 --- a/chain/consensus/filcns/filecoin.go +++ b/chain/consensus/filcns/filecoin.go @@ -14,6 +14,7 @@ import ( cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log/v2" pubsub "github.com/libp2p/go-libp2p-pubsub" + "github.com/multiformats/go-varint" cbg "github.com/whyrusleeping/cbor-gen" "go.opencensus.io/stats" "go.opencensus.io/trace" @@ -21,6 +22,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + builtintypes "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/network" blockadt "github.com/filecoin-project/specs-actors/actors/util/adt" @@ -433,6 +435,39 @@ func (filec *FilecoinEC) VerifyWinningPoStProof(ctx context.Context, nv network. return nil } +func IsValidForSending(nv network.Version, act *types.Actor) bool { + // Before nv18 (Hygge), we only supported built-in account actors as senders. + // + // Note: this gate is probably superfluous, since: + // 1. Placeholder actors cannot be created before nv18. + // 2. EthAccount actors cannot be created before nv18. + // 3. Delegated addresses cannot be created before nv18. + // + // But it's a safeguard. + // + // Note 2: ad-hoc checks for network versions like this across the codebase + // will be problematic with networks with diverging version lineages + // (e.g. Hyperspace). We need to revisit this strategy entirely. + if nv < network.Version18 { + return builtin.IsAccountActor(act.Code) + } + + // After nv18, we also support other kinds of senders. + if builtin.IsAccountActor(act.Code) || builtin.IsEthAccountActor(act.Code) { + return true + } + + // Allow placeholder actors with a delegated address and nonce 0 to send a message. + // These will be converted to an EthAccount actor on first send. + if !builtin.IsPlaceholderActor(act.Code) || act.Nonce != 0 || act.Address == nil || act.Address.Protocol() != address.Delegated { + return false + } + + // Only allow such actors to send if their delegated address is in the EAM's namespace. + id, _, err := varint.FromUvarint(act.Address.Payload()) + return err == nil && id == builtintypes.EthereumAddressManagerActorID +} + // TODO: We should extract this somewhere else and make the message pool and miner use the same logic func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBlock, baseTs *types.TipSet) error { { @@ -505,7 +540,7 @@ func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBl return xerrors.Errorf("failed to get actor: %w", err) } - if !builtin.IsAccountActor(act.Code) { + if !IsValidForSending(nv, act) { return xerrors.New("Sender must be an account actor") } nonces[sender] = act.Nonce @@ -542,25 +577,23 @@ func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBl smArr := blockadt.MakeEmptyArray(tmpstore) for i, m := range b.SecpkMessages { - if filec.sm.GetNetworkVersion(ctx, b.Header.Height) >= network.Version14 { - if m.Signature.Type != crypto.SigTypeSecp256k1 { - return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err) - } + if nv >= network.Version14 && !chain.IsValidSecpkSigType(nv, m.Signature.Type) { + return xerrors.Errorf("block had invalid signed message at index %d: %w", i, err) } if err := checkMsg(m); err != nil { return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err) } - // `From` being an account actor is only validated inside the `vm.ResolveToKeyAddr` call - // in `StateManager.ResolveToKeyAddress` here (and not in `checkMsg`). - kaddr, err := filec.sm.ResolveToKeyAddress(ctx, m.Message.From, baseTs) + // `From` being an account actor is only validated inside the `vm.ResolveToDeterministicAddr` call + // in `StateManager.ResolveToDeterministicAddress` here (and not in `checkMsg`). + kaddr, err := filec.sm.ResolveToDeterministicAddress(ctx, m.Message.From, baseTs) if err != nil { return xerrors.Errorf("failed to resolve key addr: %w", err) } - if err := sigs.Verify(&m.Signature, kaddr, m.Message.Cid().Bytes()); err != nil { - return xerrors.Errorf("secpk message %s has invalid signature: %w", m.Cid(), err) + if err := chain.AuthenticateMessage(m, kaddr); err != nil { + return xerrors.Errorf("failed to validate signature: %w", err) } c, err := store.PutMessage(ctx, tmpbs, m) diff --git a/chain/consensus/filcns/mine.go b/chain/consensus/filcns/mine.go index 35e38883d..234c1d654 100644 --- a/chain/consensus/filcns/mine.go +++ b/chain/consensus/filcns/mine.go @@ -9,6 +9,7 @@ import ( "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/consensus" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" @@ -54,6 +55,7 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api. var blsMsgCids, secpkMsgCids []cid.Cid var blsSigs []crypto.Signature + nv := filec.sm.GetNetworkVersion(ctx, bt.Epoch) for _, msg := range bt.Messages { if msg.Signature.Type == crypto.SigTypeBLS { blsSigs = append(blsSigs, msg.Signature) @@ -65,7 +67,7 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api. } blsMsgCids = append(blsMsgCids, c) - } else if msg.Signature.Type == crypto.SigTypeSecp256k1 { + } else if chain.IsValidSecpkSigType(nv, msg.Signature.Type) { c, err := filec.sm.ChainStore().PutMessage(ctx, msg) if err != nil { return nil, err diff --git a/chain/consensus/filcns/upgrades.go b/chain/consensus/filcns/upgrades.go index ef401b933..617d44fb5 100644 --- a/chain/consensus/filcns/upgrades.go +++ b/chain/consensus/filcns/upgrades.go @@ -4,7 +4,9 @@ import ( "context" _ "embed" "fmt" + "os" "runtime" + "strconv" "time" "github.com/docker/go-units" @@ -16,8 +18,10 @@ import ( "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + nv18 "github.com/filecoin-project/go-state-types/builtin/v10/migration" nv17 "github.com/filecoin-project/go-state-types/builtin/v9/migration" "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/go-state-types/migration" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-state-types/rt" gstStore "github.com/filecoin-project/go-state-types/store" @@ -53,6 +57,29 @@ import ( //go:embed FVMLiftoff.txt var fvmLiftoffBanner string +var ( + MigrationMaxWorkerCount int + EnvMigrationMaxWorkerCount = "LOTUS_MIGRATION_MAX_WORKER_COUNT" +) + +func init() { + // the default calculation used for migration worker count + MigrationMaxWorkerCount = runtime.NumCPU() + // check if an alternative value was request by environment + if mwcs := os.Getenv(EnvMigrationMaxWorkerCount); mwcs != "" { + mwc, err := strconv.ParseInt(mwcs, 10, 32) + if err != nil { + log.Warnf("invalid value for %s (%s) defaulting to %d: %s", EnvMigrationMaxWorkerCount, mwcs, MigrationMaxWorkerCount, err) + return + } + // use value from environment + log.Infof("migration worker cound set from %s (%d)", EnvMigrationMaxWorkerCount, mwc) + MigrationMaxWorkerCount = int(mwc) + return + } + log.Infof("migration worker count: %d", MigrationMaxWorkerCount) +} + func DefaultUpgradeSchedule() stmgr.UpgradeSchedule { var us stmgr.UpgradeSchedule @@ -207,6 +234,17 @@ func DefaultUpgradeSchedule() stmgr.UpgradeSchedule { StopWithin: 5, }}, Expensive: true, + }, { + Height: build.UpgradeHyggeHeight, + Network: network.Version18, + Migration: UpgradeActorsV10, + PreMigrations: []stmgr.PreMigration{{ + PreMigration: PreUpgradeActorsV10, + StartWithin: 60, + DontStartWithin: 10, + StopWithin: 5, + }}, + Expensive: true, }, } @@ -890,7 +928,7 @@ func UpgradeCalico(ctx context.Context, sm *stmgr.StateManager, _ stmgr.Migratio func UpgradeActorsV3(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { // Use all the CPUs except 3. - workerCount := runtime.NumCPU() - 3 + workerCount := MigrationMaxWorkerCount - 3 if workerCount <= 0 { workerCount = 1 } @@ -928,7 +966,7 @@ func UpgradeActorsV3(ctx context.Context, sm *stmgr.StateManager, cache stmgr.Mi func PreUpgradeActorsV3(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error { // Use half the CPUs for pre-migration, but leave at least 3. - workerCount := runtime.NumCPU() + workerCount := MigrationMaxWorkerCount if workerCount <= 4 { workerCount = 1 } else { @@ -992,7 +1030,7 @@ func upgradeActorsV3Common( func UpgradeActorsV4(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { // Use all the CPUs except 3. - workerCount := runtime.NumCPU() - 3 + workerCount := MigrationMaxWorkerCount - 3 if workerCount <= 0 { workerCount = 1 } @@ -1014,7 +1052,7 @@ func UpgradeActorsV4(ctx context.Context, sm *stmgr.StateManager, cache stmgr.Mi func PreUpgradeActorsV4(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error { // Use half the CPUs for pre-migration, but leave at least 3. - workerCount := runtime.NumCPU() + workerCount := MigrationMaxWorkerCount if workerCount <= 4 { workerCount = 1 } else { @@ -1078,7 +1116,7 @@ func upgradeActorsV4Common( func UpgradeActorsV5(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { // Use all the CPUs except 3. - workerCount := runtime.NumCPU() - 3 + workerCount := MigrationMaxWorkerCount - 3 if workerCount <= 0 { workerCount = 1 } @@ -1100,7 +1138,7 @@ func UpgradeActorsV5(ctx context.Context, sm *stmgr.StateManager, cache stmgr.Mi func PreUpgradeActorsV5(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error { // Use half the CPUs for pre-migration, but leave at least 3. - workerCount := runtime.NumCPU() + workerCount := MigrationMaxWorkerCount if workerCount <= 4 { workerCount = 1 } else { @@ -1164,7 +1202,7 @@ func upgradeActorsV5Common( func UpgradeActorsV6(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { // Use all the CPUs except 3. - workerCount := runtime.NumCPU() - 3 + workerCount := MigrationMaxWorkerCount - 3 if workerCount <= 0 { workerCount = 1 } @@ -1186,7 +1224,7 @@ func UpgradeActorsV6(ctx context.Context, sm *stmgr.StateManager, cache stmgr.Mi func PreUpgradeActorsV6(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error { // Use half the CPUs for pre-migration, but leave at least 3. - workerCount := runtime.NumCPU() + workerCount := MigrationMaxWorkerCount if workerCount <= 4 { workerCount = 1 } else { @@ -1250,7 +1288,7 @@ func upgradeActorsV6Common( func UpgradeActorsV7(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { // Use all the CPUs except 3. - workerCount := runtime.NumCPU() - 3 + workerCount := MigrationMaxWorkerCount - 3 if workerCount <= 0 { workerCount = 1 } @@ -1272,7 +1310,7 @@ func UpgradeActorsV7(ctx context.Context, sm *stmgr.StateManager, cache stmgr.Mi func PreUpgradeActorsV7(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error { // Use half the CPUs for pre-migration, but leave at least 3. - workerCount := runtime.NumCPU() + workerCount := MigrationMaxWorkerCount if workerCount <= 4 { workerCount = 1 } else { @@ -1343,7 +1381,7 @@ func upgradeActorsV7Common( func UpgradeActorsV8(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { // Use all the CPUs except 3. - workerCount := runtime.NumCPU() - 3 + workerCount := MigrationMaxWorkerCount - 3 if workerCount <= 0 { workerCount = 1 } @@ -1367,7 +1405,7 @@ func UpgradeActorsV8(ctx context.Context, sm *stmgr.StateManager, cache stmgr.Mi func PreUpgradeActorsV8(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error { // Use half the CPUs for pre-migration, but leave at least 3. - workerCount := runtime.NumCPU() + workerCount := MigrationMaxWorkerCount if workerCount <= 4 { workerCount = 1 } else { @@ -1450,7 +1488,7 @@ func upgradeActorsV8Common( func UpgradeActorsV9(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { // Use all the CPUs except 3. - workerCount := runtime.NumCPU() - 3 + workerCount := MigrationMaxWorkerCount - 3 if workerCount <= 0 { workerCount = 1 } @@ -1473,7 +1511,7 @@ func UpgradeActorsV9(ctx context.Context, sm *stmgr.StateManager, cache stmgr.Mi func PreUpgradeActorsV9(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error { // Use half the CPUs for pre-migration, but leave at least 3. - workerCount := runtime.NumCPU() + workerCount := MigrationMaxWorkerCount if workerCount <= 4 { workerCount = 1 } else { @@ -1552,6 +1590,114 @@ func upgradeActorsV9Common( return newRoot, nil } +func UpgradeActorsV10(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, + root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { + // Use all the CPUs except 3. + workerCount := MigrationMaxWorkerCount - 3 + if workerCount <= 0 { + workerCount = 1 + } + + config := migration.Config{ + MaxWorkers: uint(workerCount), + JobQueueSize: 1000, + ResultQueueSize: 100, + ProgressLogPeriod: 10 * time.Second, + } + + newRoot, err := upgradeActorsV10Common(ctx, sm, cache, root, epoch, ts, config) + if err != nil { + return cid.Undef, xerrors.Errorf("migrating actors v10 state: %w", err) + } + + return newRoot, nil +} + +func PreUpgradeActorsV10(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error { + // Use half the CPUs for pre-migration, but leave at least 3. + workerCount := MigrationMaxWorkerCount + if workerCount <= 4 { + workerCount = 1 + } else { + workerCount /= 2 + } + + lbts, lbRoot, err := stmgr.GetLookbackTipSetForRound(ctx, sm, ts, epoch) + if err != nil { + return xerrors.Errorf("error getting lookback ts for premigration: %w", err) + } + + config := migration.Config{ + MaxWorkers: uint(workerCount), + ProgressLogPeriod: time.Minute * 5, + } + + _, err = upgradeActorsV10Common(ctx, sm, cache, lbRoot, epoch, lbts, config) + return err +} + +func upgradeActorsV10Common( + ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, + root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet, + config migration.Config, +) (cid.Cid, error) { + buf := blockstore.NewTieredBstore(sm.ChainStore().StateBlockstore(), blockstore.NewMemorySync()) + store := store.ActorStore(ctx, buf) + + // ensure that the manifest is loaded in the blockstore + if err := bundle.LoadBundles(ctx, sm.ChainStore().StateBlockstore(), actorstypes.Version10); err != nil { + return cid.Undef, xerrors.Errorf("failed to load manifest bundle: %w", err) + } + + // Load the state root. + var stateRoot types.StateRoot + if err := store.Get(ctx, root, &stateRoot); err != nil { + return cid.Undef, xerrors.Errorf("failed to decode state root: %w", err) + } + + if stateRoot.Version != types.StateTreeVersion4 { + return cid.Undef, xerrors.Errorf( + "expected state root version 4 for actors v9 upgrade, got %d", + stateRoot.Version, + ) + } + + manifest, ok := actors.GetManifest(actorstypes.Version10) + if !ok { + return cid.Undef, xerrors.Errorf("no manifest CID for v9 upgrade") + } + + // Perform the migration + newHamtRoot, err := nv18.MigrateStateTree(ctx, store, manifest, stateRoot.Actors, epoch, config, + migrationLogger{}, cache) + if err != nil { + return cid.Undef, xerrors.Errorf("upgrading to actors v10: %w", err) + } + + // Persist the result. + newRoot, err := store.Put(ctx, &types.StateRoot{ + Version: types.StateTreeVersion5, + Actors: newHamtRoot, + Info: stateRoot.Info, + }) + if err != nil { + return cid.Undef, xerrors.Errorf("failed to persist new state root: %w", err) + } + + // Persist the new tree. + + { + from := buf + to := buf.Read() + + if err := vm.Copy(ctx, from, to, newRoot); err != nil { + return cid.Undef, xerrors.Errorf("copying migrated tree: %w", err) + } + } + + return newRoot, nil +} + // Example upgrade function if upgrade requires only code changes //func UpgradeActorsV9(ctx context.Context, sm *stmgr.StateManager, _ stmgr.MigrationCache, _ stmgr.ExecMonitor, root cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) (cid.Cid, error) { // buf := blockstore.NewTieredBstore(sm.ChainStore().StateBlockstore(), blockstore.NewMemorySync()) @@ -1616,10 +1762,10 @@ func LiteMigration(ctx context.Context, bstore blockstore.Blockstore, newActorsM return cid.Undef, xerrors.Errorf("error loading new manifest data: %w", err) } - if len(oldManifestData.Entries) != len(actors.GetBuiltinActorsKeys(oldAv)) { + if len(oldManifestData.Entries) != len(manifest.GetBuiltinActorsKeys(oldAv)) { return cid.Undef, xerrors.Errorf("incomplete old manifest with %d code CIDs", len(oldManifestData.Entries)) } - if len(newManifestData.Entries) != len(actors.GetBuiltinActorsKeys(newAv)) { + if len(newManifestData.Entries) != len(manifest.GetBuiltinActorsKeys(newAv)) { return cid.Undef, xerrors.Errorf("incomplete new manifest with %d code CIDs", len(newManifestData.Entries)) } diff --git a/chain/consensus/filcns/weight.go b/chain/consensus/filcns/weight.go index f5966aa19..ab90840c5 100644 --- a/chain/consensus/filcns/weight.go +++ b/chain/consensus/filcns/weight.go @@ -29,7 +29,7 @@ func Weight(ctx context.Context, stateBs bstore.Blockstore, ts *types.TipSet) (t // >>> wFunction(totalPowerAtTipset(ts)) * 2^8 <<< + (wFunction(totalPowerAtTipset(ts)) * sum(ts.blocks[].ElectionProof.WinCount) * wRatio_num * 2^8) / (e * wRatio_den) - tpow := big2.Zero() + var tpow big2.Int { cst := cbor.NewCborStore(stateBs) state, err := state.LoadStateTree(cst, ts.ParentState()) diff --git a/chain/ethhashlookup/eth_transaction_hash_lookup.go b/chain/ethhashlookup/eth_transaction_hash_lookup.go new file mode 100644 index 000000000..d93680912 --- /dev/null +++ b/chain/ethhashlookup/eth_transaction_hash_lookup.go @@ -0,0 +1,157 @@ +package ethhashlookup + +import ( + "database/sql" + "errors" + "strconv" + + "github.com/ipfs/go-cid" + _ "github.com/mattn/go-sqlite3" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/types/ethtypes" +) + +var ErrNotFound = errors.New("not found") + +var pragmas = []string{ + "PRAGMA synchronous = normal", + "PRAGMA temp_store = memory", + "PRAGMA mmap_size = 30000000000", + "PRAGMA page_size = 32768", + "PRAGMA auto_vacuum = NONE", + "PRAGMA automatic_index = OFF", + "PRAGMA journal_mode = WAL", + "PRAGMA read_uncommitted = ON", +} + +var ddls = []string{ + `CREATE TABLE IF NOT EXISTS eth_tx_hashes ( + hash TEXT PRIMARY KEY NOT NULL, + cid TEXT NOT NULL UNIQUE, + insertion_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL + )`, + + `CREATE INDEX IF NOT EXISTS insertion_time_index ON eth_tx_hashes (insertion_time)`, + + // metadata containing version of schema + `CREATE TABLE IF NOT EXISTS _meta ( + version UINT64 NOT NULL UNIQUE + )`, + + // version 1. + `INSERT OR IGNORE INTO _meta (version) VALUES (1)`, +} + +const schemaVersion = 1 + +const ( + insertTxHash = `INSERT INTO eth_tx_hashes + (hash, cid) + VALUES(?, ?) + ON CONFLICT (hash) DO UPDATE SET insertion_time = CURRENT_TIMESTAMP` +) + +type EthTxHashLookup struct { + db *sql.DB +} + +func (ei *EthTxHashLookup) UpsertHash(txHash ethtypes.EthHash, c cid.Cid) error { + hashEntry, err := ei.db.Prepare(insertTxHash) + if err != nil { + return xerrors.Errorf("prepare insert event: %w", err) + } + + _, err = hashEntry.Exec(txHash.String(), c.String()) + return err +} + +func (ei *EthTxHashLookup) GetCidFromHash(txHash ethtypes.EthHash) (cid.Cid, error) { + row := ei.db.QueryRow("SELECT cid FROM eth_tx_hashes WHERE hash = :hash;", sql.Named("hash", txHash.String())) + + var c string + err := row.Scan(&c) + if err != nil { + if err == sql.ErrNoRows { + return cid.Undef, ErrNotFound + } + return cid.Undef, err + } + return cid.Decode(c) +} + +func (ei *EthTxHashLookup) GetHashFromCid(c cid.Cid) (ethtypes.EthHash, error) { + row := ei.db.QueryRow("SELECT hash FROM eth_tx_hashes WHERE cid = :cid;", sql.Named("cid", c.String())) + + var hashString string + err := row.Scan(&c) + if err != nil { + if err == sql.ErrNoRows { + return ethtypes.EmptyEthHash, ErrNotFound + } + return ethtypes.EmptyEthHash, err + } + return ethtypes.ParseEthHash(hashString) +} + +func (ei *EthTxHashLookup) DeleteEntriesOlderThan(days int) (int64, error) { + res, err := ei.db.Exec("DELETE FROM eth_tx_hashes WHERE insertion_time < datetime('now', ?);", "-"+strconv.Itoa(days)+" day") + if err != nil { + return 0, err + } + + return res.RowsAffected() +} + +func NewTransactionHashLookup(path string) (*EthTxHashLookup, error) { + db, err := sql.Open("sqlite3", path+"?mode=rwc") + if err != nil { + return nil, xerrors.Errorf("open sqlite3 database: %w", err) + } + + for _, pragma := range pragmas { + if _, err := db.Exec(pragma); err != nil { + _ = db.Close() + return nil, xerrors.Errorf("exec pragma %q: %w", pragma, err) + } + } + + q, err := db.Query("SELECT name FROM sqlite_master WHERE type='table' AND name='_meta';") + if err == sql.ErrNoRows || !q.Next() { + // empty database, create the schema + for _, ddl := range ddls { + if _, err := db.Exec(ddl); err != nil { + _ = db.Close() + return nil, xerrors.Errorf("exec ddl %q: %w", ddl, err) + } + } + } else if err != nil { + _ = db.Close() + return nil, xerrors.Errorf("looking for _meta table: %w", err) + } else { + // Ensure we don't open a database from a different schema version + + row := db.QueryRow("SELECT max(version) FROM _meta") + var version int + err := row.Scan(&version) + if err != nil { + _ = db.Close() + return nil, xerrors.Errorf("invalid database version: no version found") + } + if version != schemaVersion { + _ = db.Close() + return nil, xerrors.Errorf("invalid database version: got %d, expected %d", version, schemaVersion) + } + } + + return &EthTxHashLookup{ + db: db, + }, nil +} + +func (ei *EthTxHashLookup) Close() error { + if ei.db == nil { + return nil + } + return ei.db.Close() +} diff --git a/chain/events/filter/event.go b/chain/events/filter/event.go new file mode 100644 index 000000000..b821a2f83 --- /dev/null +++ b/chain/events/filter/event.go @@ -0,0 +1,479 @@ +package filter + +import ( + "bytes" + "context" + "math" + "sync" + "time" + + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + amt4 "github.com/filecoin-project/go-amt-ipld/v4" + "github.com/filecoin-project/go-state-types/abi" + blockadt "github.com/filecoin-project/specs-actors/actors/util/adt" + + cstore "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" +) + +func isIndexedValue(b uint8) bool { + // currently we mark the full entry as indexed if either the key + // or the value are indexed; in the future we will need finer-grained + // management of indices + return b&(types.EventFlagIndexedKey|types.EventFlagIndexedValue) > 0 +} + +type EventFilter struct { + id types.FilterID + minHeight abi.ChainEpoch // minimum epoch to apply filter or -1 if no minimum + maxHeight abi.ChainEpoch // maximum epoch to apply filter or -1 if no maximum + tipsetCid cid.Cid + addresses []address.Address // list of f4 actor addresses that are extpected to emit the event + keys map[string][][]byte // map of key names to a list of alternate values that may match + maxResults int // maximum number of results to collect, 0 is unlimited + + mu sync.Mutex + collected []*CollectedEvent + lastTaken time.Time + ch chan<- interface{} +} + +var _ Filter = (*EventFilter)(nil) + +type CollectedEvent struct { + Entries []types.EventEntry + EmitterAddr address.Address // f4 address of emitter + EventIdx int // index of the event within the list of emitted events + Reverted bool + Height abi.ChainEpoch + TipSetKey types.TipSetKey // tipset that contained the message + MsgIdx int // index of the message in the tipset + MsgCid cid.Cid // cid of message that produced event +} + +func (f *EventFilter) ID() types.FilterID { + return f.id +} + +func (f *EventFilter) SetSubChannel(ch chan<- interface{}) { + f.mu.Lock() + defer f.mu.Unlock() + f.ch = ch + f.collected = nil +} + +func (f *EventFilter) ClearSubChannel() { + f.mu.Lock() + defer f.mu.Unlock() + f.ch = nil +} + +func (f *EventFilter) CollectEvents(ctx context.Context, te *TipSetEvents, revert bool, resolver func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool)) error { + if !f.matchTipset(te) { + return nil + } + + // cache of lookups between actor id and f4 address + addressLookups := make(map[abi.ActorID]address.Address) + + ems, err := te.messages(ctx) + if err != nil { + return xerrors.Errorf("load executed messages: %w", err) + } + for msgIdx, em := range ems { + for evIdx, ev := range em.Events() { + // lookup address corresponding to the actor id + addr, found := addressLookups[ev.Emitter] + if !found { + var ok bool + addr, ok = resolver(ctx, ev.Emitter, te.rctTs) + if !ok { + // not an address we will be able to match against + continue + } + addressLookups[ev.Emitter] = addr + } + + if !f.matchAddress(addr) { + continue + } + if !f.matchKeys(ev.Entries) { + continue + } + + // event matches filter, so record it + cev := &CollectedEvent{ + Entries: ev.Entries, + EmitterAddr: addr, + EventIdx: evIdx, + Reverted: revert, + Height: te.msgTs.Height(), + TipSetKey: te.msgTs.Key(), + MsgCid: em.Message().Cid(), + MsgIdx: msgIdx, + } + + f.mu.Lock() + // if we have a subscription channel then push event to it + if f.ch != nil { + f.ch <- cev + f.mu.Unlock() + continue + } + + if f.maxResults > 0 && len(f.collected) == f.maxResults { + copy(f.collected, f.collected[1:]) + f.collected = f.collected[:len(f.collected)-1] + } + f.collected = append(f.collected, cev) + f.mu.Unlock() + } + } + + return nil +} + +func (f *EventFilter) setCollectedEvents(ces []*CollectedEvent) { + f.mu.Lock() + f.collected = ces + f.mu.Unlock() +} + +func (f *EventFilter) TakeCollectedEvents(ctx context.Context) []*CollectedEvent { + f.mu.Lock() + collected := f.collected + f.collected = nil + f.lastTaken = time.Now().UTC() + f.mu.Unlock() + + return collected +} + +func (f *EventFilter) LastTaken() time.Time { + f.mu.Lock() + defer f.mu.Unlock() + return f.lastTaken +} + +// matchTipset reports whether this filter matches the given tipset +func (f *EventFilter) matchTipset(te *TipSetEvents) bool { + if f.tipsetCid != cid.Undef { + tsCid, err := te.Cid() + if err != nil { + return false + } + return f.tipsetCid.Equals(tsCid) + } + + if f.minHeight >= 0 && f.minHeight > te.Height() { + return false + } + if f.maxHeight >= 0 && f.maxHeight < te.Height() { + return false + } + return true +} + +func (f *EventFilter) matchAddress(o address.Address) bool { + if len(f.addresses) == 0 { + return true + } + + // Assume short lists of addresses + // TODO: binary search for longer lists or restrict list length + for _, a := range f.addresses { + if a == o { + return true + } + } + return false +} + +func (f *EventFilter) matchKeys(ees []types.EventEntry) bool { + if len(f.keys) == 0 { + return true + } + // TODO: optimize this naive algorithm + // tracked in https://github.com/filecoin-project/lotus/issues/9987 + + // Note keys names may be repeated so we may have multiple opportunities to match + + matched := map[string]bool{} + for _, ee := range ees { + // Skip an entry that is not indexable + if !isIndexedValue(ee.Flags) { + continue + } + + keyname := ee.Key + + // skip if we have already matched this key + if matched[keyname] { + continue + } + + wantlist, ok := f.keys[keyname] + if !ok || len(wantlist) == 0 { + continue + } + + for _, w := range wantlist { + if bytes.Equal(w, ee.Value) { + matched[keyname] = true + break + } + } + + if len(matched) == len(f.keys) { + // all keys have been matched + return true + } + + } + + return false +} + +type TipSetEvents struct { + rctTs *types.TipSet // rctTs is the tipset containing the receipts of executed messages + msgTs *types.TipSet // msgTs is the tipset containing the messages that have been executed + + load func(ctx context.Context, msgTs, rctTs *types.TipSet) ([]executedMessage, error) + + once sync.Once // for lazy population of ems + ems []executedMessage + err error +} + +func (te *TipSetEvents) Height() abi.ChainEpoch { + return te.msgTs.Height() +} + +func (te *TipSetEvents) Cid() (cid.Cid, error) { + return te.msgTs.Key().Cid() +} + +func (te *TipSetEvents) messages(ctx context.Context) ([]executedMessage, error) { + te.once.Do(func() { + // populate executed message list + ems, err := te.load(ctx, te.msgTs, te.rctTs) + if err != nil { + te.err = err + return + } + te.ems = ems + }) + return te.ems, te.err +} + +type executedMessage struct { + msg types.ChainMsg + rct *types.MessageReceipt + // events extracted from receipt + evs []*types.Event +} + +func (e *executedMessage) Message() types.ChainMsg { + return e.msg +} + +func (e *executedMessage) Receipt() *types.MessageReceipt { + return e.rct +} + +func (e *executedMessage) Events() []*types.Event { + return e.evs +} + +type EventFilterManager struct { + ChainStore *cstore.ChainStore + AddressResolver func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool) + MaxFilterResults int + EventIndex *EventIndex + + mu sync.Mutex // guards mutations to filters + filters map[types.FilterID]*EventFilter + currentHeight abi.ChainEpoch +} + +func (m *EventFilterManager) Apply(ctx context.Context, from, to *types.TipSet) error { + m.mu.Lock() + defer m.mu.Unlock() + m.currentHeight = to.Height() + + if len(m.filters) == 0 && m.EventIndex == nil { + return nil + } + + tse := &TipSetEvents{ + msgTs: from, + rctTs: to, + load: m.loadExecutedMessages, + } + + if m.EventIndex != nil { + if err := m.EventIndex.CollectEvents(ctx, tse, false, m.AddressResolver); err != nil { + return err + } + } + + // TODO: could run this loop in parallel with errgroup if there are many filters + for _, f := range m.filters { + if err := f.CollectEvents(ctx, tse, false, m.AddressResolver); err != nil { + return err + } + } + + return nil +} + +func (m *EventFilterManager) Revert(ctx context.Context, from, to *types.TipSet) error { + m.mu.Lock() + defer m.mu.Unlock() + m.currentHeight = to.Height() + + if len(m.filters) == 0 && m.EventIndex == nil { + return nil + } + + tse := &TipSetEvents{ + msgTs: to, + rctTs: from, + load: m.loadExecutedMessages, + } + + if m.EventIndex != nil { + if err := m.EventIndex.CollectEvents(ctx, tse, true, m.AddressResolver); err != nil { + return err + } + } + + // TODO: could run this loop in parallel with errgroup if there are many filters + for _, f := range m.filters { + if err := f.CollectEvents(ctx, tse, true, m.AddressResolver); err != nil { + return err + } + } + + return nil +} + +func (m *EventFilterManager) Install(ctx context.Context, minHeight, maxHeight abi.ChainEpoch, tipsetCid cid.Cid, addresses []address.Address, keys map[string][][]byte) (*EventFilter, error) { + m.mu.Lock() + currentHeight := m.currentHeight + m.mu.Unlock() + + if m.EventIndex == nil && minHeight != -1 && minHeight < currentHeight { + return nil, xerrors.Errorf("historic event index disabled") + } + + id, err := newFilterID() + if err != nil { + return nil, xerrors.Errorf("new filter id: %w", err) + } + + f := &EventFilter{ + id: id, + minHeight: minHeight, + maxHeight: maxHeight, + tipsetCid: tipsetCid, + addresses: addresses, + keys: keys, + maxResults: m.MaxFilterResults, + } + + if m.EventIndex != nil && minHeight != -1 && minHeight < currentHeight { + // Filter needs historic events + if err := m.EventIndex.PrefillFilter(ctx, f); err != nil { + return nil, err + } + } + + m.mu.Lock() + if m.filters == nil { + m.filters = make(map[types.FilterID]*EventFilter) + } + m.filters[id] = f + m.mu.Unlock() + + return f, nil +} + +func (m *EventFilterManager) Remove(ctx context.Context, id types.FilterID) error { + m.mu.Lock() + defer m.mu.Unlock() + if _, found := m.filters[id]; !found { + return ErrFilterNotFound + } + delete(m.filters, id) + return nil +} + +func (m *EventFilterManager) loadExecutedMessages(ctx context.Context, msgTs, rctTs *types.TipSet) ([]executedMessage, error) { + msgs, err := m.ChainStore.MessagesForTipset(ctx, msgTs) + if err != nil { + return nil, xerrors.Errorf("read messages: %w", err) + } + + st := m.ChainStore.ActorStore(ctx) + + arr, err := blockadt.AsArray(st, rctTs.Blocks()[0].ParentMessageReceipts) + if err != nil { + return nil, xerrors.Errorf("load receipts amt: %w", err) + } + + if uint64(len(msgs)) != arr.Length() { + return nil, xerrors.Errorf("mismatching message and receipt counts (%d msgs, %d rcts)", len(msgs), arr.Length()) + } + + ems := make([]executedMessage, len(msgs)) + + for i := 0; i < len(msgs); i++ { + ems[i].msg = msgs[i] + + var rct types.MessageReceipt + found, err := arr.Get(uint64(i), &rct) + if err != nil { + return nil, xerrors.Errorf("load receipt: %w", err) + } + if !found { + return nil, xerrors.Errorf("receipt %d not found", i) + } + ems[i].rct = &rct + + if rct.EventsRoot == nil { + continue + } + + evtArr, err := amt4.LoadAMT(ctx, st, *rct.EventsRoot, amt4.UseTreeBitWidth(types.EventAMTBitwidth)) + if err != nil { + return nil, xerrors.Errorf("load events amt: %w", err) + } + + ems[i].evs = make([]*types.Event, evtArr.Len()) + var evt types.Event + err = evtArr.ForEach(ctx, func(u uint64, deferred *cbg.Deferred) error { + if u > math.MaxInt { + return xerrors.Errorf("too many events") + } + if err := evt.UnmarshalCBOR(bytes.NewReader(deferred.Raw)); err != nil { + return err + } + + cpy := evt + ems[i].evs[int(u)] = &cpy //nolint:scopelint + return nil + }) + + if err != nil { + return nil, xerrors.Errorf("read events: %w", err) + } + + } + + return ems, nil +} diff --git a/chain/events/filter/event_test.go b/chain/events/filter/event_test.go new file mode 100644 index 000000000..329573bc1 --- /dev/null +++ b/chain/events/filter/event_test.go @@ -0,0 +1,433 @@ +package filter + +import ( + "context" + pseudo "math/rand" + "testing" + + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + mh "github.com/multiformats/go-multihash" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + builtintypes "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/exitcode" + blockadt "github.com/filecoin-project/specs-actors/actors/util/adt" + + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" +) + +func TestEventFilterCollectEvents(t *testing.T) { + rng := pseudo.New(pseudo.NewSource(299792458)) + a1 := randomF4Addr(t, rng) + a2 := randomF4Addr(t, rng) + + a1ID := abi.ActorID(1) + a2ID := abi.ActorID(2) + + addrMap := addressMap{} + addrMap.add(a1ID, a1) + addrMap.add(a2ID, a2) + + ev1 := fakeEvent( + a1ID, + []kv{ + {k: "type", v: []byte("approval")}, + {k: "signer", v: []byte("addr1")}, + }, + []kv{ + {k: "amount", v: []byte("2988181")}, + }, + ) + + st := newStore() + events := []*types.Event{ev1} + em := executedMessage{ + msg: fakeMessage(randomF4Addr(t, rng), randomF4Addr(t, rng)), + rct: fakeReceipt(t, rng, st, events), + evs: events, + } + + events14000 := buildTipSetEvents(t, rng, 14000, em) + cid14000, err := events14000.msgTs.Key().Cid() + require.NoError(t, err, "tipset cid") + + noCollectedEvents := []*CollectedEvent{} + oneCollectedEvent := []*CollectedEvent{ + { + Entries: ev1.Entries, + EmitterAddr: a1, + EventIdx: 0, + Reverted: false, + Height: 14000, + TipSetKey: events14000.msgTs.Key(), + MsgIdx: 0, + MsgCid: em.msg.Cid(), + }, + } + + testCases := []struct { + name string + filter *EventFilter + te *TipSetEvents + want []*CollectedEvent + }{ + { + name: "nomatch tipset min height", + filter: &EventFilter{ + minHeight: 14001, + maxHeight: -1, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "nomatch tipset max height", + filter: &EventFilter{ + minHeight: -1, + maxHeight: 13999, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "match tipset min height", + filter: &EventFilter{ + minHeight: 14000, + maxHeight: -1, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "match tipset cid", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + tipsetCid: cid14000, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "nomatch address", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + addresses: []address.Address{a2}, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "match address", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + addresses: []address.Address{a1}, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "match one entry", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("approval"), + }, + }, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "match one entry with alternate values", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("cancel"), + []byte("propose"), + []byte("approval"), + }, + }, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "nomatch one entry by missing value", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("cancel"), + []byte("propose"), + }, + }, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "nomatch one entry by missing key", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "method": { + []byte("approval"), + }, + }, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "match one entry with multiple keys", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("approval"), + }, + "signer": { + []byte("addr1"), + }, + }, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "nomatch one entry with one mismatching key", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("approval"), + }, + "approver": { + []byte("addr1"), + }, + }, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "nomatch one entry with one mismatching value", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("approval"), + }, + "signer": { + []byte("addr2"), + }, + }, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "nomatch one entry with one unindexed key", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "amount": { + []byte("2988181"), + }, + }, + }, + te: events14000, + want: noCollectedEvents, + }, + } + + for _, tc := range testCases { + tc := tc // appease lint + t.Run(tc.name, func(t *testing.T) { + if err := tc.filter.CollectEvents(context.Background(), tc.te, false, addrMap.ResolveAddress); err != nil { + require.NoError(t, err, "collect events") + } + + coll := tc.filter.TakeCollectedEvents(context.Background()) + require.ElementsMatch(t, coll, tc.want) + }) + } +} + +type kv struct { + k string + v []byte +} + +func fakeEvent(emitter abi.ActorID, indexed []kv, unindexed []kv) *types.Event { + ev := &types.Event{ + Emitter: emitter, + } + + for _, in := range indexed { + ev.Entries = append(ev.Entries, types.EventEntry{ + Flags: 0x01, + Key: in.k, + Codec: cid.Raw, + Value: in.v, + }) + } + + for _, in := range unindexed { + ev.Entries = append(ev.Entries, types.EventEntry{ + Flags: 0x00, + Key: in.k, + Codec: cid.Raw, + Value: in.v, + }) + } + + return ev +} + +func randomF4Addr(tb testing.TB, rng *pseudo.Rand) address.Address { + tb.Helper() + addr, err := address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, randomBytes(32, rng)) + require.NoError(tb, err) + + return addr +} + +func randomIDAddr(tb testing.TB, rng *pseudo.Rand) address.Address { + tb.Helper() + addr, err := address.NewIDAddress(uint64(rng.Int63())) + require.NoError(tb, err) + return addr +} + +func randomCid(tb testing.TB, rng *pseudo.Rand) cid.Cid { + tb.Helper() + cb := cid.V1Builder{Codec: cid.Raw, MhType: mh.IDENTITY} + c, err := cb.Sum(randomBytes(10, rng)) + require.NoError(tb, err) + return c +} + +func randomBytes(n int, rng *pseudo.Rand) []byte { + buf := make([]byte, n) + rng.Read(buf) + return buf +} + +func fakeMessage(to, from address.Address) *types.Message { + return &types.Message{ + To: to, + From: from, + Nonce: 197, + Method: 1, + Params: []byte("some random bytes"), + GasLimit: 126723, + GasPremium: types.NewInt(4), + GasFeeCap: types.NewInt(120), + } +} + +func fakeReceipt(tb testing.TB, rng *pseudo.Rand, st adt.Store, events []*types.Event) *types.MessageReceipt { + arr := blockadt.MakeEmptyArray(st) + for _, ev := range events { + err := arr.AppendContinuous(ev) + require.NoError(tb, err, "append event") + } + eventsRoot, err := arr.Root() + require.NoError(tb, err, "flush events amt") + + rec := types.NewMessageReceiptV1(exitcode.Ok, randomBytes(32, rng), rng.Int63(), &eventsRoot) + return &rec +} + +func fakeTipSet(tb testing.TB, rng *pseudo.Rand, h abi.ChainEpoch, parents []cid.Cid) *types.TipSet { + tb.Helper() + ts, err := types.NewTipSet([]*types.BlockHeader{ + { + Height: h, + Miner: randomIDAddr(tb, rng), + + Parents: parents, + + Ticket: &types.Ticket{VRFProof: []byte{byte(h % 2)}}, + + ParentStateRoot: randomCid(tb, rng), + Messages: randomCid(tb, rng), + ParentMessageReceipts: randomCid(tb, rng), + + BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS}, + BLSAggregate: &crypto.Signature{Type: crypto.SigTypeBLS}, + }, + { + Height: h, + Miner: randomIDAddr(tb, rng), + + Parents: parents, + + Ticket: &types.Ticket{VRFProof: []byte{byte((h + 1) % 2)}}, + + ParentStateRoot: randomCid(tb, rng), + Messages: randomCid(tb, rng), + ParentMessageReceipts: randomCid(tb, rng), + + BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS}, + BLSAggregate: &crypto.Signature{Type: crypto.SigTypeBLS}, + }, + }) + + require.NoError(tb, err) + + return ts +} + +func newStore() adt.Store { + ctx := context.Background() + bs := blockstore.NewMemorySync() + store := cbor.NewCborStore(bs) + return adt.WrapStore(ctx, store) +} + +func buildTipSetEvents(tb testing.TB, rng *pseudo.Rand, h abi.ChainEpoch, em executedMessage) *TipSetEvents { + tb.Helper() + + msgTs := fakeTipSet(tb, rng, h, []cid.Cid{}) + rctTs := fakeTipSet(tb, rng, h+1, msgTs.Cids()) + + return &TipSetEvents{ + msgTs: msgTs, + rctTs: rctTs, + load: func(ctx context.Context, msgTs, rctTs *types.TipSet) ([]executedMessage, error) { + return []executedMessage{em}, nil + }, + } +} + +type addressMap map[abi.ActorID]address.Address + +func (a addressMap) add(actorID abi.ActorID, addr address.Address) { + a[actorID] = addr +} + +func (a addressMap) ResolveAddress(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool) { + ra, ok := a[emitter] + return ra, ok +} diff --git a/chain/events/filter/index.go b/chain/events/filter/index.go new file mode 100644 index 000000000..ab4e24493 --- /dev/null +++ b/chain/events/filter/index.go @@ -0,0 +1,406 @@ +package filter + +import ( + "context" + "database/sql" + "errors" + "fmt" + "sort" + "strings" + + "github.com/ipfs/go-cid" + _ "github.com/mattn/go-sqlite3" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/chain/types" +) + +var pragmas = []string{ + "PRAGMA synchronous = normal", + "PRAGMA temp_store = memory", + "PRAGMA mmap_size = 30000000000", + "PRAGMA page_size = 32768", + "PRAGMA auto_vacuum = NONE", + "PRAGMA automatic_index = OFF", + "PRAGMA journal_mode = WAL", + "PRAGMA read_uncommitted = ON", +} + +var ddls = []string{ + `CREATE TABLE IF NOT EXISTS event ( + id INTEGER PRIMARY KEY, + height INTEGER NOT NULL, + tipset_key BLOB NOT NULL, + tipset_key_cid BLOB NOT NULL, + emitter_addr BLOB NOT NULL, + event_index INTEGER NOT NULL, + message_cid BLOB NOT NULL, + message_index INTEGER NOT NULL, + reverted INTEGER NOT NULL + )`, + + `CREATE TABLE IF NOT EXISTS event_entry ( + event_id INTEGER, + indexed INTEGER NOT NULL, + flags BLOB NOT NULL, + key TEXT NOT NULL, + codec INTEGER, + value BLOB NOT NULL + )`, + + // metadata containing version of schema + `CREATE TABLE IF NOT EXISTS _meta ( + version UINT64 NOT NULL UNIQUE + )`, + + // version 1. + `INSERT OR IGNORE INTO _meta (version) VALUES (1)`, +} + +const schemaVersion = 1 + +const ( + insertEvent = `INSERT OR IGNORE INTO event + (height, tipset_key, tipset_key_cid, emitter_addr, event_index, message_cid, message_index, reverted) + VALUES(?, ?, ?, ?, ?, ?, ?, ?)` + + insertEntry = `INSERT OR IGNORE INTO event_entry + (event_id, indexed, flags, key, codec, value) + VALUES(?, ?, ?, ?, ?, ?)` +) + +type EventIndex struct { + db *sql.DB +} + +func NewEventIndex(path string) (*EventIndex, error) { + db, err := sql.Open("sqlite3", path+"?mode=rwc") + if err != nil { + return nil, xerrors.Errorf("open sqlite3 database: %w", err) + } + + for _, pragma := range pragmas { + if _, err := db.Exec(pragma); err != nil { + _ = db.Close() + return nil, xerrors.Errorf("exec pragma %q: %w", pragma, err) + } + } + + q, err := db.Query("SELECT name FROM sqlite_master WHERE type='table' AND name='_meta';") + if err == sql.ErrNoRows || !q.Next() { + // empty database, create the schema + for _, ddl := range ddls { + if _, err := db.Exec(ddl); err != nil { + _ = db.Close() + return nil, xerrors.Errorf("exec ddl %q: %w", ddl, err) + } + } + } else if err != nil { + _ = db.Close() + return nil, xerrors.Errorf("looking for _meta table: %w", err) + } else { + // Ensure we don't open a database from a different schema version + + row := db.QueryRow("SELECT max(version) FROM _meta") + var version int + err := row.Scan(&version) + if err != nil { + _ = db.Close() + return nil, xerrors.Errorf("invalid database version: no version found") + } + if version != schemaVersion { + _ = db.Close() + return nil, xerrors.Errorf("invalid database version: got %d, expected %d", version, schemaVersion) + } + } + + return &EventIndex{ + db: db, + }, nil +} + +func (ei *EventIndex) Close() error { + if ei.db == nil { + return nil + } + return ei.db.Close() +} + +func (ei *EventIndex) CollectEvents(ctx context.Context, te *TipSetEvents, revert bool, resolver func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool)) error { + // cache of lookups between actor id and f4 address + + addressLookups := make(map[abi.ActorID]address.Address) + + ems, err := te.messages(ctx) + if err != nil { + return xerrors.Errorf("load executed messages: %w", err) + } + + tx, err := ei.db.Begin() + if err != nil { + return xerrors.Errorf("begin transaction: %w", err) + } + stmtEvent, err := tx.Prepare(insertEvent) + if err != nil { + return xerrors.Errorf("prepare insert event: %w", err) + } + stmtEntry, err := tx.Prepare(insertEntry) + if err != nil { + return xerrors.Errorf("prepare insert entry: %w", err) + } + + for msgIdx, em := range ems { + for evIdx, ev := range em.Events() { + addr, found := addressLookups[ev.Emitter] + if !found { + var ok bool + addr, ok = resolver(ctx, ev.Emitter, te.rctTs) + if !ok { + // not an address we will be able to match against + continue + } + addressLookups[ev.Emitter] = addr + } + + tsKeyCid, err := te.msgTs.Key().Cid() + if err != nil { + return xerrors.Errorf("tipset key cid: %w", err) + } + + res, err := stmtEvent.Exec( + te.msgTs.Height(), // height + te.msgTs.Key().Bytes(), // tipset_key + tsKeyCid.Bytes(), // tipset_key_cid + addr.Bytes(), // emitter_addr + evIdx, // event_index + em.Message().Cid().Bytes(), // message_cid + msgIdx, // message_index + revert, // reverted + ) + if err != nil { + return xerrors.Errorf("exec insert event: %w", err) + } + + lastID, err := res.LastInsertId() + if err != nil { + return xerrors.Errorf("get last row id: %w", err) + } + + for _, entry := range ev.Entries { + _, err := stmtEntry.Exec( + lastID, // event_id + isIndexedValue(entry.Flags), // indexed + []byte{entry.Flags}, // flags + entry.Key, // key + entry.Codec, // codec + entry.Value, // value + ) + if err != nil { + return xerrors.Errorf("exec insert entry: %w", err) + } + } + } + } + + if err := tx.Commit(); err != nil { + return xerrors.Errorf("commit transaction: %w", err) + } + + return nil +} + +// PrefillFilter fills a filter's collection of events from the historic index +func (ei *EventIndex) PrefillFilter(ctx context.Context, f *EventFilter) error { + clauses := []string{} + values := []any{} + joins := []string{} + + if f.tipsetCid != cid.Undef { + clauses = append(clauses, "event.tipset_key_cid=?") + values = append(values, f.tipsetCid.Bytes()) + } else { + if f.minHeight >= 0 { + clauses = append(clauses, "event.height>=?") + values = append(values, f.minHeight) + } + if f.maxHeight >= 0 { + clauses = append(clauses, "event.height<=?") + values = append(values, f.maxHeight) + } + } + + if len(f.addresses) > 0 { + subclauses := []string{} + for _, addr := range f.addresses { + subclauses = append(subclauses, "emitter_addr=?") + values = append(values, addr.Bytes()) + } + clauses = append(clauses, "("+strings.Join(subclauses, " OR ")+")") + } + + if len(f.keys) > 0 { + join := 0 + for key, vals := range f.keys { + if len(vals) > 0 { + join++ + joinAlias := fmt.Sprintf("ee%d", join) + joins = append(joins, fmt.Sprintf("event_entry %s on event.id=%[1]s.event_id", joinAlias)) + clauses = append(clauses, fmt.Sprintf("%s.indexed=1 AND %[1]s.key=?", joinAlias)) + values = append(values, key) + subclauses := []string{} + for _, val := range vals { + subclauses = append(subclauses, fmt.Sprintf("%s.value=?", joinAlias)) + values = append(values, val) + } + clauses = append(clauses, "("+strings.Join(subclauses, " OR ")+")") + } + } + } + + s := `SELECT + event.id, + event.height, + event.tipset_key, + event.tipset_key_cid, + event.emitter_addr, + event.event_index, + event.message_cid, + event.message_index, + event.reverted, + event_entry.flags, + event_entry.key, + event_entry.codec, + event_entry.value + FROM event JOIN event_entry ON event.id=event_entry.event_id` + + if len(joins) > 0 { + s = s + ", " + strings.Join(joins, ", ") + } + + if len(clauses) > 0 { + s = s + " WHERE " + strings.Join(clauses, " AND ") + } + + s += " ORDER BY event.height DESC" + + stmt, err := ei.db.Prepare(s) + if err != nil { + return xerrors.Errorf("prepare prefill query: %w", err) + } + + q, err := stmt.QueryContext(ctx, values...) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil + } + return xerrors.Errorf("exec prefill query: %w", err) + } + + var ces []*CollectedEvent + var currentID int64 = -1 + var ce *CollectedEvent + + for q.Next() { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + + var row struct { + id int64 + height uint64 + tipsetKey []byte + tipsetKeyCid []byte + emitterAddr []byte + eventIndex int + messageCid []byte + messageIndex int + reverted bool + flags []byte + key string + codec uint64 + value []byte + } + + if err := q.Scan( + &row.id, + &row.height, + &row.tipsetKey, + &row.tipsetKeyCid, + &row.emitterAddr, + &row.eventIndex, + &row.messageCid, + &row.messageIndex, + &row.reverted, + &row.flags, + &row.key, + &row.codec, + &row.value, + ); err != nil { + return xerrors.Errorf("read prefill row: %w", err) + } + + if row.id != currentID { + if ce != nil { + ces = append(ces, ce) + ce = nil + // Unfortunately we can't easily incorporate the max results limit into the query due to the + // unpredictable number of rows caused by joins + // Break here to stop collecting rows + if f.maxResults > 0 && len(ces) >= f.maxResults { + break + } + } + + currentID = row.id + ce = &CollectedEvent{ + EventIdx: row.eventIndex, + Reverted: row.reverted, + Height: abi.ChainEpoch(row.height), + MsgIdx: row.messageIndex, + } + + ce.EmitterAddr, err = address.NewFromBytes(row.emitterAddr) + if err != nil { + return xerrors.Errorf("parse emitter addr: %w", err) + } + + ce.TipSetKey, err = types.TipSetKeyFromBytes(row.tipsetKey) + if err != nil { + return xerrors.Errorf("parse tipsetkey: %w", err) + } + + ce.MsgCid, err = cid.Cast(row.messageCid) + if err != nil { + return xerrors.Errorf("parse message cid: %w", err) + } + } + + ce.Entries = append(ce.Entries, types.EventEntry{ + Flags: row.flags[0], + Key: row.key, + Codec: row.codec, + Value: row.value, + }) + + } + + if ce != nil { + ces = append(ces, ce) + } + + if len(ces) == 0 { + return nil + } + + // collected event list is in inverted order since we selected only the most recent events + // sort it into height order + sort.Slice(ces, func(i, j int) bool { return ces[i].Height < ces[j].Height }) + f.setCollectedEvents(ces) + + return nil +} diff --git a/chain/events/filter/index_test.go b/chain/events/filter/index_test.go new file mode 100644 index 000000000..ee2ae8611 --- /dev/null +++ b/chain/events/filter/index_test.go @@ -0,0 +1,283 @@ +package filter + +import ( + "context" + pseudo "math/rand" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/chain/types" +) + +func TestEventIndexPrefillFilter(t *testing.T) { + rng := pseudo.New(pseudo.NewSource(299792458)) + a1 := randomF4Addr(t, rng) + a2 := randomF4Addr(t, rng) + + a1ID := abi.ActorID(1) + a2ID := abi.ActorID(2) + + addrMap := addressMap{} + addrMap.add(a1ID, a1) + addrMap.add(a2ID, a2) + + ev1 := fakeEvent( + a1ID, + []kv{ + {k: "type", v: []byte("approval")}, + {k: "signer", v: []byte("addr1")}, + }, + []kv{ + {k: "amount", v: []byte("2988181")}, + }, + ) + + st := newStore() + events := []*types.Event{ev1} + em := executedMessage{ + msg: fakeMessage(randomF4Addr(t, rng), randomF4Addr(t, rng)), + rct: fakeReceipt(t, rng, st, events), + evs: events, + } + + events14000 := buildTipSetEvents(t, rng, 14000, em) + cid14000, err := events14000.msgTs.Key().Cid() + require.NoError(t, err, "tipset cid") + + noCollectedEvents := []*CollectedEvent{} + oneCollectedEvent := []*CollectedEvent{ + { + Entries: ev1.Entries, + EmitterAddr: a1, + EventIdx: 0, + Reverted: false, + Height: 14000, + TipSetKey: events14000.msgTs.Key(), + MsgIdx: 0, + MsgCid: em.msg.Cid(), + }, + } + + workDir, err := os.MkdirTemp("", "lotusevents") + require.NoError(t, err, "create temporary work directory") + + defer func() { + _ = os.RemoveAll(workDir) + }() + t.Logf("using work dir %q", workDir) + + dbPath := filepath.Join(workDir, "actorevents.db") + + ei, err := NewEventIndex(dbPath) + require.NoError(t, err, "create event index") + if err := ei.CollectEvents(context.Background(), events14000, false, addrMap.ResolveAddress); err != nil { + require.NoError(t, err, "collect events") + } + + testCases := []struct { + name string + filter *EventFilter + te *TipSetEvents + want []*CollectedEvent + }{ + { + name: "nomatch tipset min height", + filter: &EventFilter{ + minHeight: 14001, + maxHeight: -1, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "nomatch tipset max height", + filter: &EventFilter{ + minHeight: -1, + maxHeight: 13999, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "match tipset min height", + filter: &EventFilter{ + minHeight: 14000, + maxHeight: -1, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "match tipset cid", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + tipsetCid: cid14000, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "nomatch address", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + addresses: []address.Address{a2}, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "match address", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + addresses: []address.Address{a1}, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "match one entry", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("approval"), + }, + }, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "match one entry with alternate values", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("cancel"), + []byte("propose"), + []byte("approval"), + }, + }, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "nomatch one entry by missing value", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("cancel"), + []byte("propose"), + }, + }, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "nomatch one entry by missing key", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "method": { + []byte("approval"), + }, + }, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "match one entry with multiple keys", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("approval"), + }, + "signer": { + []byte("addr1"), + }, + }, + }, + te: events14000, + want: oneCollectedEvent, + }, + { + name: "nomatch one entry with one mismatching key", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("approval"), + }, + "approver": { + []byte("addr1"), + }, + }, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "nomatch one entry with one mismatching value", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "type": { + []byte("approval"), + }, + "signer": { + []byte("addr2"), + }, + }, + }, + te: events14000, + want: noCollectedEvents, + }, + { + name: "nomatch one entry with one unindexed key", + filter: &EventFilter{ + minHeight: -1, + maxHeight: -1, + keys: map[string][][]byte{ + "amount": { + []byte("2988181"), + }, + }, + }, + te: events14000, + want: noCollectedEvents, + }, + } + + for _, tc := range testCases { + tc := tc // appease lint + t.Run(tc.name, func(t *testing.T) { + if err := ei.PrefillFilter(context.Background(), tc.filter); err != nil { + require.NoError(t, err, "prefill filter events") + } + + coll := tc.filter.TakeCollectedEvents(context.Background()) + require.ElementsMatch(t, coll, tc.want) + }) + } +} diff --git a/chain/events/filter/mempool.go b/chain/events/filter/mempool.go new file mode 100644 index 000000000..39ccf12c2 --- /dev/null +++ b/chain/events/filter/mempool.go @@ -0,0 +1,142 @@ +package filter + +import ( + "context" + "sync" + "time" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" +) + +type MemPoolFilter struct { + id types.FilterID + maxResults int // maximum number of results to collect, 0 is unlimited + ch chan<- interface{} + + mu sync.Mutex + collected []*types.SignedMessage + lastTaken time.Time +} + +var _ Filter = (*MemPoolFilter)(nil) + +func (f *MemPoolFilter) ID() types.FilterID { + return f.id +} + +func (f *MemPoolFilter) SetSubChannel(ch chan<- interface{}) { + f.mu.Lock() + defer f.mu.Unlock() + f.ch = ch + f.collected = nil +} + +func (f *MemPoolFilter) ClearSubChannel() { + f.mu.Lock() + defer f.mu.Unlock() + f.ch = nil +} + +func (f *MemPoolFilter) CollectMessage(ctx context.Context, msg *types.SignedMessage) { + f.mu.Lock() + defer f.mu.Unlock() + + // if we have a subscription channel then push message to it + if f.ch != nil { + f.ch <- msg + return + } + + if f.maxResults > 0 && len(f.collected) == f.maxResults { + copy(f.collected, f.collected[1:]) + f.collected = f.collected[:len(f.collected)-1] + } + f.collected = append(f.collected, msg) +} + +func (f *MemPoolFilter) TakeCollectedMessages(context.Context) []*types.SignedMessage { + f.mu.Lock() + collected := f.collected + f.collected = nil + f.lastTaken = time.Now().UTC() + f.mu.Unlock() + + return collected +} + +func (f *MemPoolFilter) LastTaken() time.Time { + f.mu.Lock() + defer f.mu.Unlock() + return f.lastTaken +} + +type MemPoolFilterManager struct { + MaxFilterResults int + + mu sync.Mutex // guards mutations to filters + filters map[types.FilterID]*MemPoolFilter +} + +func (m *MemPoolFilterManager) WaitForMpoolUpdates(ctx context.Context, ch <-chan api.MpoolUpdate) { + for { + select { + case <-ctx.Done(): + return + case u := <-ch: + m.processUpdate(ctx, u) + } + } +} + +func (m *MemPoolFilterManager) processUpdate(ctx context.Context, u api.MpoolUpdate) { + // only process added messages + if u.Type == api.MpoolRemove { + return + } + + m.mu.Lock() + defer m.mu.Unlock() + + if len(m.filters) == 0 { + return + } + + // TODO: could run this loop in parallel with errgroup if we expect large numbers of filters + for _, f := range m.filters { + f.CollectMessage(ctx, u.Message) + } +} + +func (m *MemPoolFilterManager) Install(ctx context.Context) (*MemPoolFilter, error) { + id, err := newFilterID() + if err != nil { + return nil, xerrors.Errorf("new filter id: %w", err) + } + + f := &MemPoolFilter{ + id: id, + maxResults: m.MaxFilterResults, + } + + m.mu.Lock() + if m.filters == nil { + m.filters = make(map[types.FilterID]*MemPoolFilter) + } + m.filters[id] = f + m.mu.Unlock() + + return f, nil +} + +func (m *MemPoolFilterManager) Remove(ctx context.Context, id types.FilterID) error { + m.mu.Lock() + defer m.mu.Unlock() + if _, found := m.filters[id]; !found { + return ErrFilterNotFound + } + delete(m.filters, id) + return nil +} diff --git a/chain/events/filter/store.go b/chain/events/filter/store.go new file mode 100644 index 000000000..d3c173ec0 --- /dev/null +++ b/chain/events/filter/store.go @@ -0,0 +1,108 @@ +package filter + +import ( + "context" + "errors" + "sync" + "time" + + "github.com/google/uuid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/types" +) + +type Filter interface { + ID() types.FilterID + LastTaken() time.Time + SetSubChannel(chan<- interface{}) + ClearSubChannel() +} + +type FilterStore interface { + Add(context.Context, Filter) error + Get(context.Context, types.FilterID) (Filter, error) + Remove(context.Context, types.FilterID) error + NotTakenSince(when time.Time) []Filter // returns a list of filters that have not had their collected results taken +} + +var ( + ErrFilterAlreadyRegistered = errors.New("filter already registered") + ErrFilterNotFound = errors.New("filter not found") + ErrMaximumNumberOfFilters = errors.New("maximum number of filters registered") +) + +func newFilterID() (types.FilterID, error) { + rawid, err := uuid.NewRandom() + if err != nil { + return types.FilterID{}, xerrors.Errorf("new uuid: %w", err) + } + id := types.FilterID{} + copy(id[:], rawid[:]) // uuid is 16 bytes, the last 16 bytes are zeroed + return id, nil +} + +type memFilterStore struct { + max int + mu sync.Mutex + filters map[types.FilterID]Filter +} + +var _ FilterStore = (*memFilterStore)(nil) + +func NewMemFilterStore(maxFilters int) FilterStore { + return &memFilterStore{ + max: maxFilters, + filters: make(map[types.FilterID]Filter), + } +} + +func (m *memFilterStore) Add(_ context.Context, f Filter) error { + m.mu.Lock() + defer m.mu.Unlock() + + if len(m.filters) >= m.max { + return ErrMaximumNumberOfFilters + } + + if _, exists := m.filters[f.ID()]; exists { + return ErrFilterAlreadyRegistered + } + m.filters[f.ID()] = f + return nil +} + +func (m *memFilterStore) Get(_ context.Context, id types.FilterID) (Filter, error) { + m.mu.Lock() + f, found := m.filters[id] + m.mu.Unlock() + if !found { + return nil, ErrFilterNotFound + } + return f, nil +} + +func (m *memFilterStore) Remove(_ context.Context, id types.FilterID) error { + m.mu.Lock() + defer m.mu.Unlock() + + if _, exists := m.filters[id]; !exists { + return ErrFilterNotFound + } + delete(m.filters, id) + return nil +} + +func (m *memFilterStore) NotTakenSince(when time.Time) []Filter { + m.mu.Lock() + defer m.mu.Unlock() + + var res []Filter + for _, f := range m.filters { + if f.LastTaken().Before(when) { + res = append(res, f) + } + } + + return res +} diff --git a/chain/events/filter/tipset.go b/chain/events/filter/tipset.go new file mode 100644 index 000000000..be734c6f7 --- /dev/null +++ b/chain/events/filter/tipset.go @@ -0,0 +1,130 @@ +package filter + +import ( + "context" + "sync" + "time" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/types" +) + +type TipSetFilter struct { + id types.FilterID + maxResults int // maximum number of results to collect, 0 is unlimited + ch chan<- interface{} + + mu sync.Mutex + collected []types.TipSetKey + lastTaken time.Time +} + +var _ Filter = (*TipSetFilter)(nil) + +func (f *TipSetFilter) ID() types.FilterID { + return f.id +} + +func (f *TipSetFilter) SetSubChannel(ch chan<- interface{}) { + f.mu.Lock() + defer f.mu.Unlock() + f.ch = ch + f.collected = nil +} + +func (f *TipSetFilter) ClearSubChannel() { + f.mu.Lock() + defer f.mu.Unlock() + f.ch = nil +} + +func (f *TipSetFilter) CollectTipSet(ctx context.Context, ts *types.TipSet) { + f.mu.Lock() + defer f.mu.Unlock() + + // if we have a subscription channel then push tipset to it + if f.ch != nil { + f.ch <- ts + return + } + + if f.maxResults > 0 && len(f.collected) == f.maxResults { + copy(f.collected, f.collected[1:]) + f.collected = f.collected[:len(f.collected)-1] + } + f.collected = append(f.collected, ts.Key()) +} + +func (f *TipSetFilter) TakeCollectedTipSets(context.Context) []types.TipSetKey { + f.mu.Lock() + collected := f.collected + f.collected = nil + f.lastTaken = time.Now().UTC() + f.mu.Unlock() + + return collected +} + +func (f *TipSetFilter) LastTaken() time.Time { + f.mu.Lock() + defer f.mu.Unlock() + return f.lastTaken +} + +type TipSetFilterManager struct { + MaxFilterResults int + + mu sync.Mutex // guards mutations to filters + filters map[types.FilterID]*TipSetFilter +} + +func (m *TipSetFilterManager) Apply(ctx context.Context, from, to *types.TipSet) error { + m.mu.Lock() + defer m.mu.Unlock() + if len(m.filters) == 0 { + return nil + } + + // TODO: could run this loop in parallel with errgroup + for _, f := range m.filters { + f.CollectTipSet(ctx, to) + } + + return nil +} + +func (m *TipSetFilterManager) Revert(ctx context.Context, from, to *types.TipSet) error { + return nil +} + +func (m *TipSetFilterManager) Install(ctx context.Context) (*TipSetFilter, error) { + id, err := newFilterID() + if err != nil { + return nil, xerrors.Errorf("new filter id: %w", err) + } + + f := &TipSetFilter{ + id: id, + maxResults: m.MaxFilterResults, + } + + m.mu.Lock() + if m.filters == nil { + m.filters = make(map[types.FilterID]*TipSetFilter) + } + m.filters[id] = f + m.mu.Unlock() + + return f, nil +} + +func (m *TipSetFilterManager) Remove(ctx context.Context, id types.FilterID) error { + m.mu.Lock() + defer m.mu.Unlock() + if _, found := m.filters[id]; !found { + return ErrFilterNotFound + } + delete(m.filters, id) + return nil +} diff --git a/chain/events/state/mock/api.go b/chain/events/state/mock/api.go index cdec42659..680e304f5 100644 --- a/chain/events/state/mock/api.go +++ b/chain/events/state/mock/api.go @@ -4,8 +4,8 @@ import ( "context" "sync" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" diff --git a/chain/exchange/client.go b/chain/exchange/client.go index 7c3ea4f7e..db39628be 100644 --- a/chain/exchange/client.go +++ b/chain/exchange/client.go @@ -430,6 +430,9 @@ func (c *client) sendRequestToPeer(ctx context.Context, peer peer.ID, req *Reque } _ = stream.SetWriteDeadline(time.Time{}) // clear deadline // FIXME: Needs // its own API (https://github.com/libp2p/go-libp2p/core/issues/162). + if err := stream.CloseWrite(); err != nil { + log.Warnw("CloseWrite err", "error", err) + } // Read response. var res Response diff --git a/chain/gen/gen.go b/chain/gen/gen.go index fe7480202..f3b1ae212 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -468,10 +468,6 @@ func (cg *ChainGen) NextTipSetFromMinersWithMessagesAndNulls(base *types.TipSet, return nil, xerrors.Errorf("making a block for next tipset failed: %w", err) } - if err := cg.cs.PersistBlockHeaders(context.TODO(), fblk.Header); err != nil { - return nil, xerrors.Errorf("chainstore AddBlock: %w", err) - } - blks = append(blks, fblk) } } diff --git a/chain/gen/genesis/f00_system.go b/chain/gen/genesis/f00_system.go index 93849bcc9..5c6ecacbf 100644 --- a/chain/gen/genesis/f00_system.go +++ b/chain/gen/genesis/f00_system.go @@ -48,7 +48,7 @@ func SetupSystemActor(ctx context.Context, bs bstore.Blockstore, av actorstypes. return nil, err } - actcid, ok := actors.GetActorCodeID(av, actors.SystemKey) + actcid, ok := actors.GetActorCodeID(av, manifest.SystemKey) if !ok { return nil, xerrors.Errorf("failed to get system actor code ID for actors version %d", av) } diff --git a/chain/gen/genesis/f01_init.go b/chain/gen/genesis/f01_init.go index 26062cf27..706328d21 100644 --- a/chain/gen/genesis/f01_init.go +++ b/chain/gen/genesis/f01_init.go @@ -13,6 +13,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/specs-actors/actors/util/adt" bstore "github.com/filecoin-project/lotus/blockstore" @@ -174,7 +175,7 @@ func SetupInitActor(ctx context.Context, bs bstore.Blockstore, netname string, i return 0, nil, nil, err } - actcid, ok := actors.GetActorCodeID(av, actors.InitKey) + actcid, ok := actors.GetActorCodeID(av, manifest.InitKey) if !ok { return 0, nil, nil, xerrors.Errorf("failed to get init actor code ID for actors version %d", av) } diff --git a/chain/gen/genesis/f02_reward.go b/chain/gen/genesis/f02_reward.go index 4a5ac9fa1..db32517f9 100644 --- a/chain/gen/genesis/f02_reward.go +++ b/chain/gen/genesis/f02_reward.go @@ -8,6 +8,7 @@ import ( actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" bstore "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/build" @@ -29,7 +30,7 @@ func SetupRewardActor(ctx context.Context, bs bstore.Blockstore, qaPower big.Int return nil, err } - actcid, ok := actors.GetActorCodeID(av, actors.RewardKey) + actcid, ok := actors.GetActorCodeID(av, manifest.RewardKey) if !ok { return nil, xerrors.Errorf("failed to get reward actor code ID for actors version %d", av) } diff --git a/chain/gen/genesis/f03_cron.go b/chain/gen/genesis/f03_cron.go index 16396c437..4c377b191 100644 --- a/chain/gen/genesis/f03_cron.go +++ b/chain/gen/genesis/f03_cron.go @@ -8,6 +8,7 @@ import ( actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" bstore "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/chain/actors" @@ -28,7 +29,7 @@ func SetupCronActor(ctx context.Context, bs bstore.Blockstore, av actorstypes.Ve return nil, err } - actcid, ok := actors.GetActorCodeID(av, actors.CronKey) + actcid, ok := actors.GetActorCodeID(av, manifest.CronKey) if !ok { return nil, xerrors.Errorf("failed to get cron actor code ID for actors version %d", av) } diff --git a/chain/gen/genesis/f04_power.go b/chain/gen/genesis/f04_power.go index f05b0c746..385cc97d2 100644 --- a/chain/gen/genesis/f04_power.go +++ b/chain/gen/genesis/f04_power.go @@ -8,6 +8,7 @@ import ( actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/specs-actors/actors/util/adt" bstore "github.com/filecoin-project/lotus/blockstore" @@ -29,7 +30,7 @@ func SetupStoragePowerActor(ctx context.Context, bs bstore.Blockstore, av actors return nil, err } - actcid, ok := actors.GetActorCodeID(av, actors.PowerKey) + actcid, ok := actors.GetActorCodeID(av, manifest.PowerKey) if !ok { return nil, xerrors.Errorf("failed to get power actor code ID for actors version %d", av) } diff --git a/chain/gen/genesis/f05_market.go b/chain/gen/genesis/f05_market.go index 28a258c40..59c61a3ae 100644 --- a/chain/gen/genesis/f05_market.go +++ b/chain/gen/genesis/f05_market.go @@ -8,6 +8,7 @@ import ( actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" bstore "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/chain/actors" @@ -28,7 +29,7 @@ func SetupStorageMarketActor(ctx context.Context, bs bstore.Blockstore, av actor return nil, err } - actcid, ok := actors.GetActorCodeID(av, actors.MarketKey) + actcid, ok := actors.GetActorCodeID(av, manifest.MarketKey) if !ok { return nil, xerrors.Errorf("failed to get market actor code ID for actors version %d", av) } diff --git a/chain/gen/genesis/f06_vreg.go b/chain/gen/genesis/f06_vreg.go index 1b3582d4d..ffddc814f 100644 --- a/chain/gen/genesis/f06_vreg.go +++ b/chain/gen/genesis/f06_vreg.go @@ -9,6 +9,7 @@ import ( "github.com/filecoin-project/go-address" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/specs-actors/actors/util/adt" bstore "github.com/filecoin-project/lotus/blockstore" @@ -41,7 +42,7 @@ func SetupVerifiedRegistryActor(ctx context.Context, bs bstore.Blockstore, av ac return nil, err } - actcid, ok := actors.GetActorCodeID(av, actors.VerifregKey) + actcid, ok := actors.GetActorCodeID(av, manifest.VerifregKey) if !ok { return nil, xerrors.Errorf("failed to get verifreg actor code ID for actors version %d", av) } diff --git a/chain/gen/genesis/f07_dcap.go b/chain/gen/genesis/f07_dcap.go index 235cb0ce3..6d8e3258e 100644 --- a/chain/gen/genesis/f07_dcap.go +++ b/chain/gen/genesis/f07_dcap.go @@ -10,6 +10,7 @@ import ( actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/specs-actors/actors/util/adt" bstore "github.com/filecoin-project/lotus/blockstore" @@ -41,7 +42,7 @@ func SetupDatacapActor(ctx context.Context, bs bstore.Blockstore, av actorstypes return nil, err } - actcid, ok := actors.GetActorCodeID(av, actors.DatacapKey) + actcid, ok := actors.GetActorCodeID(av, manifest.DatacapKey) if !ok { return nil, xerrors.Errorf("failed to get datacap actor code ID for actors version %d", av) } diff --git a/chain/gen/genesis/genblock.go b/chain/gen/genesis/genblock.go index f26659cdf..930b3ccff 100644 --- a/chain/gen/genesis/genblock.go +++ b/chain/gen/genesis/genblock.go @@ -3,8 +3,8 @@ package genesis import ( "encoding/hex" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/multiformats/go-multihash" ) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index a37cdd2e8..d1c7d308e 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -17,6 +17,7 @@ import ( actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/go-state-types/network" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" @@ -122,12 +123,7 @@ Genesis: { func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template genesis.Template) (*state.StateTree, map[address.Address]address.Address, error) { // Create empty state tree - cst := cbor.NewCborStore(bs) - _, err := cst.Put(context.TODO(), []struct{}{}) - if err != nil { - return nil, nil, xerrors.Errorf("putting empty object: %w", err) - } sv, err := state.VersionForNetwork(template.NetworkVersion) if err != nil { @@ -237,15 +233,12 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge // Create accounts for _, info := range template.Accounts { - switch info.Type { case genesis.TAccount: if err := CreateAccountActor(ctx, cst, state, info, keyIDs, av); err != nil { return nil, nil, xerrors.Errorf("failed to create account actor: %w", err) } - case genesis.TMultisig: - ida, err := address.NewIDAddress(uint64(idStart)) if err != nil { return nil, nil, err @@ -380,7 +373,7 @@ func MakeAccountActor(ctx context.Context, cst cbor.IpldStore, av actorstypes.Ve return nil, err } - actcid, ok := actors.GetActorCodeID(av, actors.AccountKey) + actcid, ok := actors.GetActorCodeID(av, manifest.AccountKey) if !ok { return nil, xerrors.Errorf("failed to get account actor code ID for actors version %d", av) } @@ -389,6 +382,7 @@ func MakeAccountActor(ctx context.Context, cst cbor.IpldStore, av actorstypes.Ve Code: actcid, Head: statecid, Balance: bal, + Address: &addr, } return act, nil @@ -462,7 +456,7 @@ func CreateMultisigAccount(ctx context.Context, cst cbor.IpldStore, state *state return err } - actcid, ok := actors.GetActorCodeID(av, actors.MultisigKey) + actcid, ok := actors.GetActorCodeID(av, manifest.MultisigKey) if !ok { return xerrors.Errorf("failed to get multisig code ID for actors version %d", av) } @@ -564,6 +558,11 @@ func MakeGenesisBlock(ctx context.Context, j journal.Journal, bs bstore.Blocksto return nil, xerrors.Errorf("make initial state tree failed: %w", err) } + // Set up the Ethereum Address Manager + if err = SetupEAM(ctx, st, template.NetworkVersion); err != nil { + return nil, xerrors.Errorf("failed to setup EAM: %w", err) + } + stateroot, err := st.Flush(ctx) if err != nil { return nil, xerrors.Errorf("flush state tree failed: %w", err) @@ -578,11 +577,27 @@ func MakeGenesisBlock(ctx context.Context, j journal.Journal, bs bstore.Blocksto return nil, xerrors.Errorf("failed to verify presealed data: %w", err) } + // setup Storage Miners stateroot, err = SetupStorageMiners(ctx, cs, sys, stateroot, template.Miners, template.NetworkVersion) if err != nil { return nil, xerrors.Errorf("setup miners failed: %w", err) } + st, err = state.LoadStateTree(st.Store, stateroot) + if err != nil { + return nil, xerrors.Errorf("failed to load updated state tree: %w", err) + } + + // Set up Eth null addresses. + if _, err := SetupEthNullAddresses(ctx, st, template.NetworkVersion); err != nil { + return nil, xerrors.Errorf("failed to set up Eth null addresses: %w", err) + } + + stateroot, err = st.Flush(ctx) + if err != nil { + return nil, xerrors.Errorf("failed to flush state tree: %w", err) + } + store := adt.WrapStore(ctx, cbor.NewCborStore(bs)) emptyroot, err := adt0.MakeEmptyArray(store).Root() if err != nil { diff --git a/chain/gen/genesis/genesis_eth.go b/chain/gen/genesis/genesis_eth.go new file mode 100644 index 000000000..d5aa2f0b5 --- /dev/null +++ b/chain/gen/genesis/genesis_eth.go @@ -0,0 +1,139 @@ +package genesis + +import ( + "context" + "fmt" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/go-state-types/network" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/chain/vm" +) + +// EthNullAddresses are the Ethereum addresses we want to create zero-balanced EthAccounts in. +// We may want to add null addresses for precompiles going forward. +var EthNullAddresses = []string{ + "0x0000000000000000000000000000000000000000", +} + +func SetupEAM(_ context.Context, nst *state.StateTree, nv network.Version) error { + av, err := actorstypes.VersionForNetwork(nv) + if err != nil { + return fmt.Errorf("failed to get actors version for network version %d: %w", nv, err) + } + + if av < actorstypes.Version10 { + // Not defined before version 10; migration has to create. + return nil + } + + codecid, ok := actors.GetActorCodeID(av, manifest.EamKey) + if !ok { + return fmt.Errorf("failed to get CodeCID for EAM during genesis") + } + + header := &types.Actor{ + Code: codecid, + Head: vm.EmptyObjectCid, + Balance: big.Zero(), + Address: &builtin.EthereumAddressManagerActorAddr, // so that it can create ETH0 + } + return nst.SetActor(builtin.EthereumAddressManagerActorAddr, header) +} + +// MakeEthNullAddressActor creates a null address actor at the specified Ethereum address. +func MakeEthNullAddressActor(av actorstypes.Version, addr address.Address) (*types.Actor, error) { + actcid, ok := actors.GetActorCodeID(av, manifest.EthAccountKey) + if !ok { + return nil, xerrors.Errorf("failed to get EthAccount actor code ID for actors version %d", av) + } + + act := &types.Actor{ + Code: actcid, + Head: vm.EmptyObjectCid, + Nonce: 0, + Balance: big.Zero(), + Address: &addr, + } + + return act, nil +} + +func SetupEthNullAddresses(ctx context.Context, st *state.StateTree, nv network.Version) ([]address.Address, error) { + av, err := actorstypes.VersionForNetwork(nv) + if err != nil { + return nil, xerrors.Errorf("failed to resolve actors version for network version %d: %w", av, err) + } + + if av < actorstypes.Version10 { + // Not defined before version 10. + return nil, nil + } + + var ethAddresses []ethtypes.EthAddress + for _, addr := range EthNullAddresses { + a, err := ethtypes.ParseEthAddress(addr) + if err != nil { + return nil, xerrors.Errorf("failed to represent the 0x0 as an EthAddress: %w", err) + } + ethAddresses = append(ethAddresses, a) + } + + initAct, err := st.GetActor(builtin.InitActorAddr) + if err != nil { + return nil, xerrors.Errorf("failed to load init actor: %w", err) + } + + initState, err := init_.Load(adt.WrapStore(ctx, st.Store), initAct) + if err != nil { + return nil, xerrors.Errorf("failed to load init actor state: %w", err) + } + + var ret []address.Address + for _, ethAddr := range ethAddresses { + // Place an EthAccount at the 0x0 Eth Null Address. + f4Addr, err := ethAddr.ToFilecoinAddress() + if err != nil { + return nil, xerrors.Errorf("failed to compute Filecoin address for Eth addr 0x0: %w", err) + } + + idAddr, err := initState.MapAddressToNewID(f4Addr) + if err != nil { + return nil, xerrors.Errorf("failed to map addr in init actor: %w", err) + } + + actState, err := MakeEthNullAddressActor(av, f4Addr) + if err != nil { + return nil, xerrors.Errorf("failed to create EthAccount actor for null address: %w", err) + } + + if err := st.SetActor(idAddr, actState); err != nil { + return nil, xerrors.Errorf("failed to set Eth Null Address EthAccount actor state: %w", err) + } + + ret = append(ret, idAddr) + } + + initAct.Head, err = st.Store.Put(ctx, initState) + if err != nil { + return nil, xerrors.Errorf("failed to add init actor state to store: %w", err) + } + + if err := st.SetActor(builtin.InitActorAddr, initAct); err != nil { + return nil, xerrors.Errorf("failed to set updated state for init actor: %w", err) + } + + return ret, nil +} diff --git a/chain/market/fundmanager_test.go b/chain/market/fundmanager_test.go index 33d057c22..d79afbc51 100644 --- a/chain/market/fundmanager_test.go +++ b/chain/market/fundmanager_test.go @@ -105,7 +105,7 @@ func TestFundManagerBasic(t *testing.T) { // Note: Expect failure because there is no available balance to withdraw: // balance - reserved = 16 - 16 = 0 amt = abi.NewTokenAmount(1) - sentinel, err = s.fm.Withdraw(s.ctx, s.walletAddr, s.acctAddr, amt) + _, err = s.fm.Withdraw(s.ctx, s.walletAddr, s.acctAddr, amt) require.Error(t, err) } diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 7016b7242..dabd2cb33 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -33,12 +33,13 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain" + "github.com/filecoin-project/lotus/chain/consensus/filcns" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/journal" - "github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/metrics" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -219,6 +220,7 @@ func CapGasFee(mff dtypes.DefaultMaxFeeFunc, msg *types.Message, sendSpec *api.M totalFee := types.BigMul(msg.GasFeeCap, gl) if totalFee.LessThanEqual(maxFee) { + msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap return } @@ -281,7 +283,7 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict, untrusted } ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.RequiredFunds().Int) - //ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.Value.Int) + // ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.Value.Int) } if !has && strict && len(ms.msgs) >= maxActorPendingMessages { @@ -297,7 +299,7 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict, untrusted ms.nextNonce = nextNonce ms.msgs[m.Message.Nonce] = m ms.requiredFunds.Add(ms.requiredFunds, m.Message.RequiredFunds().Int) - //ms.requiredFunds.Add(ms.requiredFunds, m.Message.Value.Int) + // ms.requiredFunds.Add(ms.requiredFunds, m.Message.Value.Int) return !has, nil } @@ -317,7 +319,7 @@ func (ms *msgSet) rm(nonce uint64, applied bool) { } ms.requiredFunds.Sub(ms.requiredFunds, m.Message.RequiredFunds().Int) - //ms.requiredFunds.Sub(ms.requiredFunds, m.Message.Value.Int) + // ms.requiredFunds.Sub(ms.requiredFunds, m.Message.Value.Int) delete(ms.msgs, nonce) // adjust next nonce @@ -343,7 +345,7 @@ func (ms *msgSet) getRequiredFunds(nonce uint64) types.BigInt { m, has := ms.msgs[nonce] if has { requiredFunds.Sub(requiredFunds, m.Message.RequiredFunds().Int) - //requiredFunds.Sub(requiredFunds, m.Message.Value.Int) + // requiredFunds.Sub(requiredFunds, m.Message.Value.Int) } return types.BigInt{Int: requiredFunds} @@ -442,8 +444,12 @@ func New(ctx context.Context, api Provider, ds dtypes.MetadataDS, us stmgr.Upgra return mp, nil } -func (mp *MessagePool) ForEachPendingMessage(f func(cid.Cid) error) error { - mp.lk.Lock() +func (mp *MessagePool) TryForEachPendingMessage(f func(cid.Cid) error) error { + // avoid deadlocks in splitstore compaction when something else needs to access the blockstore + // while holding the mpool lock + if !mp.lk.TryLock() { + return xerrors.Errorf("mpool TryForEachPendingMessage: could not acquire lock") + } defer mp.lk.Unlock() for _, mset := range mp.pending { @@ -471,7 +477,7 @@ func (mp *MessagePool) resolveToKey(ctx context.Context, addr address.Address) ( } // resolve the address - ka, err := mp.api.StateAccountKeyAtFinality(ctx, addr, mp.curTs) + ka, err := mp.api.StateDeterministicAddressAtFinality(ctx, addr, mp.curTs) if err != nil { return address.Undef, err } @@ -767,11 +773,9 @@ func sigCacheKey(m *types.SignedMessage) (string, error) { if len(m.Signature.Data) != ffi.SignatureBytes { return "", fmt.Errorf("bls signature incorrectly sized") } - hashCache := blake2b.Sum256(append(m.Cid().Bytes(), m.Signature.Data...)) - return string(hashCache[:]), nil - case crypto.SigTypeSecp256k1: + case crypto.SigTypeSecp256k1, crypto.SigTypeDelegated: return string(m.Cid().Bytes()), nil default: return "", xerrors.Errorf("unrecognized signature type: %d", m.Signature.Type) @@ -790,8 +794,8 @@ func (mp *MessagePool) VerifyMsgSig(m *types.SignedMessage) error { return nil } - if err := sigs.Verify(&m.Signature, m.Message.From, m.Message.Cid().Bytes()); err != nil { - return err + if err := chain.AuthenticateMessage(m, m.Message.From); err != nil { + return xerrors.Errorf("failed to validate signature: %w", err) } mp.sigValCache.Add(sck, struct{}{}) @@ -811,7 +815,7 @@ func (mp *MessagePool) checkBalance(ctx context.Context, m *types.SignedMessage, } // add Value for soft failure check - //requiredFunds = types.BigAdd(requiredFunds, m.Message.Value) + // requiredFunds = types.BigAdd(requiredFunds, m.Message.Value) mset, ok, err := mp.getPendingMset(ctx, m.Message.From) if err != nil { @@ -848,18 +852,32 @@ func (mp *MessagePool) addTs(ctx context.Context, m *types.SignedMessage, curTs mp.lk.Lock() defer mp.lk.Unlock() + senderAct, err := mp.api.GetActorAfter(m.Message.From, curTs) + if err != nil { + return false, xerrors.Errorf("failed to get sender actor: %w", err) + } + + // This message can only be included in the _next_ epoch and beyond, hence the +1. + epoch := curTs.Height() + 1 + nv := mp.api.StateNetworkVersion(ctx, epoch) + + // TODO: I'm not thrilled about depending on filcns here, but I prefer this to duplicating logic + if !filcns.IsValidForSending(nv, senderAct) { + return false, xerrors.Errorf("sender actor %s is not a valid top-level sender", m.Message.From) + } + publish, err := mp.verifyMsgBeforeAdd(ctx, m, curTs, local) if err != nil { - return false, err + return false, xerrors.Errorf("verify msg failed: %w", err) } if err := mp.checkBalance(ctx, m, curTs); err != nil { - return false, err + return false, xerrors.Errorf("failed to check balance: %w", err) } err = mp.addLocked(ctx, m, !local, untrusted) if err != nil { - return false, err + return false, xerrors.Errorf("failed to add locked: %w", err) } if local { diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index 37122492e..20da2317e 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -155,14 +155,14 @@ func (tma *testMpoolAPI) GetActorAfter(addr address.Address, ts *types.TipSet) ( } return &types.Actor{ - Code: builtin2.StorageMarketActorCodeID, + Code: builtin2.AccountActorCodeID, Nonce: nonce, Balance: balance, }, nil } -func (tma *testMpoolAPI) StateAccountKeyAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { - if addr.Protocol() != address.BLS && addr.Protocol() != address.SECP256K1 { +func (tma *testMpoolAPI) StateDeterministicAddressAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { + if addr.Protocol() != address.BLS && addr.Protocol() != address.SECP256K1 && addr.Protocol() != address.Delegated { return address.Undef, fmt.Errorf("given address was not a key addr") } return addr, nil @@ -214,7 +214,7 @@ func (tma *testMpoolAPI) ChainComputeBaseFee(ctx context.Context, ts *types.TipS func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) { t.Helper() - //stm: @CHAIN_MEMPOOL_GET_NONCE_001 + // stm: @CHAIN_MEMPOOL_GET_NONCE_001 n, err := mp.GetNonce(context.TODO(), addr, types.EmptyTSK) if err != nil { t.Fatal(err) @@ -233,7 +233,7 @@ func mustAdd(t *testing.T, mp *MessagePool, msg *types.SignedMessage) { } func TestMessagePool(t *testing.T) { - //stm: @CHAIN_MEMPOOL_GET_NONCE_001 + // stm: @CHAIN_MEMPOOL_GET_NONCE_001 tma := newTestMpoolAPI() @@ -336,7 +336,7 @@ func TestCheckMessageBig(t *testing.T) { Message: *msg, Signature: *sig, } - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 err = mp.Add(context.TODO(), sm) assert.ErrorIs(t, err, ErrMessageTooBig) } @@ -378,10 +378,10 @@ func TestMessagePoolMessagesInEachBlock(t *testing.T) { tma.applyBlock(t, a) tsa := mock.TipSet(a) - //stm: @CHAIN_MEMPOOL_PENDING_001 + // stm: @CHAIN_MEMPOOL_PENDING_001 _, _ = mp.Pending(context.TODO()) - //stm: @CHAIN_MEMPOOL_SELECT_001 + // stm: @CHAIN_MEMPOOL_SELECT_001 selm, _ := mp.SelectMessages(context.Background(), tsa, 1) if len(selm) == 0 { t.Fatal("should have returned the rest of the messages") @@ -442,7 +442,7 @@ func TestRevertMessages(t *testing.T) { assertNonce(t, mp, sender, 4) - //stm: @CHAIN_MEMPOOL_PENDING_001 + // stm: @CHAIN_MEMPOOL_PENDING_001 p, _ := mp.Pending(context.TODO()) fmt.Printf("%+v\n", p) if len(p) != 3 { @@ -501,7 +501,7 @@ func TestPruningSimple(t *testing.T) { mp.Prune() - //stm: @CHAIN_MEMPOOL_PENDING_001 + // stm: @CHAIN_MEMPOOL_PENDING_001 msgs, _ := mp.Pending(context.TODO()) if len(msgs) != 5 { t.Fatal("expected only 5 messages in pool, got: ", len(msgs)) @@ -544,7 +544,7 @@ func TestLoadLocal(t *testing.T) { msgs := make(map[cid.Cid]struct{}) for i := 0; i < 10; i++ { m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1)) - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 cid, err := mp.Push(context.TODO(), m, true) if err != nil { t.Fatal(err) @@ -561,7 +561,7 @@ func TestLoadLocal(t *testing.T) { t.Fatal(err) } - //stm: @CHAIN_MEMPOOL_PENDING_001 + // stm: @CHAIN_MEMPOOL_PENDING_001 pmsgs, _ := mp.Pending(context.TODO()) if len(msgs) != len(pmsgs) { t.Fatalf("expected %d messages, but got %d", len(msgs), len(pmsgs)) @@ -617,7 +617,7 @@ func TestClearAll(t *testing.T) { gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}] for i := 0; i < 10; i++ { m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1)) - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 _, err := mp.Push(context.TODO(), m, true) if err != nil { t.Fatal(err) @@ -629,10 +629,10 @@ func TestClearAll(t *testing.T) { mustAdd(t, mp, m) } - //stm: @CHAIN_MEMPOOL_CLEAR_001 + // stm: @CHAIN_MEMPOOL_CLEAR_001 mp.Clear(context.Background(), true) - //stm: @CHAIN_MEMPOOL_PENDING_001 + // stm: @CHAIN_MEMPOOL_PENDING_001 pending, _ := mp.Pending(context.TODO()) if len(pending) > 0 { t.Fatalf("cleared the mpool, but got %d pending messages", len(pending)) @@ -675,7 +675,7 @@ func TestClearNonLocal(t *testing.T) { gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}] for i := 0; i < 10; i++ { m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1)) - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 _, err := mp.Push(context.TODO(), m, true) if err != nil { t.Fatal(err) @@ -687,10 +687,10 @@ func TestClearNonLocal(t *testing.T) { mustAdd(t, mp, m) } - //stm: @CHAIN_MEMPOOL_CLEAR_001 + // stm: @CHAIN_MEMPOOL_CLEAR_001 mp.Clear(context.Background(), false) - //stm: @CHAIN_MEMPOOL_PENDING_001 + // stm: @CHAIN_MEMPOOL_PENDING_001 pending, _ := mp.Pending(context.TODO()) if len(pending) != 10 { t.Fatalf("expected 10 pending messages, but got %d instead", len(pending)) @@ -748,7 +748,7 @@ func TestUpdates(t *testing.T) { for i := 0; i < 10; i++ { m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1)) - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 _, err := mp.Push(context.TODO(), m, true) if err != nil { t.Fatal(err) @@ -772,7 +772,7 @@ func TestUpdates(t *testing.T) { } func TestMessageBelowMinGasFee(t *testing.T) { - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 tma := newTestMpoolAPI() w, err := wallet.NewWallet(wallet.NewMemKeyStore()) @@ -818,7 +818,7 @@ func TestMessageBelowMinGasFee(t *testing.T) { } func TestMessageValueTooHigh(t *testing.T) { - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 tma := newTestMpoolAPI() w, err := wallet.NewWallet(wallet.NewMemKeyStore()) @@ -866,7 +866,7 @@ func TestMessageValueTooHigh(t *testing.T) { } func TestMessageSignatureInvalid(t *testing.T) { - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 tma := newTestMpoolAPI() w, err := wallet.NewWallet(wallet.NewMemKeyStore()) @@ -911,7 +911,7 @@ func TestMessageSignatureInvalid(t *testing.T) { } func TestAddMessageTwice(t *testing.T) { - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 tma := newTestMpoolAPI() w, err := wallet.NewWallet(wallet.NewMemKeyStore()) @@ -957,7 +957,7 @@ func TestAddMessageTwice(t *testing.T) { } func TestAddMessageTwiceNonceGap(t *testing.T) { - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 tma := newTestMpoolAPI() w, err := wallet.NewWallet(wallet.NewMemKeyStore()) @@ -1011,7 +1011,7 @@ func TestAddMessageTwiceCidDiff(t *testing.T) { // Create message with different data, so CID is different sm2 := makeTestMessage(w, from, to, 0, 50_000_001, minimumBaseFee.Uint64()) - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 // then try to add message again err = mp.Add(context.TODO(), sm2) // assert.Contains(t, err.Error(), "replace by fee has too low GasPremium") @@ -1020,7 +1020,7 @@ func TestAddMessageTwiceCidDiff(t *testing.T) { } func TestAddMessageTwiceCidDiffReplaced(t *testing.T) { - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 tma := newTestMpoolAPI() w, err := wallet.NewWallet(wallet.NewMemKeyStore()) @@ -1049,7 +1049,7 @@ func TestAddMessageTwiceCidDiffReplaced(t *testing.T) { } func TestRemoveMessage(t *testing.T) { - //stm: @CHAIN_MEMPOOL_PUSH_001 + // stm: @CHAIN_MEMPOOL_PUSH_001 tma := newTestMpoolAPI() w, err := wallet.NewWallet(wallet.NewMemKeyStore()) @@ -1071,13 +1071,50 @@ func TestRemoveMessage(t *testing.T) { sm := makeTestMessage(w, from, to, 0, 50_000_000, minimumBaseFee.Uint64()) mustAdd(t, mp, sm) - //stm: @CHAIN_MEMPOOL_REMOVE_001 + // stm: @CHAIN_MEMPOOL_REMOVE_001 // remove message for sender mp.Remove(context.TODO(), from, sm.Message.Nonce, true) - //stm: @CHAIN_MEMPOOL_PENDING_FOR_001 + // stm: @CHAIN_MEMPOOL_PENDING_FOR_001 // check messages in pool: should be none present msgs := mp.pendingFor(context.TODO(), from) assert.Len(t, msgs, 0) } } + +func TestCapGasFee(t *testing.T) { + t.Run("use default maxfee", func(t *testing.T) { + msg := &types.Message{ + GasLimit: 100_000_000, + GasFeeCap: abi.NewTokenAmount(100_000_000), + GasPremium: abi.NewTokenAmount(100_000), + } + CapGasFee(func() (abi.TokenAmount, error) { + return abi.NewTokenAmount(100_000_000_000), nil + }, msg, nil) + assert.Equal(t, msg.GasFeeCap.Int64(), int64(1000)) + assert.Equal(t, msg.GasPremium.Int.Int64(), int64(1000)) + }) + + t.Run("use spec maxfee", func(t *testing.T) { + msg := &types.Message{ + GasLimit: 100_000_000, + GasFeeCap: abi.NewTokenAmount(100_000_000), + GasPremium: abi.NewTokenAmount(100_000), + } + CapGasFee(nil, msg, &api.MessageSendSpec{MaxFee: abi.NewTokenAmount(100_000_000_000)}) + assert.Equal(t, msg.GasFeeCap.Int64(), int64(1000)) + assert.Equal(t, msg.GasPremium.Int.Int64(), int64(1000)) + }) + + t.Run("use smaller feecap value when fee is enough", func(t *testing.T) { + msg := &types.Message{ + GasLimit: 100_000_000, + GasFeeCap: abi.NewTokenAmount(100_000), + GasPremium: abi.NewTokenAmount(100_000_000), + } + CapGasFee(nil, msg, &api.MessageSendSpec{MaxFee: abi.NewTokenAmount(100_000_000_000_000)}) + assert.Equal(t, msg.GasFeeCap.Int64(), int64(100_000)) + assert.Equal(t, msg.GasPremium.Int.Int64(), int64(100_000)) + }) +} diff --git a/chain/messagepool/provider.go b/chain/messagepool/provider.go index f8bbbc01e..123a2607e 100644 --- a/chain/messagepool/provider.go +++ b/chain/messagepool/provider.go @@ -28,7 +28,7 @@ type Provider interface { PutMessage(ctx context.Context, m types.ChainMsg) (cid.Cid, error) PubSubPublish(string, []byte) error GetActorAfter(address.Address, *types.TipSet) (*types.Actor, error) - StateAccountKeyAtFinality(context.Context, address.Address, *types.TipSet) (address.Address, error) + StateDeterministicAddressAtFinality(context.Context, address.Address, *types.TipSet) (address.Address, error) StateNetworkVersion(context.Context, abi.ChainEpoch) network.Version MessagesForBlock(context.Context, *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) MessagesForTipset(context.Context, *types.TipSet) ([]types.ChainMsg, error) @@ -74,7 +74,7 @@ func (mpp *mpoolProvider) PutMessage(ctx context.Context, m types.ChainMsg) (cid } func (mpp *mpoolProvider) PubSubPublish(k string, v []byte) error { - return mpp.ps.Publish(k, v) //nolint + return mpp.ps.Publish(k, v) // nolint } func (mpp *mpoolProvider) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) { @@ -102,8 +102,8 @@ func (mpp *mpoolProvider) GetActorAfter(addr address.Address, ts *types.TipSet) return st.GetActor(addr) } -func (mpp *mpoolProvider) StateAccountKeyAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { - return mpp.sm.ResolveToKeyAddressAtFinality(ctx, addr, ts) +func (mpp *mpoolProvider) StateDeterministicAddressAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { + return mpp.sm.ResolveToDeterministicAddressAtFinality(ctx, addr, ts) } func (mpp *mpoolProvider) StateNetworkVersion(ctx context.Context, height abi.ChainEpoch) network.Version { diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index e84962869..bd5044128 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -97,7 +97,7 @@ func (sm *selectedMessages) tryToAdd(mc *msgChain) bool { sm.msgs = append(sm.msgs, mc.msgs...) sm.blsLimit -= l sm.gasLimit -= mc.gasLimit - } else if mc.sigType == crypto.SigTypeSecp256k1 { + } else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated { if sm.secpLimit < l { return false } @@ -123,7 +123,7 @@ func (sm *selectedMessages) tryToAddWithDeps(mc *msgChain, mp *MessagePool, base if mc.sigType == crypto.SigTypeBLS { smMsgLimit = sm.blsLimit - } else if mc.sigType == crypto.SigTypeSecp256k1 { + } else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated { smMsgLimit = sm.secpLimit } else { return false @@ -174,7 +174,7 @@ func (sm *selectedMessages) tryToAddWithDeps(mc *msgChain, mp *MessagePool, base if mc.sigType == crypto.SigTypeBLS { sm.blsLimit -= chainMsgLimit - } else if mc.sigType == crypto.SigTypeSecp256k1 { + } else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated { sm.secpLimit -= chainMsgLimit } @@ -187,7 +187,7 @@ func (sm *selectedMessages) trimChain(mc *msgChain, mp *MessagePool, baseFee typ if msgLimit > sm.blsLimit { msgLimit = sm.blsLimit } - } else if mc.sigType == crypto.SigTypeSecp256k1 { + } else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated { if msgLimit > sm.secpLimit { msgLimit = sm.secpLimit } diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index a5b2f3266..c3a5c6d6f 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -31,6 +31,7 @@ import ( "github.com/filecoin-project/lotus/chain/types/mock" "github.com/filecoin-project/lotus/chain/wallet" _ "github.com/filecoin-project/lotus/lib/sigs/bls" + _ "github.com/filecoin-project/lotus/lib/sigs/delegated" _ "github.com/filecoin-project/lotus/lib/sigs/secp" ) diff --git a/chain/messagesigner/messagesigner.go b/chain/messagesigner/messagesigner.go index 96457e9f8..cd31a3b73 100644 --- a/chain/messagesigner/messagesigner.go +++ b/chain/messagesigner/messagesigner.go @@ -17,6 +17,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -66,15 +67,20 @@ func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, sp // Sign the message with the nonce msg.Nonce = nonce + sb, err := SigningBytes(msg, msg.From.Protocol()) + if err != nil { + return nil, err + } mb, err := msg.ToStorageBlock() if err != nil { return nil, xerrors.Errorf("serializing message: %w", err) } - sig, err := ms.wallet.WalletSign(ctx, msg.From, mb.Cid().Bytes(), api.MsgMeta{ + sig, err := ms.wallet.WalletSign(ctx, msg.From, sb, api.MsgMeta{ Type: api.MTChainMsg, Extra: mb.RawData(), }) + if err != nil { return nil, xerrors.Errorf("failed to sign message: %w, addr=%s", err, msg.From) } @@ -187,3 +193,19 @@ func (ms *MessageSigner) SaveNonce(ctx context.Context, addr address.Address, no func (ms *MessageSigner) dstoreKey(addr address.Address) datastore.Key { return datastore.KeyWithNamespaces([]string{dsKeyActorNonce, addr.String()}) } + +func SigningBytes(msg *types.Message, sigType address.Protocol) ([]byte, error) { + if sigType == address.Delegated { + txArgs, err := ethtypes.EthTxArgsFromUnsignedEthMessage(msg) + if err != nil { + return nil, xerrors.Errorf("failed to reconstruct eth transaction: %w", err) + } + rlpEncodedMsg, err := txArgs.ToRlpUnsignedMsg() + if err != nil { + return nil, xerrors.Errorf("failed to repack eth rlp message: %w", err) + } + return rlpEncodedMsg, nil + } + + return msg.Cid().Bytes(), nil +} diff --git a/chain/signatures.go b/chain/signatures.go new file mode 100644 index 000000000..1dc67fd2c --- /dev/null +++ b/chain/signatures.go @@ -0,0 +1,62 @@ +package chain + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/network" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/lib/sigs" +) + +// AuthenticateMessage authenticates the message by verifying that the supplied +// SignedMessage was signed by the indicated Address, computing the correct +// signature payload depending on the signature type. The supplied Address type +// must be recognized by the registered verifier for the signature type. +func AuthenticateMessage(msg *types.SignedMessage, signer address.Address) error { + var digest []byte + + typ := msg.Signature.Type + switch typ { + case crypto.SigTypeDelegated: + txArgs, err := ethtypes.EthTxArgsFromUnsignedEthMessage(&msg.Message) + if err != nil { + return xerrors.Errorf("failed to reconstruct eth transaction: %w", err) + } + roundTripMsg, err := txArgs.ToUnsignedMessage(msg.Message.From) + if err != nil { + return xerrors.Errorf("failed to reconstruct filecoin msg: %w", err) + } + + if !msg.Message.Equals(roundTripMsg) { + return xerrors.New("ethereum tx failed to roundtrip") + } + + rlpEncodedMsg, err := txArgs.ToRlpUnsignedMsg() + if err != nil { + return xerrors.Errorf("failed to repack eth rlp message: %w", err) + } + digest = rlpEncodedMsg + default: + digest = msg.Message.Cid().Bytes() + } + + if err := sigs.Verify(&msg.Signature, signer, digest); err != nil { + return xerrors.Errorf("message %s has invalid signature (type %d): %w", msg.Cid(), typ, err) + } + return nil +} + +// IsValidSecpkSigType checks that a signature type is valid for the network +// version, for a "secpk" message. +func IsValidSecpkSigType(nv network.Version, typ crypto.SigType) bool { + switch { + case nv < network.Version18: + return typ == crypto.SigTypeSecp256k1 + default: + return typ == crypto.SigTypeSecp256k1 || typ == crypto.SigTypeDelegated + } +} diff --git a/chain/state/statetree.go b/chain/state/statetree.go index ff921a04d..62d70eff7 100644 --- a/chain/state/statetree.go +++ b/chain/state/statetree.go @@ -14,6 +14,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + builtin_types "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/go-state-types/network" states0 "github.com/filecoin-project/specs-actors/actors/states" states2 "github.com/filecoin-project/specs-actors/v2/actors/states" @@ -152,16 +153,12 @@ func VersionForNetwork(ver network.Version) (types.StateTreeVersion, error) { case network.Version12: return types.StateTreeVersion3, nil - /* inline-gen template - {{$lastNv := .latestNetworkVersion}} - case{{range .networkVersions}} {{if (ge . 13.)}} network.Version{{.}}{{if (lt . $lastNv)}},{{end}}{{end}}{{end}}: - - /* inline-gen start */ - case network.Version13, network.Version14, network.Version15, network.Version16, network.Version17: - - /* inline-gen end */ return types.StateTreeVersion4, nil + + case network.Version18: + return types.StateTreeVersion5, nil + default: panic(fmt.Sprintf("unsupported network version %d", ver)) } @@ -172,7 +169,7 @@ func NewStateTree(cst cbor.IpldStore, ver types.StateTreeVersion) (*StateTree, e switch ver { case types.StateTreeVersion0: // info is undefined - case types.StateTreeVersion1, types.StateTreeVersion2, types.StateTreeVersion3, types.StateTreeVersion4: + case types.StateTreeVersion1, types.StateTreeVersion2, types.StateTreeVersion3, types.StateTreeVersion4, types.StateTreeVersion5: var err error info, err = cst.Put(context.TODO(), new(types.StateInfo0)) if err != nil { @@ -215,6 +212,13 @@ func NewStateTree(cst cbor.IpldStore, ver types.StateTreeVersion) (*StateTree, e return nil, xerrors.Errorf("failed to create state tree: %w", err) } hamt = tree.Map + case types.StateTreeVersion5: + tree, err := builtin_types.NewTree(store) + if err != nil { + return nil, xerrors.Errorf("failed to create state tree: %w", err) + } + hamt = tree.Map + default: return nil, xerrors.Errorf("unsupported state tree version: %d", ver) } @@ -276,6 +280,13 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) { if tree != nil { hamt = tree.Map } + case types.StateTreeVersion5: + var tree *builtin_types.ActorTree + tree, err = builtin_types.LoadTree(store, root.Actors) + if tree != nil { + hamt = tree.Map + } + default: return nil, xerrors.Errorf("unsupported state tree version: %d", root.Version) } @@ -374,7 +385,17 @@ func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) { } var act types.Actor - if found, err := st.root.Get(abi.AddrKey(addr), &act); err != nil { + var found bool + if st.version <= types.StateTreeVersion4 { + var act4 types.ActorV4 + found, err = st.root.Get(abi.AddrKey(addr), &act4) + if found { + act = *types.AsActorV5(&act4) + } + } else { + found, err = st.root.Get(abi.AddrKey(addr), &act) + } + if err != nil { return nil, xerrors.Errorf("hamt find failed: %w", err) } else if !found { return nil, types.ErrActorNotFound @@ -423,8 +444,15 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) { return cid.Undef, err } } else { - if err := st.root.Put(abi.AddrKey(addr), &sto.Act); err != nil { - return cid.Undef, err + if st.version <= types.StateTreeVersion4 { + act4 := types.AsActorV4(&sto.Act) + if err := st.root.Put(abi.AddrKey(addr), act4); err != nil { + return cid.Undef, err + } + } else { + if err := st.root.Put(abi.AddrKey(addr), &sto.Act); err != nil { + return cid.Undef, err + } } } } @@ -532,6 +560,25 @@ func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error } // Now walk through the saved actors. + if st.version <= types.StateTreeVersion4 { + var act types.ActorV4 + return st.root.ForEach(&act, func(k string) error { + act := act // copy + addr, err := address.NewFromBytes([]byte(k)) + if err != nil { + return xerrors.Errorf("invalid address (%x) found in state tree key: %w", []byte(k), err) + } + + // no need to record anything here, there are no duplicates in the actors HAMT + // iself. + if _, ok := seen[addr]; ok { + return nil + } + + return f(addr, types.AsActorV5(&act)) + }) + } + var act types.Actor return st.root.ForEach(&act, func(k string) error { act := act // copy @@ -567,8 +614,6 @@ func Diff(ctx context.Context, oldTree, newTree *StateTree) (map[string]types.Ac case <-ctx.Done(): return ctx.Err() default: - var act types.Actor - addr, err := address.NewFromBytes([]byte(k)) if err != nil { return xerrors.Errorf("address in state tree was not valid: %w", err) @@ -583,16 +628,33 @@ func Diff(ctx context.Context, oldTree, newTree *StateTree) (map[string]types.Ac return nil // not changed } - buf.Reset(ncval.Raw) - err = act.UnmarshalCBOR(buf) - buf.Reset(nil) + if newTree.version <= types.StateTreeVersion4 { + var act types.ActorV4 - if err != nil { - return err + buf.Reset(ncval.Raw) + err = act.UnmarshalCBOR(buf) + buf.Reset(nil) + + if err != nil { + return err + } + + out[addr.String()] = *types.AsActorV5(&act) + + } else { + var act types.Actor + + buf.Reset(ncval.Raw) + err = act.UnmarshalCBOR(buf) + buf.Reset(nil) + + if err != nil { + return err + } + + out[addr.String()] = act } - out[addr.String()] = act - return nil } }); err != nil { diff --git a/chain/stmgr/actors.go b/chain/stmgr/actors.go index f4fa2d98d..4de39c7f1 100644 --- a/chain/stmgr/actors.go +++ b/chain/stmgr/actors.go @@ -48,7 +48,7 @@ func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr return address.Undef, xerrors.Errorf("failed to load actor info: %w", err) } - return vm.ResolveToKeyAddr(state, sm.cs.ActorStore(ctx), info.Worker) + return vm.ResolveToDeterministicAddr(state, sm.cs.ActorStore(ctx), info.Worker) } func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (power.Claim, power.Claim, bool, error) { @@ -103,6 +103,7 @@ func PreCommitInfo(ctx context.Context, sm *StateManager, maddr address.Address, return mas.GetPrecommittedSector(sid) } +// Returns nil, nil if sector is not found func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorOnChainInfo, error) { act, err := sm.LoadActor(ctx, maddr, ts) if err != nil { @@ -380,7 +381,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule return nil, err } - worker, err := sm.ResolveToKeyAddress(ctx, info.Worker, ts) + worker, err := sm.ResolveToDeterministicAddress(ctx, info.Worker, ts) if err != nil { return nil, xerrors.Errorf("resolving worker address: %w", err) } diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index 92066ca81..901fc2d12 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -14,6 +14,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/blockstore" @@ -29,73 +30,10 @@ var ErrExpensiveFork = errors.New("refusing explicit call due to state fork at e // Call applies the given message to the given tipset's parent state, at the epoch following the // tipset's parent. In the presence of null blocks, the height at which the message is invoked may // be less than the specified tipset. -// -// - If no tipset is specified, the first tipset without an expensive migration is used. -// - If executing a message at a given tipset would trigger an expensive migration, the call will -// fail with ErrExpensiveFork. func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) { - ctx, span := trace.StartSpan(ctx, "statemanager.Call") - defer span.End() - - var pheight abi.ChainEpoch = -1 - - // If no tipset is provided, try to find one without a fork. - if ts == nil { - ts = sm.cs.GetHeaviestTipSet() - // Search back till we find a height with no fork, or we reach the beginning. - for ts.Height() > 0 { - pts, err := sm.cs.GetTipSetFromKey(ctx, ts.Parents()) - if err != nil { - return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err) - } - if !sm.hasExpensiveFork(pts.Height()) { - pheight = pts.Height() - break - } - ts = pts - } - } else if ts.Height() > 0 { - pts, err := sm.cs.LoadTipSet(ctx, ts.Parents()) - if err != nil { - return nil, xerrors.Errorf("failed to load parent tipset: %w", err) - } - pheight = pts.Height() - if sm.hasExpensiveFork(pheight) { - return nil, ErrExpensiveFork - } - } else { - // We can't get the parent tipset in this case. - pheight = ts.Height() - 1 - } - - // Since we're simulating a future message, pretend we're applying it in the "next" tipset - vmHeight := pheight + 1 - bstate := ts.ParentState() - - // Run the (not expensive) migration. - bstate, err := sm.HandleStateForks(ctx, bstate, pheight, nil, ts) - if err != nil { - return nil, fmt.Errorf("failed to handle fork: %w", err) - } - - vmopt := &vm.VMOpts{ - StateBase: bstate, - Epoch: vmHeight, - Rand: rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon, sm.GetNetworkVersion), - Bstore: sm.cs.StateBlockstore(), - Actors: sm.tsExec.NewActorRegistry(), - Syscalls: sm.Syscalls, - CircSupplyCalc: sm.GetVMCirculatingSupply, - NetworkVersion: sm.GetNetworkVersion(ctx, pheight+1), - BaseFee: types.NewInt(0), - LookbackState: LookbackStateGetterForTipset(sm, ts), - Tracing: true, - } - - vmi, err := sm.newVM(ctx, vmopt) - if err != nil { - return nil, xerrors.Errorf("failed to set up vm: %w", err) - } + // Copy the message as we modify it below. + msgCopy := *msg + msg = &msgCopy if msg.GasLimit == 0 { msg.GasLimit = build.BlockGasLimit @@ -106,61 +44,43 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types. if msg.GasPremium == types.EmptyInt { msg.GasPremium = types.NewInt(0) } - if msg.Value == types.EmptyInt { msg.Value = types.NewInt(0) } - if span.IsRecordingEvents() { - span.AddAttributes( - trace.Int64Attribute("gas_limit", msg.GasLimit), - trace.StringAttribute("gas_feecap", msg.GasFeeCap.String()), - trace.StringAttribute("value", msg.Value.String()), - ) - } - - stTree, err := sm.StateTree(bstate) - if err != nil { - return nil, xerrors.Errorf("failed to load state tree: %w", err) - } - - fromActor, err := stTree.GetActor(msg.From) - if err != nil { - return nil, xerrors.Errorf("call raw get actor: %s", err) - } - - msg.Nonce = fromActor.Nonce - - // TODO: maybe just use the invoker directly? - ret, err := vmi.ApplyImplicitMessage(ctx, msg) - if err != nil && ret == nil { - return nil, xerrors.Errorf("apply message failed: %w", err) - } - - var errs string - if ret.ActorErr != nil { - errs = ret.ActorErr.Error() - log.Warnf("chain call failed: %s", ret.ActorErr) - } - - return &api.InvocResult{ - MsgCid: msg.Cid(), - Msg: msg, - MsgRct: &ret.MessageReceipt, - ExecutionTrace: ret.ExecutionTrace, - Error: errs, - Duration: ret.Duration, - }, err + return sm.callInternal(ctx, msg, nil, ts, cid.Undef, sm.GetNetworkVersion, false, false) } +// CallWithGas calculates the state for a given tipset, and then applies the given message on top of that state. func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, priorMsgs []types.ChainMsg, ts *types.TipSet) (*api.InvocResult, error) { - ctx, span := trace.StartSpan(ctx, "statemanager.CallWithGas") + return sm.callInternal(ctx, msg, priorMsgs, ts, cid.Undef, sm.GetNetworkVersion, true, true) +} + +// CallAtStateAndVersion allows you to specify a message to execute on the given stateCid and network version. +// This should mostly be used for gas modelling on a migrated state. +// Tipset here is not needed because stateCid and network version fully describe execution we want. The internal function +// will get the heaviest tipset for use for things like basefee, which we don't really care about here. +func (sm *StateManager) CallAtStateAndVersion(ctx context.Context, msg *types.Message, stateCid cid.Cid, v network.Version) (*api.InvocResult, error) { + nvGetter := func(context.Context, abi.ChainEpoch) network.Version { + return v + } + + return sm.callInternal(ctx, msg, nil, nil, stateCid, nvGetter, true, false) +} + +// - If no tipset is specified, the first tipset without an expensive migration or one in its parent is used. +// - If executing a message at a given tipset or its parent would trigger an expensive migration, the call will +// fail with ErrExpensiveFork. +func (sm *StateManager) callInternal(ctx context.Context, msg *types.Message, priorMsgs []types.ChainMsg, ts *types.TipSet, stateCid cid.Cid, nvGetter rand.NetworkVersionGetter, checkGas, applyTsMessages bool) (*api.InvocResult, error) { + ctx, span := trace.StartSpan(ctx, "statemanager.callInternal") defer span.End() // Copy the message as we'll be modifying the nonce. msgCopy := *msg msg = &msgCopy + var err error + var pts *types.TipSet if ts == nil { ts = sm.cs.GetHeaviestTipSet() @@ -170,10 +90,11 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri // height to have no fork, because we'll run it inside this // function before executing the given message. for ts.Height() > 0 { - pts, err := sm.cs.GetTipSetFromKey(ctx, ts.Parents()) + pts, err = sm.cs.GetTipSetFromKey(ctx, ts.Parents()) if err != nil { return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err) } + // Checks for expensive forks from the parents to the tipset, including nil tipsets if !sm.hasExpensiveForkBetween(pts.Height(), ts.Height()+1) { break } @@ -181,7 +102,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri ts = pts } } else if ts.Height() > 0 { - pts, err := sm.cs.GetTipSetFromKey(ctx, ts.Parents()) + pts, err = sm.cs.GetTipSetFromKey(ctx, ts.Parents()) if err != nil { return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err) } @@ -190,12 +111,18 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri } } - // Since we're simulating a future message, pretend we're applying it in the "next" tipset - vmHeight := ts.Height() + 1 - - stateCid, _, err := sm.TipSetState(ctx, ts) - if err != nil { - return nil, xerrors.Errorf("computing tipset state: %w", err) + // Unless executing on a specific state cid, apply all the messages from the current tipset + // first. Unfortunately, we can't just execute the tipset, because that will run cron. We + // don't want to apply miner messages after cron runs in a given epoch. + if stateCid == cid.Undef { + stateCid = ts.ParentState() + } + if applyTsMessages { + tsMsgs, err := sm.cs.MessagesForTipset(ctx, ts) + if err != nil { + return nil, xerrors.Errorf("failed to lookup messages for parent tipset: %w", err) + } + priorMsgs = append(tsMsgs, priorMsgs...) } // Technically, the tipset we're passing in here should be ts+1, but that may not exist. @@ -204,8 +131,6 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri return nil, fmt.Errorf("failed to handle fork: %w", err) } - r := rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon, sm.GetNetworkVersion) - if span.IsRecordingEvents() { span.AddAttributes( trace.Int64Attribute("gas_limit", msg.GasLimit), @@ -217,15 +142,17 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri buffStore := blockstore.NewTieredBstore(sm.cs.StateBlockstore(), blockstore.NewMemorySync()) vmopt := &vm.VMOpts{ StateBase: stateCid, - Epoch: vmHeight, - Rand: r, + Epoch: ts.Height(), + Timestamp: ts.MinTimestamp(), + Rand: rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon, nvGetter), Bstore: buffStore, Actors: sm.tsExec.NewActorRegistry(), Syscalls: sm.Syscalls, CircSupplyCalc: sm.GetVMCirculatingSupply, - NetworkVersion: sm.GetNetworkVersion(ctx, ts.Height()+1), + NetworkVersion: nvGetter(ctx, ts.Height()), BaseFee: ts.Blocks()[0].ParentBaseFee, LookbackState: LookbackStateGetterForTipset(sm, ts), + TipSetGetter: TipSetGetterForTipset(sm.cs, ts), Tracing: true, } vmi, err := sm.newVM(ctx, vmopt) @@ -233,7 +160,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri return nil, xerrors.Errorf("failed to set up vm: %w", err) } for i, m := range priorMsgs { - _, err := vmi.ApplyMessage(ctx, m) + _, err = vmi.ApplyMessage(ctx, m) if err != nil { return nil, xerrors.Errorf("applying prior message (%d, %s): %w", i, m.Cid(), err) } @@ -258,27 +185,6 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri msg.Nonce = fromActor.Nonce - fromKey, err := sm.ResolveToKeyAddress(ctx, msg.From, ts) - if err != nil { - return nil, xerrors.Errorf("could not resolve key: %w", err) - } - - var msgApply types.ChainMsg - - switch fromKey.Protocol() { - case address.BLS: - msgApply = msg - case address.SECP256K1: - msgApply = &types.SignedMessage{ - Message: *msg, - Signature: crypto.Signature{ - Type: crypto.SigTypeSecp256k1, - Data: make([]byte, 65), - }, - } - - } - // If the fee cap is set to zero, make gas free. if msg.GasFeeCap.NilOrZero() { // Now estimate with a new VM with no base fee. @@ -291,9 +197,47 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri } } - ret, err := vmi.ApplyMessage(ctx, msgApply) - if err != nil { - return nil, xerrors.Errorf("gas estimation failed: %w", err) + var ret *vm.ApplyRet + var gasInfo api.MsgGasCost + if checkGas { + fromKey, err := sm.ResolveToDeterministicAddress(ctx, msg.From, ts) + if err != nil { + return nil, xerrors.Errorf("could not resolve key: %w", err) + } + + var msgApply types.ChainMsg + + switch fromKey.Protocol() { + case address.BLS: + msgApply = msg + case address.SECP256K1: + msgApply = &types.SignedMessage{ + Message: *msg, + Signature: crypto.Signature{ + Type: crypto.SigTypeSecp256k1, + Data: make([]byte, 65), + }, + } + case address.Delegated: + msgApply = &types.SignedMessage{ + Message: *msg, + Signature: crypto.Signature{ + Type: crypto.SigTypeDelegated, + Data: make([]byte, 65), + }, + } + } + + ret, err = vmi.ApplyMessage(ctx, msgApply) + if err != nil { + return nil, xerrors.Errorf("gas estimation failed: %w", err) + } + gasInfo = MakeMsgGasCost(msg, ret) + } else { + ret, err = vmi.ApplyImplicitMessage(ctx, msg) + if err != nil && ret == nil { + return nil, xerrors.Errorf("apply message failed: %w", err) + } } var errs string @@ -305,11 +249,11 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri MsgCid: msg.Cid(), Msg: msg, MsgRct: &ret.MessageReceipt, - GasCost: MakeMsgGasCost(msg, ret), + GasCost: gasInfo, ExecutionTrace: ret.ExecutionTrace, Error: errs, Duration: ret.Duration, - }, nil + }, err } var errHaltExecution = fmt.Errorf("halt") diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index 3c774a790..98ab647c9 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -335,7 +335,7 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) { parentHeight := pts.Height() currentHeight := ts.TipSet.TipSet().Height() - // CallWithGas calls _at_ the current tipset. + // CallWithGas calls on top of the given tipset. ret, err := sm.CallWithGas(ctx, m, nil, ts.TipSet.TipSet()) if parentHeight <= testForkHeight && currentHeight >= testForkHeight { // If I had a fork, or I _will_ have a fork, it should fail. @@ -347,7 +347,7 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) { // Call always applies the message to the "next block" after the tipset's parent state. ret, err = sm.Call(ctx, m, ts.TipSet.TipSet()) - if parentHeight == testForkHeight { + if parentHeight <= testForkHeight && currentHeight >= testForkHeight { require.Equal(t, ErrExpensiveFork, err) } else { require.NoError(t, err) diff --git a/chain/stmgr/rpc/rpcstatemanager.go b/chain/stmgr/rpc/rpcstatemanager.go index 2c9893cc0..9186501ea 100644 --- a/chain/stmgr/rpc/rpcstatemanager.go +++ b/chain/stmgr/rpc/rpcstatemanager.go @@ -48,7 +48,7 @@ func (s *RPCStateManager) LookupID(ctx context.Context, addr address.Address, ts return s.gapi.StateLookupID(ctx, addr, ts.Key()) } -func (s *RPCStateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { +func (s *RPCStateManager) ResolveToDeterministicAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { return s.gapi.StateAccountKey(ctx, addr, ts.Key()) } diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 926646a4c..ee9338e63 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -42,7 +42,7 @@ type StateManagerAPI interface { GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) LoadActorTsk(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error) LookupID(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) - ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) + ResolveToDeterministicAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) } type versionSpec struct { @@ -207,11 +207,11 @@ func (sm *StateManager) Beacon() beacon.Schedule { return sm.beacon } -// ResolveToKeyAddress is similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses. +// ResolveToDeterministicAddress is similar to `vm.ResolveToDeterministicAddr` but does not allow `Actor` type of addresses. // Uses the `TipSet` `ts` to generate the VM state. -func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { +func (sm *StateManager) ResolveToDeterministicAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { switch addr.Protocol() { - case address.BLS, address.SECP256K1: + case address.BLS, address.SECP256K1, address.Delegated: return addr, nil case address.Actor: return address.Undef, xerrors.New("cannot resolve actor address to key address") @@ -230,7 +230,7 @@ func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Ad return address.Undef, xerrors.Errorf("failed to load parent state tree at tipset %s: %w", ts.Parents(), err) } - resolved, err := vm.ResolveToKeyAddr(tree, cst, addr) + resolved, err := vm.ResolveToDeterministicAddr(tree, cst, addr) if err == nil { return resolved, nil } @@ -246,14 +246,14 @@ func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Ad return address.Undef, xerrors.Errorf("failed to load state tree at tipset %s: %w", ts, err) } - return vm.ResolveToKeyAddr(tree, cst, addr) + return vm.ResolveToDeterministicAddr(tree, cst, addr) } -// ResolveToKeyAddressAtFinality is similar to stmgr.ResolveToKeyAddress but fails if the ID address being resolved isn't reorg-stable yet. +// ResolveToDeterministicAddressAtFinality is similar to stmgr.ResolveToDeterministicAddress but fails if the ID address being resolved isn't reorg-stable yet. // It should not be used for consensus-critical subsystems. -func (sm *StateManager) ResolveToKeyAddressAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { +func (sm *StateManager) ResolveToDeterministicAddressAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { switch addr.Protocol() { - case address.BLS, address.SECP256K1: + case address.BLS, address.SECP256K1, address.Delegated: return addr, nil case address.Actor: return address.Undef, xerrors.New("cannot resolve actor address to key address") @@ -287,7 +287,7 @@ func (sm *StateManager) ResolveToKeyAddressAtFinality(ctx context.Context, addr } } - resolved, err := vm.ResolveToKeyAddr(tree, cst, addr) + resolved, err := vm.ResolveToDeterministicAddr(tree, cst, addr) if err == nil { return resolved, nil } @@ -296,7 +296,7 @@ func (sm *StateManager) ResolveToKeyAddressAtFinality(ctx context.Context, addr } func (sm *StateManager) GetBlsPublicKey(ctx context.Context, addr address.Address, ts *types.TipSet) (pubk []byte, err error) { - kaddr, err := sm.ResolveToKeyAddress(ctx, addr, ts) + kaddr, err := sm.ResolveToDeterministicAddress(ctx, addr, ts) if err != nil { return pubk, xerrors.Errorf("failed to resolve address to key address: %w", err) } diff --git a/chain/stmgr/supply.go b/chain/stmgr/supply.go index 89708097e..a48ff36c7 100644 --- a/chain/stmgr/supply.go +++ b/chain/stmgr/supply.go @@ -403,7 +403,8 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha a == builtin.CronActorAddr || a == builtin.BurntFundsActorAddr || a == builtin.SaftAddress || - a == builtin.ReserveAddress: + a == builtin.ReserveAddress || + a == builtin.EthereumAddressManagerActorAddr: unCirc = big.Add(unCirc, actor.Balance) @@ -421,7 +422,12 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha circ = big.Add(circ, big.Sub(actor.Balance, lb)) unCirc = big.Add(unCirc, lb) - case builtin.IsAccountActor(actor.Code) || builtin.IsPaymentChannelActor(actor.Code): + case builtin.IsAccountActor(actor.Code) || + builtin.IsPaymentChannelActor(actor.Code) || + builtin.IsEthAccountActor(actor.Code) || + builtin.IsEvmActor(actor.Code) || + builtin.IsPlaceholderActor(actor.Code): + circ = big.Add(circ, actor.Balance) case builtin.IsStorageMinerActor(actor.Code): diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index a466029ce..c93267d50 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -2,6 +2,7 @@ package stmgr import ( "context" + "errors" "fmt" "reflect" @@ -27,6 +28,8 @@ import ( "github.com/filecoin-project/lotus/node/modules/dtypes" ) +var ErrMetadataNotFound = errors.New("actor metadata not found") + func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) { act, err := sm.LoadActor(ctx, to, ts) if err != nil { @@ -35,7 +38,7 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me m, found := sm.tsExec.NewActorRegistry().Methods[act.Code][method] if !found { - return nil, fmt.Errorf("unknown method %d for actor %s", method, act.Code) + return nil, fmt.Errorf("unknown method %d for actor %s: %w", method, act.Code, ErrMetadataNotFound) } return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil @@ -44,7 +47,7 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me func GetParamType(ar *vm.ActorRegistry, actCode cid.Cid, method abi.MethodNum) (cbg.CBORUnmarshaler, error) { m, found := ar.Methods[actCode][method] if !found { - return nil, fmt.Errorf("unknown method %d for actor %s", method, actCode) + return nil, fmt.Errorf("unknown method %d for actor %s: %w", method, actCode, ErrMetadataNotFound) } return reflect.New(m.Params.Elem()).Interface().(cbg.CBORUnmarshaler), nil } @@ -87,6 +90,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, vmopt := &vm.VMOpts{ StateBase: base, Epoch: height, + Timestamp: ts.MinTimestamp(), Rand: r, Bstore: sm.cs.StateBlockstore(), Actors: sm.tsExec.NewActorRegistry(), @@ -95,6 +99,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, NetworkVersion: sm.GetNetworkVersion(ctx, height), BaseFee: ts.Blocks()[0].ParentBaseFee, LookbackState: LookbackStateGetterForTipset(sm, ts), + TipSetGetter: TipSetGetterForTipset(sm.cs, ts), Tracing: true, } vmi, err := sm.newVM(ctx, vmopt) @@ -131,6 +136,16 @@ func LookbackStateGetterForTipset(sm *StateManager, ts *types.TipSet) vm.Lookbac } } +func TipSetGetterForTipset(cs *store.ChainStore, ts *types.TipSet) vm.TipSetGetter { + return func(ctx context.Context, round abi.ChainEpoch) (types.TipSetKey, error) { + ts, err := cs.GetTipsetByHeight(ctx, round, ts, true) + if err != nil { + return types.EmptyTSK, err + } + return ts.Key(), nil + } +} + func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.TipSet, round abi.ChainEpoch) (*types.TipSet, cid.Cid, error) { var lbr abi.ChainEpoch lb := policy.GetWinningPoStSectorSetLookback(sm.GetNetworkVersion(ctx, round)) diff --git a/chain/store/messages.go b/chain/store/messages.go index 5e2880c4a..5ac62d394 100644 --- a/chain/store/messages.go +++ b/chain/store/messages.go @@ -3,10 +3,10 @@ package store import ( "context" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" ipld "github.com/ipfs/go-ipld-format" + block "github.com/ipfs/go-libipfs/blocks" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" @@ -256,6 +256,20 @@ func (cs *ChainStore) MessagesForBlock(ctx context.Context, b *types.BlockHeader return blsmsgs, secpkmsgs, nil } +func (cs *ChainStore) SecpkMessagesForBlock(ctx context.Context, b *types.BlockHeader) ([]*types.SignedMessage, error) { + _, secpkcids, err := cs.ReadMsgMetaCids(ctx, b.Messages) + if err != nil { + return nil, err + } + + secpkmsgs, err := cs.LoadSignedMessagesFromCids(ctx, secpkcids) + if err != nil { + return nil, xerrors.Errorf("loading secpk messages for block: %w", err) + } + + return secpkmsgs, nil +} + func (cs *ChainStore) GetParentReceipt(ctx context.Context, b *types.BlockHeader, i int) (*types.MessageReceipt, error) { // block headers use adt0, for now. a, err := blockadt.AsArray(cs.ActorStore(ctx), b.ParentMessageReceipts) diff --git a/chain/store/snapshot.go b/chain/store/snapshot.go index b5a457b71..36435152e 100644 --- a/chain/store/snapshot.go +++ b/chain/store/snapshot.go @@ -6,8 +6,10 @@ import ( "io" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/ipld/go-car" carutil "github.com/ipld/go-car/util" + carv2 "github.com/ipld/go-car/v2" mh "github.com/multiformats/go-multihash" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" @@ -20,6 +22,8 @@ import ( "github.com/filecoin-project/lotus/chain/types" ) +const TipsetkeyBackfillRange = 2 * build.Finality + func (cs *ChainStore) UnionStore() bstore.Blockstore { return bstore.Union(cs.stateBlockstore, cs.chainBlockstore) } @@ -55,16 +59,76 @@ func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, e // universal store. When we physically segregate the stores, we will need // to route state objects to the state blockstore, and chain objects to // the chain blockstore. - header, err := car.LoadCar(ctx, cs.StateBlockstore(), r) + + br, err := carv2.NewBlockReader(r) if err != nil { return nil, xerrors.Errorf("loadcar failed: %w", err) } - root, err := cs.LoadTipSet(ctx, types.NewTipSetKey(header.Roots...)) + s := cs.StateBlockstore() + + parallelPuts := 5 + putThrottle := make(chan error, parallelPuts) + for i := 0; i < parallelPuts; i++ { + putThrottle <- nil + } + + var buf []blocks.Block + for { + blk, err := br.Next() + if err != nil { + if err == io.EOF { + if len(buf) > 0 { + if err := s.PutMany(ctx, buf); err != nil { + return nil, err + } + } + + break + } + return nil, err + } + + buf = append(buf, blk) + + if len(buf) > 1000 { + if lastErr := <-putThrottle; lastErr != nil { // consume one error to have the right to add one + return nil, lastErr + } + + go func(buf []blocks.Block) { + putThrottle <- s.PutMany(ctx, buf) + }(buf) + buf = nil + } + } + + // check errors + for i := 0; i < parallelPuts; i++ { + if lastErr := <-putThrottle; lastErr != nil { + return nil, lastErr + } + } + + root, err := cs.LoadTipSet(ctx, types.NewTipSetKey(br.Roots...)) if err != nil { return nil, xerrors.Errorf("failed to load root tipset from chainfile: %w", err) } + ts := root + for i := 0; i < int(TipsetkeyBackfillRange); i++ { + err = cs.PersistTipset(ctx, ts) + if err != nil { + return nil, err + } + parentTsKey := ts.Parents() + ts, err = cs.LoadTipSet(ctx, parentTsKey) + if ts == nil || err != nil { + log.Warnf("Only able to load the last %d tipsets", i) + break + } + } + return root, nil } diff --git a/chain/store/store.go b/chain/store/store.go index 6313492a7..754e3a123 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -1,6 +1,7 @@ package store import ( + "bytes" "context" "encoding/json" "errors" @@ -11,11 +12,11 @@ import ( "time" lru "github.com/hashicorp/golang-lru" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" dstore "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/query" cbor "github.com/ipfs/go-ipld-cbor" + block "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" "go.opencensus.io/stats" "go.opencensus.io/trace" @@ -125,6 +126,8 @@ type ChainStore struct { evtTypes [1]journal.EventType journal journal.Journal + storeEvents bool + cancelFn context.CancelFunc wg sync.WaitGroup } @@ -375,17 +378,27 @@ func (cs *ChainStore) SetGenesis(ctx context.Context, b *types.BlockHeader) erro } func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error { - for _, b := range ts.Blocks() { - if err := cs.PersistBlockHeaders(ctx, b); err != nil { - return err - } + if err := cs.PersistTipset(ctx, ts); err != nil { + return xerrors.Errorf("failed to persist tipset: %w", err) } expanded, err := cs.expandTipset(ctx, ts.Blocks()[0]) if err != nil { return xerrors.Errorf("errored while expanding tipset: %w", err) } - log.Debugf("expanded %s into %s\n", ts.Cids(), expanded.Cids()) + + if expanded.Key() != ts.Key() { + log.Debugf("expanded %s into %s\n", ts.Cids(), expanded.Cids()) + + tsBlk, err := expanded.Key().ToStorageBlock() + if err != nil { + return xerrors.Errorf("failed to get tipset key block: %w", err) + } + + if err = cs.chainLocalBlockstore.Put(ctx, tsBlk); err != nil { + return xerrors.Errorf("failed to put tipset key block: %w", err) + } + } if err := cs.MaybeTakeHeavierTipSet(ctx, expanded); err != nil { return xerrors.Errorf("MaybeTakeHeavierTipSet failed in PutTipSet: %w", err) @@ -646,7 +659,7 @@ func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet) if err := cs.writeHead(ctx, ts); err != nil { log.Errorf("failed to write chain head: %s", err) - return nil + return err } return nil @@ -669,7 +682,7 @@ func FlushValidationCache(ctx context.Context, ds dstore.Batching) error { // If this is addressed (blockcache goes into its own sub-namespace) then // strings.HasPrefix(...) below can be skipped // - //Prefix: blockValidationCacheKeyPrefix.String() + // Prefix: blockValidationCacheKeyPrefix.String() KeysOnly: true, }) if err != nil { @@ -958,7 +971,24 @@ func (cs *ChainStore) AddToTipSetTracker(ctx context.Context, b *types.BlockHead return nil } -func (cs *ChainStore) PersistBlockHeaders(ctx context.Context, b ...*types.BlockHeader) error { +func (cs *ChainStore) PersistTipset(ctx context.Context, ts *types.TipSet) error { + if err := cs.persistBlockHeaders(ctx, ts.Blocks()...); err != nil { + return xerrors.Errorf("failed to persist block headers: %w", err) + } + + tsBlk, err := ts.Key().ToStorageBlock() + if err != nil { + return xerrors.Errorf("failed to get tipset key block: %w", err) + } + + if err = cs.chainLocalBlockstore.Put(ctx, tsBlk); err != nil { + return xerrors.Errorf("failed to put tipset key block: %w", err) + } + + return nil +} + +func (cs *ChainStore) persistBlockHeaders(ctx context.Context, b ...*types.BlockHeader) error { sbs := make([]block.Block, len(b)) for i, header := range b { @@ -1026,23 +1056,6 @@ func (cs *ChainStore) expandTipset(ctx context.Context, b *types.BlockHeader) (* return types.NewTipSet(all) } -func (cs *ChainStore) AddBlock(ctx context.Context, b *types.BlockHeader) error { - if err := cs.PersistBlockHeaders(ctx, b); err != nil { - return err - } - - ts, err := cs.expandTipset(ctx, b) - if err != nil { - return err - } - - if err := cs.MaybeTakeHeavierTipSet(ctx, ts); err != nil { - return xerrors.Errorf("MaybeTakeHeavierTipSet failed: %w", err) - } - - return nil -} - func (cs *ChainStore) GetGenesis(ctx context.Context) (*types.BlockHeader, error) { data, err := cs.metadataDs.Get(ctx, dstore.NewKey("0")) if err != nil { @@ -1098,6 +1111,10 @@ func (cs *ChainStore) StateBlockstore() bstore.Blockstore { return cs.stateBlockstore } +func (cs *ChainStore) ChainLocalBlockstore() bstore.Blockstore { + return cs.chainLocalBlockstore +} + func ActorStore(ctx context.Context, bs bstore.Blockstore) adt.Store { return adt.WrapStore(ctx, cbor.NewCborStore(bs)) } @@ -1165,10 +1182,38 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t return cs.LoadTipSet(ctx, lbts.Parents()) } +func (cs *ChainStore) GetTipSetByCid(ctx context.Context, c cid.Cid) (*types.TipSet, error) { + blk, err := cs.chainBlockstore.Get(ctx, c) + if err != nil { + return nil, xerrors.Errorf("cannot find tipset with cid %s: %w", c, err) + } + + tsk := new(types.TipSetKey) + if err := tsk.UnmarshalCBOR(bytes.NewReader(blk.RawData())); err != nil { + return nil, xerrors.Errorf("cannot unmarshal block into tipset key: %w", err) + } + + ts, err := cs.GetTipSetFromKey(ctx, *tsk) + if err != nil { + return nil, xerrors.Errorf("cannot get tipset from key: %w", err) + } + return ts, nil +} + func (cs *ChainStore) Weight(ctx context.Context, hts *types.TipSet) (types.BigInt, error) { // todo remove return cs.weight(ctx, cs.StateBlockstore(), hts) } +// StoreEvents marks this ChainStore as storing events. +func (cs *ChainStore) StoreEvents(store bool) { + cs.storeEvents = store +} + +// IsStoringEvents indicates if this ChainStore is storing events. +func (cs *ChainStore) IsStoringEvents() bool { + return cs.storeEvents +} + // true if ts1 wins according to the filecoin tie-break rule func breakWeightTie(ts1, ts2 *types.TipSet) bool { s := len(ts1.Blocks()) diff --git a/chain/store/store_test.go b/chain/store/store_test.go index af78e3dc0..89d0caa2c 100644 --- a/chain/store/store_test.go +++ b/chain/store/store_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/ipfs/go-datastore" + "github.com/stretchr/testify/require" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" @@ -110,7 +111,7 @@ func TestChainExportImport(t *testing.T) { t.Fatal(err) } - nbs := blockstore.NewMemory() + nbs := blockstore.NewMemorySync() cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil) defer cs.Close() //nolint:errcheck @@ -124,6 +125,51 @@ func TestChainExportImport(t *testing.T) { } } +// Test to check if tipset key cids are being stored on snapshot +func TestChainImportTipsetKeyCid(t *testing.T) { + + ctx := context.Background() + cg, err := gen.NewGenerator() + require.NoError(t, err) + + buf := new(bytes.Buffer) + var last *types.TipSet + var tsKeys []types.TipSetKey + for i := 0; i < 10; i++ { + ts, err := cg.NextTipSet() + require.NoError(t, err) + last = ts.TipSet.TipSet() + tsKeys = append(tsKeys, last.Key()) + } + + if err := cg.ChainStore().Export(ctx, last, last.Height(), false, buf); err != nil { + t.Fatal(err) + } + + nbs := blockstore.NewMemorySync() + cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil) + defer cs.Close() //nolint:errcheck + + root, err := cs.Import(ctx, buf) + require.NoError(t, err) + + require.Truef(t, root.Equals(last), "imported chain differed from exported chain") + + err = cs.SetHead(ctx, last) + require.NoError(t, err) + + for _, tsKey := range tsKeys { + _, err := cs.LoadTipSet(ctx, tsKey) + require.NoError(t, err) + + tsCid, err := tsKey.Cid() + require.NoError(t, err) + _, err = cs.ChainLocalBlockstore().Get(ctx, tsCid) + require.NoError(t, err) + + } +} + func TestChainExportImportFull(t *testing.T) { //stm: @CHAIN_GEN_NEXT_TIPSET_001 //stm: @CHAIN_STORE_IMPORT_001, @CHAIN_STORE_EXPORT_001, @CHAIN_STORE_SET_HEAD_001 @@ -148,7 +194,7 @@ func TestChainExportImportFull(t *testing.T) { t.Fatal(err) } - nbs := blockstore.NewMemory() + nbs := blockstore.NewMemorySync() cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil) defer cs.Close() //nolint:errcheck diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index b8427e036..4c7d16a9a 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -8,9 +8,9 @@ import ( "time" lru "github.com/hashicorp/golang-lru" - blocks "github.com/ipfs/go-block-format" bserv "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/connmgr" diff --git a/chain/sub/incoming_test.go b/chain/sub/incoming_test.go index 8566391b9..d17b08825 100644 --- a/chain/sub/incoming_test.go +++ b/chain/sub/incoming_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/golang/mock/gomock" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" pubsub "github.com/libp2p/go-libp2p-pubsub" pb "github.com/libp2p/go-libp2p-pubsub/pb" "github.com/libp2p/go-libp2p/core/peer" diff --git a/chain/sync.go b/chain/sync.go index 634313855..db7b7fc04 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -11,10 +11,10 @@ import ( "github.com/Gurpartap/async" "github.com/hashicorp/go-multierror" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p/core/connmgr" "github.com/libp2p/go-libp2p/core/peer" @@ -228,7 +228,7 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool { // TODO: IMPORTANT(GARBAGE) this needs to be put in the 'temporary' side of // the blockstore - if err := syncer.store.PersistBlockHeaders(ctx, fts.TipSet().Blocks()...); err != nil { + if err := syncer.store.PersistTipset(ctx, fts.TipSet()); err != nil { log.Warn("failed to persist incoming block header: ", err) return false } @@ -1145,7 +1145,7 @@ func persistMessages(ctx context.Context, bs bstore.Blockstore, bst *exchange.Co } } for _, m := range bst.Secpk { - if m.Signature.Type != crypto.SigTypeSecp256k1 { + if m.Signature.Type != crypto.SigTypeSecp256k1 && m.Signature.Type != crypto.SigTypeDelegated { return xerrors.Errorf("unknown signature type on message %s: %q", m.Cid(), m.Signature.Type) } //log.Infof("putting secp256k1 message: %s", m.Cid()) @@ -1198,16 +1198,13 @@ func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet, hts *t ss.SetStage(api.StagePersistHeaders) - toPersist := make([]*types.BlockHeader, 0, len(headers)*int(build.BlocksPerEpoch)) for _, ts := range headers { - toPersist = append(toPersist, ts.Blocks()...) + if err := syncer.store.PersistTipset(ctx, ts); err != nil { + err = xerrors.Errorf("failed to persist synced tipset to the chainstore: %w", err) + ss.Error(err) + return err + } } - if err := syncer.store.PersistBlockHeaders(ctx, toPersist...); err != nil { - err = xerrors.Errorf("failed to persist synced blocks to the chainstore: %w", err) - ss.Error(err) - return err - } - toPersist = nil ss.SetStage(api.StageMessages) diff --git a/chain/sync_test.go b/chain/sync_test.go index 18520a07f..a86d42f17 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -306,13 +306,13 @@ func (tu *syncTestUtil) addSourceNode(gen int) { require.NoError(tu.t, err) tu.t.Cleanup(func() { _ = stop(context.Background()) }) - lastTs := blocks[len(blocks)-1].Blocks - for _, lastB := range lastTs { - cs := out.(*impl.FullNodeAPI).ChainAPI.Chain + lastTs := blocks[len(blocks)-1] + cs := out.(*impl.FullNodeAPI).ChainAPI.Chain + for _, lastB := range lastTs.Blocks { require.NoError(tu.t, cs.AddToTipSetTracker(context.Background(), lastB.Header)) - err = cs.AddBlock(tu.ctx, lastB.Header) - require.NoError(tu.t, err) } + err = cs.PutTipSet(tu.ctx, lastTs.TipSet()) + require.NoError(tu.t, err) tu.genesis = genesis tu.blocks = blocks diff --git a/chain/types/actor.go b/chain/types/actor.go index a9974a01f..8ba611617 100644 --- a/chain/types/actor.go +++ b/chain/types/actor.go @@ -4,14 +4,48 @@ import ( "errors" "github.com/ipfs/go-cid" + + "github.com/filecoin-project/go-address" ) var ErrActorNotFound = errors.New("actor not found") -type Actor struct { +// Actor State for state tree version up to 4 +type ActorV4 struct { // Identifies the type of actor (string coded as a CID), see `chain/actors/actors.go`. Code cid.Cid Head cid.Cid Nonce uint64 Balance BigInt } + +// Actor State for state tree version 5 +type ActorV5 struct { + // Identifies the type of actor (string coded as a CID), see `chain/actors/actors.go`. + Code cid.Cid + Head cid.Cid + Nonce uint64 + Balance BigInt + // Deterministic Address. + Address *address.Address +} + +type Actor = ActorV5 + +func AsActorV4(a *ActorV5) *ActorV4 { + return &ActorV4{ + Code: a.Code, + Head: a.Head, + Nonce: a.Nonce, + Balance: a.Balance, + } +} + +func AsActorV5(a *ActorV4) *ActorV5 { + return &ActorV5{ + Code: a.Code, + Head: a.Head, + Nonce: a.Nonce, + Balance: a.Balance, + } +} diff --git a/chain/types/blockheader.go b/chain/types/blockheader.go index e0b9e6b30..559569ba0 100644 --- a/chain/types/blockheader.go +++ b/chain/types/blockheader.go @@ -4,8 +4,8 @@ import ( "bytes" "math/big" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" "github.com/minio/blake2b-simd" "golang.org/x/xerrors" diff --git a/chain/types/cbor_gen.go b/chain/types/cbor_gen.go index 78a3449ee..314b2be6c 100644 --- a/chain/types/cbor_gen.go +++ b/chain/types/cbor_gen.go @@ -12,9 +12,9 @@ import ( cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" + address "github.com/filecoin-project/go-address" abi "github.com/filecoin-project/go-state-types/abi" crypto "github.com/filecoin-project/go-state-types/crypto" - exitcode "github.com/filecoin-project/go-state-types/exitcode" proof "github.com/filecoin-project/go-state-types/proof" ) @@ -1040,9 +1040,9 @@ func (t *MsgMeta) UnmarshalCBOR(r io.Reader) (err error) { return nil } -var lengthBufActor = []byte{132} +var lengthBufActorV4 = []byte{132} -func (t *Actor) MarshalCBOR(w io.Writer) error { +func (t *ActorV4) MarshalCBOR(w io.Writer) error { if t == nil { _, err := w.Write(cbg.CborNull) return err @@ -1050,7 +1050,7 @@ func (t *Actor) MarshalCBOR(w io.Writer) error { cw := cbg.NewCborWriter(w) - if _, err := cw.Write(lengthBufActor); err != nil { + if _, err := cw.Write(lengthBufActorV4); err != nil { return err } @@ -1079,8 +1079,8 @@ func (t *Actor) MarshalCBOR(w io.Writer) error { return nil } -func (t *Actor) UnmarshalCBOR(r io.Reader) (err error) { - *t = Actor{} +func (t *ActorV4) UnmarshalCBOR(r io.Reader) (err error) { + *t = ActorV4{} cr := cbg.NewCborReader(r) @@ -1152,9 +1152,9 @@ func (t *Actor) UnmarshalCBOR(r io.Reader) (err error) { return nil } -var lengthBufMessageReceipt = []byte{131} +var lengthBufActorV5 = []byte{133} -func (t *MessageReceipt) MarshalCBOR(w io.Writer) error { +func (t *ActorV5) MarshalCBOR(w io.Writer) error { if t == nil { _, err := w.Write(cbg.CborNull) return err @@ -1162,49 +1162,42 @@ func (t *MessageReceipt) MarshalCBOR(w io.Writer) error { cw := cbg.NewCborWriter(w) - if _, err := cw.Write(lengthBufMessageReceipt); err != nil { + if _, err := cw.Write(lengthBufActorV5); err != nil { return err } - // t.ExitCode (exitcode.ExitCode) (int64) - if t.ExitCode >= 0 { - if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ExitCode)); err != nil { - return err - } - } else { - if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.ExitCode-1)); err != nil { - return err - } + // t.Code (cid.Cid) (struct) + + if err := cbg.WriteCid(cw, t.Code); err != nil { + return xerrors.Errorf("failed to write cid field t.Code: %w", err) } - // t.Return ([]uint8) (slice) - if len(t.Return) > cbg.ByteArrayMaxLen { - return xerrors.Errorf("Byte array in field t.Return was too long") + // t.Head (cid.Cid) (struct) + + if err := cbg.WriteCid(cw, t.Head); err != nil { + return xerrors.Errorf("failed to write cid field t.Head: %w", err) } - if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Return))); err != nil { + // t.Nonce (uint64) (uint64) + + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Nonce)); err != nil { return err } - if _, err := cw.Write(t.Return[:]); err != nil { + // t.Balance (big.Int) (struct) + if err := t.Balance.MarshalCBOR(cw); err != nil { return err } - // t.GasUsed (int64) (int64) - if t.GasUsed >= 0 { - if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.GasUsed)); err != nil { - return err - } - } else { - if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.GasUsed-1)); err != nil { - return err - } + // t.Address (address.Address) (struct) + if err := t.Address.MarshalCBOR(cw); err != nil { + return err } return nil } -func (t *MessageReceipt) UnmarshalCBOR(r io.Reader) (err error) { - *t = MessageReceipt{} +func (t *ActorV5) UnmarshalCBOR(r io.Reader) (err error) { + *t = ActorV5{} cr := cbg.NewCborReader(r) @@ -1222,80 +1215,75 @@ func (t *MessageReceipt) UnmarshalCBOR(r io.Reader) (err error) { return fmt.Errorf("cbor input should be of type array") } - if extra != 3 { + if extra != 5 { return fmt.Errorf("cbor input had wrong number of fields") } - // t.ExitCode (exitcode.ExitCode) (int64) + // t.Code (cid.Cid) (struct) + { - maj, extra, err := cr.ReadHeader() - var extraI int64 + + c, err := cbg.ReadCid(cr) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Code: %w", err) + } + + t.Code = c + + } + // t.Head (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(cr) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Head: %w", err) + } + + t.Head = c + + } + // t.Nonce (uint64) (uint64) + + { + + maj, extra, err = cr.ReadHeader() if err != nil { return err } - switch maj { - case cbg.MajUnsignedInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 positive overflow") - } - case cbg.MajNegativeInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 negative oveflow") - } - extraI = -1 - extraI - default: - return fmt.Errorf("wrong type for int64 field: %d", maj) + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Nonce = uint64(extra) + + } + // t.Balance (big.Int) (struct) + + { + + if err := t.Balance.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Balance: %w", err) } - t.ExitCode = exitcode.ExitCode(extraI) } - // t.Return ([]uint8) (slice) + // t.Address (address.Address) (struct) - maj, extra, err = cr.ReadHeader() - if err != nil { - return err - } - - if extra > cbg.ByteArrayMaxLen { - return fmt.Errorf("t.Return: byte array too large (%d)", extra) - } - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - - if extra > 0 { - t.Return = make([]uint8, extra) - } - - if _, err := io.ReadFull(cr, t.Return[:]); err != nil { - return err - } - // t.GasUsed (int64) (int64) { - maj, extra, err := cr.ReadHeader() - var extraI int64 + + b, err := cr.ReadByte() if err != nil { return err } - switch maj { - case cbg.MajUnsignedInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 positive overflow") + if b != cbg.CborNull[0] { + if err := cr.UnreadByte(); err != nil { + return err } - case cbg.MajNegativeInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 negative oveflow") + t.Address = new(address.Address) + if err := t.Address.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Address pointer: %w", err) } - extraI = -1 - extraI - default: - return fmt.Errorf("wrong type for int64 field: %d", maj) } - t.GasUsed = int64(extraI) } return nil } @@ -1849,3 +1837,244 @@ func (t *StateInfo0) UnmarshalCBOR(r io.Reader) (err error) { return nil } + +var lengthBufEvent = []byte{130} + +func (t *Event) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write(lengthBufEvent); err != nil { + return err + } + + // t.Emitter (abi.ActorID) (uint64) + + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Emitter)); err != nil { + return err + } + + // t.Entries ([]types.EventEntry) (slice) + if len(t.Entries) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Entries was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Entries))); err != nil { + return err + } + for _, v := range t.Entries { + if err := v.MarshalCBOR(cw); err != nil { + return err + } + } + return nil +} + +func (t *Event) UnmarshalCBOR(r io.Reader) (err error) { + *t = Event{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Emitter (abi.ActorID) (uint64) + + { + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Emitter = abi.ActorID(extra) + + } + // t.Entries ([]types.EventEntry) (slice) + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Entries: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Entries = make([]EventEntry, extra) + } + + for i := 0; i < int(extra); i++ { + + var v EventEntry + if err := v.UnmarshalCBOR(cr); err != nil { + return err + } + + t.Entries[i] = v + } + + return nil +} + +var lengthBufEventEntry = []byte{132} + +func (t *EventEntry) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write(lengthBufEventEntry); err != nil { + return err + } + + // t.Flags (uint8) (uint8) + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Flags)); err != nil { + return err + } + + // t.Key (string) (string) + if len(t.Key) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Key was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Key))); err != nil { + return err + } + if _, err := io.WriteString(w, string(t.Key)); err != nil { + return err + } + + // t.Codec (uint64) (uint64) + + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Codec)); err != nil { + return err + } + + // t.Value ([]uint8) (slice) + if len(t.Value) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Value was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Value))); err != nil { + return err + } + + if _, err := cw.Write(t.Value[:]); err != nil { + return err + } + return nil +} + +func (t *EventEntry) UnmarshalCBOR(r io.Reader) (err error) { + *t = EventEntry{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Flags (uint8) (uint8) + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint8 field") + } + if extra > math.MaxUint8 { + return fmt.Errorf("integer in input was too large for uint8 field") + } + t.Flags = uint8(extra) + // t.Key (string) (string) + + { + sval, err := cbg.ReadString(cr) + if err != nil { + return err + } + + t.Key = string(sval) + } + // t.Codec (uint64) (uint64) + + { + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Codec = uint64(extra) + + } + // t.Value ([]uint8) (slice) + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Value: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Value = make([]uint8, extra) + } + + if _, err := io.ReadFull(cr, t.Value[:]); err != nil { + return err + } + return nil +} diff --git a/chain/types/ethtypes/eth_transactions.go b/chain/types/ethtypes/eth_transactions.go new file mode 100644 index 000000000..7afde4bd2 --- /dev/null +++ b/chain/types/ethtypes/eth_transactions.go @@ -0,0 +1,664 @@ +package ethtypes + +import ( + "bytes" + "encoding/binary" + "fmt" + mathbig "math/big" + + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/crypto/sha3" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + gocrypto "github.com/filecoin-project/go-crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + builtintypes "github.com/filecoin-project/go-state-types/builtin" + typescrypto "github.com/filecoin-project/go-state-types/crypto" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" +) + +const Eip1559TxType = 2 + +type EthTx struct { + ChainID EthUint64 `json:"chainId"` + Nonce EthUint64 `json:"nonce"` + Hash EthHash `json:"hash"` + BlockHash *EthHash `json:"blockHash"` + BlockNumber *EthUint64 `json:"blockNumber"` + TransactionIndex *EthUint64 `json:"transactionIndex"` + From EthAddress `json:"from"` + To *EthAddress `json:"to"` + Value EthBigInt `json:"value"` + Type EthUint64 `json:"type"` + Input EthBytes `json:"input"` + Gas EthUint64 `json:"gas"` + MaxFeePerGas EthBigInt `json:"maxFeePerGas"` + MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"` + AccessList []EthHash `json:"accessList"` + V EthBigInt `json:"v"` + R EthBigInt `json:"r"` + S EthBigInt `json:"s"` +} + +func (tx *EthTx) Reward(blkBaseFee big.Int) EthBigInt { + availablePriorityFee := big.Sub(big.Int(tx.MaxFeePerGas), blkBaseFee) + if big.Cmp(big.Int(tx.MaxPriorityFeePerGas), availablePriorityFee) <= 0 { + return tx.MaxPriorityFeePerGas + } + return EthBigInt(availablePriorityFee) +} + +type EthTxArgs struct { + ChainID int `json:"chainId"` + Nonce int `json:"nonce"` + To *EthAddress `json:"to"` + Value big.Int `json:"value"` + MaxFeePerGas big.Int `json:"maxFeePerGas"` + MaxPriorityFeePerGas big.Int `json:"maxPriorityFeePerGas"` + GasLimit int `json:"gasLimit"` + Input []byte `json:"input"` + V big.Int `json:"v"` + R big.Int `json:"r"` + S big.Int `json:"s"` +} + +// EthTxFromSignedEthMessage does NOT populate: +// - BlockHash +// - BlockNumber +// - TransactionIndex +// - From +// - Hash +func EthTxFromSignedEthMessage(smsg *types.SignedMessage) (EthTx, error) { + if smsg.Signature.Type != typescrypto.SigTypeDelegated { + return EthTx{}, xerrors.Errorf("signature is not delegated type, is type: %d", smsg.Signature.Type) + } + + txArgs, err := EthTxArgsFromUnsignedEthMessage(&smsg.Message) + if err != nil { + return EthTx{}, xerrors.Errorf("failed to convert the unsigned message: %w", err) + } + + r, s, v, err := RecoverSignature(smsg.Signature) + if err != nil { + return EthTx{}, xerrors.Errorf("failed to recover signature: %w", err) + } + + return EthTx{ + Nonce: EthUint64(txArgs.Nonce), + ChainID: EthUint64(txArgs.ChainID), + To: txArgs.To, + Value: EthBigInt(txArgs.Value), + Type: Eip1559TxType, + Gas: EthUint64(txArgs.GasLimit), + MaxFeePerGas: EthBigInt(txArgs.MaxFeePerGas), + MaxPriorityFeePerGas: EthBigInt(txArgs.MaxPriorityFeePerGas), + AccessList: []EthHash{}, + V: v, + R: r, + S: s, + Input: txArgs.Input, + }, nil +} + +func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) { + var ( + to *EthAddress + params []byte + err error + ) + + if msg.Version != 0 { + return EthTxArgs{}, xerrors.Errorf("unsupported msg version: %d", msg.Version) + } + + if len(msg.Params) > 0 { + paramsReader := bytes.NewReader(msg.Params) + params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params))) + if err != nil { + return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err) + } + if paramsReader.Len() != 0 { + return EthTxArgs{}, xerrors.Errorf("extra data found in params") + } + if len(params) == 0 { + return EthTxArgs{}, xerrors.Errorf("non-empty params encode empty byte array") + } + } + + if msg.To == builtintypes.EthereumAddressManagerActorAddr { + if msg.Method != builtintypes.MethodsEAM.CreateExternal { + return EthTxArgs{}, fmt.Errorf("unsupported EAM method") + } + } else if msg.Method == builtintypes.MethodsEVM.InvokeContract { + addr, err := EthAddressFromFilecoinAddress(msg.To) + if err != nil { + return EthTxArgs{}, err + } + to = &addr + } else { + return EthTxArgs{}, + xerrors.Errorf("invalid methodnum %d: only allowed method is InvokeContract(%d)", + msg.Method, builtintypes.MethodsEVM.InvokeContract) + } + + return EthTxArgs{ + ChainID: build.Eip155ChainId, + Nonce: int(msg.Nonce), + To: to, + Value: msg.Value, + Input: params, + MaxFeePerGas: msg.GasFeeCap, + MaxPriorityFeePerGas: msg.GasPremium, + GasLimit: int(msg.GasLimit), + }, nil +} + +func (tx *EthTxArgs) ToUnsignedMessage(from address.Address) (*types.Message, error) { + if tx.ChainID != build.Eip155ChainId { + return nil, xerrors.Errorf("unsupported chain id: %d", tx.ChainID) + } + + var err error + var params []byte + if len(tx.Input) > 0 { + buf := new(bytes.Buffer) + if err = cbg.WriteByteArray(buf, tx.Input); err != nil { + return nil, xerrors.Errorf("failed to write input args: %w", err) + } + params = buf.Bytes() + } + + var to address.Address + var method abi.MethodNum + // nil indicates the EAM, only CreateExternal is allowed + if tx.To == nil { + method = builtintypes.MethodsEAM.CreateExternal + to = builtintypes.EthereumAddressManagerActorAddr + } else { + method = builtintypes.MethodsEVM.InvokeContract + to, err = tx.To.ToFilecoinAddress() + if err != nil { + return nil, xerrors.Errorf("failed to convert To into filecoin addr: %w", err) + } + } + + return &types.Message{ + Version: 0, + To: to, + From: from, + Nonce: uint64(tx.Nonce), + Value: tx.Value, + GasLimit: int64(tx.GasLimit), + GasFeeCap: tx.MaxFeePerGas, + GasPremium: tx.MaxPriorityFeePerGas, + Method: method, + Params: params, + }, nil +} + +func (tx *EthTxArgs) ToSignedMessage() (*types.SignedMessage, error) { + from, err := tx.Sender() + if err != nil { + return nil, xerrors.Errorf("failed to calculate sender: %w", err) + } + + unsignedMsg, err := tx.ToUnsignedMessage(from) + if err != nil { + return nil, xerrors.Errorf("failed to convert to unsigned msg: %w", err) + } + + siggy, err := tx.Signature() + if err != nil { + return nil, xerrors.Errorf("failed to calculate signature: %w", err) + } + + return &types.SignedMessage{ + Message: *unsignedMsg, + Signature: *siggy, + }, nil +} + +func (tx *EthTxArgs) HashedOriginalRlpMsg() ([]byte, error) { + msg, err := tx.ToRlpUnsignedMsg() + if err != nil { + return nil, err + } + + hasher := sha3.NewLegacyKeccak256() + hasher.Write(msg) + hash := hasher.Sum(nil) + return hash, nil +} + +func (tx *EthTxArgs) ToRlpUnsignedMsg() ([]byte, error) { + packed, err := tx.packTxFields() + if err != nil { + return nil, err + } + + encoded, err := EncodeRLP(packed) + if err != nil { + return nil, err + } + return append([]byte{0x02}, encoded...), nil +} + +func (tx *EthTx) ToEthTxArgs() EthTxArgs { + return EthTxArgs{ + ChainID: int(tx.ChainID), + Nonce: int(tx.Nonce), + To: tx.To, + Value: big.Int(tx.Value), + MaxFeePerGas: big.Int(tx.MaxFeePerGas), + MaxPriorityFeePerGas: big.Int(tx.MaxPriorityFeePerGas), + GasLimit: int(tx.Gas), + Input: tx.Input, + V: big.Int(tx.V), + R: big.Int(tx.R), + S: big.Int(tx.S), + } +} + +func (tx *EthTx) TxHash() (EthHash, error) { + ethTxArgs := tx.ToEthTxArgs() + return (ðTxArgs).TxHash() +} + +func (tx *EthTxArgs) TxHash() (EthHash, error) { + rlp, err := tx.ToRlpSignedMsg() + if err != nil { + return EmptyEthHash, err + } + + return EthHashFromTxBytes(rlp), nil +} + +func (tx *EthTxArgs) ToRlpSignedMsg() ([]byte, error) { + packed1, err := tx.packTxFields() + if err != nil { + return nil, err + } + + packed2, err := tx.packSigFields() + if err != nil { + return nil, err + } + + encoded, err := EncodeRLP(append(packed1, packed2...)) + if err != nil { + return nil, err + } + return append([]byte{0x02}, encoded...), nil +} + +func (tx *EthTxArgs) packTxFields() ([]interface{}, error) { + chainId, err := formatInt(tx.ChainID) + if err != nil { + return nil, err + } + + nonce, err := formatInt(tx.Nonce) + if err != nil { + return nil, err + } + + maxPriorityFeePerGas, err := formatBigInt(tx.MaxPriorityFeePerGas) + if err != nil { + return nil, err + } + + maxFeePerGas, err := formatBigInt(tx.MaxFeePerGas) + if err != nil { + return nil, err + } + + gasLimit, err := formatInt(tx.GasLimit) + if err != nil { + return nil, err + } + + value, err := formatBigInt(tx.Value) + if err != nil { + return nil, err + } + + res := []interface{}{ + chainId, + nonce, + maxPriorityFeePerGas, + maxFeePerGas, + gasLimit, + formatEthAddr(tx.To), + value, + tx.Input, + []interface{}{}, // access list + } + return res, nil +} + +func (tx *EthTxArgs) packSigFields() ([]interface{}, error) { + r, err := formatBigInt(tx.R) + if err != nil { + return nil, err + } + + s, err := formatBigInt(tx.S) + if err != nil { + return nil, err + } + + v, err := formatBigInt(tx.V) + if err != nil { + return nil, err + } + + res := []interface{}{v, r, s} + return res, nil +} + +func (tx *EthTxArgs) Signature() (*typescrypto.Signature, error) { + r := tx.R.Int.Bytes() + s := tx.S.Int.Bytes() + v := tx.V.Int.Bytes() + + sig := append([]byte{}, padLeadingZeros(r, 32)...) + sig = append(sig, padLeadingZeros(s, 32)...) + if len(v) == 0 { + sig = append(sig, 0) + } else { + sig = append(sig, v[0]) + } + + if len(sig) != 65 { + return nil, fmt.Errorf("signature is not 65 bytes") + } + return &typescrypto.Signature{ + Type: typescrypto.SigTypeDelegated, Data: sig, + }, nil +} + +func (tx *EthTxArgs) Sender() (address.Address, error) { + msg, err := tx.ToRlpUnsignedMsg() + if err != nil { + return address.Undef, err + } + + hasher := sha3.NewLegacyKeccak256() + hasher.Write(msg) + hash := hasher.Sum(nil) + + sig, err := tx.Signature() + if err != nil { + return address.Undef, err + } + + pubk, err := gocrypto.EcRecover(hash, sig.Data) + if err != nil { + return address.Undef, err + } + + ethAddr, err := EthAddressFromPubKey(pubk) + if err != nil { + return address.Undef, err + } + + ea, err := CastEthAddress(ethAddr) + if err != nil { + return address.Undef, err + } + + return ea.ToFilecoinAddress() +} + +func RecoverSignature(sig typescrypto.Signature) (r, s, v EthBigInt, err error) { + if sig.Type != typescrypto.SigTypeDelegated { + return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("RecoverSignature only supports Delegated signature") + } + + if len(sig.Data) != 65 { + return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("signature should be 65 bytes long, but got %d bytes", len(sig.Data)) + } + + r_, err := parseBigInt(sig.Data[0:32]) + if err != nil { + return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("cannot parse r into EthBigInt") + } + + s_, err := parseBigInt(sig.Data[32:64]) + if err != nil { + return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("cannot parse s into EthBigInt") + } + + v_, err := parseBigInt([]byte{sig.Data[64]}) + if err != nil { + return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("cannot parse v into EthBigInt") + } + + return EthBigInt(r_), EthBigInt(s_), EthBigInt(v_), nil +} + +func parseEip1559Tx(data []byte) (*EthTxArgs, error) { + if data[0] != 2 { + return nil, fmt.Errorf("not an EIP-1559 transaction: first byte is not 2") + } + + d, err := DecodeRLP(data[1:]) + if err != nil { + return nil, err + } + decoded, ok := d.([]interface{}) + if !ok { + return nil, fmt.Errorf("not an EIP-1559 transaction: decoded data is not a list") + } + + if len(decoded) != 12 { + return nil, fmt.Errorf("not an EIP-1559 transaction: should have 12 elements in the rlp list") + } + + chainId, err := parseInt(decoded[0]) + if err != nil { + return nil, err + } + + nonce, err := parseInt(decoded[1]) + if err != nil { + return nil, err + } + + maxPriorityFeePerGas, err := parseBigInt(decoded[2]) + if err != nil { + return nil, err + } + + maxFeePerGas, err := parseBigInt(decoded[3]) + if err != nil { + return nil, err + } + + gasLimit, err := parseInt(decoded[4]) + if err != nil { + return nil, err + } + + to, err := parseEthAddr(decoded[5]) + if err != nil { + return nil, err + } + + value, err := parseBigInt(decoded[6]) + if err != nil { + return nil, err + } + + input, err := parseBytes(decoded[7]) + if err != nil { + return nil, err + } + + accessList, ok := decoded[8].([]interface{}) + if !ok || (ok && len(accessList) != 0) { + return nil, fmt.Errorf("access list should be an empty list") + } + + r, err := parseBigInt(decoded[10]) + if err != nil { + return nil, err + } + + s, err := parseBigInt(decoded[11]) + if err != nil { + return nil, err + } + + v, err := parseBigInt(decoded[9]) + if err != nil { + return nil, err + } + + // EIP-1559 and EIP-2930 transactions only support 0 or 1 for v + // Legacy and EIP-155 transactions support other values + // https://github.com/ethers-io/ethers.js/blob/56fabe987bb8c1e4891fdf1e5d3fe8a4c0471751/packages/transactions/src.ts/index.ts#L333 + if !v.Equals(big.NewInt(0)) && !v.Equals(big.NewInt(1)) { + return nil, fmt.Errorf("EIP-1559 transactions only support 0 or 1 for v") + } + + args := EthTxArgs{ + ChainID: chainId, + Nonce: nonce, + To: to, + MaxPriorityFeePerGas: maxPriorityFeePerGas, + MaxFeePerGas: maxFeePerGas, + GasLimit: gasLimit, + Value: value, + Input: input, + V: v, + R: r, + S: s, + } + return &args, nil +} + +func ParseEthTxArgs(data []byte) (*EthTxArgs, error) { + if len(data) == 0 { + return nil, fmt.Errorf("empty data") + } + + if data[0] > 0x7f { + // legacy transaction + return nil, fmt.Errorf("legacy transaction is not supported") + } + + if data[0] == 1 { + // EIP-2930 + return nil, fmt.Errorf("EIP-2930 transaction is not supported") + } + + if data[0] == Eip1559TxType { + // EIP-1559 + return parseEip1559Tx(data) + } + + return nil, fmt.Errorf("unsupported transaction type") +} + +func padLeadingZeros(data []byte, length int) []byte { + if len(data) >= length { + return data + } + zeros := make([]byte, length-len(data)) + return append(zeros, data...) +} + +func removeLeadingZeros(data []byte) []byte { + firstNonZeroIndex := len(data) + for i, b := range data { + if b > 0 { + firstNonZeroIndex = i + break + } + } + return data[firstNonZeroIndex:] +} + +func formatInt(val int) ([]byte, error) { + buf := new(bytes.Buffer) + err := binary.Write(buf, binary.BigEndian, int64(val)) + if err != nil { + return nil, err + } + return removeLeadingZeros(buf.Bytes()), nil +} + +func formatEthAddr(addr *EthAddress) []byte { + if addr == nil { + return nil + } + return addr[:] +} + +func formatBigInt(val big.Int) ([]byte, error) { + b, err := val.Bytes() + if err != nil { + return nil, err + } + return removeLeadingZeros(b), nil +} + +func parseInt(v interface{}) (int, error) { + data, ok := v.([]byte) + if !ok { + return 0, fmt.Errorf("cannot parse interface to int: input is not a byte array") + } + if len(data) == 0 { + return 0, nil + } + if len(data) > 8 { + return 0, fmt.Errorf("cannot parse interface to int: length is more than 8 bytes") + } + var value int64 + r := bytes.NewReader(append(make([]byte, 8-len(data)), data...)) + if err := binary.Read(r, binary.BigEndian, &value); err != nil { + return 0, fmt.Errorf("cannot parse interface to EthUint64: %w", err) + } + return int(value), nil +} + +func parseBigInt(v interface{}) (big.Int, error) { + data, ok := v.([]byte) + if !ok { + return big.Zero(), fmt.Errorf("cannot parse interface to big.Int: input is not a byte array") + } + if len(data) == 0 { + return big.Zero(), nil + } + var b mathbig.Int + b.SetBytes(data) + return big.NewFromGo(&b), nil +} + +func parseBytes(v interface{}) ([]byte, error) { + val, ok := v.([]byte) + if !ok { + return nil, fmt.Errorf("cannot parse interface into bytes: input is not a byte array") + } + return val, nil +} + +func parseEthAddr(v interface{}) (*EthAddress, error) { + b, err := parseBytes(v) + if err != nil { + return nil, err + } + if len(b) == 0 { + return nil, nil + } + addr, err := CastEthAddress(b) + if err != nil { + return nil, err + } + return &addr, nil +} diff --git a/chain/types/ethtypes/eth_transactions_test.go b/chain/types/ethtypes/eth_transactions_test.go new file mode 100644 index 000000000..68abc55dd --- /dev/null +++ b/chain/types/ethtypes/eth_transactions_test.go @@ -0,0 +1,251 @@ +package ethtypes + +import ( + "bytes" + "encoding/hex" + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + "golang.org/x/crypto/sha3" + + "github.com/filecoin-project/go-address" + gocrypto "github.com/filecoin-project/go-crypto" + actorstypes "github.com/filecoin-project/go-state-types/actors" + builtintypes "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/builtin/v10/evm" + init10 "github.com/filecoin-project/go-state-types/builtin/v10/init" + crypto1 "github.com/filecoin-project/go-state-types/crypto" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/lib/sigs" + _ "github.com/filecoin-project/lotus/lib/sigs/delegated" +) + +type TxTestcase struct { + TxJSON string + NosigTx string + Input EthBytes + Output EthTxArgs +} + +func TestTxArgs(t *testing.T) { + testcases, err := prepareTxTestcases() + require.Nil(t, err) + require.NotEmpty(t, testcases) + + for i, tc := range testcases { + comment := fmt.Sprintf("case %d: \n%s\n%s", i, tc.TxJSON, hex.EncodeToString(tc.Input)) + + // parse txargs + txArgs, err := ParseEthTxArgs(tc.Input) + require.NoError(t, err, comment) + + msgRecovered, err := txArgs.ToRlpUnsignedMsg() + require.NoError(t, err, comment) + require.Equal(t, tc.NosigTx, "0x"+hex.EncodeToString(msgRecovered), comment) + + // verify signatures + from, err := txArgs.Sender() + require.NoError(t, err, comment) + + smsg, err := txArgs.ToSignedMessage() + require.NoError(t, err, comment) + + err = sigs.Verify(&smsg.Signature, from, msgRecovered) + require.NoError(t, err, comment) + + // verify data + require.Equal(t, tc.Output.ChainID, txArgs.ChainID, comment) + require.Equal(t, tc.Output.Nonce, txArgs.Nonce, comment) + require.Equal(t, tc.Output.To, txArgs.To, comment) + } +} + +func TestSignatures(t *testing.T) { + testcases := []struct { + RawTx string + ExpectedR string + ExpectedS string + ExpectedV string + ExpectErr bool + }{ + { + "0x02f8598401df5e76028301d69083086a5e835532dd808080c080a0457e33227ac7ceee2ef121755e26b872b6fb04221993f9939349bb7b0a3e1595a02d8ef379e1d2a9e30fa61c92623cc9ed72d80cf6a48cfea341cb916bcc0a81bc", + `"0x457e33227ac7ceee2ef121755e26b872b6fb04221993f9939349bb7b0a3e1595"`, + `"0x2d8ef379e1d2a9e30fa61c92623cc9ed72d80cf6a48cfea341cb916bcc0a81bc"`, + `"0x0"`, + false, + }, + { + "0x02f8598401df5e76038301d69083086a5e835532dd808080c001a012a232866dcb0671eb0ddc01fb9c01d6ef384ec892bb29691ed0d2d293052ddfa052a6ae38c6139930db21a00eee2a4caced9a6500991b823d64ec664d003bc4b1", + `"0x12a232866dcb0671eb0ddc01fb9c01d6ef384ec892bb29691ed0d2d293052ddf"`, + `"0x52a6ae38c6139930db21a00eee2a4caced9a6500991b823d64ec664d003bc4b1"`, + `"0x1"`, + false, + }, + { + "0x00", + `""`, + `""`, + `""`, + true, + }, + } + + for _, tc := range testcases { + tx, err := ParseEthTxArgs(mustDecodeHex(tc.RawTx)) + if tc.ExpectErr { + require.Error(t, err) + continue + } + require.Nil(t, err) + + sig, err := tx.Signature() + require.Nil(t, err) + + r, s, v, err := RecoverSignature(*sig) + require.Nil(t, err) + + marshaledR, err := r.MarshalJSON() + require.Nil(t, err) + + marshaledS, err := s.MarshalJSON() + require.Nil(t, err) + + marshaledV, err := v.MarshalJSON() + require.Nil(t, err) + + require.Equal(t, tc.ExpectedR, string(marshaledR)) + require.Equal(t, tc.ExpectedS, string(marshaledS)) + require.Equal(t, tc.ExpectedV, string(marshaledV)) + } +} + +func TestTransformParams(t *testing.T) { + constructorParams, err := actors.SerializeParams(&evm.ConstructorParams{ + Initcode: mustDecodeHex("0x1122334455"), + }) + require.Nil(t, err) + + evmActorCid, ok := actors.GetActorCodeID(actorstypes.Version10, "reward") + require.True(t, ok) + + params, err := actors.SerializeParams(&init10.ExecParams{ + CodeCID: evmActorCid, + ConstructorParams: constructorParams, + }) + require.Nil(t, err) + + var exec init10.ExecParams + reader := bytes.NewReader(params) + err1 := exec.UnmarshalCBOR(reader) + require.Nil(t, err1) + + var evmParams evm.ConstructorParams + reader1 := bytes.NewReader(exec.ConstructorParams) + err1 = evmParams.UnmarshalCBOR(reader1) + require.Nil(t, err1) + + require.Equal(t, mustDecodeHex("0x1122334455"), evmParams.Initcode) +} + +func TestEcRecover(t *testing.T) { + rHex := "0x479ff7fa64cf8bf641eb81635d1e8a698530d2f219951d234539e6d074819529" + sHex := "0x4b6146d27be50cdbb2853ba9a42f207af8d730272f1ebe9c9a78aeef1d6aa924" + fromHex := "0x3947D223fc5415f43ea099866AB62B1d4D33814D" + v := byte(0) + + msgHex := "0x02f1030185012a05f2008504a817c800825208942b87d1cb599bc2a606db9a0169fcec96af04ad3a880de0b6b3a764000080c0" + pubKeyHex := "0x048362749392a0e192eff600d21155236c5a0648d300a8e0e44d8617712c7c96384c75825dc5c7595df2a5005fd8a0f7c809119fb9ab36403ed712244fc329348e" + + msg := mustDecodeHex(msgHex) + pubKey := mustDecodeHex(pubKeyHex) + r := mustDecodeHex(rHex) + s := mustDecodeHex(sHex) + from := mustDecodeHex(fromHex) + + sig := append(r, s...) + sig = append(sig, v) + require.Equal(t, 65, len(sig)) + + sha := sha3.NewLegacyKeccak256() + sha.Write(msg) + h := sha.Sum(nil) + + pubk, err := gocrypto.EcRecover(h, sig) + require.Nil(t, err) + require.Equal(t, pubKey, pubk) + + sha.Reset() + sha.Write(pubk[1:]) + h = sha.Sum(nil) + h = h[len(h)-20:] + + require.Equal(t, from, h) +} + +func TestDelegatedSigner(t *testing.T) { + rHex := "0xcf1fa52fae9154ba21d67aeca9b42adfe186eb9e426c441051a8473efd190848" + sHex := "0x0e6c8c79ffaf35fb8f136c8cf6c5656f1f3befad21f2644321aa6dba58d68737" + v := byte(0) + + msgHex := "0x02f08401df5e76038502540be400843b9aca008398968094ff000000000000000000000000000000000003f2832dc6c080c0" + pubKeyHex := "0x04cfecc0520d906cbfea387759246e89d85e2998843e56ad1c41de247ce10b3e4c453aa73c8de13c178d94461b6fa3f8b6f74406ce43d2fbab6992d0b283394242" + + msg := mustDecodeHex(msgHex) + pubk := mustDecodeHex(pubKeyHex) + r := mustDecodeHex(rHex) + s := mustDecodeHex(sHex) + + addrHash, err := EthAddressFromPubKey(pubk) + require.NoError(t, err) + + from, err := address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, addrHash) + require.NoError(t, err) + + sig := append(r, s...) + sig = append(sig, v) + require.Equal(t, 65, len(sig)) + + signature := &crypto1.Signature{ + Type: crypto1.SigTypeDelegated, + Data: sig, + } + + err = sigs.Verify(signature, from, msg) + require.NoError(t, err) +} + +func prepareTxTestcases() ([]TxTestcase, error) { + tcstr := `[{"input":"0x02f86282013a8080808094ff000000000000000000000000000000000003ec8080c080a0f411a73e33523b40c1a916e79e67746bd01a4a4fb4ecfa87b441375a215ddfb4a0551692c1553574fab4c227ca70cb1c121dc3a2ef82179a9c984bd7acc0880a38","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02df82013a8080808094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86382013a81c880808094ff000000000000000000000000000000000003ec8080c001a0ed75a56e365c88479bf3f60251a2dd47ae181f1a3d95724581a3f648487b4396a046628bb9734edf4b4c455f2bbd351e43c466f315272cd1927f2c55d9b52e058b","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e082013a81c880808094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86282013a8080808094ff000000000000000000000000000000000003ec8080c080a0f411a73e33523b40c1a916e79e67746bd01a4a4fb4ecfa87b441375a215ddfb4a0551692c1553574fab4c227ca70cb1c121dc3a2ef82179a9c984bd7acc0880a38","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02df82013a8080808094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86382013a81c880808094ff000000000000000000000000000000000003ec8080c001a0ed75a56e365c88479bf3f60251a2dd47ae181f1a3d95724581a3f648487b4396a046628bb9734edf4b4c455f2bbd351e43c466f315272cd1927f2c55d9b52e058b","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e082013a81c880808094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f88682013a8080808094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a0706d871013403cf8b965dfa7f2be5a4d185d746da45b21d5a67c667c26d255d6a02e68a14f386aa325ce8e82d30405107d53103d038cf20e40af961ef3a3963608","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84382013a8080808094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88782013a81c880808094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a0df137d0a6733354b2f2419a4ea5fe77d333deca28b2fe091d76190b51c2bae73a0232cbf9c29b8840cbf104ff77360fbf3ca4acda29b5e230636e19ac253ad92de","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84482013a81c880808094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86482013a808082ea608094ff000000000000000000000000000000000003ec8080c001a03a2880cc65e88d5320067f502a0ffda72111d01f0ebeeea9fbeb812e457aa0f9a020c08483b104dbfbbbffffedc3acdbe8245ca6daf97c0dbab843d747e587d625","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a808082ea608094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86582013a81c88082ea608094ff000000000000000000000000000000000003ec8080c001a03427daf1639de6bf1b948abeab765b0a6a9170cc6a16d263c71c859f78916b03a01bbbb824b9953b5eb9f3098b4358a7ebb78f3358866eed997de66350ae4c9475","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c88082ea608094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86482013a808082ea608094ff000000000000000000000000000000000003ec8080c001a03a2880cc65e88d5320067f502a0ffda72111d01f0ebeeea9fbeb812e457aa0f9a020c08483b104dbfbbbffffedc3acdbe8245ca6daf97c0dbab843d747e587d625","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a808082ea608094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86582013a81c88082ea608094ff000000000000000000000000000000000003ec8080c001a03427daf1639de6bf1b948abeab765b0a6a9170cc6a16d263c71c859f78916b03a01bbbb824b9953b5eb9f3098b4358a7ebb78f3358866eed997de66350ae4c9475","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c88082ea608094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f88882013a808082ea608094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0b9ebc36653a4800816f71ceacf93a1ee601a136916a3476ea9073a9a55ff026aa0647665249b12e8d1d1773b91844588ed70f65c91bc088ccb259ec0f0a24330d5","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84582013a808082ea608094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88982013a81c88082ea608094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0122dd8468dbd34e111e1a5ea1997199be633aa3bc9c1a7ee27dc3a8eda39c29da07cb99cd28ac67f55e507a8b8ef5b931c56cacf79273a4a2969a004a4b4a2864a","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84682013a81c88082ea608094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86482013a8082ea60808094ff000000000000000000000000000000000003ec8080c080a0c1d020df63cb6db76e3a27a60ba0500a3cdd30f9f47b08733009dc8d610ea29ba05cbafb4c223417526ded0b02b8eb66a73535386d0e62da0e20f3641b532aa406","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a8082ea60808094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86582013a81c882ea60808094ff000000000000000000000000000000000003ec8080c080a090e30d32c6cd3f1ba2109b6a9f1c9fffc50b96a934192edf98adc086299e410ba057db0c136436de2e907942bdaad8e0113cf576f250b336ab652ef094c260dae6","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c882ea60808094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86482013a8082ea60808094ff000000000000000000000000000000000003ec8080c080a0c1d020df63cb6db76e3a27a60ba0500a3cdd30f9f47b08733009dc8d610ea29ba05cbafb4c223417526ded0b02b8eb66a73535386d0e62da0e20f3641b532aa406","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a8082ea60808094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86582013a81c882ea60808094ff000000000000000000000000000000000003ec8080c080a090e30d32c6cd3f1ba2109b6a9f1c9fffc50b96a934192edf98adc086299e410ba057db0c136436de2e907942bdaad8e0113cf576f250b336ab652ef094c260dae6","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c882ea60808094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f88882013a8082ea60808094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a016e3f30a612fc802bb64b765325ecf78f2769b879a9acf62f07669f9723335d6a0781bb3444a73819f28233f1eebf8c3a4de288842fd73c2e05a7a7b0c288d5b25","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84582013a8082ea60808094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88982013a81c882ea60808094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a0b652a447bdcdd1906ed86406ee543ee06023e4f762784c1d3aaf4c3bd85c6a17a0368ae9995e15258f14b74f937e97140a659d052d341674be0c24452257b56b30","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84682013a81c882ea60808094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86682013a8082ea6082ea608094ff000000000000000000000000000000000003ec8080c001a0b1411f337b69609a256c0e76c57ccf4af87e977c98fd2a889f29281bf623cab4a049bec0fb4773aed870bae9c1cdf1ee398c498f0b436dcd19cae588b4ecd8bdf2","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a8082ea6082ea608094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86782013a81c882ea6082ea608094ff000000000000000000000000000000000003ec8080c080a00b845fec9c96bf593c3501753764e14867d3f5d4bd02051e49329b6810d6513ea070d046e5b38c18c542594b328f02345a8f34ab05fd00db33974f914f7ae31c63","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c882ea6082ea608094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86682013a8082ea6082ea608094ff000000000000000000000000000000000003ec8080c001a0b1411f337b69609a256c0e76c57ccf4af87e977c98fd2a889f29281bf623cab4a049bec0fb4773aed870bae9c1cdf1ee398c498f0b436dcd19cae588b4ecd8bdf2","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a8082ea6082ea608094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86782013a81c882ea6082ea608094ff000000000000000000000000000000000003ec8080c080a00b845fec9c96bf593c3501753764e14867d3f5d4bd02051e49329b6810d6513ea070d046e5b38c18c542594b328f02345a8f34ab05fd00db33974f914f7ae31c63","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c882ea6082ea608094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f88a82013a8082ea6082ea608094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a02d8215d8408d2f4b83a2e68f4aad6fe5dee97d7ef6a43b02ec413ead2215ac80a0641a43cebd6905e3e324c0dd06585d5ffc9b971b519045999c48e31db7aa7f9d","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84782013a8082ea6082ea608094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88a82013a81c882ea6082ea608094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0da68784e191ce0806527d389f84b5d15bed3908e1c2cc0d8f0cea7a29eb0dba39f231a0b438b7d0f0f57292c68dc174d4ee6df7add933ab4e0b3789f597a7d3b","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84882013a81c882ea6082ea608094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86482013a80808082ea6094ff000000000000000000000000000000000003ec8080c080a04c97162e2d2ab508116a23c522fd816ecd9cb091d4c288afe45c37ee3a8dde34a06ebf67ff15b74d65c276340aaebde8e6ebb8da0d3bbab43deffac8eb1e6a0630","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a80808082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86582013a81c8808082ea6094ff000000000000000000000000000000000003ec8080c080a0d503d409e667c2876ab9e420854cecce4c0092985855234be07f270bfcf3ed4aa07a40deecc8a4448d4dc0e2014b4b23ac5721409c62bffa05aee6938d8447f72d","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c8808082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86482013a80808082ea6094ff000000000000000000000000000000000003ec8080c080a04c97162e2d2ab508116a23c522fd816ecd9cb091d4c288afe45c37ee3a8dde34a06ebf67ff15b74d65c276340aaebde8e6ebb8da0d3bbab43deffac8eb1e6a0630","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a80808082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86582013a81c8808082ea6094ff000000000000000000000000000000000003ec8080c080a0d503d409e667c2876ab9e420854cecce4c0092985855234be07f270bfcf3ed4aa07a40deecc8a4448d4dc0e2014b4b23ac5721409c62bffa05aee6938d8447f72d","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c8808082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f88882013a80808082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a059aecc1d365ee0dc56a577d162f04c0912a5c5b62f889cff1acc706ac17a4489a017209b3ec43a10a40c5863a2b7a1ee823380ad42697a5f7d5f537c230583a4c7","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84582013a80808082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88982013a81c8808082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a0dc1eb40f93e311f3f9a94d8a695db2bbb38973ce097121875885e4bc54f18152a0075da0bd405bb4f5c69034daaf8f40052b941fae5b9f3b8df218d80fb4d7ea99","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84682013a81c8808082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86682013a808082ea6082ea6094ff000000000000000000000000000000000003ec8080c080a03d392fd5e83c64554907a55204572aaeec6ffab25f2c73655c6a22344fa02a14a03b9ae94b7dc21108db6dda65125ecaff844f8f43f483bed35f32f6d5d530fe9f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a808082ea6082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86782013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec8080c001a0405e8a430ef6ad4c3403150776af08c255b6f6fbe278d194f88517733c816caca0364203b5bca7953dd863d4cf90c0a77b499ef4a3d5831c4fdf33926c31709c4f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86682013a808082ea6082ea6094ff000000000000000000000000000000000003ec8080c080a03d392fd5e83c64554907a55204572aaeec6ffab25f2c73655c6a22344fa02a14a03b9ae94b7dc21108db6dda65125ecaff844f8f43f483bed35f32f6d5d530fe9f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a808082ea6082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86782013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec8080c001a0405e8a430ef6ad4c3403150776af08c255b6f6fbe278d194f88517733c816caca0364203b5bca7953dd863d4cf90c0a77b499ef4a3d5831c4fdf33926c31709c4f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f88a82013a808082ea6082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a083cf6701aee00872946b6550c059f028f72e3052acb8cc9c25b830ace860e046a03fd969d73e995d43896659f94d3956a17da18451050349e7db6f7881f8c057d3","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84782013a808082ea6082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88b82013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0c5a545f2d94e719068d9a43b01879bcb46b56e236dd378dd26ef3b8e4ec8314aa04024b9936960b9b156405e4f3e0b6562518df8778324a927381e380b23f47fb8","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84882013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86682013a8082ea608082ea6094ff000000000000000000000000000000000003ec8080c080a0aa406ec7f4901a1777e44b975ff41603b9d46257efdc1ca904a3e7890f2b020ea03bda5c785182cfa2d9f9b7a54f194cd08b9d0f913069a4514ff21e8fa0ef3850","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a8082ea608082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86782013a81c882ea608082ea6094ff000000000000000000000000000000000003ec8080c080a089fc465c24b4bad898cf900f585eddab6d40189e8d19746da76597f86fbadf51a005732ffa2ebac36646afab9105540b543f74a5c91b441834a2b1930815c2ccc8","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c882ea608082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86682013a8082ea608082ea6094ff000000000000000000000000000000000003ec8080c080a0aa406ec7f4901a1777e44b975ff41603b9d46257efdc1ca904a3e7890f2b020ea03bda5c785182cfa2d9f9b7a54f194cd08b9d0f913069a4514ff21e8fa0ef3850","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a8082ea608082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86782013a81c882ea608082ea6094ff000000000000000000000000000000000003ec8080c080a089fc465c24b4bad898cf900f585eddab6d40189e8d19746da76597f86fbadf51a005732ffa2ebac36646afab9105540b543f74a5c91b441834a2b1930815c2ccc8","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c882ea608082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f88a82013a8082ea608082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a09d9a8ee802486b826348a76346987b3e7331d70ef0c0257ff976ceebef1141a2a07d97d14ed877c16bd932f08a67c374e773ee3337d512ff8241c8d78566a04d46","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84782013a8082ea608082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88b82013a81c882ea608082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a024ad1ec1578f51beb2b574507bda7691a486cdbc9c22add01ad4c1f686beb567a048445e0fe8945b8052e5e87139690c0615a11c52503b226cf23610c999eada40","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84882013a81c882ea608082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86882013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec8080c080a06b382fcbe48de85615ff6e2dcc0c84021beb4abc527878accd36c9c77af84ba8a06a07d34a6896b270538525cb14b0856ceb442714fa85e4c9ee36dedf638935f9","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e582013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86982013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec8080c080a0ba2586cfb3323fd0f9d7bb38bf9948758a52f156bda66f7100b789760894ad89a01e4bd2ff4eff2c391915141250313ab845401d5e2f71c23691d20a0b3c68cbd9","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e682013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86882013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec8080c080a06b382fcbe48de85615ff6e2dcc0c84021beb4abc527878accd36c9c77af84ba8a06a07d34a6896b270538525cb14b0856ceb442714fa85e4c9ee36dedf638935f9","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e582013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f86982013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec8080c080a0ba2586cfb3323fd0f9d7bb38bf9948758a52f156bda66f7100b789760894ad89a01e4bd2ff4eff2c391915141250313ab845401d5e2f71c23691d20a0b3c68cbd9","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e682013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec8080c0"},{"input":"0x02f88c82013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a0f36ff02ab3e90d2de77cdb24423dc39ca5c959429db62cb5c9ed4f0c9e04703aa0476bf841b0602af44039801d4e68648971f63fc2152002b127be6d914d4fc5ca","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84982013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88d82013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a08267ae8838a8a5d9c2a761c182b5759184b7672b761278d499c1514fb6e8a495a023aa268f67da7728767e114fdec4d141bf649e0ad931117b5b325834dbf72803","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"0\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84a82013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec80a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86282013a8080808094ff000000000000000000000000000000000003ec6480c080a011ec4af7fc663080460b70ae8829f47e9cfa1814c616750d359459cbbba55563a0446e4ec9ea504d13dcbef44238e442caad366dbae1ae9408d39c6d902a5577b0","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02df82013a8080808094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86382013a81c880808094ff000000000000000000000000000000000003ec6480c001a0b80bc30bef46b3f824d1460685db875ff070f7798c3148c1fc49c01d6acc550ca0437efe7721563800e6a56ac54877a72c7860cd5e17ef4675afe989822ae87759","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e082013a81c880808094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86282013a8080808094ff000000000000000000000000000000000003ec6480c080a011ec4af7fc663080460b70ae8829f47e9cfa1814c616750d359459cbbba55563a0446e4ec9ea504d13dcbef44238e442caad366dbae1ae9408d39c6d902a5577b0","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02df82013a8080808094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86382013a81c880808094ff000000000000000000000000000000000003ec6480c001a0b80bc30bef46b3f824d1460685db875ff070f7798c3148c1fc49c01d6acc550ca0437efe7721563800e6a56ac54877a72c7860cd5e17ef4675afe989822ae87759","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e082013a81c880808094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f88682013a8080808094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a06ab9d5988105d28dd090e509c8caabaa7773fc08ec5ef3dfeae532e01938ff69a078bca296df26dd2497a49110e138a49a67a6e232a35524b041d04a10fc583651","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84382013a8080808094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88782013a81c880808094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a031d51b866a02a9966250d312ed6cb4e083f9131ad8f6bb5814074375093d7536a03f8f819c4011dd54348930b6f98f365de8060b487ada38a62a5617aab6cc6e09","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84482013a81c880808094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86482013a808082ea608094ff000000000000000000000000000000000003ec6480c001a05bda5ad44c8f9a7516226488cf2d4f53188b40352f35ea7cece8076acda26dbba015373b3b78c88b74c7cca32fd02696a248bb9bea22a09c7a4a17b9e3b629b896","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a808082ea608094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86582013a81c88082ea608094ff000000000000000000000000000000000003ec6480c080a00d92624cc3335c903077e318204929b4a8c9cd96d94690b0191f8a3bb24e937aa02f1d0315ececf46900154791a732eb8fee9efd0dc998a4e6b892d07ad657a815","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c88082ea608094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86482013a808082ea608094ff000000000000000000000000000000000003ec6480c001a05bda5ad44c8f9a7516226488cf2d4f53188b40352f35ea7cece8076acda26dbba015373b3b78c88b74c7cca32fd02696a248bb9bea22a09c7a4a17b9e3b629b896","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a808082ea608094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86582013a81c88082ea608094ff000000000000000000000000000000000003ec6480c080a00d92624cc3335c903077e318204929b4a8c9cd96d94690b0191f8a3bb24e937aa02f1d0315ececf46900154791a732eb8fee9efd0dc998a4e6b892d07ad657a815","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c88082ea608094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f88882013a808082ea608094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0def168136c0532ec148a9e200e3cc1b22f90c7bbc5d9ef25ac0c5d342e8f3784a022f94642dfc81ba321b3e09879888332fa7c25b623bead7686e3e493c0911b55","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84582013a808082ea608094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88982013a81c88082ea608094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0626f43b80260f84cde2c67538c5cfbd328ce85b0f934e8568769e51709b100a7a0283fff5dbfde72b72e2b74c464b1add985d72750be3f4e16ae8ffb4747a40ff2","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84682013a81c88082ea608094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86482013a8082ea60808094ff000000000000000000000000000000000003ec6480c080a051b109080002dab4aae47139eb92ddea8951ef5ac6dfc3d7fa07621047dbc680a0334aa47a2888a6cc52b8cf3c3635192b66c692416e954822c1c93c3896ff1ead","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a8082ea60808094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86582013a81c882ea60808094ff000000000000000000000000000000000003ec6480c080a009e179e3bad2da6fb5e205e52fd8d1c462007162aabde5a4d6b052dd4fc4f23ca063922c31438835adf2e4424e2e7d5d2702ec65de2e24a72b491ff0004a53865d","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c882ea60808094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86482013a8082ea60808094ff000000000000000000000000000000000003ec6480c080a051b109080002dab4aae47139eb92ddea8951ef5ac6dfc3d7fa07621047dbc680a0334aa47a2888a6cc52b8cf3c3635192b66c692416e954822c1c93c3896ff1ead","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a8082ea60808094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86582013a81c882ea60808094ff000000000000000000000000000000000003ec6480c080a009e179e3bad2da6fb5e205e52fd8d1c462007162aabde5a4d6b052dd4fc4f23ca063922c31438835adf2e4424e2e7d5d2702ec65de2e24a72b491ff0004a53865d","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c882ea60808094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f88882013a8082ea60808094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0d3bfebc6597304c6a06491f68d2ac149fc233d28e81af48dd5b1f83e6ff951d2a06668da06d86aba341971dabb58016ca7764cd4b4c1634e3f829dcc8ef8bca4f6","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84582013a8082ea60808094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88982013a81c882ea60808094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a0d45b9fd9a2a3fdf79805cf73b70348037cc69927209a5e3728fe62cbe9543f03a02f5f8477666487ee5148a65ce59f400beac7c208369162b2d555411314d358fb","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84682013a81c882ea60808094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86682013a8082ea6082ea608094ff000000000000000000000000000000000003ec6480c001a02a6a910f7b5f83fda937006021b9c074f4544d5bb37b9b5a1b7045095f461836a038572b25418528bce7e6a3a480cf9fc90a33d9c63b392c2dbc8faf72a1e4ab8f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a8082ea6082ea608094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86782013a81c882ea6082ea608094ff000000000000000000000000000000000003ec6480c080a07a6dd661b5da27c809cce22aa186c158fe3b07a484a9395fd9a7a31a2b90636fa02b86f82b661264e27c3fda085b59740d3059335bff91693291afcf93c7ca627c","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c882ea6082ea608094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86682013a8082ea6082ea608094ff000000000000000000000000000000000003ec6480c001a02a6a910f7b5f83fda937006021b9c074f4544d5bb37b9b5a1b7045095f461836a038572b25418528bce7e6a3a480cf9fc90a33d9c63b392c2dbc8faf72a1e4ab8f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a8082ea6082ea608094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86782013a81c882ea6082ea608094ff000000000000000000000000000000000003ec6480c080a07a6dd661b5da27c809cce22aa186c158fe3b07a484a9395fd9a7a31a2b90636fa02b86f82b661264e27c3fda085b59740d3059335bff91693291afcf93c7ca627c","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c882ea6082ea608094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f88a82013a8082ea6082ea608094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a08c13c10490bc20cb1e55dc54ececb37a6c9cc8d013dbe513feacbb0416f09feba045c4e038759a0901820091e043db326b1bf9a8a1cd046ac72629969497c6a86f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84782013a8082ea6082ea608094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88b82013a81c882ea6082ea608094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0b904edf8eb9b6beb9cde9e1fae538e12f8d40e9124ace0cba2eee8cbbe77aa10a0788a0bd9a6fb98e7230f5db89be2f5067d1a227ba277b9cb155fb5859c57aae6","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84882013a81c882ea6082ea608094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86482013a80808082ea6094ff000000000000000000000000000000000003ec6480c080a08d10a7a81c561391fe88bcb2c1dfbf4f7140fb7884fec0558606e76ffc4eaa91a049fa2a95e0f07a4376df9c6f2e1563ad443ce8369d44c6e1ce8ee521805b3623","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a80808082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86582013a81c8808082ea6094ff000000000000000000000000000000000003ec6480c001a00de6dc2841a25e5ea2dc1e054d69638ec519a9953666930060797cd110cde122a07fd1dcb6319eca7c681cef006efb3f7dcd74ff98a79ce05917d5d1fa7a175b6f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c8808082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86482013a80808082ea6094ff000000000000000000000000000000000003ec6480c080a08d10a7a81c561391fe88bcb2c1dfbf4f7140fb7884fec0558606e76ffc4eaa91a049fa2a95e0f07a4376df9c6f2e1563ad443ce8369d44c6e1ce8ee521805b3623","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e182013a80808082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86582013a81c8808082ea6094ff000000000000000000000000000000000003ec6480c001a00de6dc2841a25e5ea2dc1e054d69638ec519a9953666930060797cd110cde122a07fd1dcb6319eca7c681cef006efb3f7dcd74ff98a79ce05917d5d1fa7a175b6f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e282013a81c8808082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f88882013a80808082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a04c43dab94dd746973a1f7f051cc520cc01e93e9c6c55147cef34e5fdc0b182a2a06d148cc6ec017f9aeb6442a17d72e388ffc835950e19abd0c06057520f893542","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84582013a80808082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88982013a81c8808082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a025b50c1db31c0ae7aaa73374659201b54b71488efecbb6985dc50015abde7e36a04dd8cf68920de7232ab8d1fb28ab94ac05466c1f9d9a3a658f2054fce7868e2c","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84682013a81c8808082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86682013a808082ea6082ea6094ff000000000000000000000000000000000003ec6480c080a0415ad0a93225eaec617206ec835e362d5e75fd0e1903747c1806270ec2684c7da0487ec1479cdb2affa891ff56413818ec169651c906ab932594b6e5bbb79d4998","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a808082ea6082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86782013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec6480c001a0a46ac278c400ef099ad23ac4ccb066a37db8bb5c4d65e0a347152a499ae9eb92a07505f9c67f0897cbe6f848c9a2164c3c234dab2fea7a4dd6f4436be34080e2ff","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86682013a808082ea6082ea6094ff000000000000000000000000000000000003ec6480c080a0415ad0a93225eaec617206ec835e362d5e75fd0e1903747c1806270ec2684c7da0487ec1479cdb2affa891ff56413818ec169651c906ab932594b6e5bbb79d4998","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a808082ea6082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86782013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec6480c001a0a46ac278c400ef099ad23ac4ccb066a37db8bb5c4d65e0a347152a499ae9eb92a07505f9c67f0897cbe6f848c9a2164c3c234dab2fea7a4dd6f4436be34080e2ff","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f88a82013a808082ea6082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a0a43aba5078d2da3ecc1ec0c67191f8cf58f29f5b4db7f8d4765ea691ddbd4195a0110e568c803db5ea587b406f452cf49ddf6b6f24d41207973d6c785ffaed1454","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84782013a808082ea6082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88b82013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a00caeadf2fcba95f0deab5ee4899348ecac4a18eeb09317d6f8156b891626d219a0549c5376aba320889c2f7b61fd4a51aec5f9a1d9ed9b26cef0a3bee52fac4989","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84882013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86682013a8082ea608082ea6094ff000000000000000000000000000000000003ec6480c001a07b5568d8a3ec3c7e126f570955db304e31d3f3d7b0c4fd103b6d064a2f6f5e23a030a1b17f299352ae193b8dbce2adda473ccb04e00670f416877762971697606f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a8082ea608082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86782013a81c882ea608082ea6094ff000000000000000000000000000000000003ec6480c080a07bb69d01062f9d6ecb011ad344bbe08d4eca2f6b192dde45015def4c2e6096e0a03a3df52d753e3293d2fd544f72e62ceae00ea6dcab7229685d7b1873d873d203","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c882ea608082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86682013a8082ea608082ea6094ff000000000000000000000000000000000003ec6480c001a07b5568d8a3ec3c7e126f570955db304e31d3f3d7b0c4fd103b6d064a2f6f5e23a030a1b17f299352ae193b8dbce2adda473ccb04e00670f416877762971697606f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e382013a8082ea608082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86782013a81c882ea608082ea6094ff000000000000000000000000000000000003ec6480c080a07bb69d01062f9d6ecb011ad344bbe08d4eca2f6b192dde45015def4c2e6096e0a03a3df52d753e3293d2fd544f72e62ceae00ea6dcab7229685d7b1873d873d203","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e482013a81c882ea608082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f88a82013a8082ea608082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0621255015626b35acf19629ce318999336441537920f9f3ff1bfd44e54d8abd3a03b3426f8fa963debdfa6b44561772bdebc9524c7f63abd0d947b678f5e966502","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84782013a8082ea608082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88b82013a81c882ea608082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0b73c3ba53fc5a0f7fab636cc2b826c3873cda5d0be9dd2100fdceae7899f3310a0491905f676063924cf847fdf2e488be4606ce351748e5c88d49ed50c8d595c94","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84882013a81c882ea608082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86882013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec6480c001a0e60702e3f5c5f56e3d1bc2907015ec889d0557ea14e81f137056471fef0fdb9da066e601e6e55c2e37e2042401b352e81841d492d0fe4f05bfe81bba29c9e6ce1f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e582013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86982013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec6480c001a085a947fb201d0b50272e7bb7a056adc9ee6f5904634ed91dbde0d650641b7de3a03635c731769302e955d41f794a63262d5d4d37d117c9db89a6b6bce927b71f42","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e682013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86882013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec6480c001a0e60702e3f5c5f56e3d1bc2907015ec889d0557ea14e81f137056471fef0fdb9da066e601e6e55c2e37e2042401b352e81841d492d0fe4f05bfe81bba29c9e6ce1f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e582013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f86982013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec6480c001a085a947fb201d0b50272e7bb7a056adc9ee6f5904634ed91dbde0d650641b7de3a03635c731769302e955d41f794a63262d5d4d37d117c9db89a6b6bce927b71f42","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e682013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec6480c0"},{"input":"0x02f88c82013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0d67e28d31489af5129c4832af814a01e0baa5e5ba6245fe2d3304693ceea48e0a03bc06f1c6dd01a14826c67aa35258c0bbf7c516a9bb21e9190eaa8d3768f49bb","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84982013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88d82013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0a5368984aca4bc1e3d7ebc7ae4ead5e09ffd3b4b4712d039c19fdac948e5952ea065953ace0a29210440d6a0f05d6b43f482950b463b3be6b23fc63452c94b9446","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"100\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84a82013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec64a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86a82013a8080808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a086da25ab078729b08cf48da02eb1c1e05fe0f4e5d7b332262b68f4db3dc9b72fa04102c03c7d9f11a6fdb77d6a36d3f07e09b1ceaab0bf4ef1fdc604bcd726f83b","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e782013a8080808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86b82013a81c880808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0cde92f395919b3205b4260867b11597f9ecf363bc1be9bbd8b5400d3381d64b3a01b9555cfa22ee8615c3033235ebad605d0bef616d08876de26719866fcc4d41e","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e882013a81c880808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86a82013a8080808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a086da25ab078729b08cf48da02eb1c1e05fe0f4e5d7b332262b68f4db3dc9b72fa04102c03c7d9f11a6fdb77d6a36d3f07e09b1ceaab0bf4ef1fdc604bcd726f83b","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e782013a8080808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86b82013a81c880808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0cde92f395919b3205b4260867b11597f9ecf363bc1be9bbd8b5400d3381d64b3a01b9555cfa22ee8615c3033235ebad605d0bef616d08876de26719866fcc4d41e","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02e882013a81c880808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f88e82013a8080808094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a03dd64e48a1ae228665b3f180367997ee96bc60ee226615c900e3d86634044328a00f6cdb24633e75fa65f6b93fce9b084c1f30dd03dde97d01f25c6f10f34d5d9d","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84b82013a8080808094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f88f82013a81c880808094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a07475efeb8dd5bf4ba7efb31ab67a9077401ed71f4e8dd13e7058ce5cfeb5a0f2a01046e93a5258bf320bc392173a49b6fef15976be4c1210f2e367af223ad8c026","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84c82013a81c880808094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86c82013a808082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0ca84441c7ba097a7afa5ef9ad7ef70ba58ddfffc06c5d015b5c8553f1632d103a057fee6d92055c9c031a1efa667f3ee554804c4f34a195b6dfc781e1592c20444","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e982013a808082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86d82013a81c88082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a04055dfcd6e0b7264d3474ba13f76659384e5f365ebc6ba271641481b12bf410ca01ef7d04dc33fdf0c3137e31d8c822ad68bbd4f89ada52db9705bb66813d11583","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ea82013a81c88082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86c82013a808082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0ca84441c7ba097a7afa5ef9ad7ef70ba58ddfffc06c5d015b5c8553f1632d103a057fee6d92055c9c031a1efa667f3ee554804c4f34a195b6dfc781e1592c20444","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e982013a808082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86d82013a81c88082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a04055dfcd6e0b7264d3474ba13f76659384e5f365ebc6ba271641481b12bf410ca01ef7d04dc33fdf0c3137e31d8c822ad68bbd4f89ada52db9705bb66813d11583","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ea82013a81c88082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f89082013a808082ea608094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a02080212bb64a798e1e138e4991ab830cf04d37ffeedf6fde7eba0eb7d972b350a02aff43f9e5ca8d6cea6e918391188fa37bdb91b864eadec705f7c69c4a61bc5a","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84d82013a808082ea608094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f89182013a81c88082ea608094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a0e41c052d72950a563b8ed7fb15855beabea43ff5b038bd6a3ccc6416e3498619a0568bbd7cbff31a47e1d0b9712f382c52e74b7b28cbcb8458974d82a8d54ddc57","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84e82013a81c88082ea608094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86c82013a8082ea60808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a057c342304f133ff8832d3d16a43571afe905dc9b10afc24c6e99225cca6d8817a00e2155d1904751ce0d2ba01e6475aeae254c02966773f5bc7650e37252a01a92","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e982013a8082ea60808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86d82013a81c882ea60808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0fc2a550a7798085cae28028abbe4829be29e5f3a40af221086831d0e17ca3c83a01ce21f5934b9ca566958e09e89c99fd9ed2dc4acae209a6fb81fd3a6c9879a99","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ea82013a81c882ea60808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86c82013a8082ea60808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a057c342304f133ff8832d3d16a43571afe905dc9b10afc24c6e99225cca6d8817a00e2155d1904751ce0d2ba01e6475aeae254c02966773f5bc7650e37252a01a92","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e982013a8082ea60808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86d82013a81c882ea60808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0fc2a550a7798085cae28028abbe4829be29e5f3a40af221086831d0e17ca3c83a01ce21f5934b9ca566958e09e89c99fd9ed2dc4acae209a6fb81fd3a6c9879a99","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ea82013a81c882ea60808094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f89082013a8082ea60808094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0fa33b63666310ca1c72fc5d82639c5b8e2a7638910be7bee23ada9f139c6b891a02012cad8e991beea7dcf0b6e9346b0228699698e183e2fadfc5b9b880601af9b","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84d82013a8082ea60808094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f89182013a81c882ea60808094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0bc6ae4e92e7a20d5ff61258653dffda636cee0fd97dd156eac7a1f231f1f2785a0323055e0e0bed496b3fec30be292338d0956ecf8baeeb34458230821589aa7fb","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84e82013a81c882ea60808094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86e82013a8082ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a0bd2889395392859a83a33bfe549c09d172e1f289de29d4bc9d0a3d25ea8aa71ba075fe92140a08d8e680061852438623c9cd10e211955577d1a3b56e49e960e4e7","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02eb82013a8082ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86f82013a81c882ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a05553c929ae32692a9f742371ffcfc8c8d2b77f31a7795460297cb78c29e357e8a043e42ca4ed7eb1b8e3546de2364522735d79a2e2ff5d16f7f96d165c5815c80c","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ec82013a81c882ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86e82013a8082ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a0bd2889395392859a83a33bfe549c09d172e1f289de29d4bc9d0a3d25ea8aa71ba075fe92140a08d8e680061852438623c9cd10e211955577d1a3b56e49e960e4e7","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02eb82013a8082ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86f82013a81c882ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a05553c929ae32692a9f742371ffcfc8c8d2b77f31a7795460297cb78c29e357e8a043e42ca4ed7eb1b8e3546de2364522735d79a2e2ff5d16f7f96d165c5815c80c","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ec82013a81c882ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f89282013a8082ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a055f63a6bef8e23dc437ff4ac9349a59fcde2f72d1879de50b0d3686ff648749da04cf8034df06cf6f15f31bb55979b40eeacbd28fb1d745e608acdc088e22beb66","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84f82013a8082ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f89382013a81c882ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0c4a0253448dad999692c1bf3cfb5de9e95a2e96da4e1f64133ada452a825fe9aa0757b576ceb7a2c494819960ac59e9d3a4e3da384f23c0e88ada758dc265eae94","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":0,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f85082013a81c882ea6082ea608094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86c82013a80808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a02632c4d8a443afb8d39f91d036fd4915ca3ad2f253b8f93211b4b3ee15566519a009bdc00c8eaaf22f3d7d04b53dbc777fd027a780fb4ddaf01002724ddf2879dd","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e982013a80808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86d82013a81c8808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a08bda02c15ca37d35d9ad2e2f7731d24dd039f5c6c6f7eaad739daadac6db33e5a044c01e493e10929e4021c69d9df886b211eb349a865df9f0796846ad1cdf23e8","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ea82013a81c8808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86c82013a80808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a02632c4d8a443afb8d39f91d036fd4915ca3ad2f253b8f93211b4b3ee15566519a009bdc00c8eaaf22f3d7d04b53dbc777fd027a780fb4ddaf01002724ddf2879dd","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02e982013a80808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86d82013a81c8808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a08bda02c15ca37d35d9ad2e2f7731d24dd039f5c6c6f7eaad739daadac6db33e5a044c01e493e10929e4021c69d9df886b211eb349a865df9f0796846ad1cdf23e8","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ea82013a81c8808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f89082013a80808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0ed0db75f41b2b8b89768ce5ad08716aff149dc1d5a2e593140d8964eb2da3229a02e5248cca9b5af340d73271cad4d690f7efa11c9278824aca528eb15d28aec4d","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84d82013a80808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f89182013a81c8808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a07108fbbabc45826dbdc8e4cf831240fb39ead7bd4b8ec5d8de64d04e2885e554a04dae4fb4bdbabb9d8f923d579e75ee980da1b4fac5773ec68f395af240f037f0","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84e82013a81c8808082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86e82013a808082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0130b6723050095faa2e7abc69c2f785e73d333c65fae6cf2835518f970c627d5a00b90bd4f2ded1da0163ab5e81ad76d51aef005d663137347fc550313e1c8b6fc","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02eb82013a808082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86f82013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a0993a50431e82d10d632466d45f8aaffea9a56efa59d529dfd497d3c2a06aabeba0070d3132c6ce1e4ff70b0721d1f4c03ab566b8e2af29d33148033fb3009dc29d","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ec82013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86e82013a808082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0130b6723050095faa2e7abc69c2f785e73d333c65fae6cf2835518f970c627d5a00b90bd4f2ded1da0163ab5e81ad76d51aef005d663137347fc550313e1c8b6fc","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02eb82013a808082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86f82013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a0993a50431e82d10d632466d45f8aaffea9a56efa59d529dfd497d3c2a06aabeba0070d3132c6ce1e4ff70b0721d1f4c03ab566b8e2af29d33148033fb3009dc29d","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ec82013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f89282013a808082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a09c9d3b0d7b58bfe81a6881b9db184e0ade03c1ad11aa8f1566e2f24f50f85525a06c10cf91f4dbc24d0f78ef09a8e2310d349a034cec7e86e807d7a48ea26161e1","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84f82013a808082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f89382013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a0f8423b51e513618c6a4bdd2696479d91c760e11ea24657dd27fa6eb9b7da8c0ea07e9456113fb034718d1b4f4e09ade1ce78251a8c86f298b152850bc5925156cb","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"0\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f85082013a81c88082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f86e82013a8082ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0d09b373d45c1bfc1c5d9b5198e69f974d4df456245e2f7a5edd486f3dd2795a9a011396197a670e7b0c4613b7ebf8aee53382930c7bd25c35dda15acae78ec0e2c","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02eb82013a8082ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86f82013a81c882ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a0131f5af3ece9a0b723d0c812dbcfc6cb458acf5e0846cc506215fc04d6af66d5a078d0bf7a40cc1ddcebbc4e86fb9a04bfc94f3da94b4a74476883b7b1729f8a44","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ec82013a81c882ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86e82013a8082ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0d09b373d45c1bfc1c5d9b5198e69f974d4df456245e2f7a5edd486f3dd2795a9a011396197a670e7b0c4613b7ebf8aee53382930c7bd25c35dda15acae78ec0e2c","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02eb82013a8082ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f86f82013a81c882ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c080a0131f5af3ece9a0b723d0c812dbcfc6cb458acf5e0846cc506215fc04d6af66d5a078d0bf7a40cc1ddcebbc4e86fb9a04bfc94f3da94b4a74476883b7b1729f8a44","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ec82013a81c882ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f89282013a8082ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0c286f4ee350eab70273cf9a952537534446a0f39e9bfea7340eabc04396a0e3da01e1302ae987a69836ec2c9266e6fe623db5fcdc566e37084c0c57630c4de8ee6","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f84f82013a8082ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f89382013a81c882ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c080a09dee3fa88e365133a18035618af718a045e1a957f10f50c632f23923fd337b9ba06bbbd59489849803f8c61138932ac1a8361edb4c80789d030542829c0a2b5b7f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"0\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f85082013a81c882ea608082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f87082013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0c1cb1e2b41e48fecd59d72039147c76993653f061f9ea156b53c377673eef7f1a01822506f755206b60209a12ed3c84446f4fcb4ad602fa7ab7ee4ff2acde19ed6","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02ed82013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f87182013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a09817043ad22797d2f26ca46697db5f586c38336a171dce2d22d659889e9e9eb5a0369a5d6169586d9c831b6e017aa29fd49eac0636a136bfa5bafb95390fa95b8f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":null,\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ee82013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f87082013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a0c1cb1e2b41e48fecd59d72039147c76993653f061f9ea156b53c377673eef7f1a01822506f755206b60209a12ed3c84446f4fcb4ad602fa7ab7ee4ff2acde19ed6","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02ed82013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f87182013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c001a09817043ad22797d2f26ca46697db5f586c38336a171dce2d22d659889e9e9eb5a0369a5d6169586d9c831b6e017aa29fd49eac0636a136bfa5bafb95390fa95b8f","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02ee82013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a764000080c0"},{"input":"0x02f89482013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a039357ad40087d17551ca2b94723f0394185a993671db02172a7de70c24054852a046c84070dfadd244b358690e5b89c75f3988b21b6614e6e3af2f8ca302d6c42a","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":0,\"type\":2,\"chainId\":314}","nosigTx":"0x02f85182013a8082ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"},{"input":"0x02f89582013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c001a0c991c81705a4c53a9255e72beb8243638c68f10c63b082755972bbbe15245d12a014f6852ae34c92882559e6810d4372109930a23b522368fdef2c85ce04e27839","output":"{\"to\":\"0xff000000000000000000000000000000000003EC\",\"value\":\"1000000000000000000\",\"gasLimit\":60000,\"maxFeePerGas\":\"60000\",\"maxPriorityFeePerGas\":\"60000\",\"data\":\"0xf8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064\",\"nonce\":200,\"type\":2,\"chainId\":314}","nosigTx":"0x02f85282013a81c882ea6082ea6082ea6094ff000000000000000000000000000000000003ec880de0b6b3a7640000a4f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064c0"}]` + + testcases := []struct { + Input EthBytes `json:"input"` + Output string `json:"output"` + NosigTx string `json:"nosigTx"` + }{} + + err := json.Unmarshal([]byte(tcstr), &testcases) + if err != nil { + return nil, err + } + + res := []TxTestcase{} + for _, tc := range testcases { + tx := EthTxArgs{} + err := json.Unmarshal([]byte(tc.Output), &tx) + if err != nil { + return nil, err + } + res = append(res, TxTestcase{ + Input: tc.Input, + Output: tx, + TxJSON: tc.Output, + NosigTx: tc.NosigTx, + }) + } + + return res, err +} diff --git a/chain/types/ethtypes/eth_types.go b/chain/types/ethtypes/eth_types.go new file mode 100644 index 000000000..ddda91ea0 --- /dev/null +++ b/chain/types/ethtypes/eth_types.go @@ -0,0 +1,806 @@ +package ethtypes + +import ( + "bytes" + "encoding/binary" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + mathbig "math/big" + "strconv" + "strings" + + "github.com/ipfs/go-cid" + "github.com/multiformats/go-multihash" + "github.com/multiformats/go-varint" + "golang.org/x/crypto/sha3" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/big" + builtintypes "github.com/filecoin-project/go-state-types/builtin" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/lib/must" +) + +var ErrInvalidAddress = errors.New("invalid Filecoin Eth address") + +type EthUint64 uint64 + +func (e EthUint64) MarshalJSON() ([]byte, error) { + return json.Marshal(e.Hex()) +} + +// UnmarshalJSON should be able to parse these types of input: +// 1. a JSON string containing a hex-encoded uint64 starting with 0x +// 2. a JSON string containing an uint64 in decimal +// 3. a string containing an uint64 in decimal +func (e *EthUint64) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err == nil { + base := 10 + if strings.HasPrefix(s, "0x") { + base = 16 + } + parsedInt, err := strconv.ParseUint(strings.Replace(s, "0x", "", -1), base, 64) + if err != nil { + return err + } + eint := EthUint64(parsedInt) + *e = eint + return nil + } else if eint, err := strconv.ParseUint(string(b), 10, 64); err == nil { + *e = EthUint64(eint) + return nil + } + return fmt.Errorf("cannot interpret %s as a hex-encoded uint64, or a number", string(b)) +} + +func EthUint64FromHex(s string) (EthUint64, error) { + parsedInt, err := strconv.ParseUint(strings.Replace(s, "0x", "", -1), 16, 64) + if err != nil { + return EthUint64(0), err + } + return EthUint64(parsedInt), nil +} + +// Parse a uint64 from big-endian encoded bytes. +func EthUint64FromBytes(b []byte) (EthUint64, error) { + if len(b) != 32 { + return 0, xerrors.Errorf("eth int must be 32 bytes long") + } + var zeros [32 - 8]byte + if !bytes.Equal(b[:len(zeros)], zeros[:]) { + return 0, xerrors.Errorf("eth int overflows 64 bits") + } + return EthUint64(binary.BigEndian.Uint64(b[len(zeros):])), nil +} + +func (e EthUint64) Hex() string { + if e == 0 { + return "0x0" + } + return fmt.Sprintf("0x%x", e) +} + +// EthBigInt represents a large integer whose zero value serializes to "0x0". +type EthBigInt big.Int + +var EthBigIntZero = EthBigInt{Int: big.Zero().Int} + +func (e EthBigInt) String() string { + if e.Int == nil || e.Int.BitLen() == 0 { + return "0x0" + } + return fmt.Sprintf("0x%x", e.Int) +} + +func (e EthBigInt) MarshalJSON() ([]byte, error) { + return json.Marshal(e.String()) +} + +func (e *EthBigInt) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + + replaced := strings.Replace(s, "0x", "", -1) + if len(replaced)%2 == 1 { + replaced = "0" + replaced + } + + i := new(mathbig.Int) + i.SetString(replaced, 16) + + *e = EthBigInt(big.NewFromGo(i)) + return nil +} + +// EthBytes represent arbitrary bytes. A nil or empty slice serializes to "0x". +type EthBytes []byte + +func (e EthBytes) String() string { + if len(e) == 0 { + return "0x" + } + return "0x" + hex.EncodeToString(e) +} + +func (e EthBytes) MarshalJSON() ([]byte, error) { + return json.Marshal(e.String()) +} + +func (e *EthBytes) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + + s = strings.Replace(s, "0x", "", -1) + if len(s)%2 == 1 { + s = "0" + s + } + + decoded, err := hex.DecodeString(s) + if err != nil { + return err + } + + *e = decoded + return nil +} + +type EthBlock struct { + Hash EthHash `json:"hash"` + ParentHash EthHash `json:"parentHash"` + Sha3Uncles EthHash `json:"sha3Uncles"` + Miner EthAddress `json:"miner"` + StateRoot EthHash `json:"stateRoot"` + TransactionsRoot EthHash `json:"transactionsRoot"` + ReceiptsRoot EthHash `json:"receiptsRoot"` + LogsBloom EthBytes `json:"logsBloom"` + Difficulty EthUint64 `json:"difficulty"` + TotalDifficulty EthUint64 `json:"totalDifficulty"` + Number EthUint64 `json:"number"` + GasLimit EthUint64 `json:"gasLimit"` + GasUsed EthUint64 `json:"gasUsed"` + Timestamp EthUint64 `json:"timestamp"` + Extradata EthBytes `json:"extraData"` + MixHash EthHash `json:"mixHash"` + Nonce EthNonce `json:"nonce"` + BaseFeePerGas EthBigInt `json:"baseFeePerGas"` + Size EthUint64 `json:"size"` + // can be []EthTx or []string depending on query params + Transactions []interface{} `json:"transactions"` + Uncles []EthHash `json:"uncles"` +} + +const EthBloomSize = 2048 + +var ( + EmptyEthBloom = [EthBloomSize / 8]byte{} + FullEthBloom = [EthBloomSize / 8]byte{} + EmptyEthHash = EthHash{} + EmptyUncleHash = must.One(ParseEthHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")) // Keccak-256 of an RLP of an empty array + EmptyRootHash = must.One(ParseEthHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) // Keccak-256 hash of the RLP of null + EmptyEthInt = EthUint64(0) + EmptyEthNonce = [8]byte{0, 0, 0, 0, 0, 0, 0, 0} +) + +func init() { + for i := range FullEthBloom { + FullEthBloom[i] = 0xff + } +} + +func NewEthBlock(hasTransactions bool) EthBlock { + b := EthBlock{ + Sha3Uncles: EmptyUncleHash, // Sha3Uncles set to a hardcoded value which is used by some clients to determine if has no uncles. + StateRoot: EmptyEthHash, + TransactionsRoot: EmptyRootHash, // TransactionsRoot set to a hardcoded value which is used by some clients to determine if has no transactions. + ReceiptsRoot: EmptyEthHash, + Difficulty: EmptyEthInt, + LogsBloom: FullEthBloom[:], + Extradata: []byte{}, + MixHash: EmptyEthHash, + Nonce: EmptyEthNonce, + GasLimit: EthUint64(build.BlockGasLimit), // TODO we map Ethereum blocks to Filecoin tipsets; this is inconsistent. + Uncles: []EthHash{}, + Transactions: []interface{}{}, + } + if hasTransactions { + b.TransactionsRoot = EmptyEthHash + } + + return b +} + +type EthCall struct { + From *EthAddress `json:"from"` + To *EthAddress `json:"to"` + Gas EthUint64 `json:"gas"` + GasPrice EthBigInt `json:"gasPrice"` + Value EthBigInt `json:"value"` + Data EthBytes `json:"data"` +} + +func (c *EthCall) UnmarshalJSON(b []byte) error { + type TempEthCall EthCall + var params TempEthCall + + if err := json.Unmarshal(b, ¶ms); err != nil { + return err + } + *c = EthCall(params) + return nil +} + +const ( + EthAddressLength = 20 + EthHashLength = 32 +) + +type EthNonce [8]byte + +func (n EthNonce) String() string { + return "0x" + hex.EncodeToString(n[:]) +} + +func (n EthNonce) MarshalJSON() ([]byte, error) { + return json.Marshal(n.String()) +} + +func (n *EthNonce) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + + s = strings.Replace(s, "0x", "", -1) + if len(s)%2 == 1 { + s = "0" + s + } + + decoded, err := hex.DecodeString(s) + if err != nil { + return err + } + copy(n[:], decoded[:8]) + return nil +} + +type EthAddress [EthAddressLength]byte + +// EthAddressFromPubKey returns the Ethereum address corresponding to an +// uncompressed secp256k1 public key. +func EthAddressFromPubKey(pubk []byte) ([]byte, error) { + // if we get an uncompressed public key (that's what we get from the library, + // but putting this check here for defensiveness), strip the prefix + const pubKeyLen = 65 + if len(pubk) != pubKeyLen { + return nil, fmt.Errorf("public key should have %d in length, but got %d", pubKeyLen, len(pubk)) + } + if pubk[0] != 0x04 { + return nil, fmt.Errorf("expected first byte of secp256k1 to be 0x04 (uncompressed)") + } + pubk = pubk[1:] + + // Calculate the Ethereum address based on the keccak hash of the pubkey. + hasher := sha3.NewLegacyKeccak256() + hasher.Write(pubk) + ethAddr := hasher.Sum(nil)[12:] + return ethAddr, nil +} + +func IsEthAddress(addr address.Address) bool { + if addr.Protocol() != address.Delegated { + return false + } + payload := addr.Payload() + namespace, _, err := varint.FromUvarint(payload) + if err != nil { + return false + } + + return namespace == builtintypes.EthereumAddressManagerActorID +} + +func EthAddressFromFilecoinAddress(addr address.Address) (EthAddress, error) { + switch addr.Protocol() { + case address.ID: + id, err := address.IDFromAddress(addr) + if err != nil { + return EthAddress{}, err + } + var ethaddr EthAddress + ethaddr[0] = 0xff + binary.BigEndian.PutUint64(ethaddr[12:], id) + return ethaddr, nil + case address.Delegated: + payload := addr.Payload() + namespace, n, err := varint.FromUvarint(payload) + if err != nil { + return EthAddress{}, xerrors.Errorf("invalid delegated address namespace in: %s", addr) + } + payload = payload[n:] + if namespace == builtintypes.EthereumAddressManagerActorID { + return CastEthAddress(payload) + } + } + return EthAddress{}, ErrInvalidAddress +} + +// ParseEthAddress parses an Ethereum address from a hex string. +func ParseEthAddress(s string) (EthAddress, error) { + b, err := decodeHexString(s, EthAddressLength) + if err != nil { + return EthAddress{}, err + } + var h EthAddress + copy(h[EthAddressLength-len(b):], b) + return h, nil +} + +// CastEthAddress interprets bytes as an EthAddress, performing some basic checks. +func CastEthAddress(b []byte) (EthAddress, error) { + var a EthAddress + if len(b) != EthAddressLength { + return EthAddress{}, xerrors.Errorf("cannot parse bytes into an EthAddress: incorrect input length") + } + copy(a[:], b[:]) + return a, nil +} + +func (ea EthAddress) String() string { + return "0x" + hex.EncodeToString(ea[:]) +} + +func (ea EthAddress) MarshalJSON() ([]byte, error) { + return json.Marshal(ea.String()) +} + +func (ea *EthAddress) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + addr, err := ParseEthAddress(s) + if err != nil { + return err + } + copy(ea[:], addr[:]) + return nil +} + +func (ea EthAddress) IsMaskedID() bool { + idmask := [12]byte{0xff} + return bytes.Equal(ea[:12], idmask[:]) +} + +func (ea EthAddress) ToFilecoinAddress() (address.Address, error) { + if ea.IsMaskedID() { + // This is a masked ID address. + id := binary.BigEndian.Uint64(ea[12:]) + return address.NewIDAddress(id) + } + + // Otherwise, translate the address into an address controlled by the + // Ethereum Address Manager. + addr, err := address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, ea[:]) + if err != nil { + return address.Undef, fmt.Errorf("failed to translate supplied address (%s) into a "+ + "Filecoin f4 address: %w", hex.EncodeToString(ea[:]), err) + } + return addr, nil +} + +type EthHash [EthHashLength]byte + +func (h EthHash) MarshalJSON() ([]byte, error) { + return json.Marshal(h.String()) +} + +func (h *EthHash) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + hash, err := ParseEthHash(s) + if err != nil { + return err + } + copy(h[:], hash[:]) + return nil +} + +func (h EthHash) String() string { + return "0x" + hex.EncodeToString(h[:]) +} + +// Should ONLY be used for blocks and Filecoin messages. Eth transactions expect a different hashing scheme. +func (h EthHash) ToCid() cid.Cid { + // err is always nil + mh, _ := multihash.EncodeName(h[:], "blake2b-256") + + return cid.NewCidV1(cid.DagCBOR, mh) +} + +func decodeHexString(s string, expectedLen int) ([]byte, error) { + s = handleHexStringPrefix(s) + if len(s) != expectedLen*2 { + return nil, xerrors.Errorf("expected hex string length sans prefix %d, got %d", expectedLen*2, len(s)) + } + b, err := hex.DecodeString(s) + if err != nil { + return nil, xerrors.Errorf("cannot parse hex value: %w", err) + } + return b, nil +} + +func DecodeHexString(s string) ([]byte, error) { + s = handleHexStringPrefix(s) + b, err := hex.DecodeString(s) + if err != nil { + return nil, xerrors.Errorf("cannot parse hex value: %w", err) + } + return b, nil +} + +func DecodeHexStringTrimSpace(s string) ([]byte, error) { + return DecodeHexString(strings.TrimSpace(s)) +} + +func handleHexStringPrefix(s string) string { + // Strip the leading 0x or 0X prefix since hex.DecodeString does not support it. + if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") { + s = s[2:] + } + // Sometimes clients will omit a leading zero in a byte; pad so we can decode correctly. + if len(s)%2 == 1 { + s = "0" + s + } + return s +} + +func EthHashFromCid(c cid.Cid) (EthHash, error) { + return ParseEthHash(c.Hash().HexString()[8:]) +} + +func ParseEthHash(s string) (EthHash, error) { + b, err := decodeHexString(s, EthHashLength) + if err != nil { + return EthHash{}, err + } + var h EthHash + copy(h[EthHashLength-len(b):], b) + return h, nil +} + +func EthHashFromTxBytes(b []byte) EthHash { + hasher := sha3.NewLegacyKeccak256() + hasher.Write(b) + hash := hasher.Sum(nil) + + var ethHash EthHash + copy(ethHash[:], hash) + return ethHash +} + +func EthBloomSet(f EthBytes, data []byte) { + hasher := sha3.NewLegacyKeccak256() + hasher.Write(data) + hash := hasher.Sum(nil) + + for i := 0; i < 3; i++ { + n := binary.BigEndian.Uint16(hash[i*2:]) % EthBloomSize + f[(EthBloomSize/8)-(n/8)-1] |= 1 << (n % 8) + } +} + +type EthFeeHistory struct { + OldestBlock EthUint64 `json:"oldestBlock"` + BaseFeePerGas []EthBigInt `json:"baseFeePerGas"` + GasUsedRatio []float64 `json:"gasUsedRatio"` + Reward *[][]EthBigInt `json:"reward,omitempty"` +} + +type EthFilterID EthHash + +func (h EthFilterID) MarshalJSON() ([]byte, error) { + return (EthHash)(h).MarshalJSON() +} + +func (h *EthFilterID) UnmarshalJSON(b []byte) error { + return (*EthHash)(h).UnmarshalJSON(b) +} + +func (h EthFilterID) String() string { + return (EthHash)(h).String() +} + +// An opaque identifier generated by the Lotus node to refer to an active subscription. +type EthSubscriptionID EthHash + +func (h EthSubscriptionID) MarshalJSON() ([]byte, error) { + return (EthHash)(h).MarshalJSON() +} + +func (h *EthSubscriptionID) UnmarshalJSON(b []byte) error { + return (*EthHash)(h).UnmarshalJSON(b) +} + +func (h EthSubscriptionID) String() string { + return (EthHash)(h).String() +} + +type EthFilterSpec struct { + // Interpreted as an epoch or one of "latest" for last mined block, "earliest" for first, + // "pending" for not yet committed messages. + // Optional, default: "latest". + FromBlock *string `json:"fromBlock,omitempty"` + + // Interpreted as an epoch or one of "latest" for last mined block, "earliest" for first, + // "pending" for not yet committed messages. + // Optional, default: "latest". + ToBlock *string `json:"toBlock,omitempty"` + + // Actor address or a list of addresses from which event logs should originate. + // Optional, default nil. + // The JSON decoding must treat a string as equivalent to an array with one value, for example + // "0x8888f1f195afa192cfee86069858" must be decoded as [ "0x8888f1f195afa192cfee86069858" ] + Address EthAddressList `json:"address"` + + // List of topics to be matched. + // Optional, default: empty list + Topics EthTopicSpec `json:"topics"` + + // Restricts event logs returned to those emitted from messages contained in this tipset. + // If BlockHash is present in in the filter criteria, then neither FromBlock nor ToBlock are allowed. + // Added in EIP-234 + BlockHash *EthHash `json:"blockHash,omitempty"` +} + +// EthAddressSpec represents a list of addresses. +// The JSON decoding must treat a string as equivalent to an array with one value, for example +// "0x8888f1f195afa192cfee86069858" must be decoded as [ "0x8888f1f195afa192cfee86069858" ] +type EthAddressList []EthAddress + +func (e *EthAddressList) UnmarshalJSON(b []byte) error { + if bytes.Equal(b, []byte{'n', 'u', 'l', 'l'}) { + return nil + } + if len(b) > 0 && b[0] == '[' { + var addrs []EthAddress + err := json.Unmarshal(b, &addrs) + if err != nil { + return err + } + *e = addrs + return nil + } + var addr EthAddress + err := json.Unmarshal(b, &addr) + if err != nil { + return err + } + *e = []EthAddress{addr} + return nil +} + +// TopicSpec represents a specification for matching by topic. An empty spec means all topics +// will be matched. Otherwise topics are matched conjunctively in the first dimension of the +// slice and disjunctively in the second dimension. Topics are matched in order. +// An event log with topics [A, B] will be matched by the following topic specs: +// [] "all" +// [[A]] "A in first position (and anything after)" +// [nil, [B] ] "anything in first position AND B in second position (and anything after)" +// [[A], [B]] "A in first position AND B in second position (and anything after)" +// [[A, B], [A, B]] "(A OR B) in first position AND (A OR B) in second position (and anything after)" +// +// The JSON decoding must treat string values as equivalent to arrays with one value, for example +// { "A", [ "B", "C" ] } must be decoded as [ [ A ], [ B, C ] ] +type EthTopicSpec []EthHashList + +// EthHashList represents a list of EthHashes. +// The JSON decoding treats string values as equivalent to arrays with one value. +type EthHashList []EthHash + +func (e *EthHashList) UnmarshalJSON(b []byte) error { + if bytes.Equal(b, []byte{'n', 'u', 'l', 'l'}) { + return nil + } + if len(b) > 0 && b[0] == '[' { + var hashes []EthHash + err := json.Unmarshal(b, &hashes) + if err != nil { + return err + } + *e = hashes + return nil + } + var hash EthHash + err := json.Unmarshal(b, &hash) + if err != nil { + return err + } + *e = []EthHash{hash} + return nil +} + +// FilterResult represents the response from executing a filter: a list of block hashes, a list of transaction hashes +// or a list of logs +// This is a union type. Only one field will be populated. +// The JSON encoding must produce an array of the populated field. +type EthFilterResult struct { + Results []interface{} +} + +func (h EthFilterResult) MarshalJSON() ([]byte, error) { + if h.Results != nil { + return json.Marshal(h.Results) + } + return []byte{'[', ']'}, nil +} + +func (h *EthFilterResult) UnmarshalJSON(b []byte) error { + if bytes.Equal(b, []byte{'n', 'u', 'l', 'l'}) { + return nil + } + err := json.Unmarshal(b, &h.Results) + return err +} + +// EthLog represents the results of an event filter execution. +type EthLog struct { + // Address is the address of the actor that produced the event log. + Address EthAddress `json:"address"` + + // Data is the value of the event log, excluding topics + Data EthBytes `json:"data"` + + // List of topics associated with the event log. + Topics []EthHash `json:"topics"` + + // Following fields are derived from the transaction containing the log + + // Indicates whether the log was removed due to a chain reorganization. + Removed bool `json:"removed"` + + // LogIndex is the index of the event log in the sequence of events produced by the message execution. + // (this is the index in the events AMT on the message receipt) + LogIndex EthUint64 `json:"logIndex"` + + // TransactionIndex is the index in the tipset of the transaction that produced the event log. + // The index corresponds to the sequence of messages produced by ChainGetParentMessages + TransactionIndex EthUint64 `json:"transactionIndex"` + + // TransactionHash is the hash of the RLP message that produced the event log. + TransactionHash EthHash `json:"transactionHash"` + + // BlockHash is the hash of the tipset containing the message that produced the log. + BlockHash EthHash `json:"blockHash"` + + // BlockNumber is the epoch of the tipset containing the message. + BlockNumber EthUint64 `json:"blockNumber"` +} + +// EthSubscribeParams handles raw jsonrpc params for eth_subscribe +type EthSubscribeParams struct { + EventType string + Params *EthSubscriptionParams +} + +func (e *EthSubscribeParams) UnmarshalJSON(b []byte) error { + var params []json.RawMessage + err := json.Unmarshal(b, ¶ms) + if err != nil { + return err + } + switch len(params) { + case 2: + err = json.Unmarshal(params[1], &e.Params) + if err != nil { + return err + } + fallthrough + case 1: + err = json.Unmarshal(params[0], &e.EventType) + if err != nil { + return err + } + default: + return xerrors.Errorf("expected 1 or 2 params, got %d", len(params)) + } + return nil +} + +func (e EthSubscribeParams) MarshalJSON() ([]byte, error) { + if e.Params != nil { + return json.Marshal([]interface{}{e.EventType, e.Params}) + } + return json.Marshal([]interface{}{e.EventType}) +} + +type EthSubscriptionParams struct { + // List of topics to be matched. + // Optional, default: empty list + Topics EthTopicSpec `json:"topics,omitempty"` + + // Actor address or a list of addresses from which event logs should originate. + // Optional, default nil. + // The JSON decoding must treat a string as equivalent to an array with one value, for example + // "0x8888f1f195afa192cfee86069858" must be decoded as [ "0x8888f1f195afa192cfee86069858" ] + Address EthAddressList `json:"address"` +} + +type EthSubscriptionResponse struct { + // The persistent identifier for the subscription which can be used to unsubscribe. + SubscriptionID EthSubscriptionID `json:"subscription"` + + // The object matching the subscription. This may be a Block (tipset), a Transaction (message) or an EthLog + Result interface{} `json:"result"` +} + +func GetContractEthAddressFromCode(sender EthAddress, salt [32]byte, initcode []byte) (EthAddress, error) { + hasher := sha3.NewLegacyKeccak256() + hasher.Write(initcode) + inithash := hasher.Sum(nil) + + hasher.Reset() + hasher.Write([]byte{0xff}) + hasher.Write(sender[:]) + hasher.Write(salt[:]) + hasher.Write(inithash) + + ethAddr, err := CastEthAddress(hasher.Sum(nil)[12:]) + if err != nil { + return [20]byte{}, err + } + + return ethAddr, nil +} + +// EthFeeHistoryParams handles raw jsonrpc params for eth_feeHistory +type EthFeeHistoryParams struct { + BlkCount EthUint64 + NewestBlkNum string + RewardPercentiles *[]float64 +} + +func (e *EthFeeHistoryParams) UnmarshalJSON(b []byte) error { + var params []json.RawMessage + err := json.Unmarshal(b, ¶ms) + if err != nil { + return err + } + switch len(params) { + case 3: + err = json.Unmarshal(params[2], &e.RewardPercentiles) + if err != nil { + return err + } + fallthrough + case 2: + err = json.Unmarshal(params[1], &e.NewestBlkNum) + if err != nil { + return err + } + err = json.Unmarshal(params[0], &e.BlkCount) + if err != nil { + return err + } + default: + return xerrors.Errorf("expected 2 or 3 params, got %d", len(params)) + } + return nil +} + +func (e EthFeeHistoryParams) MarshalJSON() ([]byte, error) { + if e.RewardPercentiles != nil { + return json.Marshal([]interface{}{e.BlkCount, e.NewestBlkNum, e.RewardPercentiles}) + } + return json.Marshal([]interface{}{e.BlkCount, e.NewestBlkNum}) +} diff --git a/chain/types/ethtypes/eth_types_test.go b/chain/types/ethtypes/eth_types_test.go new file mode 100644 index 000000000..118fbc901 --- /dev/null +++ b/chain/types/ethtypes/eth_types_test.go @@ -0,0 +1,432 @@ +package ethtypes + +import ( + "encoding/json" + "strings" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/big" +) + +type TestCase struct { + Input interface{} + Output interface{} +} + +func TestEthIntMarshalJSON(t *testing.T) { + // https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding + testcases := []TestCase{ + {EthUint64(0), []byte("\"0x0\"")}, + {EthUint64(65), []byte("\"0x41\"")}, + {EthUint64(1024), []byte("\"0x400\"")}, + } + + for _, tc := range testcases { + j, err := tc.Input.(EthUint64).MarshalJSON() + require.Nil(t, err) + require.Equal(t, j, tc.Output) + } +} + +func TestEthIntUnmarshalJSON(t *testing.T) { + testcases := []TestCase{ + {[]byte("\"0x0\""), EthUint64(0)}, + {[]byte("\"0x41\""), EthUint64(65)}, + {[]byte("\"0x400\""), EthUint64(1024)}, + {[]byte("\"0\""), EthUint64(0)}, + {[]byte("\"41\""), EthUint64(41)}, + {[]byte("\"400\""), EthUint64(400)}, + {[]byte("0"), EthUint64(0)}, + {[]byte("100"), EthUint64(100)}, + {[]byte("1024"), EthUint64(1024)}, + } + + for _, tc := range testcases { + var i EthUint64 + err := i.UnmarshalJSON(tc.Input.([]byte)) + require.Nil(t, err) + require.Equal(t, tc.Output, i) + } +} + +func TestEthBigIntMarshalJSON(t *testing.T) { + testcases := []TestCase{ + {EthBigInt(big.NewInt(0)), []byte("\"0x0\"")}, + {EthBigInt(big.NewInt(65)), []byte("\"0x41\"")}, + {EthBigInt(big.NewInt(1024)), []byte("\"0x400\"")}, + {EthBigInt(big.Int{}), []byte("\"0x0\"")}, + } + for _, tc := range testcases { + j, err := tc.Input.(EthBigInt).MarshalJSON() + require.Nil(t, err) + require.Equal(t, j, tc.Output) + } +} + +func TestEthBigIntUnmarshalJSON(t *testing.T) { + testcases := []TestCase{ + {[]byte("\"0x0\""), EthBigInt(big.MustFromString("0"))}, + {[]byte("\"0x41\""), EthBigInt(big.MustFromString("65"))}, + {[]byte("\"0x400\""), EthBigInt(big.MustFromString("1024"))}, + {[]byte("\"0xff1000000000000000000000000\""), EthBigInt(big.MustFromString("323330131220712761719252861321216"))}, + } + + for _, tc := range testcases { + var i EthBigInt + err := i.UnmarshalJSON(tc.Input.([]byte)) + require.Nil(t, err) + require.Equal(t, i, tc.Output) + } +} + +func TestEthHash(t *testing.T) { + testcases := []string{ + `"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"`, + `"0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"`, + } + + for _, hash := range testcases { + var h EthHash + err := h.UnmarshalJSON([]byte(hash)) + + require.Nil(t, err) + require.Equal(t, h.String(), strings.Replace(hash, `"`, "", -1)) + + c := h.ToCid() + h1, err := EthHashFromCid(c) + require.Nil(t, err) + require.Equal(t, h, h1) + + jm, err := json.Marshal(h) + require.NoError(t, err) + require.Equal(t, hash, string(jm)) + } +} + +func TestEthFilterID(t *testing.T) { + testcases := []string{ + `"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"`, + `"0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"`, + } + + for _, hash := range testcases { + var h EthFilterID + err := h.UnmarshalJSON([]byte(hash)) + + require.Nil(t, err) + require.Equal(t, h.String(), strings.Replace(hash, `"`, "", -1)) + + jm, err := json.Marshal(h) + require.NoError(t, err) + require.Equal(t, hash, string(jm)) + } +} + +func TestEthSubscriptionID(t *testing.T) { + testcases := []string{ + `"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"`, + `"0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"`, + } + + for _, hash := range testcases { + var h EthSubscriptionID + err := h.UnmarshalJSON([]byte(hash)) + + require.Nil(t, err) + require.Equal(t, h.String(), strings.Replace(hash, `"`, "", -1)) + + jm, err := json.Marshal(h) + require.NoError(t, err) + require.Equal(t, hash, string(jm)) + } +} + +func TestEthAddr(t *testing.T) { + testcases := []string{ + strings.ToLower(`"0xd4c5fb16488Aa48081296299d54b0c648C9333dA"`), + strings.ToLower(`"0x2C2EC67e3e1FeA8e4A39601cB3A3Cd44f5fa830d"`), + strings.ToLower(`"0x01184F793982104363F9a8a5845743f452dE0586"`), + } + + for _, addr := range testcases { + var a EthAddress + err := a.UnmarshalJSON([]byte(addr)) + + require.Nil(t, err) + require.Equal(t, a.String(), strings.Replace(addr, `"`, "", -1)) + } +} + +func TestParseEthAddr(t *testing.T) { + testcases := []uint64{ + 1, 2, 3, 100, 101, + } + for _, id := range testcases { + addr, err := address.NewIDAddress(id) + require.Nil(t, err) + + eaddr, err := EthAddressFromFilecoinAddress(addr) + require.Nil(t, err) + + faddr, err := eaddr.ToFilecoinAddress() + require.Nil(t, err) + + require.Equal(t, addr, faddr) + } +} + +func TestUnmarshalEthCall(t *testing.T) { + data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","data":""}` + + var c EthCall + err := c.UnmarshalJSON([]byte(data)) + require.Nil(t, err) +} + +func TestUnmarshalEthBytes(t *testing.T) { + testcases := []string{ + `"0x00"`, + strings.ToLower(`"0xd4c5fb16488Aa48081296299d54b0c648C9333dA"`), + strings.ToLower(`"0x2C2EC67e3e1FeA8e4A39601cB3A3Cd44f5fa830d"`), + strings.ToLower(`"0x01184F793982104363F9a8a5845743f452dE0586"`), + } + + for _, tc := range testcases { + var s EthBytes + err := s.UnmarshalJSON([]byte(tc)) + require.Nil(t, err) + + data, err := s.MarshalJSON() + require.Nil(t, err) + require.Equal(t, string(data), tc) + } +} + +func TestEthFilterResultMarshalJSON(t *testing.T) { + hash1, err := ParseEthHash("013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184") + require.NoError(t, err, "eth hash") + + hash2, err := ParseEthHash("ab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738") + require.NoError(t, err, "eth hash") + + addr, err := ParseEthAddress("d4c5fb16488Aa48081296299d54b0c648C9333dA") + require.NoError(t, err, "eth address") + + log := EthLog{ + Removed: true, + LogIndex: 5, + TransactionIndex: 45, + TransactionHash: hash1, + BlockHash: hash2, + BlockNumber: 53, + Topics: []EthHash{hash1}, + Data: EthBytes(hash1[:]), + Address: addr, + } + logjson, err := json.Marshal(log) + require.NoError(t, err, "log json") + + testcases := []struct { + res EthFilterResult + want string + }{ + { + res: EthFilterResult{}, + want: "[]", + }, + + { + res: EthFilterResult{ + Results: []any{hash1, hash2}, + }, + want: `["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184","0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"]`, + }, + + { + res: EthFilterResult{ + Results: []any{hash1, hash2}, + }, + want: `["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184","0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"]`, + }, + + { + res: EthFilterResult{ + Results: []any{log}, + }, + want: `[` + string(logjson) + `]`, + }, + } + + for _, tc := range testcases { + tc := tc + t.Run("", func(t *testing.T) { + data, err := json.Marshal(tc.res) + require.NoError(t, err) + require.Equal(t, tc.want, string(data)) + }) + } +} + +func TestEthFilterSpecUnmarshalJSON(t *testing.T) { + hash1, err := ParseEthHash("013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184") + require.NoError(t, err, "eth hash") + + hash2, err := ParseEthHash("ab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738") + require.NoError(t, err, "eth hash") + + addr, err := ParseEthAddress("d4c5fb16488Aa48081296299d54b0c648C9333dA") + require.NoError(t, err, "eth address") + + pstring := func(s string) *string { return &s } + phash := func(h EthHash) *EthHash { return &h } + + testcases := []struct { + input string + want EthFilterSpec + }{ + { + input: `{"fromBlock":"latest"}`, + want: EthFilterSpec{FromBlock: pstring("latest")}, + }, + { + input: `{"toBlock":"pending"}`, + want: EthFilterSpec{ToBlock: pstring("pending")}, + }, + { + input: `{"address":["0xd4c5fb16488Aa48081296299d54b0c648C9333dA"]}`, + want: EthFilterSpec{Address: EthAddressList{addr}}, + }, + { + input: `{"address":"0xd4c5fb16488Aa48081296299d54b0c648C9333dA"}`, + want: EthFilterSpec{Address: EthAddressList{addr}}, + }, + { + input: `{"blockHash":"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"}`, + want: EthFilterSpec{BlockHash: phash(hash1)}, + }, + { + input: `{"topics":["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"]}`, + want: EthFilterSpec{ + Topics: EthTopicSpec{ + {hash1}, + }, + }, + }, + { + input: `{"topics":["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184","0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"]}`, + want: EthFilterSpec{ + Topics: EthTopicSpec{ + {hash1}, + {hash2}, + }, + }, + }, + { + input: `{"topics":[null, ["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184","0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"]]}`, + want: EthFilterSpec{ + Topics: EthTopicSpec{ + nil, + {hash1, hash2}, + }, + }, + }, + { + input: `{"topics":[null, "0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"]}`, + want: EthFilterSpec{ + Topics: EthTopicSpec{ + nil, + {hash1}, + }, + }, + }, + } + + for _, tc := range testcases { + var got EthFilterSpec + err := json.Unmarshal([]byte(tc.input), &got) + require.NoError(t, err) + require.Equal(t, tc.want, got) + } +} + +func TestEthAddressListUnmarshalJSON(t *testing.T) { + addr1, err := ParseEthAddress("d4c5fb16488Aa48081296299d54b0c648C9333dA") + require.NoError(t, err, "eth address") + + addr2, err := ParseEthAddress("abbbfb16488Aa48081296299d54b0c648C9333dA") + require.NoError(t, err, "eth address") + + testcases := []struct { + input string + want EthAddressList + }{ + { + input: `["0xd4c5fb16488Aa48081296299d54b0c648C9333dA"]`, + want: EthAddressList{addr1}, + }, + { + input: `["0xd4c5fb16488Aa48081296299d54b0c648C9333dA","abbbfb16488Aa48081296299d54b0c648C9333dA"]`, + want: EthAddressList{addr1, addr2}, + }, + { + input: `"0xd4c5fb16488Aa48081296299d54b0c648C9333dA"`, + want: EthAddressList{addr1}, + }, + { + input: `[]`, + want: EthAddressList{}, + }, + { + input: `null`, + want: EthAddressList(nil), + }, + } + for _, tc := range testcases { + tc := tc + t.Run("", func(t *testing.T) { + var got EthAddressList + err := json.Unmarshal([]byte(tc.input), &got) + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } +} + +func TestEthHashListUnmarshalJSON(t *testing.T) { + hash1, err := ParseEthHash("013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184") + require.NoError(t, err, "eth hash") + + hash2, err := ParseEthHash("ab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738") + require.NoError(t, err, "eth hash") + + testcases := []struct { + input string + want *EthHashList + }{ + { + input: `["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"]`, + want: &EthHashList{hash1}, + }, + { + input: `["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184","0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"]`, + want: &EthHashList{hash1, hash2}, + }, + { + input: `"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"`, + want: &EthHashList{hash1}, + }, + { + input: `null`, + want: nil, + }, + } + for _, tc := range testcases { + var got *EthHashList + err := json.Unmarshal([]byte(tc.input), &got) + require.NoError(t, err) + require.Equal(t, tc.want, got) + } +} diff --git a/chain/types/ethtypes/rlp.go b/chain/types/ethtypes/rlp.go new file mode 100644 index 000000000..049ea6fc4 --- /dev/null +++ b/chain/types/ethtypes/rlp.go @@ -0,0 +1,182 @@ +package ethtypes + +import ( + "bytes" + "encoding/binary" + "fmt" + + "golang.org/x/xerrors" +) + +// maxListElements restricts the amount of RLP list elements we'll read. +// The ETH API only ever reads EIP-1559 transactions, which are bounded by +// 12 elements exactly, so we play it safe and set exactly that limit here. +const maxListElements = 12 + +func EncodeRLP(val interface{}) ([]byte, error) { + return encodeRLP(val) +} + +func encodeRLPListItems(list []interface{}) (result []byte, err error) { + res := []byte{} + for _, elem := range list { + encoded, err := encodeRLP(elem) + if err != nil { + return nil, err + } + res = append(res, encoded...) + } + return res, nil +} + +func encodeLength(length int) (lenInBytes []byte, err error) { + if length == 0 { + return nil, fmt.Errorf("cannot encode length: length should be larger than 0") + } + + buf := new(bytes.Buffer) + err = binary.Write(buf, binary.BigEndian, int64(length)) + if err != nil { + return nil, err + } + + firstNonZeroIndex := len(buf.Bytes()) - 1 + for i, b := range buf.Bytes() { + if b != 0 { + firstNonZeroIndex = i + break + } + } + + res := buf.Bytes()[firstNonZeroIndex:] + return res, nil +} + +func encodeRLP(val interface{}) ([]byte, error) { + switch data := val.(type) { + case []byte: + if len(data) == 1 && data[0] <= 0x7f { + return data, nil + } else if len(data) <= 55 { + prefix := byte(0x80 + len(data)) + return append([]byte{prefix}, data...), nil + } else { + lenInBytes, err := encodeLength(len(data)) + if err != nil { + return nil, err + } + prefix := byte(0xb7 + len(lenInBytes)) + return append( + []byte{prefix}, + append(lenInBytes, data...)..., + ), nil + } + case []interface{}: + encodedList, err := encodeRLPListItems(data) + if err != nil { + return nil, err + } + if len(encodedList) <= 55 { + prefix := byte(0xc0 + len(encodedList)) + return append( + []byte{prefix}, + encodedList..., + ), nil + } + lenInBytes, err := encodeLength(len(encodedList)) + if err != nil { + return nil, err + } + prefix := byte(0xf7 + len(lenInBytes)) + return append( + []byte{prefix}, + append(lenInBytes, encodedList...)..., + ), nil + default: + return nil, fmt.Errorf("input data should either be a list or a byte array") + } +} + +func DecodeRLP(data []byte) (interface{}, error) { + res, consumed, err := decodeRLP(data) + if err != nil { + return nil, err + } + if consumed != len(data) { + return nil, xerrors.Errorf("invalid rlp data: length %d, consumed %d", len(data), consumed) + } + return res, nil +} + +func decodeRLP(data []byte) (res interface{}, consumed int, err error) { + if len(data) == 0 { + return data, 0, xerrors.Errorf("invalid rlp data: data cannot be empty") + } + if data[0] >= 0xf8 { + listLenInBytes := int(data[0]) - 0xf7 + listLen, err := decodeLength(data[1:], listLenInBytes) + if err != nil { + return nil, 0, err + } + if 1+listLenInBytes+listLen > len(data) { + return nil, 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list") + } + result, err := decodeListElems(data[1+listLenInBytes:], listLen) + return result, 1 + listLenInBytes + listLen, err + } else if data[0] >= 0xc0 { + length := int(data[0]) - 0xc0 + result, err := decodeListElems(data[1:], length) + return result, 1 + length, err + } else if data[0] >= 0xb8 { + strLenInBytes := int(data[0]) - 0xb7 + strLen, err := decodeLength(data[1:], strLenInBytes) + if err != nil { + return nil, 0, err + } + totalLen := 1 + strLenInBytes + strLen + if totalLen > len(data) { + return nil, 0, xerrors.Errorf("invalid rlp data: out of bound while parsing string") + } + return data[1+strLenInBytes : totalLen], totalLen, nil + } else if data[0] >= 0x80 { + length := int(data[0]) - 0x80 + if 1+length > len(data) { + return nil, 0, xerrors.Errorf("invalid rlp data: out of bound while parsing string") + } + return data[1 : 1+length], 1 + length, nil + } + return []byte{data[0]}, 1, nil +} + +func decodeLength(data []byte, lenInBytes int) (length int, err error) { + if lenInBytes > len(data) || lenInBytes > 8 { + return 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list length") + } + var decodedLength int64 + r := bytes.NewReader(append(make([]byte, 8-lenInBytes), data[:lenInBytes]...)) + if err := binary.Read(r, binary.BigEndian, &decodedLength); err != nil { + return 0, xerrors.Errorf("invalid rlp data: cannot parse string length: %w", err) + } + if lenInBytes+int(decodedLength) > len(data) { + return 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list") + } + return int(decodedLength), nil +} + +func decodeListElems(data []byte, length int) (res []interface{}, err error) { + totalConsumed := 0 + result := []interface{}{} + + for i := 0; totalConsumed < length && i < maxListElements; i++ { + elem, consumed, err := decodeRLP(data[totalConsumed:]) + if err != nil { + return nil, xerrors.Errorf("invalid rlp data: cannot decode list element: %w", err) + } + totalConsumed += consumed + result = append(result, elem) + } + if totalConsumed != length { + return nil, xerrors.Errorf("invalid rlp data: incorrect list length") + } + return result, nil +} diff --git a/chain/types/ethtypes/rlp_test.go b/chain/types/ethtypes/rlp_test.go new file mode 100644 index 000000000..bdbedff00 --- /dev/null +++ b/chain/types/ethtypes/rlp_test.go @@ -0,0 +1,190 @@ +package ethtypes + +import ( + "encoding/hex" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" +) + +func TestEncode(t *testing.T) { + testcases := []TestCase{ + {[]byte(""), mustDecodeHex("0x80")}, + {mustDecodeHex("0x01"), mustDecodeHex("0x01")}, + {mustDecodeHex("0xaa"), mustDecodeHex("0x81aa")}, + {mustDecodeHex("0x0402"), mustDecodeHex("0x820402")}, + { + []interface{}{}, + mustDecodeHex("0xc0"), + }, + { + mustDecodeHex("0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"), + mustDecodeHex("0xb83cabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"), + }, + { + mustDecodeHex("0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"), + mustDecodeHex("0xb8aaabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"), + }, + { + []interface{}{ + mustDecodeHex("0xaaaa"), + mustDecodeHex("0xbbbb"), + mustDecodeHex("0xcccc"), + mustDecodeHex("0xdddd"), + }, + mustDecodeHex("0xcc82aaaa82bbbb82cccc82dddd"), + }, + { + []interface{}{ + mustDecodeHex("0xaaaaaaaaaaaaaaaaaaaa"), + mustDecodeHex("0xbbbbbbbbbbbbbbbbbbbb"), + []interface{}{ + mustDecodeHex("0xc1c1c1c1c1c1c1c1c1c1"), + mustDecodeHex("0xc2c2c2c2c2c2c2c2c2c2"), + mustDecodeHex("0xc3c3c3c3c3c3c3c3c3c3"), + }, + mustDecodeHex("0xdddddddddddddddddddd"), + mustDecodeHex("0xeeeeeeeeeeeeeeeeeeee"), + mustDecodeHex("0xffffffffffffffffffff"), + }, + mustDecodeHex("0xf8598aaaaaaaaaaaaaaaaaaaaa8abbbbbbbbbbbbbbbbbbbbe18ac1c1c1c1c1c1c1c1c1c18ac2c2c2c2c2c2c2c2c2c28ac3c3c3c3c3c3c3c3c3c38adddddddddddddddddddd8aeeeeeeeeeeeeeeeeeeee8affffffffffffffffffff"), + }, + } + + for _, tc := range testcases { + result, err := EncodeRLP(tc.Input) + require.Nil(t, err) + + require.Equal(t, tc.Output.([]byte), result) + } +} + +func TestDecodeString(t *testing.T) { + testcases := []TestCase{ + {"0x00", "0x00"}, + {"0x80", "0x"}, + {"0x0f", "0x0f"}, + {"0x81aa", "0xaa"}, + {"0x820400", "0x0400"}, + {"0xb83cabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd", + "0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"}, + } + + for _, tc := range testcases { + input, err := hex.DecodeString(strings.Replace(tc.Input.(string), "0x", "", -1)) + require.Nil(t, err) + + output, err := hex.DecodeString(strings.Replace(tc.Output.(string), "0x", "", -1)) + require.Nil(t, err) + + result, err := DecodeRLP(input) + require.Nil(t, err) + require.Equal(t, output, result.([]byte)) + } +} + +func mustDecodeHex(s string) []byte { + d, err := hex.DecodeString(strings.Replace(s, "0x", "", -1)) + if err != nil { + panic(fmt.Errorf("err must be nil: %w", err)) + } + return d +} + +func TestDecodeList(t *testing.T) { + testcases := []TestCase{ + {"0xc0", []interface{}{}}, + {"0xc100", []interface{}{[]byte{0}}}, + {"0xc3000102", []interface{}{[]byte{0}, []byte{1}, []byte{2}}}, + {"0xc4000181aa", []interface{}{[]byte{0}, []byte{1}, []byte{0xaa}}}, + {"0xc6000181aa81ff", []interface{}{[]byte{0}, []byte{1}, []byte{0xaa}, []byte{0xff}}}, + {"0xf8428aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd", + []interface{}{ + mustDecodeHex("0xabcdabcdabcdabcdabcd"), + mustDecodeHex("0xabcdabcdabcdabcdabcd"), + mustDecodeHex("0xabcdabcdabcdabcdabcd"), + mustDecodeHex("0xabcdabcdabcdabcdabcd"), + mustDecodeHex("0xabcdabcdabcdabcdabcd"), + mustDecodeHex("0xabcdabcdabcdabcdabcd"), + }, + }, + {"0xf1030185012a05f2008504a817c800825208942b87d1cb599bc2a606db9a0169fcec96af04ad3a880de0b6b3a764000080c0", + []interface{}{ + []byte{3}, + []byte{1}, + mustDecodeHex("0x012a05f200"), + mustDecodeHex("0x04a817c800"), + mustDecodeHex("0x5208"), + mustDecodeHex("0x2b87d1CB599Bc2a606Db9A0169fcEc96Af04ad3a"), + mustDecodeHex("0x0de0b6b3a7640000"), + []byte{}, + []interface{}{}, + }}, + } + + for _, tc := range testcases { + input, err := hex.DecodeString(strings.Replace(tc.Input.(string), "0x", "", -1)) + require.Nil(t, err) + + result, err := DecodeRLP(input) + require.Nil(t, err) + + fmt.Println(result) + r := result.([]interface{}) + require.Equal(t, len(tc.Output.([]interface{})), len(r)) + + for i, v := range r { + require.Equal(t, tc.Output.([]interface{})[i], v) + } + } +} + +func TestDecodeEncodeTx(t *testing.T) { + testcases := [][]byte{ + mustDecodeHex("0xdc82013a0185012a05f2008504a817c8008080872386f26fc1000000c0"), + mustDecodeHex("0xf85f82013a0185012a05f2008504a817c8008080872386f26fc1000000c001a027fa36fb9623e4d71fcdd7f7dce71eb814c9560dcf3908c1719386e2efd122fba05fb4e4227174eeb0ba84747a4fb883c8d4e0fdb129c4b1f42e90282c41480234"), + mustDecodeHex("0xf9061c82013a0185012a05f2008504a817c8008080872386f26fc10000b905bb608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610556806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101939190610496565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104ca565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561048b5761048a61040d565b5b828202905092915050565b60006104a182610337565b91506104ac83610337565b9250828210156104bf576104be61040d565b5b828203905092915050565b60006104d582610337565b91506104e083610337565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156105155761051461040d565b5b82820190509291505056fea26469706673582212208e5b4b874c839967f88008ed2fa42d6c2d9c9b0ae05d1d2c61faa7d229c134e664736f6c634300080d0033c080a0c4e9477f57c6848b2f1ea73a14809c1f44529d20763c947f3ac8ffd3d1629d93a011485a215457579bb13ac7b53bb9d6804763ae6fe5ce8ddd41642cea55c9a09a"), + mustDecodeHex("0xf9063082013a0185012a05f2008504a817c8008094025b594a4f1c4888cafcfaf2bb24ed95507749e0872386f26fc10000b905bb608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610556806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101939190610496565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104ca565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561048b5761048a61040d565b5b828202905092915050565b60006104a182610337565b91506104ac83610337565b9250828210156104bf576104be61040d565b5b828203905092915050565b60006104d582610337565b91506104e083610337565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156105155761051461040d565b5b82820190509291505056fea26469706673582212208e5b4b874c839967f88008ed2fa42d6c2d9c9b0ae05d1d2c61faa7d229c134e664736f6c634300080d0033c080a0fe38720928596f9e9dfbf891d00311638efce3713f03cdd67b212ecbbcf18f29a05993e656c0b35b8a580da6aff7c89b3d3e8b1c6f83a7ce09473c0699a8500b9c"), + } + + for _, tc := range testcases { + decoded, err := DecodeRLP(tc) + require.Nil(t, err) + + encoded, err := EncodeRLP(decoded) + require.Nil(t, err) + require.Equal(t, tc, encoded) + } +} + +func TestDecodeError(t *testing.T) { + testcases := [][]byte{ + mustDecodeHex("0xdc82013a0185012a05f2008504a817c8008080872386f26fc1000000"), + mustDecodeHex("0xdc013a01012a05f2008504a817c8008080872386f26fc1000000"), + mustDecodeHex("0xdc82013a0185012a05f28504a817c08080872386f26fc1000000"), + mustDecodeHex("0xdc82013a0185012a05f504a817c080872386ffc1000000"), + mustDecodeHex("0x013a018505f2008504a817c8008080872386f26fc1000000"), + } + + for _, tc := range testcases { + _, err := DecodeRLP(tc) + require.NotNil(t, err, hex.EncodeToString(tc)) + } +} + +func TestDecode1(t *testing.T) { + b := mustDecodeHex("0x02f8758401df5e7680832c8411832c8411830767f89452963ef50e27e06d72d59fcb4f3c2a687be3cfef880de0b6b3a764000080c080a094b11866f453ad85a980e0e8a2fc98cbaeb4409618c7734a7e12ae2f66fd405da042dbfb1b37af102023830ceeee0e703ffba0b8b3afeb8fe59f405eca9ed61072") + decoded, err := ParseEthTxArgs(b) + require.NoError(t, err) + + sender, err := decoded.Sender() + require.NoError(t, err) + + addr, err := address.NewFromString("f410fkkld55ioe7qg24wvt7fu6pbknb56ht7pt4zamxa") + require.NoError(t, err) + require.Equal(t, sender, addr) +} diff --git a/chain/types/event.go b/chain/types/event.go new file mode 100644 index 000000000..91b0e95d3 --- /dev/null +++ b/chain/types/event.go @@ -0,0 +1,61 @@ +package types + +import ( + "bytes" + "fmt" + + cbg "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/go-state-types/abi" +) + +// EventEntry flags defined in fvm_shared +const ( + EventFlagIndexedKey = 0b00000001 + EventFlagIndexedValue = 0b00000010 +) + +type Event struct { + // The ID of the actor that emitted this event. + Emitter abi.ActorID + + // Key values making up this event. + Entries []EventEntry +} + +type EventEntry struct { + // A bitmap conveying metadata or hints about this entry. + Flags uint8 + + // The key of this event entry + Key string + + // The event value's codec + Codec uint64 + + // The event value + Value []byte +} + +type FilterID [32]byte // compatible with EthHash + +// DecodeEvents decodes a CBOR list of CBOR-encoded events. +func DecodeEvents(input []byte) ([]Event, error) { + r := bytes.NewReader(input) + typ, len, err := cbg.NewCborReader(r).ReadHeader() + if err != nil { + return nil, fmt.Errorf("failed to read events: %w", err) + } + if typ != cbg.MajArray { + return nil, fmt.Errorf("expected a CBOR list, was major type %d", typ) + } + events := make([]Event, 0, len) + for i := 0; i < int(len); i++ { + var evt Event + if err := evt.UnmarshalCBOR(r); err != nil { + return nil, fmt.Errorf("failed to parse event: %w", err) + } + events = append(events, evt) + } + return events, nil +} diff --git a/chain/types/execresult.go b/chain/types/execresult.go index 917b84a92..98d06a390 100644 --- a/chain/types/execresult.go +++ b/chain/types/execresult.go @@ -42,6 +42,25 @@ type Loc struct { Function string } +func (et ExecutionTrace) SumGas() GasTrace { + return SumGas(et.GasCharges) +} + +func SumGas(charges []*GasTrace) GasTrace { + var out GasTrace + for _, gc := range charges { + out.TotalGas += gc.TotalGas + out.ComputeGas += gc.ComputeGas + out.StorageGas += gc.StorageGas + + out.TotalVirtualGas += gc.TotalVirtualGas + out.VirtualComputeGas += gc.VirtualComputeGas + out.VirtualStorageGas += gc.VirtualStorageGas + } + + return out +} + func (l Loc) Show() bool { ignorePrefix := []string{ "reflect.", diff --git a/chain/types/fil.go b/chain/types/fil.go index 21125e6d6..60a2940c6 100644 --- a/chain/types/fil.go +++ b/chain/types/fil.go @@ -102,7 +102,7 @@ func ParseFIL(s string) (FIL, error) { return FIL{}, fmt.Errorf("string length too large: %d", len(s)) } - r, ok := new(big.Rat).SetString(s) + r, ok := new(big.Rat).SetString(s) //nolint:gosec if !ok { return FIL{}, fmt.Errorf("failed to parse %q as a decimal number", s) } diff --git a/chain/types/keystore.go b/chain/types/keystore.go index 107c1fbe3..8e8d9192b 100644 --- a/chain/types/keystore.go +++ b/chain/types/keystore.go @@ -39,6 +39,8 @@ func (kt *KeyType) UnmarshalJSON(bb []byte) error { *kt = KTBLS case crypto.SigTypeSecp256k1: *kt = KTSecp256k1 + case crypto.SigTypeDelegated: + *kt = KTDelegated default: return fmt.Errorf("unknown sigtype: %d", bst) } @@ -51,6 +53,7 @@ const ( KTBLS KeyType = "bls" KTSecp256k1 KeyType = "secp256k1" KTSecp256k1Ledger KeyType = "secp256k1-ledger" + KTDelegated KeyType = "delegated" ) // KeyInfo is used for storing keys in KeyStore diff --git a/chain/types/message.go b/chain/types/message.go index 352548d0c..a25cd05b6 100644 --- a/chain/types/message.go +++ b/chain/types/message.go @@ -5,8 +5,8 @@ import ( "encoding/json" "fmt" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" diff --git a/chain/types/message_receipt.go b/chain/types/message_receipt.go index 57761680d..b0db3b74d 100644 --- a/chain/types/message_receipt.go +++ b/chain/types/message_receipt.go @@ -3,15 +3,59 @@ package types import ( "bytes" + "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-state-types/exitcode" ) +type MessageReceiptVersion byte + +const ( + // MessageReceiptV0 refers to pre FIP-0049 receipts. + MessageReceiptV0 MessageReceiptVersion = 0 + // MessageReceiptV1 refers to post FIP-0049 receipts. + MessageReceiptV1 MessageReceiptVersion = 1 +) + +const EventAMTBitwidth = 5 + type MessageReceipt struct { - ExitCode exitcode.ExitCode - Return []byte - GasUsed int64 + version MessageReceiptVersion + + ExitCode exitcode.ExitCode + Return []byte + GasUsed int64 + EventsRoot *cid.Cid // Root of Event AMT with bitwidth = EventAMTBitwidth +} + +// NewMessageReceiptV0 creates a new pre FIP-0049 receipt with no capability to +// convey events. +func NewMessageReceiptV0(exitcode exitcode.ExitCode, ret []byte, gasUsed int64) MessageReceipt { + return MessageReceipt{ + version: MessageReceiptV0, + ExitCode: exitcode, + Return: ret, + GasUsed: gasUsed, + } +} + +// NewMessageReceiptV1 creates a new pre FIP-0049 receipt with the ability to +// convey events. +func NewMessageReceiptV1(exitcode exitcode.ExitCode, ret []byte, gasUsed int64, eventsRoot *cid.Cid) MessageReceipt { + return MessageReceipt{ + version: MessageReceiptV1, + ExitCode: exitcode, + Return: ret, + GasUsed: gasUsed, + EventsRoot: eventsRoot, + } +} + +func (mr *MessageReceipt) Version() MessageReceiptVersion { + return mr.version } func (mr *MessageReceipt) Equals(o *MessageReceipt) bool { - return mr.ExitCode == o.ExitCode && bytes.Equal(mr.Return, o.Return) && mr.GasUsed == o.GasUsed + return mr.version == o.version && mr.ExitCode == o.ExitCode && bytes.Equal(mr.Return, o.Return) && mr.GasUsed == o.GasUsed && + (mr.EventsRoot == o.EventsRoot || (mr.EventsRoot != nil && o.EventsRoot != nil && *mr.EventsRoot == *o.EventsRoot)) } diff --git a/chain/types/message_receipt_cbor.go b/chain/types/message_receipt_cbor.go new file mode 100644 index 000000000..e1364e654 --- /dev/null +++ b/chain/types/message_receipt_cbor.go @@ -0,0 +1,359 @@ +package types + +import ( + "fmt" + "io" + + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/exitcode" +) + +// This file contains custom CBOR serde logic to deal with the new versioned +// MessageReceipt resulting from the introduction of actor events (FIP-0049). + +type messageReceiptV0 struct{ *MessageReceipt } + +type messageReceiptV1 struct{ *MessageReceipt } + +func (mr *MessageReceipt) MarshalCBOR(w io.Writer) error { + if mr == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + var m cbor.Marshaler + switch mr.version { + case MessageReceiptV0: + m = &messageReceiptV0{mr} + case MessageReceiptV1: + m = &messageReceiptV1{mr} + default: + return xerrors.Errorf("invalid message receipt version: %d", mr.version) + } + + return m.MarshalCBOR(w) +} + +func (mr *MessageReceipt) UnmarshalCBOR(r io.Reader) (err error) { + *mr = MessageReceipt{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + var u cbor.Unmarshaler + switch extra { + case 3: + mr.version = MessageReceiptV0 + u = &messageReceiptV0{mr} + case 4: + mr.version = MessageReceiptV1 + u = &messageReceiptV1{mr} + default: + return fmt.Errorf("cbor input had wrong number of fields") + } + + // Ok to pass a CBOR reader since cbg.NewCborReader will return itself when + // already a CBOR reader. + return u.UnmarshalCBOR(cr) +} + +var lengthBufAMessageReceiptV0 = []byte{131} + +func (t *messageReceiptV0) MarshalCBOR(w io.Writer) error { + // eliding null check since nulls were already handled in the dispatcher + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write(lengthBufAMessageReceiptV0); err != nil { + return err + } + + // t.ExitCode (exitcode.ExitCode) (int64) + if t.ExitCode >= 0 { + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ExitCode)); err != nil { + return err + } + } else { + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.ExitCode-1)); err != nil { + return err + } + } + + // t.Return ([]uint8) (slice) + if len(t.Return) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Return was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Return))); err != nil { + return err + } + + if _, err := cw.Write(t.Return[:]); err != nil { + return err + } + + // t.GasUsed (int64) (int64) + if t.GasUsed >= 0 { + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.GasUsed)); err != nil { + return err + } + } else { + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.GasUsed-1)); err != nil { + return err + } + } + return nil +} + +func (t *messageReceiptV0) UnmarshalCBOR(r io.Reader) (err error) { + cr := cbg.NewCborReader(r) + + // t.ExitCode (exitcode.ExitCode) (int64) + { + maj, extra, err := cr.ReadHeader() + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.ExitCode = exitcode.ExitCode(extraI) + } + // t.Return ([]uint8) (slice) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Return: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Return = make([]uint8, extra) + } + + if _, err := io.ReadFull(cr, t.Return[:]); err != nil { + return err + } + // t.GasUsed (int64) (int64) + { + maj, extra, err := cr.ReadHeader() + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.GasUsed = extraI + } + return nil +} + +var lengthBufBMessageReceiptV1 = []byte{132} + +func (t *messageReceiptV1) MarshalCBOR(w io.Writer) error { + // eliding null check since nulls were already handled in the dispatcher + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write(lengthBufBMessageReceiptV1); err != nil { + return err + } + + // t.ExitCode (exitcode.ExitCode) (int64) + if t.ExitCode >= 0 { + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ExitCode)); err != nil { + return err + } + } else { + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.ExitCode-1)); err != nil { + return err + } + } + + // t.Return ([]uint8) (slice) + if len(t.Return) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Return was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Return))); err != nil { + return err + } + + if _, err := cw.Write(t.Return[:]); err != nil { + return err + } + + // t.GasUsed (int64) (int64) + if t.GasUsed >= 0 { + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.GasUsed)); err != nil { + return err + } + } else { + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.GasUsed-1)); err != nil { + return err + } + } + + // t.EventsRoot (cid.Cid) (struct) + + if t.EventsRoot == nil { + if _, err := cw.Write(cbg.CborNull); err != nil { + return err + } + } else { + if err := cbg.WriteCid(cw, *t.EventsRoot); err != nil { + return xerrors.Errorf("failed to write cid field t.EventsRoot: %w", err) + } + } + + return nil +} + +func (t *messageReceiptV1) UnmarshalCBOR(r io.Reader) (err error) { + cr := cbg.NewCborReader(r) + + // t.ExitCode (exitcode.ExitCode) (int64) + { + maj, extra, err := cr.ReadHeader() + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.ExitCode = exitcode.ExitCode(extraI) + } + // t.Return ([]uint8) (slice) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Return: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Return = make([]uint8, extra) + } + + if _, err := io.ReadFull(cr, t.Return[:]); err != nil { + return err + } + // t.GasUsed (int64) (int64) + { + maj, extra, err := cr.ReadHeader() + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.GasUsed = extraI + } + // t.EventsRoot (cid.Cid) (struct) + + { + + b, err := cr.ReadByte() + if err != nil { + return err + } + if b != cbg.CborNull[0] { + if err := cr.UnreadByte(); err != nil { + return err + } + + c, err := cbg.ReadCid(cr) + if err != nil { + return xerrors.Errorf("failed to read cid field t.EventsRoot: %w", err) + } + + t.EventsRoot = &c + } + + } + return nil +} diff --git a/chain/types/message_receipt_test.go b/chain/types/message_receipt_test.go new file mode 100644 index 000000000..f0b341f55 --- /dev/null +++ b/chain/types/message_receipt_test.go @@ -0,0 +1,75 @@ +package types + +import ( + "bytes" + "encoding/hex" + "testing" + + "github.com/ipfs/go-cid" + "github.com/stretchr/testify/assert" +) + +func TestMessageReceiptSerdeRoundrip(t *testing.T) { + var ( + assert = assert.New(t) + buf = new(bytes.Buffer) + err error + ) + + randomCid, err := cid.Decode("bafy2bzacecu7n7wbtogznrtuuvf73dsz7wasgyneqasksdblxupnyovmtwxxu") + assert.NoError(err) + + // + // Version 0 + // + mr := NewMessageReceiptV0(0, []byte{0x00, 0x01, 0x02, 0x04}, 42) + + // marshal + err = mr.MarshalCBOR(buf) + assert.NoError(err) + + t.Logf("version 0: %s\n", hex.EncodeToString(buf.Bytes())) + + // unmarshal + var mr2 MessageReceipt + err = mr2.UnmarshalCBOR(buf) + assert.NoError(err) + assert.Equal(mr, mr2) + + // version 0 with an events root -- should not serialize the events root! + mr.EventsRoot = &randomCid + + buf.Reset() + + // marshal + err = mr.MarshalCBOR(buf) + assert.NoError(err) + + t.Logf("version 0 (with root): %s\n", hex.EncodeToString(buf.Bytes())) + + // unmarshal + mr2 = MessageReceipt{} + err = mr2.UnmarshalCBOR(buf) + assert.NoError(err) + assert.NotEqual(mr, mr2) + assert.Nil(mr2.EventsRoot) + + // + // Version 1 + // + buf.Reset() + mr = NewMessageReceiptV1(0, []byte{0x00, 0x01, 0x02, 0x04}, 42, &randomCid) + + // marshal + err = mr.MarshalCBOR(buf) + assert.NoError(err) + + t.Logf("version 1: %s\n", hex.EncodeToString(buf.Bytes())) + + // unmarshal + mr2 = MessageReceipt{} + err = mr2.UnmarshalCBOR(buf) + assert.NoError(err) + assert.Equal(mr, mr2) + assert.NotNil(mr2.EventsRoot) +} diff --git a/chain/types/signedmessage.go b/chain/types/signedmessage.go index 168531714..dc867c5e5 100644 --- a/chain/types/signedmessage.go +++ b/chain/types/signedmessage.go @@ -4,8 +4,8 @@ import ( "bytes" "encoding/json" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" diff --git a/chain/types/state.go b/chain/types/state.go index 506840370..37757f362 100644 --- a/chain/types/state.go +++ b/chain/types/state.go @@ -17,6 +17,8 @@ const ( StateTreeVersion3 // StateTreeVersion4 corresponds to actors v5 and above. StateTreeVersion4 + // StateTreeVersion5 corresponds to actors v10 and above. + StateTreeVersion5 ) type StateRoot struct { diff --git a/chain/types/tipset.go b/chain/types/tipset.go index cb981e0f0..c1aa90fc9 100644 --- a/chain/types/tipset.go +++ b/chain/types/tipset.go @@ -196,8 +196,23 @@ func (ts *TipSet) MinTicket() *Ticket { } func (ts *TipSet) MinTimestamp() uint64 { - minTs := ts.Blocks()[0].Timestamp - for _, bh := range ts.Blocks()[1:] { + if ts == nil { + return 0 + } + + blks := ts.Blocks() + + // TODO::FVM @vyzo @magik Null rounds shouldn't ever be represented as + // tipsets with no blocks; Null-round generally means that the tipset at + // that epoch doesn't exist - and the next tipset that does exist links + // straight to first epoch with blocks (@raulk agrees -- this is odd) + if len(blks) == 0 { + // null rounds make things crash -- it is threaded in every fvm instantiation + return 0 + } + + minTs := blks[0].Timestamp + for _, bh := range blks[1:] { if bh.Timestamp < minTs { minTs = bh.Timestamp } diff --git a/chain/types/tipset_key.go b/chain/types/tipset_key.go index 59514a792..50753ffd2 100644 --- a/chain/types/tipset_key.go +++ b/chain/types/tipset_key.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" typegen "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-state-types/abi" @@ -98,6 +99,28 @@ func (k *TipSetKey) UnmarshalJSON(b []byte) error { return nil } +func (k TipSetKey) Cid() (cid.Cid, error) { + blk, err := k.ToStorageBlock() + if err != nil { + return cid.Cid{}, err + } + return blk.Cid(), nil +} + +func (k TipSetKey) ToStorageBlock() (block.Block, error) { + buf := new(bytes.Buffer) + if err := k.MarshalCBOR(buf); err != nil { + log.Errorf("failed to marshal ts key as CBOR: %s", k) + } + + cid, err := abi.CidBuilder.Sum(buf.Bytes()) + if err != nil { + return nil, err + } + + return block.NewBlockWithCid(buf.Bytes(), cid) +} + func (k TipSetKey) MarshalCBOR(writer io.Writer) error { if err := typegen.WriteMajorTypeHeader(writer, typegen.MajByteString, uint64(len(k.Bytes()))); err != nil { return err diff --git a/chain/types/vmcontext.go b/chain/types/vmcontext.go index 2702153b6..83ad81315 100644 --- a/chain/types/vmcontext.go +++ b/chain/types/vmcontext.go @@ -24,6 +24,8 @@ type StateTree interface { SetActor(addr address.Address, act *Actor) error // GetActor returns the actor from any type of `addr` provided. GetActor(addr address.Address) (*Actor, error) + + Version() StateTreeVersion } type storageWrapper struct { diff --git a/chain/vectors/gen/main.go b/chain/vectors/gen/main.go index fbc96d2c3..ce9f1baf8 100644 --- a/chain/vectors/gen/main.go +++ b/chain/vectors/gen/main.go @@ -19,6 +19,7 @@ import ( "github.com/filecoin-project/lotus/chain/vectors" "github.com/filecoin-project/lotus/chain/wallet" _ "github.com/filecoin-project/lotus/lib/sigs/bls" + _ "github.com/filecoin-project/lotus/lib/sigs/delegated" _ "github.com/filecoin-project/lotus/lib/sigs/secp" ) diff --git a/chain/vm/fvm.go b/chain/vm/fvm.go index 440470761..8e78e58d9 100644 --- a/chain/vm/fvm.go +++ b/chain/vm/fvm.go @@ -23,6 +23,8 @@ import ( "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/build" @@ -45,6 +47,7 @@ type FvmExtern struct { blockstore.Blockstore epoch abi.ChainEpoch lbState LookbackStateGetter + tsGet TipSetGetter base cid.Cid } @@ -99,6 +102,14 @@ func (t *FvmExecutionTrace) ToExecutionTrace() types.ExecutionTrace { return ret } +func (x *FvmExtern) TipsetCid(ctx context.Context, epoch abi.ChainEpoch) (cid.Cid, error) { + tsk, err := x.tsGet(ctx, epoch) + if err != nil { + return cid.Undef, err + } + return tsk.Cid() +} + // VerifyConsensusFault is similar to the one in syscalls.go used by the Lotus VM, except it never errors // Errors are logged and "no fault" is returned, which is functionally what go-actors does anyway func (x *FvmExtern) VerifyConsensusFault(ctx context.Context, a, b, extra []byte) (*ffi_cgo.ConsensusFault, int64) { @@ -195,14 +206,14 @@ func (x *FvmExtern) VerifyConsensusFault(ctx context.Context, a, b, extra []byte // check blocks are properly signed by their respective miner // note we do not need to check extra's: it is a parent to block b // which itself is signed, so it was willingly included by the miner - gasA, sigErr := x.VerifyBlockSig(ctx, &blockA) + gasA, sigErr := x.verifyBlockSig(ctx, &blockA) totalGas += gasA if sigErr != nil { log.Info("invalid consensus fault: cannot verify first block sig: %w", sigErr) return ret, totalGas } - gas2, sigErr := x.VerifyBlockSig(ctx, &blockB) + gas2, sigErr := x.verifyBlockSig(ctx, &blockB) totalGas += gas2 if sigErr != nil { log.Info("invalid consensus fault: cannot verify second block sig: %w", sigErr) @@ -215,7 +226,7 @@ func (x *FvmExtern) VerifyConsensusFault(ctx context.Context, a, b, extra []byte return ret, totalGas } -func (x *FvmExtern) VerifyBlockSig(ctx context.Context, blk *types.BlockHeader) (int64, error) { +func (x *FvmExtern) verifyBlockSig(ctx context.Context, blk *types.BlockHeader) (int64, error) { waddr, gasUsed, err := x.workerKeyAtLookback(ctx, blk.Miner, blk.Height) if err != nil { return gasUsed, err @@ -265,7 +276,7 @@ func (x *FvmExtern) workerKeyAtLookback(ctx context.Context, minerId address.Add return address.Undef, gasUsed, err } - raddr, err := ResolveToKeyAddr(stateTree, cstWithGas, info.Worker) + raddr, err := ResolveToDeterministicAddr(stateTree, cstWithGas, info.Worker) if err != nil { return address.Undef, gasUsed, err } @@ -275,6 +286,10 @@ func (x *FvmExtern) workerKeyAtLookback(ctx context.Context, minerId address.Add type FVM struct { fvm *ffi.FVM + nv network.Version + + // returnEvents specifies whether to parse and return events when applying messages. + returnEvents bool } func defaultFVMOpts(ctx context.Context, opts *VMOpts) (*ffi.FVMOpts, error) { @@ -294,15 +309,19 @@ func defaultFVMOpts(ctx context.Context, opts *VMOpts) (*ffi.FVMOpts, error) { Rand: opts.Rand, Blockstore: opts.Bstore, lbState: opts.LookbackState, + tsGet: opts.TipSetGetter, base: opts.StateBase, epoch: opts.Epoch, }, Epoch: opts.Epoch, + Timestamp: opts.Timestamp, + ChainID: build.Eip155ChainId, BaseFee: opts.BaseFee, BaseCircSupply: circToReport, NetworkVersion: opts.NetworkVersion, StateBase: opts.StateBase, Tracing: opts.Tracing || EnableDetailedTracing, + Debug: build.ActorDebugging, }, nil } @@ -313,29 +332,19 @@ func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) { return nil, xerrors.Errorf("creating fvm opts: %w", err) } - if os.Getenv("LOTUS_USE_FVM_CUSTOM_BUNDLE") == "1" { - av, err := actorstypes.VersionForNetwork(opts.NetworkVersion) - if err != nil { - return nil, xerrors.Errorf("mapping network version to actors version: %w", err) - } - - c, ok := actors.GetManifest(av) - if !ok { - return nil, xerrors.Errorf("no manifest for custom bundle (actors version %d)", av) - } - - fvmOpts.Manifest = c - } - fvm, err := ffi.CreateFVM(fvmOpts) if err != nil { return nil, xerrors.Errorf("failed to create FVM: %w", err) } - return &FVM{ - fvm: fvm, - }, nil + ret := &FVM{ + fvm: fvm, + nv: opts.NetworkVersion, + returnEvents: opts.ReturnEvents, + } + + return ret, nil } func NewDebugFVM(ctx context.Context, opts *VMOpts) (*FVM, error) { @@ -390,7 +399,7 @@ func NewDebugFVM(ctx context.Context, opts *VMOpts) (*FVM, error) { // create actor redirect mapping actorRedirect := make(map[cid.Cid]cid.Cid) - for _, key := range actors.GetBuiltinActorsKeys(av) { + for _, key := range manifest.GetBuiltinActorsKeys(av) { from, ok := actors.GetActorCodeID(av, key) if !ok { log.Warnf("actor missing in the from manifest %s", key) @@ -435,9 +444,13 @@ func NewDebugFVM(ctx context.Context, opts *VMOpts) (*FVM, error) { return nil, err } - return &FVM{ - fvm: fvm, - }, nil + ret := &FVM{ + fvm: fvm, + nv: opts.NetworkVersion, + returnEvents: opts.ReturnEvents, + } + + return ret, nil } func (vm *FVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, error) { @@ -455,10 +468,12 @@ func (vm *FVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet } duration := time.Since(start) - receipt := types.MessageReceipt{ - Return: ret.Return, - ExitCode: exitcode.ExitCode(ret.ExitCode), - GasUsed: ret.GasUsed, + + var receipt types.MessageReceipt + if vm.nv >= network.Version18 { + receipt = types.NewMessageReceiptV1(exitcode.ExitCode(ret.ExitCode), ret.Return, ret.GasUsed, ret.EventsRoot) + } else { + receipt = types.NewMessageReceiptV0(exitcode.ExitCode(ret.ExitCode), ret.Return, ret.GasUsed) } var aerr aerrors.ActorError @@ -487,7 +502,7 @@ func (vm *FVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet et.Error = aerr.Error() } - return &ApplyRet{ + applyRet := &ApplyRet{ MessageReceipt: receipt, GasCosts: &GasOutputs{ BaseFeeBurn: ret.BaseFeeBurn, @@ -501,7 +516,16 @@ func (vm *FVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet ActorErr: aerr, ExecutionTrace: et, Duration: duration, - }, nil + } + + if vm.returnEvents && len(ret.EventsBytes) > 0 { + applyRet.Events, err = types.DecodeEvents(ret.EventsBytes) + if err != nil { + return nil, fmt.Errorf("failed to decode events returned by the FVM: %w", err) + } + } + + return applyRet, nil } func (vm *FVM) ApplyImplicitMessage(ctx context.Context, cmsg *types.Message) (*ApplyRet, error) { @@ -519,10 +543,12 @@ func (vm *FVM) ApplyImplicitMessage(ctx context.Context, cmsg *types.Message) (* } duration := time.Since(start) - receipt := types.MessageReceipt{ - Return: ret.Return, - ExitCode: exitcode.ExitCode(ret.ExitCode), - GasUsed: ret.GasUsed, + + var receipt types.MessageReceipt + if vm.nv >= network.Version18 { + receipt = types.NewMessageReceiptV1(exitcode.ExitCode(ret.ExitCode), ret.Return, ret.GasUsed, ret.EventsRoot) + } else { + receipt = types.NewMessageReceiptV0(exitcode.ExitCode(ret.ExitCode), ret.Return, ret.GasUsed) } var aerr aerrors.ActorError @@ -557,6 +583,13 @@ func (vm *FVM) ApplyImplicitMessage(ctx context.Context, cmsg *types.Message) (* Duration: duration, } + if vm.returnEvents && len(ret.EventsBytes) > 0 { + applyRet.Events, err = types.DecodeEvents(ret.EventsBytes) + if err != nil { + return nil, fmt.Errorf("failed to decode events returned by the FVM: %w", err) + } + } + if ret.ExitCode != 0 { return applyRet, fmt.Errorf("implicit message failed with exit code: %d and error: %w", ret.ExitCode, applyRet.ActorErr) } diff --git a/chain/vm/gas.go b/chain/vm/gas.go index ca6e5571a..cb0c5def9 100644 --- a/chain/vm/gas.go +++ b/chain/vm/gas.go @@ -111,6 +111,7 @@ var Prices = map[abi.ChainEpoch]Pricelist{ verifySignature: map[crypto.SigType]int64{ crypto.SigTypeBLS: 16598605, crypto.SigTypeSecp256k1: 1637292, + crypto.SigTypeDelegated: 1637292, }, hashingBase: 31355, @@ -212,6 +213,16 @@ var Prices = map[abi.ChainEpoch]Pricelist{ verifyReplicaUpdate: 36316136, }, + build.UpgradeHyggeHeight: &pricelistV0{ + computeGasMulti: 1, + storageGasMulti: 1300, // only applies to messages/return values. + + onChainMessageComputeBase: 38863 + 475000, // includes the actor update cost + onChainMessageStorageBase: 36, + onChainMessageStoragePerByte: 1, + + onChainReturnValuePerByte: 1, + }, } // PricelistByEpoch finds the latest prices for the given epoch diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index bcd81995f..cea17f61d 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -53,7 +53,7 @@ func ActorsVersionPredicate(ver actorstypes.Version) ActorPredicate { } type invokeFunc func(rt vmr.Runtime, params []byte) ([]byte, aerrors.ActorError) -type nativeCode map[uint64]invokeFunc +type nativeCode map[abi.MethodNum]invokeFunc type actorInfo struct { methods nativeCode @@ -78,10 +78,10 @@ func (ar *ActorRegistry) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.Meth if err := act.predicate(rt, codeCid); err != nil { return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "unsupported actor: %s", err) } - if act.methods[uint64(method)] == nil { + if act.methods[method] == nil { return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "no method %d on actor", method) } - return act.methods[uint64(method)](rt, params) + return act.methods[method](rt, params) } @@ -156,7 +156,7 @@ func (ar *ActorRegistry) Register(av actorstypes.Version, pred ActorPredicate, v mm.Params = et.In(0) } - methods[abi.MethodNum(number)] = mm + methods[number] = mm } if realCode.Defined() { ar.Methods[realCode] = methods @@ -185,7 +185,7 @@ func (ar *ActorRegistry) Create(codeCid cid.Cid, rt vmr.Runtime) (*types.Actor, } type invokee interface { - Exports() map[uint64]builtinst.MethodMeta + Exports() map[abi.MethodNum]builtinst.MethodMeta } func (*ActorRegistry) transform(instance invokee) (nativeCode, error) { @@ -284,16 +284,19 @@ func DecodeParams(b []byte, out interface{}) error { } func DumpActorState(i *ActorRegistry, act *types.Actor, b []byte) (interface{}, error) { - if builtin.IsAccountActor(act.Code) { // Account code special case - return nil, nil - } - actInfo, ok := i.actors[act.Code] if !ok { return nil, xerrors.Errorf("state type for actor %s not found", act.Code) } um := actInfo.vmActor.State() + if um == nil { + if act.Head != EmptyObjectCid { + return nil, xerrors.Errorf("actor with code %s should only have empty object (%s) as its Head, instead has %s", act.Code, EmptyObjectCid, act.Head) + } + + return nil, nil + } if err := um.UnmarshalCBOR(bytes.NewReader(b)); err != nil { return nil, xerrors.Errorf("unmarshaling actor state: %w", err) } diff --git a/chain/vm/mkactor.go b/chain/vm/mkactor.go index 3a0ee6699..b33085c05 100644 --- a/chain/vm/mkactor.go +++ b/chain/vm/mkactor.go @@ -89,7 +89,7 @@ func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, add func makeAccountActor(ver actorstypes.Version, addr address.Address) (*types.Actor, aerrors.ActorError) { switch addr.Protocol() { case address.BLS, address.SECP256K1: - return newAccountActor(ver), nil + return newAccountActor(ver, addr), nil case address.ID: return nil, aerrors.Newf(exitcode.SysErrInvalidReceiver, "no actor with given ID: %s", addr) case address.Actor: @@ -99,7 +99,7 @@ func makeAccountActor(ver actorstypes.Version, addr address.Address) (*types.Act } } -func newAccountActor(ver actorstypes.Version) *types.Actor { +func newAccountActor(ver actorstypes.Version, addr address.Address) *types.Actor { // TODO: ActorsUpgrade use a global actor registry? var code cid.Cid switch ver { @@ -124,6 +124,7 @@ func newAccountActor(ver actorstypes.Version) *types.Actor { Code: code, Balance: types.NewInt(0), Head: EmptyObjectCid, + Address: &addr, } return nact diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 05f8de2f0..daa55e4f4 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -168,8 +168,8 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act aerr = ar return } - //log.Desugar().WithOptions(zap.AddStacktrace(zapcore.ErrorLevel)). - //Sugar().Errorf("spec actors failure: %s", r) + // log.Desugar().WithOptions(zap.AddStacktrace(zapcore.ErrorLevel)). + // Sugar().Errorf("spec actors failure: %s", r) log.Errorf("spec actors failure: %s", r) if rt.NetworkVersion() <= network.Version3 { aerr = aerrors.Newf(1, "spec actors failure: %s", r) @@ -249,7 +249,7 @@ func (rt *Runtime) GetRandomnessFromBeacon(personalization crypto.DomainSeparati func (rt *Runtime) NewActorAddress() address.Address { var b bytes.Buffer - oa, _ := ResolveToKeyAddr(rt.vm.cstate, rt.vm.cst, rt.origin) + oa, _ := ResolveToDeterministicAddr(rt.vm.cstate, rt.vm.cst, rt.origin) if err := oa.MarshalCBOR(&b); err != nil { // todo: spec says cbor; why not just bytes? panic(aerrors.Fatalf("writing caller address into a buffer: %v", err)) } diff --git a/chain/vm/syscalls.go b/chain/vm/syscalls.go index f6adc8940..68dbbb2df 100644 --- a/chain/vm/syscalls.go +++ b/chain/vm/syscalls.go @@ -255,7 +255,7 @@ func (ss *syscallShim) workerKeyAtLookback(height abi.ChainEpoch) (address.Addre return address.Undef, err } - return ResolveToKeyAddr(ss.cstate, ss.cst, info.Worker) + return ResolveToDeterministicAddr(ss.cstate, ss.cst, info.Worker) } func (ss *syscallShim) VerifyPoSt(info proof7.WindowPoStVerifyInfo) error { @@ -270,8 +270,8 @@ func (ss *syscallShim) VerifyPoSt(info proof7.WindowPoStVerifyInfo) error { } func (ss *syscallShim) VerifySeal(info proof7.SealVerifyInfo) error { - //_, span := trace.StartSpan(ctx, "ValidatePoRep") - //defer span.End() + // _, span := trace.StartSpan(ctx, "ValidatePoRep") + // defer span.End() miner, err := address.NewIDAddress(uint64(info.Miner)) if err != nil { @@ -284,7 +284,7 @@ func (ss *syscallShim) VerifySeal(info proof7.SealVerifyInfo) error { log.Debugf("Verif r:%s; d:%s; m:%s; t:%x; s:%x; N:%d; p:%x", info.SealedCID, info.UnsealedCID, miner, ticket, seed, info.SectorID.Number, proof) - //func(ctx context.Context, maddr address.Address, ssize abi.SectorSize, commD, commR, ticket, proof, seed []byte, sectorID abi.SectorNumber) + // func(ctx context.Context, maddr address.Address, ssize abi.SectorSize, commD, commR, ticket, proof, seed []byte, sectorID abi.SectorNumber) ok, err := ss.verifier.VerifySeal(info) if err != nil { return xerrors.Errorf("failed to validate PoRep: %w", err) @@ -325,7 +325,7 @@ func (ss *syscallShim) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) erro func (ss *syscallShim) VerifySignature(sig crypto.Signature, addr address.Address, input []byte) error { // TODO: in genesis setup, we are currently faking signatures - kaddr, err := ResolveToKeyAddr(ss.cstate, ss.cst, addr) + kaddr, err := ResolveToDeterministicAddr(ss.cstate, ss.cst, addr) if err != nil { return err } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 669f7e306..f09864c2d 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -7,9 +7,9 @@ import ( "sync/atomic" "time" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" + block "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" mh "github.com/multiformats/go-multihash" cbg "github.com/whyrusleeping/cbor-gen" @@ -45,9 +45,11 @@ var ( gasOnActorExec = newGasCharge("OnActorExec", 0, 0) ) -// ResolveToKeyAddr returns the public key type of address (`BLS`/`SECP256K1`) of an account actor identified by `addr`. -func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, error) { - if addr.Protocol() == address.BLS || addr.Protocol() == address.SECP256K1 { +// ResolveToDeterministicAddr returns the public key type of address +// (`BLS`/`SECP256K1`) of an actor identified by `addr`, or its +// delegated address. +func ResolveToDeterministicAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, error) { + if addr.Protocol() == address.BLS || addr.Protocol() == address.SECP256K1 || addr.Protocol() == address.Delegated { return addr, nil } @@ -56,12 +58,19 @@ func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Ad return address.Undef, xerrors.Errorf("failed to find actor: %s", addr) } + if state.Version() >= types.StateTreeVersion5 { + if act.Address != nil { + // If there _is_ an f4 address, return it as "key" address + return *act.Address, nil + } + } + aast, err := account.Load(adt.WrapStore(context.TODO(), cst), act) if err != nil { return address.Undef, xerrors.Errorf("failed to get account actor state for %s: %w", addr, err) } - return aast.PubkeyAddress() + } var ( @@ -192,6 +201,7 @@ type ( CircSupplyCalculator func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error) NtwkVersionGetter func(context.Context, abi.ChainEpoch) network.Version LookbackStateGetter func(context.Context, abi.ChainEpoch) (*state.StateTree, error) + TipSetGetter func(context.Context, abi.ChainEpoch) (types.TipSetKey, error) ) var _ Interface = (*LegacyVM)(nil) @@ -215,6 +225,7 @@ type LegacyVM struct { type VMOpts struct { StateBase cid.Cid Epoch abi.ChainEpoch + Timestamp uint64 Rand Rand Bstore blockstore.Blockstore Actors *ActorRegistry @@ -223,7 +234,10 @@ type VMOpts struct { NetworkVersion network.Version BaseFee abi.TokenAmount LookbackState LookbackStateGetter + TipSetGetter TipSetGetter Tracing bool + // ReturnEvents decodes and returns emitted events. + ReturnEvents bool } func NewLegacyVM(ctx context.Context, opts *VMOpts) (*LegacyVM, error) { @@ -270,6 +284,7 @@ type ApplyRet struct { ExecutionTrace types.ExecutionTrace Duration time.Duration GasCosts *GasOutputs + Events []types.Event } func (vm *LegacyVM) send(ctx context.Context, msg *types.Message, parent *Runtime, diff --git a/chain/wallet/key/key.go b/chain/wallet/key/key.go index 66053525b..422066610 100644 --- a/chain/wallet/key/key.go +++ b/chain/wallet/key/key.go @@ -7,6 +7,7 @@ import ( "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/lib/sigs" ) @@ -50,6 +51,22 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) { if err != nil { return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err) } + case types.KTDelegated: + // Transitory Delegated signature verification as per FIP-0055 + ethAddr, err := ethtypes.EthAddressFromPubKey(k.PublicKey) + if err != nil { + return nil, xerrors.Errorf("failed to calculate Eth address from public key: %w", err) + } + + ea, err := ethtypes.CastEthAddress(ethAddr) + if err != nil { + return nil, xerrors.Errorf("failed to create ethereum address from bytes: %w", err) + } + + k.Address, err = ea.ToFilecoinAddress() + if err != nil { + return nil, xerrors.Errorf("converting Delegated to address: %w", err) + } case types.KTBLS: k.Address, err = address.NewBLSAddress(k.PublicKey) if err != nil { @@ -58,6 +75,7 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) { default: return nil, xerrors.Errorf("unsupported key type: %s", k.Type) } + return k, nil } @@ -68,6 +86,8 @@ func ActSigType(typ types.KeyType) crypto.SigType { return crypto.SigTypeBLS case types.KTSecp256k1: return crypto.SigTypeSecp256k1 + case types.KTDelegated: + return crypto.SigTypeDelegated default: return crypto.SigTypeUnknown } diff --git a/chain/wallet/multi.go b/chain/wallet/multi.go index a88475c2e..91d271477 100644 --- a/chain/wallet/multi.go +++ b/chain/wallet/multi.go @@ -120,22 +120,22 @@ func (m MultiWallet) WalletSign(ctx context.Context, signer address.Address, toS return nil, err } if w == nil { - return nil, xerrors.Errorf("key not found") + return nil, xerrors.Errorf("key not found for %s", signer) } return w.WalletSign(ctx, signer, toSign, meta) } -func (m MultiWallet) WalletExport(ctx context.Context, address address.Address) (*types.KeyInfo, error) { - w, err := m.find(ctx, address, m.Remote, m.Local) +func (m MultiWallet) WalletExport(ctx context.Context, addr address.Address) (*types.KeyInfo, error) { + w, err := m.find(ctx, addr, m.Remote, m.Local) if err != nil { return nil, err } if w == nil { - return nil, xerrors.Errorf("key not found") + return nil, xerrors.Errorf("key not found for %s", addr) } - return w.WalletExport(ctx, address) + return w.WalletExport(ctx, addr) } func (m MultiWallet) WalletImport(ctx context.Context, info *types.KeyInfo) (address.Address, error) { diff --git a/chain/wallet/wallet.go b/chain/wallet/wallet.go index b88d776b5..76af663c7 100644 --- a/chain/wallet/wallet.go +++ b/chain/wallet/wallet.go @@ -16,7 +16,8 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet/key" "github.com/filecoin-project/lotus/lib/sigs" - _ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures + _ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures + _ "github.com/filecoin-project/lotus/lib/sigs/delegated" _ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures ) @@ -140,7 +141,7 @@ func (w *LocalWallet) WalletExport(ctx context.Context, addr address.Address) (* return nil, xerrors.Errorf("failed to find key to export: %w", err) } if k == nil { - return nil, xerrors.Errorf("key not found") + return nil, xerrors.Errorf("key not found for %s", addr) } return &k.KeyInfo, nil diff --git a/cli/chain.go b/cli/chain.go index 296b4dc70..57316d22d 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -149,7 +149,7 @@ var ChainGetBlock = &cli.Command{ recpts, err := api.ChainGetParentReceipts(ctx, bcid) if err != nil { log.Warn(err) - //return xerrors.Errorf("failed to get receipts: %w", err) + // return xerrors.Errorf("failed to get receipts: %w", err) } cblock := struct { @@ -1478,11 +1478,6 @@ var ChainPruneCmd = &cli.Command{ Value: false, Usage: "use moving gc for garbage collecting the coldstore", }, - &cli.StringFlag{ - Name: "move-to", - Value: "", - Usage: "specify new path for coldstore during moving gc", - }, &cli.IntFlag{ Name: "retention", Value: -1, diff --git a/cli/client.go b/cli/client.go index 377505363..a8355f9a1 100644 --- a/cli/client.go +++ b/cli/client.go @@ -627,7 +627,13 @@ uiLoop: minDealDurationDays := uint64(build.MinDealDuration) / (builtin.SecondsInDay / build.BlockDelaySecs) if days < int(minDealDurationDays) { - printErr(xerrors.Errorf("minimum duration is %d days", minDealDurationDays)) + printErr(xerrors.Errorf("minimum duration is %d days, got %d", minDealDurationDays, days)) + continue + } + + maxDealDurationDays := uint64(build.MaxDealDuration) / (builtin.SecondsInDay / build.BlockDelaySecs) + if days > int(maxDealDurationDays) { + printErr(xerrors.Errorf("maximum duration is %d days, got %d", maxDealDurationDays, days)) continue } @@ -1511,6 +1517,8 @@ func GetAsks(ctx context.Context, api lapi.FullNode) ([]QueriedAsk, error) { } }(miner) } + + wg.Wait() }() loop: @@ -1584,6 +1592,8 @@ loop: lk.Unlock() }(miner) } + + wg.Wait() }() loop2: diff --git a/cli/cmd.go b/cli/cmd.go index 79023917b..802df0c99 100644 --- a/cli/cmd.go +++ b/cli/cmd.go @@ -81,6 +81,7 @@ var Commands = []*cli.Command{ WithCategory("developer", LogCmd), WithCategory("developer", WaitApiCmd), WithCategory("developer", FetchParamCmd), + WithCategory("developer", EvmCmd), WithCategory("network", NetCmd), WithCategory("network", SyncCmd), WithCategory("status", StatusCmd), diff --git a/cli/evm.go b/cli/evm.go new file mode 100644 index 000000000..d153e7212 --- /dev/null +++ b/cli/evm.go @@ -0,0 +1,488 @@ +package cli + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/hex" + "fmt" + "os" + + "github.com/urfave/cli/v2" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + amt4 "github.com/filecoin-project/go-amt-ipld/v4" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + builtintypes "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/builtin/v10/eam" + + "github.com/filecoin-project/lotus/api/v0api" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" +) + +var EvmCmd = &cli.Command{ + Name: "evm", + Usage: "Commands related to the Filecoin EVM runtime", + Subcommands: []*cli.Command{ + EvmDeployCmd, + EvmInvokeCmd, + EvmGetInfoCmd, + EvmCallSimulateCmd, + EvmGetContractAddress, + }, +} + +var EvmGetInfoCmd = &cli.Command{ + Name: "stat", + Usage: "Print eth/filecoin addrs and code cid", + ArgsUsage: "address", + Action: func(cctx *cli.Context) error { + if cctx.NArg() != 1 { + return IncorrectNumArgs(cctx) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + addrString := cctx.Args().Get(0) + + var faddr address.Address + var eaddr ethtypes.EthAddress + addr, err := address.NewFromString(addrString) + if err != nil { // This isn't a filecoin address + eaddr, err = ethtypes.ParseEthAddress(addrString) + if err != nil { // This isn't an Eth address either + return xerrors.Errorf("address is not a filecoin or eth address") + } + faddr, err = eaddr.ToFilecoinAddress() + if err != nil { + return err + } + } else { + eaddr, faddr, err = ethAddrFromFilecoinAddress(ctx, addr, api) + if err != nil { + return err + } + } + + actor, err := api.StateGetActor(ctx, faddr, types.EmptyTSK) + fmt.Println("Filecoin address: ", faddr) + fmt.Println("Eth address: ", eaddr) + if err != nil { + fmt.Printf("Actor lookup failed for faddr %s with error: %s\n", faddr, err) + } else { + idAddr, err := api.StateLookupID(ctx, faddr, types.EmptyTSK) + if err == nil { + fmt.Println("ID address: ", idAddr) + fmt.Println("Code cid: ", actor.Code.String()) + fmt.Println("Actor Type: ", builtin.ActorNameByCode(actor.Code)) + } + } + + return nil + }, +} + +var EvmCallSimulateCmd = &cli.Command{ + Name: "call", + Usage: "Simulate an eth contract call", + ArgsUsage: "[from] [to] [params]", + Action: func(cctx *cli.Context) error { + + if cctx.NArg() != 3 { + return IncorrectNumArgs(cctx) + } + + fromEthAddr, err := ethtypes.ParseEthAddress(cctx.Args().Get(0)) + if err != nil { + return err + } + + toEthAddr, err := ethtypes.ParseEthAddress(cctx.Args().Get(1)) + if err != nil { + return err + } + + params, err := ethtypes.DecodeHexStringTrimSpace(cctx.Args().Get(2)) + if err != nil { + return err + } + + api, closer, err := GetFullNodeAPIV1(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + res, err := api.EthCall(ctx, ethtypes.EthCall{ + From: &fromEthAddr, + To: &toEthAddr, + Data: params, + }, "") + if err != nil { + fmt.Println("Eth call fails, return val: ", res) + return err + } + + fmt.Println("Result: ", res) + + return nil + + }, +} + +var EvmGetContractAddress = &cli.Command{ + Name: "contract-address", + Usage: "Generate contract address from smart contract code", + ArgsUsage: "[senderEthAddr] [salt] [contractHexPath]", + Action: func(cctx *cli.Context) error { + + if cctx.NArg() != 3 { + return IncorrectNumArgs(cctx) + } + + sender, err := ethtypes.ParseEthAddress(cctx.Args().Get(0)) + if err != nil { + return err + } + + salt, err := ethtypes.DecodeHexStringTrimSpace(cctx.Args().Get(1)) + if err != nil { + return xerrors.Errorf("Could not decode salt: %w", err) + } + if len(salt) > 32 { + return xerrors.Errorf("Len of salt bytes greater than 32") + } + var fsalt [32]byte + copy(fsalt[:], salt[:]) + + contractBin := cctx.Args().Get(2) + if err != nil { + return err + } + contractHex, err := os.ReadFile(contractBin) + if err != nil { + + return err + } + contract, err := ethtypes.DecodeHexStringTrimSpace(string(contractHex)) + if err != nil { + return xerrors.Errorf("Could not decode contract file: %w", err) + } + + contractAddr, err := ethtypes.GetContractEthAddressFromCode(sender, fsalt, contract) + if err != nil { + return err + } + + fmt.Println("Contract Eth address: ", contractAddr) + + return nil + }, +} + +var EvmDeployCmd = &cli.Command{ + Name: "deploy", + Usage: "Deploy an EVM smart contract and return its address", + ArgsUsage: "contract", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "optionally specify the account to use for sending the creation message", + }, + &cli.BoolFlag{ + Name: "hex", + Usage: "use when input contract is in hex", + }, + }, + Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if argc := cctx.Args().Len(); argc != 1 { + return xerrors.Errorf("must pass the contract init code") + } + + contract, err := os.ReadFile(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("failed to read contract: %w", err) + } + if cctx.Bool("hex") { + contract, err = ethtypes.DecodeHexStringTrimSpace(string(contract)) + if err != nil { + return xerrors.Errorf("failed to decode contract: %w", err) + } + } + + var fromAddr address.Address + if from := cctx.String("from"); from == "" { + fromAddr, err = api.WalletDefaultAddress(ctx) + } else { + fromAddr, err = address.NewFromString(from) + } + if err != nil { + return err + } + + initcode := abi.CborBytes(contract) + params, err := actors.SerializeParams(&initcode) + if err != nil { + return fmt.Errorf("failed to serialize Create params: %w", err) + } + + msg := &types.Message{ + To: builtintypes.EthereumAddressManagerActorAddr, + From: fromAddr, + Value: big.Zero(), + Method: builtintypes.MethodsEAM.CreateExternal, + Params: params, + } + + // TODO: On Jan 11th, we decided to add an `EAM#create_external` method + // that uses the nonce of the caller instead of taking a user-supplied nonce. + // Track: https://github.com/filecoin-project/ref-fvm/issues/1255 + // When that's implemented, we should migrate the CLI to use that, + // as `EAM#create` will be reserved for the EVM runtime actor. + // TODO: this is very racy. It may assign a _different_ nonce than the expected one. + afmt.Println("sending message...") + smsg, err := api.MpoolPushMessage(ctx, msg, nil) + if err != nil { + return xerrors.Errorf("failed to push message: %w", err) + } + + afmt.Println("waiting for message to execute...") + wait, err := api.StateWaitMsg(ctx, smsg.Cid(), 0) + if err != nil { + return xerrors.Errorf("error waiting for message: %w", err) + } + + // check it executed successfully + if wait.Receipt.ExitCode != 0 { + return xerrors.Errorf("actor execution failed") + } + + var result eam.CreateReturn + r := bytes.NewReader(wait.Receipt.Return) + if err := result.UnmarshalCBOR(r); err != nil { + return xerrors.Errorf("error unmarshaling return value: %w", err) + } + + addr, err := address.NewIDAddress(result.ActorID) + if err != nil { + return err + } + afmt.Printf("Actor ID: %d\n", result.ActorID) + afmt.Printf("ID Address: %s\n", addr) + afmt.Printf("Robust Address: %s\n", result.RobustAddress) + afmt.Printf("Eth Address: %s\n", "0x"+hex.EncodeToString(result.EthAddress[:])) + + ea, err := ethtypes.CastEthAddress(result.EthAddress[:]) + if err != nil { + return fmt.Errorf("failed to create ethereum address: %w", err) + } + + delegated, err := ea.ToFilecoinAddress() + if err != nil { + return fmt.Errorf("failed to calculate f4 address: %w", err) + } + + afmt.Printf("f4 Address: %s\n", delegated) + + if len(wait.Receipt.Return) > 0 { + result := base64.StdEncoding.EncodeToString(wait.Receipt.Return) + afmt.Printf("Return: %s\n", result) + } + + return nil + }, +} + +var EvmInvokeCmd = &cli.Command{ + Name: "invoke", + Usage: "Invoke an EVM smart contract using the specified CALLDATA", + ArgsUsage: "address calldata", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "optionally specify the account to use for sending the exec message", + }, &cli.IntFlag{ + Name: "value", + Usage: "optionally specify the value to be sent with the invokation message", + }, + }, + Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if argc := cctx.Args().Len(); argc != 2 { + return xerrors.Errorf("must pass the address and calldata") + } + + addr, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return xerrors.Errorf("failed to decode address: %w", err) + } + + var calldata []byte + calldata, err = ethtypes.DecodeHexStringTrimSpace(cctx.Args().Get(1)) + if err != nil { + return xerrors.Errorf("decoding hex input data: %w", err) + } + + var buffer bytes.Buffer + if err := cbg.WriteByteArray(&buffer, calldata); err != nil { + return xerrors.Errorf("failed to encode evm params as cbor: %w", err) + } + calldata = buffer.Bytes() + + var fromAddr address.Address + if from := cctx.String("from"); from == "" { + defaddr, err := api.WalletDefaultAddress(ctx) + if err != nil { + return err + } + + fromAddr = defaddr + } else { + addr, err := address.NewFromString(from) + if err != nil { + return err + } + + fromAddr = addr + } + + val := abi.NewTokenAmount(cctx.Int64("value")) + msg := &types.Message{ + To: addr, + From: fromAddr, + Value: val, + Method: builtintypes.MethodsEVM.InvokeContract, + Params: calldata, + } + + afmt.Println("sending message...") + smsg, err := api.MpoolPushMessage(ctx, msg, nil) + if err != nil { + return xerrors.Errorf("failed to push message: %w", err) + } + + afmt.Println("waiting for message to execute...") + wait, err := api.StateWaitMsg(ctx, smsg.Cid(), 0) + if err != nil { + return xerrors.Errorf("error waiting for message: %w", err) + } + + // check it executed successfully + if wait.Receipt.ExitCode != 0 { + return xerrors.Errorf("actor execution failed") + } + + afmt.Println("Gas used: ", wait.Receipt.GasUsed) + result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return))) + if err != nil { + return xerrors.Errorf("evm result not correctly encoded: %w", err) + } + + if len(result) > 0 { + afmt.Println(hex.EncodeToString(result)) + } else { + afmt.Println("OK") + } + + if eventsRoot := wait.Receipt.EventsRoot; eventsRoot != nil { + afmt.Println("Events emitted:") + + s := &apiIpldStore{ctx, api} + amt, err := amt4.LoadAMT(ctx, s, *eventsRoot, amt4.UseTreeBitWidth(types.EventAMTBitwidth)) + if err != nil { + return err + } + + var evt types.Event + err = amt.ForEach(ctx, func(u uint64, deferred *cbg.Deferred) error { + fmt.Printf("%x\n", deferred.Raw) + if err := evt.UnmarshalCBOR(bytes.NewReader(deferred.Raw)); err != nil { + return err + } + if err != nil { + return err + } + fmt.Printf("\tEmitter ID: %s\n", evt.Emitter) + for _, e := range evt.Entries { + value, err := cbg.ReadByteArray(bytes.NewBuffer(e.Value), uint64(len(e.Value))) + if err != nil { + return err + } + fmt.Printf("\t\tKey: %s, Value: 0x%x, Flags: b%b\n", e.Key, value, e.Flags) + } + return nil + + }) + } + if err != nil { + return err + } + + return nil + }, +} + +func ethAddrFromFilecoinAddress(ctx context.Context, addr address.Address, fnapi v0api.FullNode) (ethtypes.EthAddress, address.Address, error) { + var faddr address.Address + var err error + + switch addr.Protocol() { + case address.BLS, address.SECP256K1: + faddr, err = fnapi.StateLookupID(ctx, addr, types.EmptyTSK) + if err != nil { + return ethtypes.EthAddress{}, addr, err + } + case address.Actor, address.ID: + faddr, err = fnapi.StateLookupID(ctx, addr, types.EmptyTSK) + if err != nil { + return ethtypes.EthAddress{}, addr, err + } + fAct, err := fnapi.StateGetActor(ctx, faddr, types.EmptyTSK) + if err != nil { + return ethtypes.EthAddress{}, addr, err + } + if fAct.Address != nil && (*fAct.Address).Protocol() == address.Delegated { + faddr = *fAct.Address + } + case address.Delegated: + faddr = addr + default: + return ethtypes.EthAddress{}, addr, xerrors.Errorf("Filecoin address doesn't match known protocols") + } + + ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(faddr) + if err != nil { + return ethtypes.EthAddress{}, addr, err + } + + return ethAddr, faddr, nil +} diff --git a/cli/helper.go b/cli/helper.go index c4a61397c..81a5bb033 100644 --- a/cli/helper.go +++ b/cli/helper.go @@ -4,6 +4,8 @@ import ( "fmt" "io" "os" + "os/signal" + "syscall" ufcli "github.com/urfave/cli/v2" "golang.org/x/xerrors" @@ -36,6 +38,13 @@ func IncorrectNumArgs(cctx *ufcli.Context) error { } func RunApp(app *ufcli.App) { + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGTERM, syscall.SIGINT) + go func() { + <-c + os.Exit(1) + }() + if err := app.Run(os.Args); err != nil { if os.Getenv("LOTUS_DEV") != "" { log.Warnf("%+v", err) diff --git a/cli/send.go b/cli/send.go index 4268f8eb2..cfa2515c0 100644 --- a/cli/send.go +++ b/cli/send.go @@ -1,18 +1,22 @@ package cli import ( + "bytes" "encoding/hex" "fmt" "strings" "github.com/urfave/cli/v2" + cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + builtintypes "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" ) var sendCmd = &cli.Command{ @@ -24,6 +28,10 @@ var sendCmd = &cli.Command{ Name: "from", Usage: "optionally specify the account to send funds from", }, + &cli.StringFlag{ + Name: "from-eth-addr", + Usage: "optionally specify the eth addr to send funds from", + }, &cli.StringFlag{ Name: "gas-premium", Usage: "specify gas price to use in AttoFIL", @@ -98,6 +106,65 @@ var sendCmd = &cli.Command{ } params.From = addr + } else if from := cctx.String("from-eth-addr"); from != "" { + eaddr, err := ethtypes.ParseEthAddress(from) + if err != nil { + return err + } + faddr, err := eaddr.ToFilecoinAddress() + if err != nil { + fmt.Println("error on conversion to faddr") + return err + } + fmt.Println("f4 addr: ", faddr) + params.From = faddr + } + + if cctx.IsSet("params-hex") { + decparams, err := hex.DecodeString(cctx.String("params-hex")) + if err != nil { + return fmt.Errorf("failed to decode hex params: %w", err) + } + params.Params = decparams + } + + if ethtypes.IsEthAddress(params.From) { + // Method numbers don't make sense from eth accounts. + if cctx.IsSet("method") { + return xerrors.Errorf("messages from f410f addresses may not specify a method number") + } + + // Now, figure out the correct method number from the recipient. + if params.To == builtintypes.EthereumAddressManagerActorAddr { + params.Method = builtintypes.MethodsEAM.CreateExternal + } else { + params.Method = builtintypes.MethodsEVM.InvokeContract + } + + if cctx.IsSet("params-json") { + return xerrors.Errorf("may not call with json parameters from an eth account") + } + + // And format the parameters, if present. + if len(params.Params) > 0 { + var buf bytes.Buffer + if err := cbg.WriteByteArray(&buf, params.Params); err != nil { + return xerrors.Errorf("failed to marshal EVM parameters") + } + params.Params = buf.Bytes() + } + + // We can only send to an f410f or f0 address. + if !(params.To.Protocol() == address.ID || params.To.Protocol() == address.Delegated) { + api := srv.FullNodeAPI() + // Resolve id addr if possible. + params.To, err = api.StateLookupID(ctx, params.To, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("addresses starting with f410f can only send to other addresses starting with f410f, or id addresses. could not find id address for %s", params.To.String()) + } + } + } else { + params.Method = abi.MethodNum(cctx.Uint64("method")) } if cctx.IsSet("gas-premium") { @@ -121,22 +188,13 @@ var sendCmd = &cli.Command{ params.GasLimit = &limit } - params.Method = abi.MethodNum(cctx.Uint64("method")) - if cctx.IsSet("params-json") { - decparams, err := srv.DecodeTypedParamsFromJSON(ctx, params.To, params.Method, cctx.String("params-json")) - if err != nil { - return fmt.Errorf("failed to decode json params: %w", err) - } - params.Params = decparams - } - if cctx.IsSet("params-hex") { if params.Params != nil { return fmt.Errorf("can only specify one of 'params-json' and 'params-hex'") } - decparams, err := hex.DecodeString(cctx.String("params-hex")) + decparams, err := srv.DecodeTypedParamsFromJSON(ctx, params.To, params.Method, cctx.String("params-json")) if err != nil { - return fmt.Errorf("failed to decode hex params: %w", err) + return fmt.Errorf("failed to decode json params: %w", err) } params.Params = decparams } diff --git a/cli/send_test.go b/cli/send_test.go index ec858774c..2c59a9641 100644 --- a/cli/send_test.go +++ b/cli/send_test.go @@ -7,14 +7,16 @@ import ( "testing" "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ucli "github.com/urfave/cli/v2" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" ) func mustAddr(a address.Address, err error) address.Address { @@ -65,7 +67,51 @@ func TestSendCLI(t *testing.T) { mockSrvcs.EXPECT().Close(), ) err := app.Run([]string{"lotus", "send", "t01", "1"}) - assert.NoError(t, err) - assert.EqualValues(t, sigMsg.Cid().String()+"\n", buf.String()) + require.NoError(t, err) + require.EqualValues(t, sigMsg.Cid().String()+"\n", buf.String()) + }) +} + +func TestSendEthereum(t *testing.T) { + oneFil := abi.TokenAmount(types.MustParseFIL("1")) + + t.Run("simple", func(t *testing.T) { + app, mockSrvcs, buf, done := newMockApp(t, sendCmd) + defer done() + + testEthAddr, err := ethtypes.CastEthAddress(make([]byte, 20)) + require.NoError(t, err) + testAddr := mustAddr(testEthAddr.ToFilecoinAddress()) + + params := abi.CborBytes([]byte{1, 2, 3, 4}) + var paramsBuf bytes.Buffer + require.NoError(t, params.MarshalCBOR(¶msBuf)) + + arbtProto := &api.MessagePrototype{ + Message: types.Message{ + From: testAddr, + To: mustAddr(address.NewIDAddress(1)), + Value: oneFil, + Method: builtin.MethodsEVM.InvokeContract, + Params: paramsBuf.Bytes(), + }, + } + sigMsg := fakeSign(&arbtProto.Message) + + gomock.InOrder( + mockSrvcs.EXPECT().MessageForSend(gomock.Any(), SendParams{ + From: testAddr, + To: mustAddr(address.NewIDAddress(1)), + Val: oneFil, + Method: builtin.MethodsEVM.InvokeContract, + Params: paramsBuf.Bytes(), + }).Return(arbtProto, nil), + mockSrvcs.EXPECT().PublishMessage(gomock.Any(), arbtProto, false). + Return(sigMsg, nil, nil), + mockSrvcs.EXPECT().Close(), + ) + err = app.Run([]string{"lotus", "send", "--from-eth-addr", testEthAddr.String(), "--params-hex", "01020304", "f01", "1"}) + require.NoError(t, err) + require.EqualValues(t, sigMsg.Cid().String()+"\n", buf.String()) }) } diff --git a/cli/state.go b/cli/state.go index cd134b49d..3d629bb0b 100644 --- a/cli/state.go +++ b/cli/state.go @@ -776,6 +776,9 @@ var StateGetActorCmd = &cli.Command{ fmt.Printf("Nonce:\t\t%d\n", a.Nonce) fmt.Printf("Code:\t\t%s (%s)\n", a.Code, strtype) fmt.Printf("Head:\t\t%s\n", a.Head) + if a.Address != nil { + fmt.Printf("Delegated address:\t\t%s\n", a.Address) + } return nil }, @@ -1321,7 +1324,7 @@ var compStateMsg = ` {{end}} {{end}} - {{with SumGas .GasCharges}} + {{with sumGas .GasCharges}} Sum {{template "gasC" .}} {{if PrintTiming}}{{.TimeTaken}}{{end}} @@ -1351,11 +1354,11 @@ func ComputeStateHTMLTempl(w io.Writer, ts *types.TipSet, o *api.ComputeStateOut "GetMethod": getMethod, "ToFil": toFil, "JsonParams": JsonParams, - "JsonReturn": jsonReturn, + "JsonReturn": JsonReturn, "IsSlow": isSlow, "IsVerySlow": isVerySlow, "IntExit": func(i exitcode.ExitCode) int64 { return int64(i) }, - "SumGas": sumGas, + "sumGas": types.SumGas, "CodeStr": codeStr, "Call": call, "PrintTiming": func() bool { return printTiming }, @@ -1423,21 +1426,6 @@ func isVerySlow(t time.Duration) bool { return t > 50*time.Millisecond } -func sumGas(changes []*types.GasTrace) types.GasTrace { - var out types.GasTrace - for _, gc := range changes { - out.TotalGas += gc.TotalGas - out.ComputeGas += gc.ComputeGas - out.StorageGas += gc.StorageGas - - out.TotalVirtualGas += gc.TotalVirtualGas - out.VirtualComputeGas += gc.VirtualComputeGas - out.VirtualStorageGas += gc.VirtualStorageGas - } - - return out -} - func JsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) { p, err := stmgr.GetParamType(filcns.NewActorRegistry(), code, method) // todo use api for correct actor registry if err != nil { @@ -1452,7 +1440,7 @@ func JsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, erro return string(b), err } -func jsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) { +func JsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) { methodMeta, found := filcns.NewActorRegistry().Methods[code][method] // TODO: use remote if !found { return "", fmt.Errorf("method %d not found on actor %s", method, code) @@ -1561,7 +1549,7 @@ func printReceiptReturn(ctx context.Context, api v0api.FullNode, m *types.Messag return err } - jret, err := jsonReturn(act.Code, m.Method, r.Return) + jret, err := JsonReturn(act.Code, m.Method, r.Return) if err != nil { return err } @@ -1701,7 +1689,7 @@ var StateCallCmd = &cli.Command{ return xerrors.Errorf("getting actor: %w", err) } - retStr, err := jsonReturn(act.Code, abi.MethodNum(method), ret.MsgRct.Return) + retStr, err := JsonReturn(act.Code, abi.MethodNum(method), ret.MsgRct.Return) if err != nil { return xerrors.Errorf("decoding return: %w", err) } diff --git a/cli/util/api.go b/cli/util/api.go index 596322ab8..1d6928c3f 100644 --- a/cli/util/api.go +++ b/cli/util/api.go @@ -274,7 +274,7 @@ func FullNodeProxy[T api.FullNode](ins []T, outstr *api.FullNodeStruct) { } total := len(rins) - result, err := retry.Retry(ctx, 5, initialBackoff, errorsToRetry, func() (results []reflect.Value, err2 error) { + result, _ := retry.Retry(ctx, 5, initialBackoff, errorsToRetry, func() ([]reflect.Value, error) { curr = (curr + 1) % total result := fns[curr].Call(args) @@ -319,11 +319,33 @@ func GetFullNodeAPIV1Single(ctx *cli.Context) (v1api.FullNode, jsonrpc.ClientClo return v1API, closer, nil } -func GetFullNodeAPIV1(ctx *cli.Context) (v1api.FullNode, jsonrpc.ClientCloser, error) { +type GetFullNodeOptions struct { + ethSubHandler api.EthSubscriber +} + +type GetFullNodeOption func(*GetFullNodeOptions) + +func FullNodeWithEthSubscribtionHandler(sh api.EthSubscriber) GetFullNodeOption { + return func(opts *GetFullNodeOptions) { + opts.ethSubHandler = sh + } +} + +func GetFullNodeAPIV1(ctx *cli.Context, opts ...GetFullNodeOption) (v1api.FullNode, jsonrpc.ClientCloser, error) { if tn, ok := ctx.App.Metadata["testnode-full"]; ok { return tn.(v1api.FullNode), func() {}, nil } + var options GetFullNodeOptions + for _, opt := range opts { + opt(&options) + } + + var rpcOpts []jsonrpc.Option + if options.ethSubHandler != nil { + rpcOpts = append(rpcOpts, jsonrpc.WithClientHandler("Filecoin", options.ethSubHandler), jsonrpc.WithClientHandlerAlias("eth_subscription", "Filecoin.EthSubscription")) + } + heads, err := GetRawAPIMulti(ctx, repo.FullNode, "v1") if err != nil { return nil, nil, err @@ -337,7 +359,7 @@ func GetFullNodeAPIV1(ctx *cli.Context) (v1api.FullNode, jsonrpc.ClientCloser, e var closers []jsonrpc.ClientCloser for _, head := range heads { - v1api, closer, err := client.NewFullNodeRPCV1(ctx.Context, head.addr, head.header) + v1api, closer, err := client.NewFullNodeRPCV1(ctx.Context, head.addr, head.header, rpcOpts...) if err != nil { log.Warnf("Not able to establish connection to node with addr: ", head.addr) continue diff --git a/cmd/lotus-bench/import.go b/cmd/lotus-bench/import.go index ce0b8d86e..13824d07d 100644 --- a/cmd/lotus-bench/import.go +++ b/cmd/lotus-bench/import.go @@ -41,6 +41,7 @@ import ( "github.com/filecoin-project/lotus/chain/vm" lcli "github.com/filecoin-project/lotus/cli" _ "github.com/filecoin-project/lotus/lib/sigs/bls" + _ "github.com/filecoin-project/lotus/lib/sigs/delegated" _ "github.com/filecoin-project/lotus/lib/sigs/secp" "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/storage/sealer/ffiwrapper" @@ -149,7 +150,7 @@ var importBenchCmd = &cli.Command{ http.Handle("/debug/metrics", exporter) - http.ListenAndServe("localhost:6060", nil) //nolint:errcheck + _ = http.ListenAndServe("localhost:6060", nil) }() var tdir string @@ -771,7 +772,7 @@ var importAnalyzeCmd = &cli.Command{ } go func() { - http.ListenAndServe("localhost:6060", nil) //nolint:errcheck + _ = http.ListenAndServe("localhost:6060", nil) }() fi, err := os.Open(cctx.Args().First()) diff --git a/cmd/lotus-bench/main.go b/cmd/lotus-bench/main.go index d7b9b0409..279f2d5fd 100644 --- a/cmd/lotus-bench/main.go +++ b/cmd/lotus-bench/main.go @@ -468,7 +468,7 @@ var sealBenchCmd = &cli.Command{ } bo.EnvVar = make(map[string]string) - for _, envKey := range []string{"BELLMAN_NO_GPU", "FIL_PROOFS_MAXIMIZE_CACHING", "FIL_PROOFS_USE_GPU_COLUMN_BUILDER", + for _, envKey := range []string{"BELLMAN_NO_GPU", "FIL_PROOFS_USE_GPU_COLUMN_BUILDER", "FIL_PROOFS_USE_GPU_TREE_BUILDER", "FIL_PROOFS_USE_MULTICORE_SDR", "BELLMAN_CUSTOM_GPU"} { envValue, found := os.LookupEnv(envKey) if found { diff --git a/cmd/lotus-fountain/main.go b/cmd/lotus-fountain/main.go index 059c248f6..780aef916 100644 --- a/cmd/lotus-fountain/main.go +++ b/cmd/lotus-fountain/main.go @@ -74,6 +74,10 @@ var runCmd = &cli.Command{ Name: "captcha-threshold", Value: 0.5, }, + &cli.StringFlag{ + Name: "http-server-timeout", + Value: "30s", + }, }, Action: func(cctx *cli.Context) error { sendPerRequest, err := types.ParseFIL(cctx.String("amount")) @@ -127,7 +131,17 @@ var runCmd = &cli.Command{ os.Exit(0) }() - return http.ListenAndServe(cctx.String("front"), nil) + timeout, err := time.ParseDuration(cctx.String("http-server-timeout")) + if err != nil { + return xerrors.Errorf("invalid time string %s: %x", cctx.String("http-server-timeout"), err) + } + + server := &http.Server{ + Addr: cctx.String("front"), + ReadHeaderTimeout: timeout, + } + + return server.ListenAndServe() }, } diff --git a/cmd/lotus-gateway/main.go b/cmd/lotus-gateway/main.go index 89b2152dd..2023551ef 100644 --- a/cmd/lotus-gateway/main.go +++ b/cmd/lotus-gateway/main.go @@ -162,7 +162,9 @@ var runCmd = &cli.Command{ log.Fatalf("Cannot register the view: %v", err) } - api, closer, err := lcli.GetFullNodeAPIV1(cctx) + subHnd := gateway.NewEthSubHandler() + + api, closer, err := lcli.GetFullNodeAPIV1(cctx, cliutil.FullNodeWithEthSubscribtionHandler(subHnd)) if err != nil { return err } @@ -195,7 +197,7 @@ var runCmd = &cli.Command{ return xerrors.Errorf("failed to convert endpoint address to multiaddr: %w", err) } - gwapi := gateway.NewNode(api, lookbackCap, waitLookback, rateLimit, rateLimitTimeout) + gwapi := gateway.NewNode(api, subHnd, lookbackCap, waitLookback, rateLimit, rateLimitTimeout) h, err := gateway.Handler(gwapi, api, perConnRateLimit, connPerMinute, serverOptions...) if err != nil { return xerrors.Errorf("failed to set up gateway HTTP handler") diff --git a/cmd/lotus-keygen/main.go b/cmd/lotus-keygen/main.go index 1970d5074..41993a169 100644 --- a/cmd/lotus-keygen/main.go +++ b/cmd/lotus-keygen/main.go @@ -10,6 +10,7 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" _ "github.com/filecoin-project/lotus/lib/sigs/bls" + _ "github.com/filecoin-project/lotus/lib/sigs/delegated" _ "github.com/filecoin-project/lotus/lib/sigs/secp" ) diff --git a/cmd/lotus-miner/actor.go b/cmd/lotus-miner/actor.go index 843862d92..dd78adfef 100644 --- a/cmd/lotus-miner/actor.go +++ b/cmd/lotus-miner/actor.go @@ -290,7 +290,7 @@ var actorWithdrawCmd = &cli.Command{ // wait for it to get mined into a block wait, err := api.StateWaitMsg(ctx, res, uint64(cctx.Int("confidence"))) if err != nil { - return xerrors.Errorf("Timeout waiting for withdrawal message %s", wait.Message) + return xerrors.Errorf("Timeout waiting for withdrawal message %s", res) } if wait.Receipt.ExitCode.IsError() { @@ -1133,7 +1133,7 @@ var actorConfirmChangeWorker = &cli.Command{ smsg, err := api.MpoolPushMessage(ctx, &types.Message{ From: mi.Owner, To: maddr, - Method: builtin.MethodsMiner.ConfirmUpdateWorkerKey, + Method: builtin.MethodsMiner.ConfirmChangeWorkerAddress, Value: big.Zero(), }, nil) if err != nil { diff --git a/cmd/lotus-miner/info.go b/cmd/lotus-miner/info.go index b1075be37..d791b0760 100644 --- a/cmd/lotus-miner/info.go +++ b/cmd/lotus-miner/info.go @@ -93,7 +93,7 @@ func infoCmdAct(cctx *cli.Context) error { fmt.Println("Enabled subsystems (from markets API):", subsystems) - start, err := fullapi.StartTime(ctx) + start, err := minerApi.StartTime(ctx) if err != nil { return err } diff --git a/cmd/lotus-miner/sealing.go b/cmd/lotus-miner/sealing.go index 34c84772d..4810b9ab9 100644 --- a/cmd/lotus-miner/sealing.go +++ b/cmd/lotus-miner/sealing.go @@ -146,7 +146,7 @@ func workersCmd(sealing bool) *cli.Command { }) var taskStr string for _, t := range tc { - taskStr = t[1] + " " + taskStr += t[1] + " " } if taskStr != "" { fmt.Printf("\tTASK: %s\n", taskStr) diff --git a/cmd/lotus-miner/sectors.go b/cmd/lotus-miner/sectors.go index 3bb904d7a..fc5fdcef6 100644 --- a/cmd/lotus-miner/sectors.go +++ b/cmd/lotus-miner/sectors.go @@ -813,6 +813,10 @@ var sectorsRenewCmd = &cli.Command{ Usage: "use up to this amount of FIL for one message. pass this flag to avoid message congestion.", Value: "0", }, + &cli.Int64Flag{ + Name: "max-sectors", + Usage: "the maximum number of sectors contained in each message message", + }, &cli.BoolFlag{ Name: "really-do-it", Usage: "pass this flag to really renew sectors, otherwise will only print out json representation of parameters", @@ -1020,10 +1024,20 @@ var sectorsRenewCmd = &cli.Command{ for l, exts := range extensions { for newExp, numbers := range exts { scount += len(numbers) - addrSectors, err := policy.GetAddressedSectorsMax(nv) + var addrSectors int + sectorsMax, err := policy.GetAddressedSectorsMax(nv) if err != nil { return err } + if cctx.Int("max-sectors") == 0 { + addrSectors = sectorsMax + } else { + addrSectors = cctx.Int("max-sectors") + if addrSectors > sectorsMax { + return xerrors.Errorf("the specified max-sectors exceeds the maximum limit") + } + } + declMax, err := policy.GetDeclarationsMax(nv) if err != nil { return err diff --git a/cmd/lotus-pcr/main.go b/cmd/lotus-pcr/main.go index f491d9a33..57eaf0ad6 100644 --- a/cmd/lotus-pcr/main.go +++ b/cmd/lotus-pcr/main.go @@ -418,10 +418,24 @@ var runCmd = &cli.Command{ Usage: "messages with a prove cap larger than this will be skipped when processing pre commit messages", Value: "0.000000001", }, + &cli.StringFlag{ + Name: "http-server-timeout", + Value: "30s", + }, }, Action: func(cctx *cli.Context) error { + timeout, err := time.ParseDuration(cctx.String("http-timeout")) + if err != nil { + return xerrors.Errorf("invalid time string %s: %x", cctx.String("http-timeout"), err) + } + go func() { - http.ListenAndServe(":6060", nil) //nolint:errcheck + server := &http.Server{ + Addr: ":6060", + ReadHeaderTimeout: timeout, + } + + _ = server.ListenAndServe() }() ctx := context.Background() @@ -898,7 +912,7 @@ func (r *refunder) EnsureMinerMinimums(ctx context.Context, tipset *types.TipSet func (r *refunder) processTipsetStorageMarketActor(ctx context.Context, tipset *types.TipSet, msg api.Message, recp *types.MessageReceipt) (bool, string, types.BigInt, error) { m := msg.Message - refundValue := types.NewInt(0) + var refundValue types.BigInt var messageMethod string switch m.Method { @@ -925,7 +939,7 @@ func (r *refunder) processTipsetStorageMarketActor(ctx context.Context, tipset * func (r *refunder) processTipsetStorageMinerActor(ctx context.Context, tipset *types.TipSet, msg api.Message, recp *types.MessageReceipt) (bool, string, types.BigInt, error) { m := msg.Message - refundValue := types.NewInt(0) + var refundValue types.BigInt var messageMethod string if _, found := r.blockmap[m.To]; found { diff --git a/cmd/lotus-seed/seed/seed.go b/cmd/lotus-seed/seed/seed.go index 3b6359e0f..b98673712 100644 --- a/cmd/lotus-seed/seed/seed.go +++ b/cmd/lotus-seed/seed/seed.go @@ -164,7 +164,7 @@ func presealSector(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, sid storiface. return nil, xerrors.Errorf("commit: %w", err) } - if err := sb.FinalizeSector(context.TODO(), sid, nil); err != nil { + if err := sb.FinalizeSector(context.TODO(), sid); err != nil { return nil, xerrors.Errorf("trim cache: %w", err) } diff --git a/cmd/lotus-shed/actor.go b/cmd/lotus-shed/actor.go index 037b6d433..bdf2ecaf7 100644 --- a/cmd/lotus-shed/actor.go +++ b/cmd/lotus-shed/actor.go @@ -34,6 +34,7 @@ var actorCmd = &cli.Command{ actorControl, actorProposeChangeWorker, actorConfirmChangeWorker, + actorGetMethodNum, }, } @@ -777,7 +778,7 @@ var actorConfirmChangeWorker = &cli.Command{ smsg, err := nodeAPI.MpoolPushMessage(ctx, &types.Message{ From: mi.Owner, To: maddr, - Method: builtin.MethodsMiner.ConfirmUpdateWorkerKey, + Method: builtin.MethodsMiner.ConfirmChangeWorkerAddress, Value: big.Zero(), }, nil) if err != nil { @@ -809,3 +810,24 @@ var actorConfirmChangeWorker = &cli.Command{ return nil }, } + +var actorGetMethodNum = &cli.Command{ + Name: "generate-method-num", + Usage: "Generate method number from method name", + ArgsUsage: "[methodName]", + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("must pass methodNum") + } + + methodName := cctx.Args().First() + methodNum, err := builtin.GenerateFRCMethodNum(methodName) + if err != nil { + return err + } + + fmt.Println("Method Num: ", methodNum) + + return nil + }, +} diff --git a/cmd/lotus-shed/datastore-vlog.go b/cmd/lotus-shed/datastore-vlog.go index 936d33849..af412df19 100644 --- a/cmd/lotus-shed/datastore-vlog.go +++ b/cmd/lotus-shed/datastore-vlog.go @@ -12,8 +12,8 @@ import ( "strings" "github.com/dgraph-io/badger/v2/y" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" "github.com/mitchellh/go-homedir" "github.com/multiformats/go-base32" "github.com/urfave/cli/v2" diff --git a/cmd/lotus-shed/eth.go b/cmd/lotus-shed/eth.go new file mode 100644 index 000000000..1ebe2fb59 --- /dev/null +++ b/cmd/lotus-shed/eth.go @@ -0,0 +1,72 @@ +package main + +import ( + "fmt" + "reflect" + + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +var ethCmd = &cli.Command{ + Name: "eth", + Description: "Ethereum compatibility related commands", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", + }, + }, + Subcommands: []*cli.Command{ + checkTipsetsCmd, + }, +} + +var checkTipsetsCmd = &cli.Command{ + Name: "check-tipsets", + Description: "Check that eth_getBlockByNumber and eth_getBlockByHash consistently return tipsets", + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPIV1(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + head, err := api.ChainHead(ctx) + if err != nil { + return err + } + + height := head.Height() + fmt.Println("Current height:", height) + for i := int64(height); i > 0; i-- { + if _, err := api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(i), types.EmptyTSK); err != nil { + fmt.Printf("[FAIL] failed to get tipset @%d from Lotus: %s\n", i, err) + continue + } + hex := fmt.Sprintf("0x%x", i) + ethBlockA, err := api.EthGetBlockByNumber(ctx, hex, false) + if err != nil { + fmt.Printf("[FAIL] failed to get tipset @%d via eth_getBlockByNumber: %s\n", i, err) + continue + } + ethBlockB, err := api.EthGetBlockByHash(ctx, ethBlockA.Hash, false) + if err != nil { + fmt.Printf("[FAIL] failed to get tipset @%d via eth_getBlockByHash: %s\n", i, err) + continue + } + if equal := reflect.DeepEqual(ethBlockA, ethBlockB); equal { + fmt.Printf("[OK] blocks received via eth_getBlockByNumber and eth_getBlockByHash for tipset @%d are identical\n", i) + } else { + fmt.Printf("[FAIL] blocks received via eth_getBlockByNumber and eth_getBlockByHash for tipset @%d are NOT identical\n", i) + } + } + return nil + }, +} diff --git a/cmd/lotus-shed/export.go b/cmd/lotus-shed/export.go index 459de3383..d67fa4493 100644 --- a/cmd/lotus-shed/export.go +++ b/cmd/lotus-shed/export.go @@ -15,11 +15,11 @@ import ( "github.com/dgraph-io/badger/v2" "github.com/dgraph-io/badger/v2/pb" "github.com/dustin/go-humanize" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" offline "github.com/ipfs/go-ipfs-exchange-offline" ipld "github.com/ipfs/go-ipld-format" + block "github.com/ipfs/go-libipfs/blocks" "github.com/ipfs/go-merkledag" "github.com/ipld/go-car" "github.com/multiformats/go-base32" diff --git a/cmd/lotus-shed/fip-0036.go b/cmd/lotus-shed/fip-0036.go index 2725f205f..485302b9b 100644 --- a/cmd/lotus-shed/fip-0036.go +++ b/cmd/lotus-shed/fip-0036.go @@ -36,7 +36,7 @@ type Option uint64 const ( Approve Option = 49 - Reject = 50 + Reject Option = 50 ) type Vote struct { @@ -148,7 +148,7 @@ var finalResultCmd = &cli.Command{ } votes, err := getVotesMap(vj) if err != nil { - return xerrors.Errorf("failed to get voters: ", err) + return xerrors.Errorf("failed to get voters: %w\n", err) } type minerBriefInfo struct { @@ -160,23 +160,23 @@ var finalResultCmd = &cli.Command{ // power actor pa, err := st.GetActor(power.Address) if err != nil { - return xerrors.Errorf("failed to get power actor: \n", err) + return xerrors.Errorf("failed to get power actor: %w\n", err) } powerState, err := power.Load(store, pa) if err != nil { - return xerrors.Errorf("failed to get power state: \n", err) + return xerrors.Errorf("failed to get power state: %w\n", err) } //market actor ma, err := st.GetActor(market.Address) if err != nil { - return xerrors.Errorf("fail to get market actor: ", err) + return xerrors.Errorf("fail to get market actor: %w\n", err) } marketState, err := market.Load(store, ma) if err != nil { - return xerrors.Errorf("fail to load market state: ", err) + return xerrors.Errorf("fail to load market state: %w\n", err) } lookupId := func(addr address.Address) address.Address { @@ -219,7 +219,7 @@ var finalResultCmd = &cli.Command{ // TODO: Confirm that these are always ID addresses signers, err := ms.Signers() if err != nil { - return xerrors.Errorf("fail to get msig signers", err) + return xerrors.Errorf("fail to get msig signers: %w", err) } for _, s := range signers { signerId := lookupId(s) @@ -244,12 +244,12 @@ var finalResultCmd = &cli.Command{ if builtin.IsStorageMinerActor(act.Code) { m, err := miner.Load(store, act) if err != nil { - return xerrors.Errorf("fail to load miner actor: \n", err) + return xerrors.Errorf("fail to load miner actor: %w", err) } info, err := m.Info() if err != nil { - return xerrors.Errorf("fail to get miner info: \n", err) + return xerrors.Errorf("fail to get miner info: %w\n", err) } ownerId := lookupId(info.Owner) @@ -353,7 +353,7 @@ var finalResultCmd = &cli.Command{ //process votes for regular accounts accountActor, err := st.GetActor(signerId) if err != nil { - return xerrors.Errorf("fail to get account account for signer: ", err) + return xerrors.Errorf("fail to get account account for signer: %w\n", err) } clientBytes, ok := clientToDealStorage[signerId] diff --git a/cmd/lotus-shed/gas-estimation.go b/cmd/lotus-shed/gas-estimation.go new file mode 100644 index 000000000..cf56ea03d --- /dev/null +++ b/cmd/lotus-shed/gas-estimation.go @@ -0,0 +1,280 @@ +package main + +import ( + "context" + "fmt" + "io" + "os" + "strconv" + "text/tabwriter" + + "github.com/ipfs/go-cid" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/network" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/beacon" + "github.com/filecoin-project/lotus/chain/beacon/drand" + "github.com/filecoin-project/lotus/chain/consensus/filcns" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/node/repo" + "github.com/filecoin-project/lotus/storage/sealer/ffiwrapper" +) + +const MAINNET_GENESIS_TIME = 1598306400 + +// USAGE: Sync a node, then call migrate-nv17 on some old state. Pass in the cid of the migrated state root, +// the epoch you migrated at, the network version you migrated to, and a message CID. You will be able to replay any +// message from between the migration epoch, and where your node originally synced to. Note: You may run into issues +// with state that changed between the epoch you migrated at, and when the message was originally processed. +// This can be avoided by replaying messages from close to the migration epoch, or circumvented by using a custom +// FVM bundle. +var gasTraceCmd = &cli.Command{ + Name: "trace-gas", + Description: "replay a message on the specified stateRoot and network version to get an execution trace", + ArgsUsage: "[migratedStateRootCid networkVersion messageCid]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", + }, + }, + Action: func(cctx *cli.Context) error { + ctx := context.TODO() + + if cctx.NArg() != 3 { + return lcli.IncorrectNumArgs(cctx) + } + + stateRootCid, err := cid.Decode(cctx.Args().Get(0)) + if err != nil { + return fmt.Errorf("failed to parse input: %w", err) + } + + nv, err := strconv.ParseInt(cctx.Args().Get(1), 10, 32) + if err != nil { + return fmt.Errorf("failed to parse input: %w", err) + } + + messageCid, err := cid.Decode(cctx.Args().Get(2)) + if err != nil { + return fmt.Errorf("failed to parse input: %w", err) + } + + fsrepo, err := repo.NewFS(cctx.String("repo")) + if err != nil { + return err + } + + lkrepo, err := fsrepo.Lock(repo.FullNode) + if err != nil { + return err + } + + defer lkrepo.Close() //nolint:errcheck + + bs, err := lkrepo.Blockstore(ctx, repo.UniversalBlockstore) + if err != nil { + return fmt.Errorf("failed to open blockstore: %w", err) + } + + defer func() { + if c, ok := bs.(io.Closer); ok { + if err := c.Close(); err != nil { + log.Warnf("failed to close blockstore: %s", err) + } + } + }() + + mds, err := lkrepo.Datastore(context.Background(), "/metadata") + if err != nil { + return err + } + + dcs := build.DrandConfigSchedule() + shd := beacon.Schedule{} + for _, dc := range dcs { + bc, err := drand.NewDrandBeacon(MAINNET_GENESIS_TIME, build.BlockDelaySecs, nil, dc.Config) + if err != nil { + return xerrors.Errorf("creating drand beacon: %w", err) + } + shd = append(shd, beacon.BeaconPoint{Start: dc.Start, Beacon: bc}) + } + cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil) + defer cs.Close() //nolint:errcheck + + sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd) + if err != nil { + return err + } + + msg, err := cs.GetMessage(ctx, messageCid) + if err != nil { + return err + } + + // Set to block limit so message will not run out of gas + msg.GasLimit = build.BlockGasLimit + + err = cs.Load(ctx) + if err != nil { + return err + } + + tw := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', tabwriter.AlignRight) + res, err := sm.CallAtStateAndVersion(ctx, msg, stateRootCid, network.Version(nv)) + if err != nil { + return err + } + fmt.Println("Total gas used: ", res.MsgRct.GasUsed) + printInternalExecutions(0, []types.ExecutionTrace{res.ExecutionTrace}, tw) + + return tw.Flush() + }, +} + +var replayOfflineCmd = &cli.Command{ + Name: "replay-offline", + Description: "replay a message to get a gas trace", + ArgsUsage: "[messageCid]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", + }, + &cli.Int64Flag{ + Name: "lookback-limit", + Value: 10000, + }, + }, + Action: func(cctx *cli.Context) error { + ctx := context.TODO() + + if cctx.NArg() != 1 { + return lcli.IncorrectNumArgs(cctx) + } + + messageCid, err := cid.Decode(cctx.Args().Get(0)) + if err != nil { + return fmt.Errorf("failed to parse input: %w", err) + } + + lookbackLimit := cctx.Int("lookback-limit") + + fsrepo, err := repo.NewFS(cctx.String("repo")) + if err != nil { + return err + } + + lkrepo, err := fsrepo.Lock(repo.FullNode) + if err != nil { + return err + } + + defer lkrepo.Close() //nolint:errcheck + + bs, err := lkrepo.Blockstore(ctx, repo.UniversalBlockstore) + if err != nil { + return fmt.Errorf("failed to open blockstore: %w", err) + } + + defer func() { + if c, ok := bs.(io.Closer); ok { + if err := c.Close(); err != nil { + log.Warnf("failed to close blockstore: %s", err) + } + } + }() + + mds, err := lkrepo.Datastore(context.Background(), "/metadata") + if err != nil { + return err + } + + dcs := build.DrandConfigSchedule() + shd := beacon.Schedule{} + for _, dc := range dcs { + bc, err := drand.NewDrandBeacon(MAINNET_GENESIS_TIME, build.BlockDelaySecs, nil, dc.Config) + if err != nil { + return xerrors.Errorf("creating drand beacon: %w", err) + } + shd = append(shd, beacon.BeaconPoint{Start: dc.Start, Beacon: bc}) + } + + cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil) + defer cs.Close() //nolint:errcheck + + sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd) + if err != nil { + return err + } + + msg, err := cs.GetMessage(ctx, messageCid) + if err != nil { + return err + } + + err = cs.Load(ctx) + if err != nil { + return err + } + + ts, _, _, err := sm.SearchForMessage(ctx, cs.GetHeaviestTipSet(), messageCid, abi.ChainEpoch(lookbackLimit), true) + if err != nil { + return err + } + if ts == nil { + return xerrors.Errorf("could not find message within the last %d epochs", lookbackLimit) + } + executionTs, err := cs.GetTipsetByHeight(ctx, ts.Height()-2, ts, true) + if err != nil { + return err + } + + tw := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', tabwriter.AlignRight) + res, err := sm.CallWithGas(ctx, msg, []types.ChainMsg{}, executionTs) + if err != nil { + return err + } + fmt.Println("Total gas used: ", res.MsgRct.GasUsed) + printInternalExecutions(0, []types.ExecutionTrace{res.ExecutionTrace}, tw) + + return tw.Flush() + }, +} + +func printInternalExecutions(depth int, trace []types.ExecutionTrace, tw *tabwriter.Writer) { + if depth == 0 { + _, _ = fmt.Fprintf(tw, "Depth\tFrom\tTo\tMethod\tTotalGas\tComputeGas\tStorageGas\t\tExitCode\n") + } + for _, im := range trace { + sumGas := im.SumGas() + _, _ = fmt.Fprintf(tw, "%d\t%s\t%s\t%d\t%d\t%d\t%d\t\t%d\n", depth, truncateString(im.Msg.From.String(), 10), truncateString(im.Msg.To.String(), 10), im.Msg.Method, sumGas.TotalGas, sumGas.ComputeGas, sumGas.StorageGas, im.MsgRct.ExitCode) + printInternalExecutions(depth+1, im.Subcalls, tw) + } +} + +func truncateString(str string, length int) string { + if len(str) <= length { + return str + } + + truncated := "" + count := 0 + for _, char := range str { + truncated += string(char) + count++ + if count >= length { + break + } + } + truncated += "..." + return truncated +} diff --git a/cmd/lotus-shed/genesis-verify.go b/cmd/lotus-shed/genesis-verify.go index 4d961492f..6795f1528 100644 --- a/cmd/lotus-shed/genesis-verify.go +++ b/cmd/lotus-shed/genesis-verify.go @@ -51,7 +51,7 @@ var genesisVerifyCmd = &cli.Command{ if !cctx.Args().Present() { return fmt.Errorf("must pass genesis car file") } - bs := blockstore.FromDatastore(datastore.NewMapDatastore()) + bs := blockstore.NewMemory() cs := store.NewChainStore(bs, bs, datastore.NewMapDatastore(), filcns.Weight, nil) defer cs.Close() //nolint:errcheck diff --git a/cmd/lotus-shed/import-car.go b/cmd/lotus-shed/import-car.go index 973e7b31b..4c636a3af 100644 --- a/cmd/lotus-shed/import-car.go +++ b/cmd/lotus-shed/import-car.go @@ -7,8 +7,8 @@ import ( "io" "os" - block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + block "github.com/ipfs/go-libipfs/blocks" "github.com/ipld/go-car" "github.com/urfave/cli/v2" "golang.org/x/xerrors" diff --git a/cmd/lotus-shed/invariants.go b/cmd/lotus-shed/invariants.go index 9fb67393d..e48f301c4 100644 --- a/cmd/lotus-shed/invariants.go +++ b/cmd/lotus-shed/invariants.go @@ -98,6 +98,9 @@ var invariantsCmd = &cli.Command{ fmt.Println("Network Version ", nv) av, err := actorstypes.VersionForNetwork(nv) + if err != nil { + return err + } fmt.Println("Actors Version ", av) actorCodeCids, err := actors.GetActorCodeIDs(av) @@ -114,6 +117,9 @@ var invariantsCmd = &cli.Command{ } actorTree, err := builtin.LoadTree(actorStore, stateRoot.Actors) + if err != nil { + return err + } startTime := time.Now() diff --git a/cmd/lotus-shed/itestd.go b/cmd/lotus-shed/itestd.go index 3ac542d27..7b9b7460d 100644 --- a/cmd/lotus-shed/itestd.go +++ b/cmd/lotus-shed/itestd.go @@ -9,6 +9,7 @@ import ( "net/http/httptest" "os" "os/exec" + "time" "github.com/chzyer/readline" "github.com/urfave/cli/v2" @@ -25,6 +26,10 @@ var itestdCmd = &cli.Command{ Name: "listen", Value: "127.0.0.1:5674", }, + &cli.StringFlag{ + Name: "http-server-timeout", + Value: "30s", + }, }, Action: func(cctx *cli.Context) error { var nodes []kit.ItestdNotif @@ -44,9 +49,14 @@ var itestdCmd = &cli.Command{ if err != nil { return xerrors.Errorf("net listen: %w", err) } + + timeout, err := time.ParseDuration(cctx.String("http-server-timeout")) + if err != nil { + return xerrors.Errorf("invalid time string %s: %x", cctx.String("http-server-timeout"), err) + } s := &httptest.Server{ Listener: l, - Config: &http.Server{Handler: m}, + Config: &http.Server{Handler: m, ReadHeaderTimeout: timeout}, } s.Start() fmt.Printf("ITest env:\n\nLOTUS_ITESTD=%s\n\nSay 'sh' to spawn a shell connected to test nodes\n--- waiting for clients\n", s.URL) diff --git a/cmd/lotus-shed/keyinfo.go b/cmd/lotus-shed/keyinfo.go index 373964dc6..38f5ee6fe 100644 --- a/cmd/lotus-shed/keyinfo.go +++ b/cmd/lotus-shed/keyinfo.go @@ -23,6 +23,7 @@ import ( "github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet/key" _ "github.com/filecoin-project/lotus/lib/sigs/bls" + _ "github.com/filecoin-project/lotus/lib/sigs/delegated" _ "github.com/filecoin-project/lotus/lib/sigs/secp" "github.com/filecoin-project/lotus/node/modules" "github.com/filecoin-project/lotus/node/modules/lp2p" diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index 3972a625b..28a59f14d 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -13,7 +13,10 @@ import ( var log = logging.Logger("lotus-shed") func main() { - logging.SetLogLevel("*", "INFO") + _ = logging.SetLogLevel("*", "INFO") + _ = logging.SetLogLevelRegex("badger*", "ERROR") + _ = logging.SetLogLevel("drand", "ERROR") + _ = logging.SetLogLevel("chainstore", "ERROR") local := []*cli.Command{ addressCmd, @@ -46,9 +49,9 @@ func main() { minerCmd, mpoolStatsCmd, exportChainCmd, + ethCmd, exportCarCmd, consensusCmd, - storageStatsCmd, syncCmd, stateTreePruneCmd, datastoreCmd, @@ -76,6 +79,8 @@ func main() { msigCmd, fip36PollCmd, invariantsCmd, + gasTraceCmd, + replayOfflineCmd, } app := &cli.App{ @@ -108,7 +113,7 @@ func main() { } if err := app.Run(os.Args); err != nil { - log.Warnf("%+v", err) + log.Errorf("%+v", err) os.Exit(1) return } diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go index 9e4a2629c..08aceb020 100644 --- a/cmd/lotus-shed/mempool-stats.go +++ b/cmd/lotus-shed/mempool-stats.go @@ -13,6 +13,7 @@ import ( "go.opencensus.io/stats" "go.opencensus.io/stats/view" "go.opencensus.io/tag" + "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/builtin" @@ -76,8 +77,14 @@ type msgInfo struct { var mpoolStatsCmd = &cli.Command{ Name: "mpool-stats", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "http-server-timeout", + Value: "30s", + }, + }, Action: func(cctx *cli.Context) error { - logging.SetLogLevel("rpc", "ERROR") + _ = logging.SetLogLevel("rpc", "ERROR") if err := view.Register(AgeView, SizeView, InboundRate, InclusionRate, MsgWait); err != nil { return err @@ -92,8 +99,18 @@ var mpoolStatsCmd = &cli.Command{ http.Handle("/debug/metrics", expo) + timeout, err := time.ParseDuration(cctx.String("http-server-timeout")) + if err != nil { + return xerrors.Errorf("invalid time string %s: %x", cctx.String("http-server-timeout"), err) + } + go func() { - if err := http.ListenAndServe(":10555", nil); err != nil { + server := &http.Server{ + Addr: ":10555", + ReadHeaderTimeout: timeout, + } + + if err := server.ListenAndServe(); err != nil { panic(err) } }() diff --git a/cmd/lotus-shed/migrations.go b/cmd/lotus-shed/migrations.go index 415faa16d..8a1007882 100644 --- a/cmd/lotus-shed/migrations.go +++ b/cmd/lotus-shed/migrations.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "strconv" "time" "github.com/ipfs/go-cid" @@ -16,6 +17,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/builtin" + v10 "github.com/filecoin-project/go-state-types/builtin/v10" market8 "github.com/filecoin-project/go-state-types/builtin/v8/market" adt8 "github.com/filecoin-project/go-state-types/builtin/v8/util/adt" v9 "github.com/filecoin-project/go-state-types/builtin/v9" @@ -23,6 +25,9 @@ import ( miner9 "github.com/filecoin-project/go-state-types/builtin/v9/miner" adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" + "github.com/filecoin-project/go-state-types/manifest" + mutil "github.com/filecoin-project/go-state-types/migration" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/specs-actors/v7/actors/migration/nv15" "github.com/filecoin-project/lotus/blockstore" @@ -45,14 +50,17 @@ import ( ) var migrationsCmd = &cli.Command{ - Name: "migrate-nv17", - Description: "Run the nv17 migration", - ArgsUsage: "[block to look back from]", + Name: "migrate-state", + Description: "Run a network upgrade migration", + ArgsUsage: "[new network version, block to look back from]", Flags: []cli.Flag{ &cli.StringFlag{ Name: "repo", Value: "~/.lotus", }, + &cli.BoolFlag{ + Name: "skip-pre-migration", + }, &cli.BoolFlag{ Name: "check-invariants", }, @@ -60,11 +68,21 @@ var migrationsCmd = &cli.Command{ Action: func(cctx *cli.Context) error { ctx := context.TODO() - if cctx.NArg() != 1 { + if cctx.NArg() != 2 { return lcli.IncorrectNumArgs(cctx) } - blkCid, err := cid.Decode(cctx.Args().First()) + nv, err := strconv.ParseUint(cctx.Args().Get(0), 10, 32) + if err != nil { + return fmt.Errorf("failed to parse network version: %w", err) + } + + upgradeActorsFunc, preUpgradeActorsFunc, checkInvariantsFunc, err := getMigrationFuncsForNetwork(network.Version(nv)) + if err != nil { + return err + } + + blkCid, err := cid.Decode(cctx.Args().Get(1)) if err != nil { return fmt.Errorf("failed to parse input: %w", err) } @@ -107,8 +125,6 @@ var migrationsCmd = &cli.Command{ return err } - cache := nv15.NewMemMigrationCache() - blk, err := cs.GetBlock(ctx, blkCid) if err != nil { return err @@ -119,66 +135,59 @@ var migrationsCmd = &cli.Command{ return err } - ts1, err := cs.GetTipsetByHeight(ctx, blk.Height-240, migrationTs, false) - if err != nil { - return err - } - startTime := time.Now() - err = filcns.PreUpgradeActorsV9(ctx, sm, cache, ts1.ParentState(), ts1.Height()-1, ts1) - if err != nil { - return err - } - - preMigration1Time := time.Since(startTime) - - ts2, err := cs.GetTipsetByHeight(ctx, blk.Height-15, migrationTs, false) - if err != nil { - return err - } - - startTime = time.Now() - - err = filcns.PreUpgradeActorsV9(ctx, sm, cache, ts2.ParentState(), ts2.Height()-1, ts2) - if err != nil { - return err - } - - preMigration2Time := time.Since(startTime) - - startTime = time.Now() - - newCid1, err := filcns.UpgradeActorsV9(ctx, sm, cache, nil, blk.ParentStateRoot, blk.Height-1, migrationTs) - if err != nil { - return err - } - - cachedMigrationTime := time.Since(startTime) - - startTime = time.Now() - - newCid2, err := filcns.UpgradeActorsV9(ctx, sm, nv15.NewMemMigrationCache(), nil, blk.ParentStateRoot, blk.Height-1, migrationTs) + newCid2, err := upgradeActorsFunc(ctx, sm, nv15.NewMemMigrationCache(), nil, blk.ParentStateRoot, blk.Height-1, migrationTs) if err != nil { return err } uncachedMigrationTime := time.Since(startTime) - if newCid1 != newCid2 { - return xerrors.Errorf("got different results with and without the cache: %s, %s", newCid1, - newCid2) - } - fmt.Println("migration height ", blk.Height-1) + fmt.Println("old cid ", blk.ParentStateRoot) fmt.Println("new cid ", newCid2) - fmt.Println("completed premigration 1, took ", preMigration1Time) - fmt.Println("completed premigration 2, took ", preMigration2Time) - fmt.Println("completed round actual (with cache), took ", cachedMigrationTime) fmt.Println("completed round actual (without cache), took ", uncachedMigrationTime) + if !cctx.IsSet("skip-pre-migration") { + cache := mutil.NewMemMigrationCache() + + ts1, err := cs.GetTipsetByHeight(ctx, blk.Height-60, migrationTs, false) + if err != nil { + return err + } + + startTime = time.Now() + + err = preUpgradeActorsFunc(ctx, sm, cache, ts1.ParentState(), ts1.Height()-1, ts1) + if err != nil { + return err + } + + preMigrationTime := time.Since(startTime) + + startTime = time.Now() + + newCid1, err := upgradeActorsFunc(ctx, sm, cache, nil, blk.ParentStateRoot, blk.Height-1, migrationTs) + if err != nil { + return err + } + + cachedMigrationTime := time.Since(startTime) + + if newCid1 != newCid2 { + return xerrors.Errorf("got different results with and without the cache: %s, %s", newCid1, + newCid2) + } + fmt.Println("completed premigration, took ", preMigrationTime) + fmt.Println("completed round actual (with cache), took ", cachedMigrationTime) + } + if cctx.Bool("check-invariants") { - err = checkMigrationInvariants(ctx, blk.ParentStateRoot, newCid2, bs, blk.Height-1) + if checkInvariantsFunc == nil { + return xerrors.Errorf("check invariants not implemented for nv%d", nv) + } + err = checkInvariantsFunc(ctx, blk.ParentStateRoot, newCid2, bs, blk.Height-1) if err != nil { return err } @@ -188,7 +197,56 @@ var migrationsCmd = &cli.Command{ }, } -func checkMigrationInvariants(ctx context.Context, v8StateRootCid cid.Cid, v9StateRootCid cid.Cid, bs blockstore.Blockstore, epoch abi.ChainEpoch) error { +func getMigrationFuncsForNetwork(nv network.Version) (UpgradeActorsFunc, PreUpgradeActorsFunc, CheckInvariantsFunc, error) { + switch nv { + case network.Version17: + return filcns.UpgradeActorsV9, filcns.PreUpgradeActorsV9, checkNv17Invariants, nil + case network.Version18: + return filcns.UpgradeActorsV10, filcns.PreUpgradeActorsV10, checkNv18Invariants, nil + default: + return nil, nil, nil, xerrors.Errorf("migration not implemented for nv%d", nv) + } +} + +type UpgradeActorsFunc = func(context.Context, *stmgr.StateManager, stmgr.MigrationCache, stmgr.ExecMonitor, cid.Cid, abi.ChainEpoch, *types.TipSet) (cid.Cid, error) +type PreUpgradeActorsFunc = func(context.Context, *stmgr.StateManager, stmgr.MigrationCache, cid.Cid, abi.ChainEpoch, *types.TipSet) error +type CheckInvariantsFunc = func(context.Context, cid.Cid, cid.Cid, blockstore.Blockstore, abi.ChainEpoch) error + +func checkNv18Invariants(ctx context.Context, oldStateRootCid cid.Cid, newStateRootCid cid.Cid, bs blockstore.Blockstore, epoch abi.ChainEpoch) error { + actorStore := store.ActorStore(ctx, bs) + startTime := time.Now() + + // Load the new state root. + var newStateRoot types.StateRoot + if err := actorStore.Get(ctx, newStateRootCid, &newStateRoot); err != nil { + return xerrors.Errorf("failed to decode state root: %w", err) + } + + actorCodeCids, err := actors.GetActorCodeIDs(actorstypes.Version10) + if err != nil { + return err + } + newActorTree, err := builtin.LoadTree(actorStore, newStateRoot.Actors) + if err != nil { + return err + } + messages, err := v10.CheckStateInvariants(newActorTree, epoch, actorCodeCids) + if err != nil { + return xerrors.Errorf("checking state invariants: %w", err) + } + + for _, message := range messages.Messages() { + fmt.Println("got the following error: ", message) + } + + fmt.Println("completed invariant checks, took ", time.Since(startTime)) + + return nil +} + +/// NV17 and earlier stuff + +func checkNv17Invariants(ctx context.Context, v8StateRootCid cid.Cid, v9StateRootCid cid.Cid, bs blockstore.Blockstore, epoch abi.ChainEpoch) error { actorStore := store.ActorStore(ctx, bs) startTime := time.Now() @@ -227,8 +285,10 @@ func checkMigrationInvariants(ctx context.Context, v8StateRootCid cid.Cid, v9Sta if err != nil { return err } - v9actorTree, err := builtin.LoadTree(actorStore, v9stateRoot.Actors) + if err != nil { + return err + } messages, err := v9.CheckStateInvariants(v9actorTree, epoch, actorCodeCids) if err != nil { return xerrors.Errorf("checking state invariants: %w", err) @@ -453,7 +513,7 @@ func compareProposalToAllocation(prop market8.DealProposal, alloc verifreg9.Allo return xerrors.Errorf("couldnt get ID from address") } if proposalClientID != uint64(alloc.Client) { - return xerrors.Errorf("client id mismatch between proposal and allocation: %s, %s", proposalClientID, alloc.Client) + return xerrors.Errorf("client id mismatch between proposal and allocation: %v, %v", proposalClientID, alloc.Client) } proposalProviderID, err := address.IDFromAddress(prop.Provider) @@ -461,11 +521,11 @@ func compareProposalToAllocation(prop market8.DealProposal, alloc verifreg9.Allo return xerrors.Errorf("couldnt get ID from address") } if proposalProviderID != uint64(alloc.Provider) { - return xerrors.Errorf("provider id mismatch between proposal and allocation: %s, %s", proposalProviderID, alloc.Provider) + return xerrors.Errorf("provider id mismatch between proposal and allocation: %v, %v", proposalProviderID, alloc.Provider) } if prop.PieceSize != alloc.Size { - return xerrors.Errorf("piece size mismatch between proposal and allocation: %s, %s", prop.PieceSize, alloc.Size) + return xerrors.Errorf("piece size mismatch between proposal and allocation: %v, %v", prop.PieceSize, alloc.Size) } if alloc.TermMax != 540*builtin.EpochsInDay { @@ -573,7 +633,7 @@ func checkAllMinersUnsealedCID(stateTreeV9 *state.StateTree, store adt.Store) er } func checkMinerUnsealedCID(act *types.Actor, stateTreeV9 *state.StateTree, store adt.Store) error { - minerCodeCid, found := actors.GetActorCodeID(actorstypes.Version9, actors.MinerKey) + minerCodeCid, found := actors.GetActorCodeID(actorstypes.Version9, manifest.MinerKey) if !found { return xerrors.Errorf("could not find code cid for miner actor") } diff --git a/cmd/lotus-shed/miner-multisig.go b/cmd/lotus-shed/miner-multisig.go index 080229a6a..e8394b17a 100644 --- a/cmd/lotus-shed/miner-multisig.go +++ b/cmd/lotus-shed/miner-multisig.go @@ -627,7 +627,7 @@ var mmConfirmChangeWorker = &cli.Command{ return xerrors.Errorf("worker key change cannot be confirmed until %d, current height is %d", mi.WorkerChangeEpoch, head.Height()) } - pcid, err := api.MsigPropose(ctx, multisigAddr, minerAddr, big.Zero(), sender, uint64(builtin.MethodsMiner.ConfirmUpdateWorkerKey), nil) + pcid, err := api.MsigPropose(ctx, multisigAddr, minerAddr, big.Zero(), sender, uint64(builtin.MethodsMiner.ConfirmChangeWorkerAddress), nil) if err != nil { return xerrors.Errorf("proposing message: %w", err) } diff --git a/cmd/lotus-shed/msig.go b/cmd/lotus-shed/msig.go index 7d37d3d2d..ccc932c93 100644 --- a/cmd/lotus-shed/msig.go +++ b/cmd/lotus-shed/msig.go @@ -121,6 +121,10 @@ var multisigGetAllCmd = &cli.Command{ } return nil }) + if err != nil { + return err + } + out, err := json.MarshalIndent(msigActorsInfo, "", " ") if err != nil { return err diff --git a/cmd/lotus-shed/storage-stats.go b/cmd/lotus-shed/storage-stats.go deleted file mode 100644 index 68495545b..000000000 --- a/cmd/lotus-shed/storage-stats.go +++ /dev/null @@ -1,199 +0,0 @@ -package main - -import ( - "encoding/json" - corebig "math/big" - "os" - "strconv" - - "github.com/ipfs/go-cid" - "github.com/urfave/cli/v2" - - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-state-types/abi" - filbig "github.com/filecoin-project/go-state-types/big" - - "github.com/filecoin-project/lotus/chain/types" - lcli "github.com/filecoin-project/lotus/cli" -) - -// How many epochs back to look at for dealstats -var defaultEpochLookback = abi.ChainEpoch(10) - -type networkTotalsOutput struct { - Epoch int64 `json:"epoch"` - Endpoint string `json:"endpoint"` - Payload networkTotals `json:"payload"` -} - -type providerMeta struct { - nonidentifiable bool -} - -// force formatting as decimal to aid human readers -type humanFloat float64 - -func (f humanFloat) MarshalJSON() ([]byte, error) { - // 'f' uses decimal digits without exponents. - // The bit size of 32 ensures we don't use too many decimal places. - return []byte(strconv.FormatFloat(float64(f), 'f', -1, 32)), nil -} - -type Totals struct { - TotalDeals int `json:"total_num_deals"` - TotalBytes int64 `json:"total_stored_data_size"` - PrivateTotalDeals int `json:"private_total_num_deals"` - PrivateTotalBytes int64 `json:"private_total_stored_data_size"` - CapacityCarryingData humanFloat `json:"capacity_fraction_carrying_data"` -} - -type networkTotals struct { - QaNetworkPower filbig.Int `json:"total_qa_power"` - RawNetworkPower filbig.Int `json:"total_raw_capacity"` - UniqueCids int `json:"total_unique_cids"` - UniqueBytes int64 `json:"total_unique_data_size"` - UniqueClients int `json:"total_unique_clients"` - UniqueProviders int `json:"total_unique_providers"` - UniquePrivateProviders int `json:"total_unique_private_providers"` - Totals - FilPlus Totals `json:"filecoin_plus_subset"` - - pieces map[cid.Cid]struct{} - clients map[address.Address]struct{} - providers map[address.Address]providerMeta -} - -var storageStatsCmd = &cli.Command{ - Name: "storage-stats", - Usage: "Translates current lotus state into a json summary suitable for driving https://storage.filecoin.io/", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "tipset", - Usage: "Comma separated array of cids, or @height", - }, - }, - Action: func(cctx *cli.Context) error { - ctx := lcli.ReqContext(cctx) - - api, apiCloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer apiCloser() - - var ts *types.TipSet - if cctx.String("tipset") == "" { - ts, err = api.ChainHead(ctx) - if err != nil { - return err - } - ts, err = api.ChainGetTipSetByHeight(ctx, ts.Height()-defaultEpochLookback, ts.Key()) - if err != nil { - return err - } - } else { - ts, err = lcli.ParseTipSetRef(ctx, api, cctx.String("tipset")) - if err != nil { - return err - } - } - - power, err := api.StateMinerPower(ctx, address.Address{}, ts.Key()) - if err != nil { - return err - } - - netTotals := networkTotals{ - QaNetworkPower: power.TotalPower.QualityAdjPower, - RawNetworkPower: power.TotalPower.RawBytePower, - pieces: make(map[cid.Cid]struct{}), - clients: make(map[address.Address]struct{}), - providers: make(map[address.Address]providerMeta), - } - - deals, err := api.StateMarketDeals(ctx, ts.Key()) - if err != nil { - return err - } - - for _, dealInfo := range deals { - - // Only count deals that have properly started, not past/future ones - // https://github.com/filecoin-project/specs-actors/blob/v0.9.9/actors/builtin/market/deal.go#L81-L85 - // Bail on 0 as well in case SectorStartEpoch is uninitialized due to some bug - // - // Additionally if the SlashEpoch is set this means the underlying sector is - // terminated for whatever reason ( not just slashed ), and the deal record - // will soon be removed from the state entirely - if dealInfo.State.SectorStartEpoch <= 0 || - dealInfo.State.SectorStartEpoch > ts.Height() || - dealInfo.State.SlashEpoch > -1 { - continue - } - - netTotals.clients[dealInfo.Proposal.Client] = struct{}{} - - if _, seen := netTotals.providers[dealInfo.Proposal.Provider]; !seen { - pm := providerMeta{} - - mi, err := api.StateMinerInfo(ctx, dealInfo.Proposal.Provider, ts.Key()) - if err != nil { - return err - } - - if mi.PeerId == nil || *mi.PeerId == "" { - log.Infof("private provider %s", dealInfo.Proposal.Provider) - pm.nonidentifiable = true - netTotals.UniquePrivateProviders++ - } - - netTotals.providers[dealInfo.Proposal.Provider] = pm - netTotals.UniqueProviders++ - } - - if _, seen := netTotals.pieces[dealInfo.Proposal.PieceCID]; !seen { - netTotals.pieces[dealInfo.Proposal.PieceCID] = struct{}{} - netTotals.UniqueBytes += int64(dealInfo.Proposal.PieceSize) - netTotals.UniqueCids++ - } - - netTotals.TotalBytes += int64(dealInfo.Proposal.PieceSize) - netTotals.TotalDeals++ - if netTotals.providers[dealInfo.Proposal.Provider].nonidentifiable { - netTotals.PrivateTotalBytes += int64(dealInfo.Proposal.PieceSize) - netTotals.PrivateTotalDeals++ - } - - if dealInfo.Proposal.VerifiedDeal { - netTotals.FilPlus.TotalBytes += int64(dealInfo.Proposal.PieceSize) - netTotals.FilPlus.TotalDeals++ - if netTotals.providers[dealInfo.Proposal.Provider].nonidentifiable { - netTotals.FilPlus.PrivateTotalBytes += int64(dealInfo.Proposal.PieceSize) - netTotals.FilPlus.PrivateTotalDeals++ - } - } - } - - netTotals.UniqueClients = len(netTotals.clients) - - ccd, _ := new(corebig.Rat).SetFrac( - corebig.NewInt(netTotals.TotalBytes), - netTotals.RawNetworkPower.Int, - ).Float64() - netTotals.CapacityCarryingData = humanFloat(ccd) - - ccdfp, _ := new(corebig.Rat).SetFrac( - corebig.NewInt(netTotals.FilPlus.TotalBytes), - netTotals.RawNetworkPower.Int, - ).Float64() - netTotals.FilPlus.CapacityCarryingData = humanFloat(ccdfp) - - return json.NewEncoder(os.Stdout).Encode( - networkTotalsOutput{ - Epoch: int64(ts.Height()), - Endpoint: "NETWORK_WIDE_TOTALS", - Payload: netTotals, - }, - ) - }, -} diff --git a/cmd/lotus-sim/simulation/block.go b/cmd/lotus-sim/simulation/block.go index 341877a88..4dddba921 100644 --- a/cmd/lotus-sim/simulation/block.go +++ b/cmd/lotus-sim/simulation/block.go @@ -74,14 +74,17 @@ func (sim *Simulation) makeTipSet(ctx context.Context, messages []*types.Message Timestamp: uts, ElectionProof: &types.ElectionProof{WinCount: 1}, }} - err = sim.Node.Chainstore.PersistBlockHeaders(ctx, blks...) - if err != nil { - return nil, xerrors.Errorf("failed to persist block headers: %w", err) - } + newTipSet, err := types.NewTipSet(blks) if err != nil { return nil, xerrors.Errorf("failed to create new tipset: %w", err) } + + err = sim.Node.Chainstore.PersistTipset(ctx, newTipSet) + if err != nil { + return nil, xerrors.Errorf("failed to persist block headers: %w", err) + } + now := time.Now() _, _, err = sim.StateManager.TipSetState(ctx, newTipSet) if err != nil { diff --git a/cmd/lotus-stats/main.go b/cmd/lotus-stats/main.go index 20b2ee45c..20971c1f3 100644 --- a/cmd/lotus-stats/main.go +++ b/cmd/lotus-stats/main.go @@ -12,6 +12,7 @@ import ( "github.com/urfave/cli/v2" "go.opencensus.io/stats" "go.opencensus.io/stats/view" + "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" @@ -128,6 +129,10 @@ var runCmd = &cli.Command{ EnvVars: []string{"LOTUS_STATS_IPLD_STORE_CACHE_SIZE"}, Value: 2 << 15, }, + &cli.StringFlag{ + Name: "http-server-timeout", + Value: "30s", + }, }, Action: func(cctx *cli.Context) error { ctx := context.Background() @@ -158,9 +163,18 @@ var runCmd = &cli.Command{ return err } + timeout, err := time.ParseDuration(cctx.String("http-server-timeout")) + if err != nil { + return xerrors.Errorf("invalid time string %s: %x", cctx.String("http-server-timeout"), err) + } + go func() { http.Handle("/metrics", exporter) - if err := http.ListenAndServe(":6688", nil); err != nil { + server := &http.Server{ + Addr: ":6688", + ReadHeaderTimeout: timeout, + } + if err := server.ListenAndServe(); err != nil { log.Errorw("failed to start http server", "err", err) } }() diff --git a/cmd/lotus-wallet/main.go b/cmd/lotus-wallet/main.go index 75d31da56..8360dae15 100644 --- a/cmd/lotus-wallet/main.go +++ b/cmd/lotus-wallet/main.go @@ -6,6 +6,7 @@ import ( "net" "net/http" "os" + "time" "github.com/gbrlsnchs/jwt/v3" "github.com/gorilla/mux" @@ -142,6 +143,10 @@ var runCmd = &cli.Command{ Usage: "(insecure) disable api auth", Hidden: true, }, + &cli.StringFlag{ + Name: "http-server-timeout", + Value: "30s", + }, }, Description: "Needs FULLNODE_API_INFO env-var to be set before running (see lotus-wallet --help for setup instructions)", Action: func(cctx *cli.Context) error { @@ -239,8 +244,14 @@ var runCmd = &cli.Command{ } } + timeout, err := time.ParseDuration(cctx.String("http-server-timeout")) + if err != nil { + return xerrors.Errorf("invalid time string %s: %x", cctx.String("http-server-timeout"), err) + } + srv := &http.Server{ - Handler: handler, + Handler: handler, + ReadHeaderTimeout: timeout, BaseContext: func(listener net.Listener) context.Context { ctx, _ := tag.New(context.Background(), tag.Upsert(metrics.APIInterface, "lotus-wallet")) return ctx diff --git a/cmd/lotus-worker/main.go b/cmd/lotus-worker/main.go index afee6f1e1..074a6a3e5 100644 --- a/cmd/lotus-worker/main.go +++ b/cmd/lotus-worker/main.go @@ -272,6 +272,10 @@ var runCmd = &cli.Command{ Value: "30m", EnvVars: []string{"LOTUS_WORKER_TIMEOUT"}, }, + &cli.StringFlag{ + Name: "http-server-timeout", + Value: "30s", + }, }, Before: func(cctx *cli.Context) error { if cctx.IsSet("address") { @@ -369,7 +373,7 @@ var runCmd = &cli.Command{ } if workerType == "" { - taskTypes = append(taskTypes, sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTProveReplicaUpdate1, sealtasks.TTFinalize, sealtasks.TTFinalizeReplicaUpdate) + taskTypes = append(taskTypes, sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTProveReplicaUpdate1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed, sealtasks.TTFinalizeReplicaUpdate) if !cctx.Bool("no-default") { workerType = sealtasks.WorkerSealing @@ -562,8 +566,14 @@ var runCmd = &cli.Command{ log.Info("Setting up control endpoint at " + address) + timeout, err := time.ParseDuration(cctx.String("http-server-timeout")) + if err != nil { + return xerrors.Errorf("invalid time string %s: %x", cctx.String("http-server-timeout"), err) + } + srv := &http.Server{ - Handler: sealworker.WorkerHandler(nodeApi.AuthVerify, remoteHandler, workerApi, true), + Handler: sealworker.WorkerHandler(nodeApi.AuthVerify, remoteHandler, workerApi, true), + ReadHeaderTimeout: timeout, BaseContext: func(listener net.Listener) context.Context { ctx, _ := tag.New(context.Background(), tag.Upsert(metrics.APIInterface, "lotus-worker")) return ctx diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go index 0c7874dfc..59f9d7258 100644 --- a/cmd/lotus/daemon.go +++ b/cmd/lotus/daemon.go @@ -16,6 +16,7 @@ import ( "runtime/pprof" "strings" + "github.com/DataDog/zstd" metricsprom "github.com/ipfs/go-metrics-prometheus" "github.com/mitchellh/go-homedir" "github.com/multiformats/go-multiaddr" @@ -491,6 +492,11 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool) bufr := bufio.NewReaderSize(rd, 1<<20) + header, err := bufr.Peek(4) + if err != nil { + return xerrors.Errorf("peek header: %w", err) + } + bar := pb.New64(l) br := bar.NewProxyReader(bufr) bar.ShowTimeLeft = true @@ -498,8 +504,20 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool) bar.ShowSpeed = true bar.Units = pb.U_BYTES + var ir io.Reader = br + + if string(header[1:]) == "\xB5\x2F\xFD" { // zstd + zr := zstd.NewReader(br) + defer func() { + if err := zr.Close(); err != nil { + log.Errorw("closing zstd reader", "error", err) + } + }() + ir = zr + } + bar.Start() - ts, err := cst.Import(ctx, br) + ts, err := cst.Import(ctx, ir) bar.Finish() if err != nil { diff --git a/cmd/tvx/extract_message.go b/cmd/tvx/extract_message.go index db6b5322c..8ff8a2b79 100644 --- a/cmd/tvx/extract_message.go +++ b/cmd/tvx/extract_message.go @@ -417,10 +417,10 @@ func findMsgAndPrecursors(ctx context.Context, mode string, msgCid cid.Cid, send case mode == PrecursorSelectAll: fallthrough case mode == PrecursorSelectParticipants && - msgSenderID == senderID || - msgRecipientID == recipientID || - msgSenderID == recipientID || - msgRecipientID == senderID: + (msgSenderID == senderID || + msgRecipientID == recipientID || + msgSenderID == recipientID || + msgRecipientID == senderID): related = append(related, m.Message) } diff --git a/cmd/tvx/stores.go b/cmd/tvx/stores.go index 9035c482a..b863ffa74 100644 --- a/cmd/tvx/stores.go +++ b/cmd/tvx/stores.go @@ -6,7 +6,6 @@ import ( "sync" "github.com/fatih/color" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" @@ -15,6 +14,7 @@ import ( offline "github.com/ipfs/go-ipfs-exchange-offline" cbor "github.com/ipfs/go-ipld-cbor" format "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/ipfs/go-merkledag" "golang.org/x/xerrors" diff --git a/conformance/driver.go b/conformance/driver.go index db8f2ccba..39bfecd9f 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -27,7 +27,8 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/conformance/chaos" - _ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures + _ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures + _ "github.com/filecoin-project/lotus/lib/sigs/delegated" _ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures "github.com/filecoin-project/lotus/storage/sealer/ffiwrapper" ) @@ -203,6 +204,9 @@ type ExecuteMessageParams struct { // Lookback is the LookbackStateGetter; returns the state tree at a given epoch. Lookback vm.LookbackStateGetter + + // TipSetGetter returns the tipset key at any given epoch. + TipSetGetter vm.TipSetGetter } // ExecuteMessage executes a conformance test vector message in a temporary VM. @@ -217,15 +221,26 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP params.Rand = NewFixedRand() } - // TODO: This lookback state returns the supplied precondition state tree, unconditionally. - // This is obviously not correct, but the lookback state tree is only used to validate the - // worker key when verifying a consensus fault. If the worker key hasn't changed in the - // current finality window, this workaround is enough. - // The correct solutions are documented in https://github.com/filecoin-project/ref-fvm/issues/381, - // but they're much harder to implement, and the tradeoffs aren't clear. - var lookback vm.LookbackStateGetter = func(ctx context.Context, epoch abi.ChainEpoch) (*state.StateTree, error) { - cst := cbor.NewCborStore(bs) - return state.LoadStateTree(cst, params.Preroot) + if params.TipSetGetter == nil { + // TODO: If/when we start writing conformance tests against the EVM, we'll need to + // actually implement this and (unfortunately) capture any tipsets looked up by + // messages. + params.TipSetGetter = func(context.Context, abi.ChainEpoch) (types.TipSetKey, error) { + return types.EmptyTSK, nil + } + } + + if params.Lookback == nil { + // TODO: This lookback state returns the supplied precondition state tree, unconditionally. + // This is obviously not correct, but the lookback state tree is only used to validate the + // worker key when verifying a consensus fault. If the worker key hasn't changed in the + // current finality window, this workaround is enough. + // The correct solutions are documented in https://github.com/filecoin-project/ref-fvm/issues/381, + // but they're much harder to implement, and the tradeoffs aren't clear. + params.Lookback = func(ctx context.Context, epoch abi.ChainEpoch) (*state.StateTree, error) { + cst := cbor.NewCborStore(bs) + return state.LoadStateTree(cst, params.Preroot) + } } vmOpts := &vm.VMOpts{ @@ -239,7 +254,8 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP Rand: params.Rand, BaseFee: params.BaseFee, NetworkVersion: params.NetworkVersion, - LookbackState: lookback, + LookbackState: params.Lookback, + TipSetGetter: params.TipSetGetter, } var vmi vm.Interface diff --git a/conformance/runner.go b/conformance/runner.go index b6bb5a164..ff738a4a5 100644 --- a/conformance/runner.go +++ b/conformance/runner.go @@ -14,12 +14,12 @@ import ( "github.com/fatih/color" "github.com/hashicorp/go-multierror" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" offline "github.com/ipfs/go-ipfs-exchange-offline" format "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/ipfs/go-merkledag" "github.com/ipld/go-car" diff --git a/documentation/en/api-v0-methods-miner.md b/documentation/en/api-v0-methods-miner.md index 413499c1a..d18be03f5 100644 --- a/documentation/en/api-v0-methods-miner.md +++ b/documentation/en/api-v0-methods-miner.md @@ -464,7 +464,9 @@ Inputs: { "SealProof": 8, "SectorNumber": 9, - "SectorKey": null, + "SectorKey": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "SealedCID": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" } @@ -472,7 +474,7 @@ Inputs: ], "Bw==", 10101, - 17 + 18 ] ``` @@ -1279,8 +1281,12 @@ Response: "ProposalCid": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "AddFundsCid": null, - "PublishCid": null, + "AddFundsCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PublishCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Miner": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "Client": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "State": 42, @@ -1295,7 +1301,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -1457,8 +1465,12 @@ Response: "ProposalCid": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "AddFundsCid": null, - "PublishCid": null, + "AddFundsCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PublishCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Miner": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "Client": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "State": 42, @@ -1473,7 +1485,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -1509,7 +1523,9 @@ Response: "Selector": { "Raw": "Ynl0ZSBhcnJheQ==" }, - "PieceCID": null, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PricePerByte": "0", "PaymentInterval": 42, "PaymentIntervalIncrease": 42, @@ -2908,7 +2924,9 @@ Inputs: 1024, {}, { - "PublishCid": null, + "PublishCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "DealID": 5432, "DealProposal": { "PieceCID": { @@ -2962,7 +2980,9 @@ Response: "FailedSectors": { "123": "can't acquire read lock" }, - "Msg": null, + "Msg": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Error": "string value" } ] @@ -3156,7 +3176,9 @@ Response: 123, 124 ], - "Msg": null, + "Msg": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Error": "string value" } ] @@ -3204,7 +3226,9 @@ Inputs: } }, "DealInfo": { - "PublishCid": null, + "PublishCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "DealID": 5432, "DealProposal": { "PieceCID": { @@ -3232,8 +3256,12 @@ Inputs: "TicketValue": "Bw==", "TicketEpoch": 10101, "PreCommit1Out": "Bw==", - "CommD": null, - "CommR": null, + "CommD": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "CommR": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PreCommitInfo": { "SealProof": 8, "SectorNumber": 9, @@ -3245,10 +3273,14 @@ Inputs: 5432 ], "Expiration": 10101, - "UnsealedCid": null + "UnsealedCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "PreCommitDeposit": "0", - "PreCommitMessage": null, + "PreCommitMessage": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PreCommitTipSet": [ { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" @@ -3260,7 +3292,9 @@ Inputs: "SeedValue": "Bw==", "SeedEpoch": 10101, "CommitProof": "Ynl0ZSBhcnJheQ==", - "CommitMessage": null, + "CommitMessage": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Log": [ { "Kind": "string value", @@ -3396,7 +3430,12 @@ Perms: admin Inputs: `null` -Response: `null` +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` ### SectorTerminatePending SectorTerminatePending returns a list of pending sector terminations to be sent in the next batch message @@ -3497,8 +3536,12 @@ Response: { "SectorID": 9, "State": "Proving", - "CommD": null, - "CommR": null, + "CommD": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "CommR": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Proof": "Ynl0ZSBhcnJheQ==", "Deals": [ 5432 @@ -3512,7 +3555,9 @@ Response: } }, "DealInfo": { - "PublishCid": null, + "PublishCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "DealID": 5432, "DealProposal": { "PieceCID": { @@ -3545,11 +3590,17 @@ Response: "Value": "Bw==", "Epoch": 10101 }, - "PreCommitMsg": null, - "CommitMsg": null, + "PreCommitMsg": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "CommitMsg": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Retries": 42, "ToUpgrade": true, - "ReplicaUpdateMessage": null, + "ReplicaUpdateMessage": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "LastErr": "string value", "Log": [ { @@ -3603,7 +3654,9 @@ Inputs: 1040384, 1024, "Bw==", - null + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } ] ``` diff --git a/documentation/en/api-v0-methods-worker.md b/documentation/en/api-v0-methods-worker.md index e53211089..dab251a7c 100644 --- a/documentation/en/api-v0-methods-worker.md +++ b/documentation/en/api-v0-methods-worker.md @@ -1601,13 +1601,7 @@ Inputs: "Number": 9 }, "ProofType": 8 - }, - [ - { - "Offset": 1024, - "Size": 1024 - } - ] + } ] ``` @@ -1636,13 +1630,7 @@ Inputs: "Number": 9 }, "ProofType": 8 - }, - [ - { - "Offset": 1024, - "Size": 1024 - } - ] + } ] ``` diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index 7ee6ceaa9..fe639b2f3 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -754,7 +754,10 @@ Response: { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } } ] ``` @@ -1247,7 +1250,9 @@ Inputs: { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - null + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } ] ``` @@ -1259,7 +1264,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "Piece": null, + "Piece": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Size": 42, "MinPrice": "0", "UnsealPrice": "0", @@ -1270,7 +1277,9 @@ Response: "MinerPeer": { "Address": "f01234", "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", - "PieceCID": null + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } } } ] @@ -1341,7 +1350,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -1445,7 +1456,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -1510,7 +1523,9 @@ Response: "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, "ID": 5, - "PieceCID": null, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PricePerByte": "0", "UnsealPrice": "0", "Status": 0, @@ -1683,7 +1698,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -1748,7 +1765,9 @@ Response: { "Key": 50, "Err": "string value", - "Root": null, + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Source": "string value", "FilePath": "string value", "CARPath": "string value" @@ -1773,7 +1792,9 @@ Response: "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, "ID": 5, - "PieceCID": null, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PricePerByte": "0", "UnsealPrice": "0", "Status": 0, @@ -1834,7 +1855,9 @@ Inputs: { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - null + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } ] ``` @@ -1845,7 +1868,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "Piece": null, + "Piece": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Size": 42, "MinPrice": "0", "UnsealPrice": "0", @@ -1856,7 +1881,9 @@ Response: "MinerPeer": { "Address": "f01234", "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", - "PieceCID": null + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } } } ``` @@ -1933,7 +1960,9 @@ Inputs: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "Piece": null, + "Piece": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "DatamodelPathSelector": "Links/21/Hash/Links/42/Hash", "Size": 42, "FromLocalCAR": "string value", @@ -1946,7 +1975,9 @@ Inputs: "MinerPeer": { "Address": "f01234", "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", - "PieceCID": null + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } } }, { @@ -1988,7 +2019,9 @@ Inputs: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "Piece": null, + "Piece": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "DatamodelPathSelector": "Links/21/Hash/Links/42/Hash", "Size": 42, "FromLocalCAR": "string value", @@ -2001,7 +2034,9 @@ Inputs: "MinerPeer": { "Address": "f01234", "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", - "PieceCID": null + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } } }, { @@ -2037,7 +2072,9 @@ Inputs: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -2053,7 +2090,12 @@ Inputs: ] ``` -Response: `null` +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` ### ClientStatelessDeal ClientStatelessDeal fire-and-forget-proposes an offline deal to a miner without subsequent tracking. @@ -2070,7 +2112,9 @@ Inputs: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -2086,7 +2130,12 @@ Inputs: ] ``` -Response: `null` +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` ## Create @@ -2613,7 +2662,9 @@ Response: { "SealProof": 8, "SectorNumber": 9, - "SectorKey": null, + "SectorKey": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "SealedCID": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" } @@ -4156,7 +4207,9 @@ Response: "PendingAmt": "0", "NonReservedAmt": "0", "PendingAvailableAmt": "0", - "PendingWaitSentinel": null, + "PendingWaitSentinel": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "QueuedAmt": "0", "VoucherReedeemedAmt": "0" } @@ -4185,7 +4238,9 @@ Response: "PendingAmt": "0", "NonReservedAmt": "0", "PendingAvailableAmt": "0", - "PendingWaitSentinel": null, + "PendingWaitSentinel": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "QueuedAmt": "0", "VoucherReedeemedAmt": "0" } @@ -4672,7 +4727,7 @@ Perms: read Inputs: ```json [ - 17 + 18 ] ``` @@ -4687,7 +4742,7 @@ Perms: read Inputs: ```json [ - 17 + 18 ] ``` @@ -4792,7 +4847,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "GasCost": { "Message": { @@ -4825,7 +4883,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -4869,7 +4930,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -4932,7 +4996,8 @@ Response: "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, "Nonce": 42, - "Balance": "0" + "Balance": "0", + "Address": "\u003cempty\u003e" } } ``` @@ -5058,7 +5123,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "GasCost": { "Message": { @@ -5091,7 +5159,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -5135,7 +5206,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -5257,7 +5331,8 @@ Response: "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, "Nonce": 42, - "Balance": "0" + "Balance": "0", + "Address": "\u003cempty\u003e" } ``` @@ -5458,7 +5533,8 @@ Response: "UpgradeChocolateHeight": 10101, "UpgradeOhSnapHeight": 10101, "UpgradeSkyrHeight": 10101, - "UpgradeSharkHeight": 10101 + "UpgradeSharkHeight": 10101, + "UpgradeHyggeHeight": 10101 } } ``` @@ -5549,7 +5625,10 @@ Response: { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } } ``` @@ -5862,7 +5941,9 @@ Response: "ExpectedStoragePledge": "0", "ReplacedSectorAge": 10101, "ReplacedDayReward": "0", - "SectorKeyCID": null, + "SectorKeyCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "SimpleQAPower": true } ] @@ -6030,7 +6111,9 @@ Inputs: 5432 ], "Expiration": 10101, - "UnsealedCid": null + "UnsealedCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, [ { @@ -6152,7 +6235,9 @@ Inputs: 5432 ], "Expiration": 10101, - "UnsealedCid": null + "UnsealedCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, [ { @@ -6335,7 +6420,9 @@ Response: "ExpectedStoragePledge": "0", "ReplacedSectorAge": 10101, "ReplacedDayReward": "0", - "SectorKeyCID": null, + "SectorKeyCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "SimpleQAPower": true } ] @@ -6371,7 +6458,7 @@ Inputs: ] ``` -Response: `17` +Response: `18` ### StateReadState StateReadState returns the indicated actor's state. @@ -6468,7 +6555,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "GasCost": { "Message": { @@ -6501,7 +6591,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -6545,7 +6638,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -6616,7 +6712,10 @@ Response: "Receipt": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "ReturnDec": {}, "TipSet": [ @@ -6670,7 +6769,10 @@ Response: "Receipt": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "ReturnDec": {}, "TipSet": [ @@ -6759,7 +6861,9 @@ Response: "ExpectedStoragePledge": "0", "ReplacedSectorAge": 10101, "ReplacedDayReward": "0", - "SectorKeyCID": null, + "SectorKeyCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "SimpleQAPower": true } ``` @@ -6830,7 +6934,9 @@ Response: 5432 ], "Expiration": 10101, - "UnsealedCid": null + "UnsealedCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "PreCommitDeposit": "0", "PreCommitEpoch": 10101 @@ -6982,7 +7088,10 @@ Response: "Receipt": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "ReturnDec": {}, "TipSet": [ @@ -7039,7 +7148,10 @@ Response: "Receipt": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "ReturnDec": {}, "TipSet": [ diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index 9c104718c..8e8176c23 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -15,6 +15,7 @@ * [ChainExport](#ChainExport) * [ChainGetBlock](#ChainGetBlock) * [ChainGetBlockMessages](#ChainGetBlockMessages) + * [ChainGetEvents](#ChainGetEvents) * [ChainGetGenesis](#ChainGetGenesis) * [ChainGetMessage](#ChainGetMessage) * [ChainGetMessagesInTipset](#ChainGetMessagesInTipset) @@ -65,6 +66,43 @@ * [ClientStatelessDeal](#ClientStatelessDeal) * [Create](#Create) * [CreateBackup](#CreateBackup) +* [Eth](#Eth) + * [EthAccounts](#EthAccounts) + * [EthAddressToFilecoinAddress](#EthAddressToFilecoinAddress) + * [EthBlockNumber](#EthBlockNumber) + * [EthCall](#EthCall) + * [EthChainId](#EthChainId) + * [EthEstimateGas](#EthEstimateGas) + * [EthFeeHistory](#EthFeeHistory) + * [EthGasPrice](#EthGasPrice) + * [EthGetBalance](#EthGetBalance) + * [EthGetBlockByHash](#EthGetBlockByHash) + * [EthGetBlockByNumber](#EthGetBlockByNumber) + * [EthGetBlockTransactionCountByHash](#EthGetBlockTransactionCountByHash) + * [EthGetBlockTransactionCountByNumber](#EthGetBlockTransactionCountByNumber) + * [EthGetCode](#EthGetCode) + * [EthGetFilterChanges](#EthGetFilterChanges) + * [EthGetFilterLogs](#EthGetFilterLogs) + * [EthGetLogs](#EthGetLogs) + * [EthGetMessageCidByTransactionHash](#EthGetMessageCidByTransactionHash) + * [EthGetStorageAt](#EthGetStorageAt) + * [EthGetTransactionByBlockHashAndIndex](#EthGetTransactionByBlockHashAndIndex) + * [EthGetTransactionByBlockNumberAndIndex](#EthGetTransactionByBlockNumberAndIndex) + * [EthGetTransactionByHash](#EthGetTransactionByHash) + * [EthGetTransactionCount](#EthGetTransactionCount) + * [EthGetTransactionHashByCid](#EthGetTransactionHashByCid) + * [EthGetTransactionReceipt](#EthGetTransactionReceipt) + * [EthMaxPriorityFeePerGas](#EthMaxPriorityFeePerGas) + * [EthNewBlockFilter](#EthNewBlockFilter) + * [EthNewFilter](#EthNewFilter) + * [EthNewPendingTransactionFilter](#EthNewPendingTransactionFilter) + * [EthProtocolVersion](#EthProtocolVersion) + * [EthSendRawTransaction](#EthSendRawTransaction) + * [EthSubscribe](#EthSubscribe) + * [EthUninstallFilter](#EthUninstallFilter) + * [EthUnsubscribe](#EthUnsubscribe) +* [Filecoin](#Filecoin) + * [FilecoinAddressToEthAddress](#FilecoinAddressToEthAddress) * [Gas](#Gas) * [GasEstimateFeeCap](#GasEstimateFeeCap) * [GasEstimateGasLimit](#GasEstimateGasLimit) @@ -135,6 +173,7 @@ * [NetDisconnect](#NetDisconnect) * [NetFindPeer](#NetFindPeer) * [NetLimit](#NetLimit) + * [NetListening](#NetListening) * [NetPeerInfo](#NetPeerInfo) * [NetPeers](#NetPeers) * [NetPing](#NetPing) @@ -144,6 +183,7 @@ * [NetPubsubScores](#NetPubsubScores) * [NetSetLimit](#NetSetLimit) * [NetStat](#NetStat) + * [NetVersion](#NetVersion) * [Node](#Node) * [NodeStatus](#NodeStatus) * [Paych](#Paych) @@ -254,6 +294,8 @@ * [WalletSignMessage](#WalletSignMessage) * [WalletValidateAddress](#WalletValidateAddress) * [WalletVerify](#WalletVerify) +* [Web3](#Web3) + * [Web3ClientVersion](#Web3ClientVersion) ## @@ -581,6 +623,38 @@ Response: } ``` +### ChainGetEvents +ChainGetEvents returns the events under an event AMT root CID. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +[ + { + "Emitter": 1000, + "Entries": [ + { + "Flags": 7, + "Key": "string value", + "Codec": 42, + "Value": "Ynl0ZSBhcnJheQ==" + } + ] + } +] +``` + ### ChainGetGenesis ChainGetGenesis returns the genesis tipset. @@ -766,7 +840,10 @@ Response: { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } } ] ``` @@ -1291,7 +1368,9 @@ Inputs: { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - null + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } ] ``` @@ -1303,7 +1382,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "Piece": null, + "Piece": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Size": 42, "MinPrice": "0", "UnsealPrice": "0", @@ -1314,7 +1395,9 @@ Response: "MinerPeer": { "Address": "f01234", "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", - "PieceCID": null + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } } } ] @@ -1385,7 +1468,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -1489,7 +1574,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -1554,7 +1641,9 @@ Response: "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, "ID": 5, - "PieceCID": null, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PricePerByte": "0", "UnsealPrice": "0", "Status": 0, @@ -1727,7 +1816,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -1792,7 +1883,9 @@ Response: { "Key": 50, "Err": "string value", - "Root": null, + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Source": "string value", "FilePath": "string value", "CARPath": "string value" @@ -1816,7 +1909,9 @@ Response: "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, "ID": 5, - "PieceCID": null, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PricePerByte": "0", "UnsealPrice": "0", "Status": 0, @@ -1877,7 +1972,9 @@ Inputs: { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - null + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } ] ``` @@ -1888,7 +1985,9 @@ Response: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "Piece": null, + "Piece": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "Size": 42, "MinPrice": "0", "UnsealPrice": "0", @@ -1899,7 +1998,9 @@ Response: "MinerPeer": { "Address": "f01234", "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", - "PieceCID": null + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } } } ``` @@ -1982,7 +2083,9 @@ Inputs: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "Piece": null, + "Piece": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "DataSelector": "Links/21/Hash/Links/42/Hash", "Size": 42, "Total": "0", @@ -1994,7 +2097,9 @@ Inputs: "MinerPeer": { "Address": "f01234", "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", - "PieceCID": null + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "RemoteStore": "00000000-0000-0000-0000-000000000000" } @@ -2054,7 +2159,9 @@ Inputs: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -2070,7 +2177,12 @@ Inputs: ] ``` -Response: `null` +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` ### ClientStatelessDeal ClientStatelessDeal fire-and-forget-proposes an offline deal to a miner without subsequent tracking. @@ -2087,7 +2199,9 @@ Inputs: "Root": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "PieceCid": null, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "PieceSize": 1024, "RawBlockSize": 42 }, @@ -2103,7 +2217,12 @@ Inputs: ] ``` -Response: `null` +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` ## Create @@ -2126,6 +2245,725 @@ Inputs: Response: `{}` +## Eth +These methods are used for Ethereum-compatible JSON-RPC calls + +EthAccounts will always return [] since we don't expect Lotus to manage private keys + + +### EthAccounts +There are not yet any comments for this method. + +Perms: read + +Inputs: `null` + +Response: +```json +[ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" +] +``` + +### EthAddressToFilecoinAddress +EthAddressToFilecoinAddress converts an EthAddress into an f410 Filecoin Address + + +Perms: read + +Inputs: +```json +[ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" +] +``` + +Response: `"f01234"` + +### EthBlockNumber +EthBlockNumber returns the height of the latest (heaviest) TipSet + + +Perms: read + +Inputs: `null` + +Response: `"0x5"` + +### EthCall + + +Perms: read + +Inputs: +```json +[ + { + "from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "gas": "0x5", + "gasPrice": "0x0", + "value": "0x0", + "data": "0x07" + }, + "string value" +] +``` + +Response: `"0x07"` + +### EthChainId + + +Perms: read + +Inputs: `null` + +Response: `"0x5"` + +### EthEstimateGas + + +Perms: read + +Inputs: +```json +[ + { + "from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "gas": "0x5", + "gasPrice": "0x0", + "value": "0x0", + "data": "0x07" + } +] +``` + +Response: `"0x5"` + +### EthFeeHistory + + +Perms: read + +Inputs: +```json +[ + "Bw==" +] +``` + +Response: +```json +{ + "oldestBlock": "0x5", + "baseFeePerGas": [ + "0x0" + ], + "gasUsedRatio": [ + 12.3 + ], + "reward": [] +} +``` + +### EthGasPrice + + +Perms: read + +Inputs: `null` + +Response: `"0x0"` + +### EthGetBalance + + +Perms: read + +Inputs: +```json +[ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "string value" +] +``` + +Response: `"0x0"` + +### EthGetBlockByHash + + +Perms: read + +Inputs: +```json +[ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + true +] +``` + +Response: +```json +{ + "hash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "parentHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "sha3Uncles": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "miner": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "stateRoot": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "transactionsRoot": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "receiptsRoot": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "logsBloom": "0x07", + "difficulty": "0x5", + "totalDifficulty": "0x5", + "number": "0x5", + "gasLimit": "0x5", + "gasUsed": "0x5", + "timestamp": "0x5", + "extraData": "0x07", + "mixHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "nonce": "0x0707070707070707", + "baseFeePerGas": "0x0", + "size": "0x5", + "transactions": [ + {} + ], + "uncles": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ] +} +``` + +### EthGetBlockByNumber + + +Perms: read + +Inputs: +```json +[ + "string value", + true +] +``` + +Response: +```json +{ + "hash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "parentHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "sha3Uncles": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "miner": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "stateRoot": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "transactionsRoot": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "receiptsRoot": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "logsBloom": "0x07", + "difficulty": "0x5", + "totalDifficulty": "0x5", + "number": "0x5", + "gasLimit": "0x5", + "gasUsed": "0x5", + "timestamp": "0x5", + "extraData": "0x07", + "mixHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "nonce": "0x0707070707070707", + "baseFeePerGas": "0x0", + "size": "0x5", + "transactions": [ + {} + ], + "uncles": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ] +} +``` + +### EthGetBlockTransactionCountByHash +EthGetBlockTransactionCountByHash returns the number of messages in the TipSet + + +Perms: read + +Inputs: +```json +[ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" +] +``` + +Response: `"0x5"` + +### EthGetBlockTransactionCountByNumber +EthGetBlockTransactionCountByNumber returns the number of messages in the TipSet + + +Perms: read + +Inputs: +```json +[ + "0x5" +] +``` + +Response: `"0x5"` + +### EthGetCode + + +Perms: read + +Inputs: +```json +[ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "string value" +] +``` + +Response: `"0x07"` + +### EthGetFilterChanges +Polling method for a filter, returns event logs which occurred since last poll. +(requires write perm since timestamp of last filter execution will be written) + + +Perms: write + +Inputs: +```json +[ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" +] +``` + +Response: +```json +[ + {} +] +``` + +### EthGetFilterLogs +Returns event logs matching filter with given id. +(requires write perm since timestamp of last filter execution will be written) + + +Perms: write + +Inputs: +```json +[ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" +] +``` + +Response: +```json +[ + {} +] +``` + +### EthGetLogs +Returns event logs matching given filter spec. + + +Perms: read + +Inputs: +```json +[ + { + "fromBlock": "2301220", + "address": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "topics": null + } +] +``` + +Response: +```json +[ + {} +] +``` + +### EthGetMessageCidByTransactionHash + + +Perms: read + +Inputs: +```json +[ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### EthGetStorageAt + + +Perms: read + +Inputs: +```json +[ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "0x07", + "string value" +] +``` + +Response: `"0x07"` + +### EthGetTransactionByBlockHashAndIndex + + +Perms: read + +Inputs: +```json +[ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "0x5" +] +``` + +Response: +```json +{ + "chainId": "0x5", + "nonce": "0x5", + "hash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockNumber": "0x5", + "transactionIndex": "0x5", + "from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "value": "0x0", + "type": "0x5", + "input": "0x07", + "gas": "0x5", + "maxFeePerGas": "0x0", + "maxPriorityFeePerGas": "0x0", + "accessList": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "v": "0x0", + "r": "0x0", + "s": "0x0" +} +``` + +### EthGetTransactionByBlockNumberAndIndex + + +Perms: read + +Inputs: +```json +[ + "0x5", + "0x5" +] +``` + +Response: +```json +{ + "chainId": "0x5", + "nonce": "0x5", + "hash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockNumber": "0x5", + "transactionIndex": "0x5", + "from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "value": "0x0", + "type": "0x5", + "input": "0x07", + "gas": "0x5", + "maxFeePerGas": "0x0", + "maxPriorityFeePerGas": "0x0", + "accessList": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "v": "0x0", + "r": "0x0", + "s": "0x0" +} +``` + +### EthGetTransactionByHash + + +Perms: read + +Inputs: +```json +[ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" +] +``` + +Response: +```json +{ + "chainId": "0x5", + "nonce": "0x5", + "hash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockNumber": "0x5", + "transactionIndex": "0x5", + "from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "value": "0x0", + "type": "0x5", + "input": "0x07", + "gas": "0x5", + "maxFeePerGas": "0x0", + "maxPriorityFeePerGas": "0x0", + "accessList": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "v": "0x0", + "r": "0x0", + "s": "0x0" +} +``` + +### EthGetTransactionCount + + +Perms: read + +Inputs: +```json +[ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "string value" +] +``` + +Response: `"0x5"` + +### EthGetTransactionHashByCid + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"` + +### EthGetTransactionReceipt + + +Perms: read + +Inputs: +```json +[ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" +] +``` + +Response: +```json +{ + "transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "transactionIndex": "0x5", + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockNumber": "0x5", + "from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "root": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "status": "0x5", + "contractAddress": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "cumulativeGasUsed": "0x5", + "gasUsed": "0x5", + "effectiveGasPrice": "0x0", + "logsBloom": "0x07", + "logs": [ + { + "address": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "data": "0x07", + "topics": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "removed": true, + "logIndex": "0x5", + "transactionIndex": "0x5", + "transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockNumber": "0x5" + } + ], + "type": "0x5" +} +``` + +### EthMaxPriorityFeePerGas + + +Perms: read + +Inputs: `null` + +Response: `"0x0"` + +### EthNewBlockFilter +Installs a persistent filter to notify when a new block arrives. + + +Perms: write + +Inputs: `null` + +Response: `"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"` + +### EthNewFilter +Installs a persistent filter based on given filter spec. + + +Perms: write + +Inputs: +```json +[ + { + "fromBlock": "2301220", + "address": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "topics": null + } +] +``` + +Response: `"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"` + +### EthNewPendingTransactionFilter +Installs a persistent filter to notify when new messages arrive in the message pool. + + +Perms: write + +Inputs: `null` + +Response: `"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"` + +### EthProtocolVersion + + +Perms: read + +Inputs: `null` + +Response: `"0x5"` + +### EthSendRawTransaction + + +Perms: read + +Inputs: +```json +[ + "0x07" +] +``` + +Response: `"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"` + +### EthSubscribe +Subscribe to different event types using websockets +eventTypes is one or more of: + - newHeads: notify when new blocks arrive. + - pendingTransactions: notify when new messages arrive in the message pool. + - logs: notify new event logs that match a criteria +params contains additional parameters used with the log event type +The client will receive a stream of EthSubscriptionResponse values until EthUnsubscribe is called. + + +Perms: write + +Inputs: +```json +[ + "Bw==" +] +``` + +Response: `"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"` + +### EthUninstallFilter +Uninstalls a filter with given id. + + +Perms: write + +Inputs: +```json +[ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" +] +``` + +Response: `true` + +### EthUnsubscribe +Unsubscribe from a websocket subscription + + +Perms: write + +Inputs: +```json +[ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" +] +``` + +Response: `true` + +## Filecoin + + +### FilecoinAddressToEthAddress +FilecoinAddressToEthAddress converts an f410 or f0 Filecoin Address to an EthAddress + + +Perms: read + +Inputs: +```json +[ + "f01234" +] +``` + +Response: `"0x5cbeecf99d3fdb3f25e309cc264f240bb0664031"` + ## Gas @@ -2630,7 +3468,9 @@ Response: { "SealProof": 8, "SectorNumber": 9, - "SectorKey": null, + "SectorKey": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "SealedCID": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" } @@ -4249,6 +5089,15 @@ Response: } ``` +### NetListening + + +Perms: read + +Inputs: `null` + +Response: `true` + ### NetPeerInfo @@ -4482,6 +5331,15 @@ Response: } ``` +### NetVersion + + +Perms: read + +Inputs: `null` + +Response: `"string value"` + ## Node These methods are general node management and status commands @@ -4556,7 +5414,9 @@ Response: "PendingAmt": "0", "NonReservedAmt": "0", "PendingAvailableAmt": "0", - "PendingWaitSentinel": null, + "PendingWaitSentinel": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "QueuedAmt": "0", "VoucherReedeemedAmt": "0" } @@ -4585,7 +5445,9 @@ Response: "PendingAmt": "0", "NonReservedAmt": "0", "PendingAvailableAmt": "0", - "PendingWaitSentinel": null, + "PendingWaitSentinel": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "QueuedAmt": "0", "VoucherReedeemedAmt": "0" } @@ -5135,7 +5997,7 @@ Perms: read Inputs: ```json [ - 17 + 18 ] ``` @@ -5150,7 +6012,7 @@ Perms: read Inputs: ```json [ - 17 + 18 ] ``` @@ -5255,7 +6117,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "GasCost": { "Message": { @@ -5288,7 +6153,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -5332,7 +6200,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -5395,7 +6266,8 @@ Response: "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, "Nonce": 42, - "Balance": "0" + "Balance": "0", + "Address": "\u003cempty\u003e" } } ``` @@ -5521,7 +6393,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "GasCost": { "Message": { @@ -5554,7 +6429,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -5598,7 +6476,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -5771,7 +6652,8 @@ Response: "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, "Nonce": 42, - "Balance": "0" + "Balance": "0", + "Address": "\u003cempty\u003e" } ``` @@ -5996,7 +6878,8 @@ Response: "UpgradeChocolateHeight": 10101, "UpgradeOhSnapHeight": 10101, "UpgradeSkyrHeight": 10101, - "UpgradeSharkHeight": 10101 + "UpgradeSharkHeight": 10101, + "UpgradeHyggeHeight": 10101 } } ``` @@ -6383,7 +7266,9 @@ Response: "ExpectedStoragePledge": "0", "ReplacedSectorAge": 10101, "ReplacedDayReward": "0", - "SectorKeyCID": null, + "SectorKeyCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "SimpleQAPower": true } ] @@ -6579,7 +7464,9 @@ Inputs: 5432 ], "Expiration": 10101, - "UnsealedCid": null + "UnsealedCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, [ { @@ -6701,7 +7588,9 @@ Inputs: 5432 ], "Expiration": 10101, - "UnsealedCid": null + "UnsealedCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, [ { @@ -6884,7 +7773,9 @@ Response: "ExpectedStoragePledge": "0", "ReplacedSectorAge": 10101, "ReplacedDayReward": "0", - "SectorKeyCID": null, + "SectorKeyCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "SimpleQAPower": true } ] @@ -6920,7 +7811,7 @@ Inputs: ] ``` -Response: `17` +Response: `18` ### StateReadState StateReadState returns the indicated actor's state. @@ -7017,7 +7908,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "GasCost": { "Message": { @@ -7050,7 +7944,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -7094,7 +7991,10 @@ Response: "MsgRct": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "Error": "string value", "Duration": 60000000000, @@ -7176,7 +8076,10 @@ Response: "Receipt": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "ReturnDec": {}, "TipSet": [ @@ -7265,7 +8168,9 @@ Response: "ExpectedStoragePledge": "0", "ReplacedSectorAge": 10101, "ReplacedDayReward": "0", - "SectorKeyCID": null, + "SectorKeyCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, "SimpleQAPower": true } ``` @@ -7341,7 +8246,9 @@ Response: 5432 ], "Expiration": 10101, - "UnsealedCid": null + "UnsealedCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "PreCommitDeposit": "0", "PreCommitEpoch": 10101 @@ -7497,7 +8404,10 @@ Response: "Receipt": { "ExitCode": 0, "Return": "Ynl0ZSBhcnJheQ==", - "GasUsed": 9 + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } }, "ReturnDec": {}, "TipSet": [ @@ -8055,3 +8965,16 @@ Inputs: Response: `true` +## Web3 + + +### Web3ClientVersion +Returns the client version + + +Perms: read + +Inputs: `null` + +Response: `"string value"` + diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index a3b02e23f..d302a309a 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -7,7 +7,7 @@ USAGE: lotus-miner [global options] command [command options] [arguments...] VERSION: - 1.19.0 + 1.20.0 COMMANDS: init Initialize a lotus miner repo @@ -62,24 +62,24 @@ USAGE: lotus-miner init command [command options] [arguments...] COMMANDS: - restore Initialize a lotus miner repo from a backup - service Initialize a lotus miner sub-service - help, h Shows a list of commands or help for one command + restore Initialize a lotus miner repo from a backup + service Initialize a lotus miner sub-service + help, h Shows a list of commands or help for one command OPTIONS: - --actor value specify the address of an already created miner actor - --create-worker-key create separate worker key (default: false) - --worker value, -w value worker key to use (overrides --create-worker-key) - --owner value, -o value owner key to use - --sector-size value specify sector size to use - --pre-sealed-sectors value specify set of presealed sectors for starting as a genesis miner (accepts multiple inputs) - --pre-sealed-metadata value specify the metadata file for the presealed sectors - --nosync don't check full-node sync status (default: false) - --symlink-imported-sectors attempt to symlink to presealed sectors instead of copying them into place (default: false) - --no-local-storage don't use storageminer repo for sector storage (default: false) - --gas-premium value set gas premium for initialization messages in AttoFIL (default: "0") - --from value select which address to send actor creation message from - --help, -h show help (default: false) + --actor value specify the address of an already created miner actor + --create-worker-key create separate worker key (default: false) + --worker value, -w value worker key to use (overrides --create-worker-key) + --owner value, -o value owner key to use + --sector-size value specify sector size to use + --pre-sealed-sectors value [ --pre-sealed-sectors value ] specify set of presealed sectors for starting as a genesis miner + --pre-sealed-metadata value specify the metadata file for the presealed sectors + --nosync don't check full-node sync status (default: false) + --symlink-imported-sectors attempt to symlink to presealed sectors instead of copying them into place (default: false) + --no-local-storage don't use storageminer repo for sector storage (default: false) + --gas-premium value set gas premium for initialization messages in AttoFIL (default: "0") + --from value select which address to send actor creation message from + --help, -h show help (default: false) ``` @@ -107,11 +107,11 @@ USAGE: lotus-miner init service [command options] [backupFile] OPTIONS: - --api-sealer value sealer API info (lotus-miner auth api-info --perm=admin) - --api-sector-index value sector Index API info (lotus-miner auth api-info --perm=admin) - --config value config file (config.toml) - --nosync don't check full-node sync status (default: false) - --type value type of service to be enabled (accepts multiple inputs) + --api-sealer value sealer API info (lotus-miner auth api-info --perm=admin) + --api-sector-index value sector Index API info (lotus-miner auth api-info --perm=admin) + --config value config file (config.toml) + --nosync don't check full-node sync status (default: false) + --type value [ --type value ] type of service to be enabled ``` @@ -153,9 +153,9 @@ USAGE: lotus-miner config command [command options] [arguments...] COMMANDS: - default Print default node config - updated Print updated node config - help, h Shows a list of commands or help for one command + default Print default node config + updated Print updated node config + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -231,18 +231,18 @@ USAGE: lotus-miner actor command [command options] [arguments...] COMMANDS: - set-addresses, set-addrs set addresses that your miner can be publicly dialed on - withdraw withdraw available balance to beneficiary - repay-debt pay down a miner's debt - set-peer-id set the peer id of your miner - set-owner Set owner address (this command should be invoked twice, first with the old owner as the senderAddress, and then with the new owner) - control Manage control addresses - propose-change-worker Propose a worker address change - confirm-change-worker Confirm a worker address change - compact-allocated compact allocated sectors bitfield - propose-change-beneficiary Propose a beneficiary address change - confirm-change-beneficiary Confirm a beneficiary address change - help, h Shows a list of commands or help for one command + set-addresses, set-addrs set addresses that your miner can be publicly dialed on + withdraw withdraw available balance to beneficiary + repay-debt pay down a miner's debt + set-peer-id set the peer id of your miner + set-owner Set owner address (this command should be invoked twice, first with the old owner as the senderAddress, and then with the new owner) + control Manage control addresses + propose-change-worker Propose a worker address change + confirm-change-worker Confirm a worker address change + compact-allocated compact allocated sectors bitfield + propose-change-beneficiary Propose a beneficiary address change + confirm-change-beneficiary Confirm a beneficiary address change + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -315,9 +315,9 @@ USAGE: lotus-miner actor control command [command options] [arguments...] COMMANDS: - list Get currently set control addresses - set Set control address(-es) - help, h Shows a list of commands or help for one command + list Get currently set control addresses + set Set control address(-es) + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -431,8 +431,8 @@ USAGE: lotus-miner info command [command options] [arguments...] COMMANDS: - all dump all related miner info - help, h Shows a list of commands or help for one command + all dump all related miner info + help, h Shows a list of commands or help for one command OPTIONS: --hide-sectors-info hide sectors info (default: false) @@ -463,9 +463,9 @@ USAGE: lotus-miner auth command [command options] [arguments...] COMMANDS: - create-token Create token - api-info Get token with API info required to connect to this node - help, h Shows a list of commands or help for one command + create-token Create token + api-info Get token with API info required to connect to this node + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -507,10 +507,10 @@ USAGE: lotus-miner log command [command options] [arguments...] COMMANDS: - list List log systems - set-level Set log level - alerts Get alert states - help, h Shows a list of commands or help for one command + list List log systems + set-level Set log level + alerts Get alert states + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -556,9 +556,10 @@ DESCRIPTION: GOLOG_LOG_FMT - Change output log format (json, nocolor) GOLOG_FILE - Write logs to file GOLOG_OUTPUT - Specify whether to output to file, stderr, stdout or a combination, i.e. file+stderr + OPTIONS: - --system value limit to log system (accepts multiple inputs) + --system value [ --system value ] limit to log system ``` @@ -616,18 +617,18 @@ USAGE: lotus-miner storage-deals command [command options] [arguments...] COMMANDS: - import-data Manually import data for a deal - list List all deals for this miner - selection Configure acceptance criteria for storage deal proposals - set-ask Configure the miner's ask - get-ask Print the miner's ask - set-blocklist Set the miner's list of blocklisted piece CIDs - get-blocklist List the contents of the miner's piece CID blocklist - reset-blocklist Remove all entries from the miner's piece CID blocklist - set-seal-duration Set the expected time, in minutes, that you expect sealing sectors to take. Deals that start before this duration will be rejected. - pending-publish list deals waiting in publish queue - retry-publish retry publishing a deal - help, h Shows a list of commands or help for one command + import-data Manually import data for a deal + list List all deals for this miner + selection Configure acceptance criteria for storage deal proposals + set-ask Configure the miner's ask + get-ask Print the miner's ask + set-blocklist Set the miner's list of blocklisted piece CIDs + get-blocklist List the contents of the miner's piece CID blocklist + reset-blocklist Remove all entries from the miner's piece CID blocklist + set-seal-duration Set the expected time, in minutes, that you expect sealing sectors to take. Deals that start before this duration will be rejected. + pending-publish list deals waiting in publish queue + retry-publish retry publishing a deal + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -671,10 +672,10 @@ USAGE: lotus-miner storage-deals selection command [command options] [arguments...] COMMANDS: - list List storage deal proposal selection criteria - reset Reset storage deal proposal selection criteria to default values - reject Configure criteria which necessitate automatic rejection - help, h Shows a list of commands or help for one command + list List storage deal proposal selection criteria + reset Reset storage deal proposal selection criteria to default values + reject Configure criteria which necessitate automatic rejection + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -838,11 +839,11 @@ USAGE: lotus-miner retrieval-deals command [command options] [arguments...] COMMANDS: - selection Configure acceptance criteria for retrieval deal proposals - list List all active retrieval deals for this miner - set-ask Configure the provider's retrieval ask - get-ask Get the provider's current retrieval ask configured by the provider in the ask-store using the set-ask CLI command - help, h Shows a list of commands or help for one command + selection Configure acceptance criteria for retrieval deal proposals + list List all active retrieval deals for this miner + set-ask Configure the provider's retrieval ask + get-ask Get the provider's current retrieval ask configured by the provider in the ask-store using the set-ask CLI command + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -858,10 +859,10 @@ USAGE: lotus-miner retrieval-deals selection command [command options] [arguments...] COMMANDS: - list List retrieval deal proposal selection criteria - reset Reset retrieval deal proposal selection criteria to default values - reject Configure criteria which necessitate automatic rejection - help, h Shows a list of commands or help for one command + list List retrieval deal proposal selection criteria + reset Reset retrieval deal proposal selection criteria to default values + reject Configure criteria which necessitate automatic rejection + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -959,11 +960,11 @@ USAGE: lotus-miner data-transfers command [command options] [arguments...] COMMANDS: - list List ongoing data transfers for this miner - restart Force restart a stalled data transfer - cancel Force cancel a data transfer - diagnostics Get detailed diagnostics on active transfers with a specific peer - help, h Shows a list of commands or help for one command + list List ongoing data transfers for this miner + restart Force restart a stalled data transfer + cancel Force cancel a data transfer + diagnostics Get detailed diagnostics on active transfers with a specific peer + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1038,14 +1039,14 @@ USAGE: lotus-miner dagstore command [command options] [arguments...] COMMANDS: - list-shards List all shards known to the dagstore, with their current status - register-shard Register a shard - initialize-shard Initialize the specified shard - recover-shard Attempt to recover a shard in errored state - initialize-all Initialize all uninitialized shards, streaming results as they're produced; only shards for unsealed pieces are initialized by default - gc Garbage collect the dagstore - lookup-pieces Lookup pieces that a given CID belongs to - help, h Shows a list of commands or help for one command + list-shards List all shards known to the dagstore, with their current status + register-shard Register a shard + initialize-shard Initialize the specified shard + recover-shard Attempt to recover a shard in errored state + initialize-all Initialize all uninitialized shards, streaming results as they're produced; only shards for unsealed pieces are initialized by default + gc Garbage collect the dagstore + lookup-pieces Lookup pieces that a given CID belongs to + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1154,9 +1155,9 @@ USAGE: lotus-miner index command [command options] [arguments...] COMMANDS: - announce Announce a deal to indexers so they can download its index - announce-all Announce all active deals to indexers so they can download the indices - help, h Shows a list of commands or help for one command + announce Announce a deal to indexers so they can download its index + announce-all Announce all active deals to indexers so they can download the indices + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1198,23 +1199,23 @@ USAGE: lotus-miner net command [command options] [arguments...] COMMANDS: - peers Print peers - ping Ping peers - connect Connect to a peer - disconnect Disconnect from a peer - listen List listen addresses - id Get node identity - find-peer, findpeer Find the addresses of a given peerID - scores Print peers' pubsub scores - reachability Print information about reachability from the internet - bandwidth Print bandwidth usage information - block Manage network connection gating rules - stat Report resource usage for a scope - limit Get or set resource limits for a scope - protect Add one or more peer IDs to the list of protected peer connections - unprotect Remove one or more peer IDs from the list of protected peer connections. - list-protected List the peer IDs with protected connection. - help, h Shows a list of commands or help for one command + peers Print peers + ping Ping peers + connect Connect to a peer + disconnect Disconnect from a peer + listen List listen addresses + id Get node identity + find-peer, findpeer Find the addresses of a given peerID + scores Print peers' pubsub scores + reachability Print information about reachability from the internet + bandwidth Print bandwidth usage information + block Manage network connection gating rules + stat Report resource usage for a scope + limit Get or set resource limits for a scope + protect Add one or more peer IDs to the list of protected peer connections + unprotect Remove one or more peer IDs from the list of protected peer connections. + list-protected List the peer IDs with protected connection. + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1354,10 +1355,10 @@ USAGE: lotus-miner net block command [command options] [arguments...] COMMANDS: - add Add connection gating rules - remove Remove connection gating rules - list list connection gating rules - help, h Shows a list of commands or help for one command + add Add connection gating rules + remove Remove connection gating rules + list list connection gating rules + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1373,10 +1374,10 @@ USAGE: lotus-miner net block add command [command options] [arguments...] COMMANDS: - peer Block a peer - ip Block an IP address - subnet Block an IP subnet - help, h Shows a list of commands or help for one command + peer Block a peer + ip Block an IP address + subnet Block an IP subnet + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1431,10 +1432,10 @@ USAGE: lotus-miner net block remove command [command options] [arguments...] COMMANDS: - peer Unblock a peer - ip Unblock an IP address - subnet Unblock an IP subnet - help, h Shows a list of commands or help for one command + peer Unblock a peer + ip Unblock an IP address + subnet Unblock an IP subnet + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1511,6 +1512,7 @@ DESCRIPTION: - proto: -- reports the resource usage of a specific protocol. - peer: -- reports the resource usage of a specific peer. - all -- reports the resource usage for all currently active scopes. + OPTIONS: --json (default: false) @@ -1536,6 +1538,7 @@ DESCRIPTION: - peer: -- reports the resource usage of a specific peer. The limit is json-formatted, with the same structure as the limits file. + OPTIONS: --set set the limit for a scope (default: false) @@ -1593,11 +1596,11 @@ DESCRIPTION: The piecestore is a database that tracks and manages data that is made available to the retrieval market COMMANDS: - list-pieces list registered pieces - list-cids list registered payload CIDs - piece-info get registered information for a given piece CID - cid-info get registered information for a given payload CID - help, h Shows a list of commands or help for one command + list-pieces list registered pieces + list-cids list registered payload CIDs + piece-info get registered information for a given piece CID + cid-info get registered information for a given payload CID + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1665,28 +1668,28 @@ USAGE: lotus-miner sectors command [command options] [arguments...] COMMANDS: - status Get the seal status of a sector by its number - list List sectors - refs List References to sectors - update-state ADVANCED: manually update the state of a sector, this may aid in error recovery - pledge store random data in a sector - numbers manage sector number assignments - precommits Print on-chain precommit info - check-expire Inspect expiring sectors - expired Get or cleanup expired sectors - renew Renew expiring sectors while not exceeding each sector's max life - extend Extend sector expiration - terminate Terminate sector on-chain then remove (WARNING: This means losing power and collateral for the removed sector) - remove Forcefully remove a sector (WARNING: This means losing power and collateral for the removed sector (use 'terminate' for lower penalty)) - snap-up Mark a committed capacity sector to be filled with deals - abort-upgrade Abort the attempted (SnapDeals) upgrade of a CC sector, reverting it to as before - seal Manually start sealing a sector (filling any unused space with junk) - set-seal-delay Set the time, in minutes, that a new sector waits for deals before sealing starts - get-cc-collateral Get the collateral required to pledge a committed capacity sector - batching manage batch sector operations - match-pending-pieces force a refreshed match of pending pieces to open sectors without manually waiting for more deals - compact-partitions removes dead sectors from partitions and reduces the number of partitions used if possible - help, h Shows a list of commands or help for one command + status Get the seal status of a sector by its number + list List sectors + refs List References to sectors + update-state ADVANCED: manually update the state of a sector, this may aid in error recovery + pledge store random data in a sector + numbers manage sector number assignments + precommits Print on-chain precommit info + check-expire Inspect expiring sectors + expired Get or cleanup expired sectors + renew Renew expiring sectors while not exceeding each sector's max life + extend Extend sector expiration + terminate Terminate sector on-chain then remove (WARNING: This means losing power and collateral for the removed sector) + remove Forcefully remove a sector (WARNING: This means losing power and collateral for the removed sector (use 'terminate' for lower penalty)) + snap-up Mark a committed capacity sector to be filled with deals + abort-upgrade Abort the attempted (SnapDeals) upgrade of a CC sector, reverting it to as before + seal Manually start sealing a sector (filling any unused space with junk) + set-seal-delay Set the time, in minutes, that a new sector waits for deals before sealing starts + get-cc-collateral Get the collateral required to pledge a committed capacity sector + batching manage batch sector operations + match-pending-pieces force a refreshed match of pending pieces to open sectors without manually waiting for more deals + compact-partitions removes dead sectors from partitions and reduces the number of partitions used if possible + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1777,11 +1780,11 @@ USAGE: lotus-miner sectors numbers command [command options] [arguments...] COMMANDS: - info view sector assigner state - reservations list sector number reservations - reserve create sector number reservations - free remove sector number reservations - help, h Shows a list of commands or help for one command + info view sector assigner state + reservations list sector number reservations + reserve create sector number reservations + free remove sector number reservations + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1894,6 +1897,7 @@ OPTIONS: --extension value try to extend selected sectors by this number of epochs, defaults to 540 days (default: 1555200) --from value only consider sectors whose current expiration epoch is in the range of [from, to], defaults to: now + 120 (1 hour) (default: 0) --max-fee value use up to this amount of FIL for one message. pass this flag to avoid message congestion. (default: "0") + --max-sectors value the maximum number of sectors contained in each message message (default: 0) --new-expiration value try to extend selected sectors to this epoch, ignoring extension (default: 0) --only-cc only extend CC sectors (useful for making sector ready for snap upgrade) (default: false) --really-do-it pass this flag to really renew sectors, otherwise will only print out json representation of parameters (default: false) @@ -1930,9 +1934,9 @@ USAGE: lotus-miner sectors terminate command [command options] COMMANDS: - flush Send a terminate message if there are sectors queued for termination - pending List sector numbers of sectors pending termination - help, h Shows a list of commands or help for one command + flush Send a terminate message if there are sectors queued for termination + pending List sector numbers of sectors pending termination + help, h Shows a list of commands or help for one command OPTIONS: --really-do-it pass this flag if you know what you are doing (default: false) @@ -2053,9 +2057,9 @@ USAGE: lotus-miner sectors batching command [command options] [arguments...] COMMANDS: - commit list sectors waiting in commit batch queue - precommit list sectors waiting in precommit batch queue - help, h Shows a list of commands or help for one command + commit list sectors waiting in commit batch queue + precommit list sectors waiting in precommit batch queue + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2110,10 +2114,10 @@ USAGE: lotus-miner sectors compact-partitions [command options] [arguments...] OPTIONS: - --actor value Specify the address of the miner to run this command - --deadline value the deadline to compact the partitions in (default: 0) - --partitions value list of partitions to compact sectors in (accepts multiple inputs) - --really-do-it Actually send transaction performing the action (default: false) + --actor value Specify the address of the miner to run this command + --deadline value the deadline to compact the partitions in (default: 0) + --partitions value [ --partitions value ] list of partitions to compact sectors in + --really-do-it Actually send transaction performing the action (default: false) ``` @@ -2126,15 +2130,15 @@ USAGE: lotus-miner proving command [command options] [arguments...] COMMANDS: - info View current state information - deadlines View the current proving period deadlines information - deadline View the current proving period deadline information by its index - faults View the currently known proving faulty sectors information - check Check sectors provable - workers list workers - compute Compute simulated proving tasks - recover-faults Manually recovers faulty sectors on chain - help, h Shows a list of commands or help for one command + info View current state information + deadlines View the current proving period deadlines information + deadline View the current proving period deadline information by its index + faults View the currently known proving faulty sectors information + check Check sectors provable + workers list workers + compute Compute simulated proving tasks + recover-faults Manually recovers faulty sectors on chain + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2232,8 +2236,8 @@ USAGE: lotus-miner proving compute command [command options] [arguments...] COMMANDS: - windowed-post, window-post Compute WindowPoSt for a specific deadline - help, h Shows a list of commands or help for one command + windowed-post, window-post Compute WindowPoSt for a specific deadline + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2272,14 +2276,14 @@ DESCRIPTION: stored while moving through the sealing pipeline (references as 'seal'). COMMANDS: - attach attach local storage path - detach detach local storage path - redeclare redeclare sectors in a local storage path - list list local storage paths - find find sector in the storage system - cleanup trigger cleanup actions - locks show active sector locks - help, h Shows a list of commands or help for one command + attach attach local storage path + detach detach local storage path + redeclare redeclare sectors in a local storage path + list list local storage paths + find find sector in the storage system + cleanup trigger cleanup actions + locks show active sector locks + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2313,15 +2317,16 @@ DESCRIPTION: Store Finalized sectors that will be moved here for long term storage and be proven over time + OPTIONS: - --allow-to value path groups allowed to pull data from this path (allow all if not specified) (accepts multiple inputs) - --groups value path group names (accepts multiple inputs) - --init initialize the path first (default: false) - --max-storage value (for init) limit storage space for sectors (expensive for very large paths!) - --seal (for init) use path for sealing (default: false) - --store (for init) use path for long-term storage (default: false) - --weight value (for init) path weight (default: 10) + --allow-to value [ --allow-to value ] path groups allowed to pull data from this path (allow all if not specified) + --groups value [ --groups value ] path group names + --init initialize the path first (default: false) + --max-storage value (for init) limit storage space for sectors (expensive for very large paths!) + --seal (for init) use path for sealing (default: false) + --store (for init) use path for long-term storage (default: false) + --weight value (for init) path weight (default: 10) ``` @@ -2362,8 +2367,8 @@ USAGE: lotus-miner storage list command [command options] [arguments...] COMMANDS: - sectors get list of all sector files - help, h Shows a list of commands or help for one command + sectors get list of all sector files + help, h Shows a list of commands or help for one command OPTIONS: --color use color in display output (default: depends on output being a TTY) @@ -2432,12 +2437,12 @@ USAGE: lotus-miner sealing command [command options] [arguments...] COMMANDS: - jobs list running jobs - workers list workers - sched-diag Dump internal scheduler state - abort Abort a running job - data-cid Compute data CID using workers - help, h Shows a list of commands or help for one command + jobs list running jobs + workers list workers + sched-diag Dump internal scheduler state + abort Abort a running job + data-cid Compute data CID using workers + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) diff --git a/documentation/en/cli-lotus-worker.md b/documentation/en/cli-lotus-worker.md index 0b5c3f936..69d68dae5 100644 --- a/documentation/en/cli-lotus-worker.md +++ b/documentation/en/cli-lotus-worker.md @@ -7,7 +7,7 @@ USAGE: lotus-worker [global options] command [command options] [arguments...] VERSION: - 1.19.0 + 1.20.0 COMMANDS: run Start lotus worker @@ -40,6 +40,7 @@ USAGE: OPTIONS: --addpiece enable addpiece (default: true) [$LOTUS_WORKER_ADDPIECE] --commit enable commit (32G sectors: all cores or GPUs, 128GiB Memory + 64GiB swap) (default: true) [$LOTUS_WORKER_COMMIT] + --http-server-timeout value (default: "30s") --listen value host address and port the worker api will listen on (default: "0.0.0.0:3456") [$LOTUS_WORKER_LISTEN] --name value custom worker name (default: hostname) [$LOTUS_WORKER_NAME] --no-default disable all default compute tasks, use the worker for storage/fetching only (default: false) [$LOTUS_WORKER_NO_DEFAULT] @@ -96,10 +97,10 @@ USAGE: lotus-worker storage command [command options] [arguments...] COMMANDS: - attach attach local storage path - detach detach local storage path - redeclare redeclare sectors in a local storage path - help, h Shows a list of commands or help for one command + attach attach local storage path + detach detach local storage path + redeclare redeclare sectors in a local storage path + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -115,13 +116,13 @@ USAGE: lotus-worker storage attach [command options] [arguments...] OPTIONS: - --allow-to value path groups allowed to pull data from this path (allow all if not specified) (accepts multiple inputs) - --groups value path group names (accepts multiple inputs) - --init initialize the path first (default: false) - --max-storage value (for init) limit storage space for sectors (expensive for very large paths!) - --seal (for init) use path for sealing (default: false) - --store (for init) use path for long-term storage (default: false) - --weight value (for init) path weight (default: 10) + --allow-to value [ --allow-to value ] path groups allowed to pull data from this path (allow all if not specified) + --groups value [ --groups value ] path group names + --init initialize the path first (default: false) + --max-storage value (for init) limit storage space for sectors (expensive for very large paths!) + --seal (for init) use path for sealing (default: false) + --store (for init) use path for long-term storage (default: false) + --weight value (for init) path weight (default: 10) ``` @@ -202,9 +203,9 @@ USAGE: lotus-worker tasks command [command options] [arguments...] COMMANDS: - enable Enable a task type - disable Disable a task type - help, h Shows a list of commands or help for one command + enable Enable a task type + disable Disable a task type + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index 39b9b6f53..65a9a31b1 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -7,7 +7,7 @@ USAGE: lotus [global options] command [command options] [arguments...] VERSION: - 1.19.0 + 1.20.0 COMMANDS: daemon Start a lotus daemon process @@ -31,6 +31,7 @@ COMMANDS: log Manage logging wait-api Wait for lotus api to come online fetch-params Fetch proving parameters + evm Commands related to the Filecoin EVM runtime NETWORK: net Manage P2P Network sync Inspect or interact with the chain syncer @@ -55,8 +56,8 @@ USAGE: lotus daemon command [command options] [arguments...] COMMANDS: - stop Stop a running lotus daemon - help, h Shows a list of commands or help for one command + stop Stop a running lotus daemon + help, h Shows a list of commands or help for one command OPTIONS: --api value (default: "1234") @@ -120,9 +121,9 @@ USAGE: lotus config command [command options] [arguments...] COMMANDS: - default Print default node config - updated Print updated node config - help, h Shows a list of commands or help for one command + default Print default node config + updated Print updated node config + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -180,15 +181,16 @@ CATEGORY: BASIC OPTIONS: - --force Deprecated: use global 'force-send' (default: false) - --from value optionally specify the account to send funds from - --gas-feecap value specify gas fee cap to use in AttoFIL (default: "0") - --gas-limit value specify gas limit (default: 0) - --gas-premium value specify gas price to use in AttoFIL (default: "0") - --method value specify method to invoke (default: 0) - --nonce value specify the nonce to use (default: 0) - --params-hex value specify invocation parameters in hex - --params-json value specify invocation parameters in json + --force Deprecated: use global 'force-send' (default: false) + --from value optionally specify the account to send funds from + --from-eth-addr value optionally specify the eth addr to send funds from + --gas-feecap value specify gas fee cap to use in AttoFIL (default: "0") + --gas-limit value specify gas limit (default: 0) + --gas-premium value specify gas price to use in AttoFIL (default: "0") + --method value specify method to invoke (default: 0) + --nonce value specify the nonce to use (default: 0) + --params-hex value specify invocation parameters in hex + --params-json value specify invocation parameters in json ``` @@ -201,18 +203,18 @@ USAGE: lotus wallet command [command options] [arguments...] COMMANDS: - new Generate a new key of the given type - list List wallet address - balance Get account balance - export export keys - import import keys - default Get default wallet address - set-default Set default wallet address - sign sign a message - verify verify the signature of a message - delete Soft delete an address from the wallet - hard deletion needed for permanent removal - market Interact with market balances - help, h Shows a list of commands or help for one command + new Generate a new key of the given type + list List wallet address + balance Get account balance + export export keys + import import keys + default Get default wallet address + set-default Set default wallet address + sign sign a message + verify verify the signature of a message + delete Soft delete an address from the wallet - hard deletion needed for permanent removal + market Interact with market balances + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -361,9 +363,9 @@ USAGE: lotus wallet market command [command options] [arguments...] COMMANDS: - withdraw Withdraw funds from the Storage Market Actor - add Add funds to the Storage Market Actor - help, h Shows a list of commands or help for one command + withdraw Withdraw funds from the Storage Market Actor + add Add funds to the Storage Market Actor + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -424,7 +426,7 @@ USAGE: lotus client command [command options] [arguments...] COMMANDS: - help, h Shows a list of commands or help for one command + help, h Shows a list of commands or help for one command DATA: import Import data drop Remove import @@ -598,6 +600,7 @@ DESCRIPTION: - Retrieve a first file from a specified directory $ lotus client retrieve --data-selector /Links/0/Hash Qm... my-file.txt + OPTIONS: --allow-local (default: false) @@ -940,24 +943,24 @@ USAGE: lotus msig command [command options] [arguments...] COMMANDS: - create Create a new multisig wallet - inspect Inspect a multisig wallet - propose Propose a multisig transaction - propose-remove Propose to remove a signer - approve Approve a multisig message - cancel Cancel a multisig message - add-propose Propose to add a signer - add-approve Approve a message to add a signer - add-cancel Cancel a message to add a signer - swap-propose Propose to swap signers - swap-approve Approve a message to swap signers - swap-cancel Cancel a message to swap signers - lock-propose Propose to lock up some balance - lock-approve Approve a message to lock up some balance - lock-cancel Cancel a message to lock up some balance - vested Gets the amount vested in an msig between two epochs - propose-threshold Propose setting a different signing threshold on the account - help, h Shows a list of commands or help for one command + create Create a new multisig wallet + inspect Inspect a multisig wallet + propose Propose a multisig transaction + propose-remove Propose to remove a signer + approve Approve a multisig message + cancel Cancel a multisig message + add-propose Propose to add a signer + add-approve Approve a message to add a signer + add-cancel Cancel a message to add a signer + swap-propose Propose to swap signers + swap-approve Approve a message to swap signers + swap-cancel Cancel a message to swap signers + lock-propose Propose to lock up some balance + lock-approve Approve a message to lock up some balance + lock-cancel Cancel a message to lock up some balance + vested Gets the amount vested in an msig between two epochs + propose-threshold Propose setting a different signing threshold on the account + help, h Shows a list of commands or help for one command OPTIONS: --confidence value number of block confirmations to wait for (default: 5) @@ -1202,15 +1205,15 @@ USAGE: lotus filplus command [command options] [arguments...] COMMANDS: - grant-datacap give allowance to the specified verified client address - list-notaries list all notaries - list-clients list all verified clients - check-client-datacap check verified client remaining bytes - check-notary-datacap check a notary's remaining bytes - sign-remove-data-cap-proposal allows a notary to sign a Remove Data Cap Proposal - list-allocations List allocations made by client - remove-expired-allocations remove expired allocations (if no allocations are specified all eligible allocations are removed) - help, h Shows a list of commands or help for one command + grant-datacap give allowance to the specified verified client address + list-notaries list all notaries + list-clients list all verified clients + check-client-datacap check verified client remaining bytes + check-notary-datacap check a notary's remaining bytes + sign-remove-data-cap-proposal allows a notary to sign a Remove Data Cap Proposal + list-allocations List allocations made by client + remove-expired-allocations remove expired allocations (if no allocations are specified all eligible allocations are removed) + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1330,14 +1333,14 @@ USAGE: lotus paych command [command options] [arguments...] COMMANDS: - add-funds Add funds to the payment channel between fromAddress and toAddress. Creates the payment channel if it doesn't already exist. - list List all locally registered payment channels - voucher Interact with payment channel vouchers - settle Settle a payment channel - status Show the status of an outbound payment channel - status-by-from-to Show the status of an active outbound payment channel by from/to addresses - collect Collect funds for a payment channel - help, h Shows a list of commands or help for one command + add-funds Add funds to the payment channel between fromAddress and toAddress. Creates the payment channel if it doesn't already exist. + list List all locally registered payment channels + voucher Interact with payment channel vouchers + settle Settle a payment channel + status Show the status of an outbound payment channel + status-by-from-to Show the status of an active outbound payment channel by from/to addresses + collect Collect funds for a payment channel + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1380,13 +1383,13 @@ USAGE: lotus paych voucher command [command options] [arguments...] COMMANDS: - create Create a signed payment channel voucher - check Check validity of payment channel voucher - add Add payment channel voucher to local datastore - list List stored vouchers for a given payment channel - best-spendable Print vouchers with highest value that is currently spendable for each lane - submit Submit voucher to chain to update payment channel state - help, h Shows a list of commands or help for one command + create Create a signed payment channel voucher + check Check validity of payment channel voucher + add Add payment channel voucher to local datastore + list List stored vouchers for a given payment channel + best-spendable Print vouchers with highest value that is currently spendable for each lane + submit Submit voucher to chain to update payment channel state + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1532,9 +1535,9 @@ USAGE: lotus auth command [command options] [arguments...] COMMANDS: - create-token Create token - api-info Get token with API info required to connect to this node - help, h Shows a list of commands or help for one command + create-token Create token + api-info Get token with API info required to connect to this node + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1576,15 +1579,15 @@ USAGE: lotus mpool command [command options] [arguments...] COMMANDS: - pending Get pending messages - sub Subscribe to mpool changes - stat print mempool stats - replace replace a message in the mempool - find find a message in the mempool - config get or set current mpool configuration - gas-perf Check gas performance of messages in mempool - manage - help, h Shows a list of commands or help for one command + pending Get pending messages + sub Subscribe to mpool changes + stat print mempool stats + replace replace a message in the mempool + find find a message in the mempool + config get or set current mpool configuration + gas-perf Check gas performance of messages in mempool + manage + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1695,7 +1698,7 @@ OPTIONS: ### lotus mpool manage ``` NAME: - lotus mpool manage - + lotus mpool manage USAGE: lotus mpool manage [command options] [arguments...] @@ -1714,31 +1717,31 @@ USAGE: lotus state command [command options] [arguments...] COMMANDS: - power Query network or miner power - sectors Query the sector set of a miner - active-sectors Query the active sector set of a miner - list-actors list all actors in the network - list-miners list all miners in the network - circulating-supply Get the exact current circulating supply of Filecoin - sector, sector-info Get miner sector info - get-actor Print actor information - lookup Find corresponding ID address - replay Replay a particular message - sector-size Look up miners sector size - read-state View a json representation of an actors state - list-messages list messages on chain matching given criteria - compute-state Perform state computations - call Invoke a method on an actor locally - get-deal View on-chain deal info - wait-msg, wait-message Wait for a message to appear on chain - search-msg, search-message Search to see whether a message has appeared on chain - miner-info Retrieve miner information - market Inspect the storage market actor - exec-trace Get the execution trace of a given message - network-version Returns the network version - miner-proving-deadline Retrieve information about a given miner's proving deadline - actor-cids Returns the built-in actor bundle manifest ID & system actor cids - help, h Shows a list of commands or help for one command + power Query network or miner power + sectors Query the sector set of a miner + active-sectors Query the active sector set of a miner + list-actors list all actors in the network + list-miners list all miners in the network + circulating-supply Get the exact current circulating supply of Filecoin + sector, sector-info Get miner sector info + get-actor Print actor information + lookup Find corresponding ID address + replay Replay a particular message + sector-size Look up miners sector size + read-state View a json representation of an actors state + list-messages list messages on chain matching given criteria + compute-state Perform state computations + call Invoke a method on an actor locally + get-deal View on-chain deal info + wait-msg, wait-message Wait for a message to appear on chain + search-msg, search-message Search to see whether a message has appeared on chain + miner-info Retrieve miner information + market Inspect the storage market actor + exec-trace Get the execution trace of a given message + network-version Returns the network version + miner-proving-deadline Retrieve information about a given miner's proving deadline + actor-cids Returns the built-in actor bundle manifest ID & system actor cids + help, h Shows a list of commands or help for one command OPTIONS: --tipset value specify tipset to call method on (pass comma separated array of cids) @@ -1988,8 +1991,8 @@ USAGE: lotus state market command [command options] [arguments...] COMMANDS: - balance Get the market balance (locked and escrowed) for a given account - help, h Shows a list of commands or help for one command + balance Get the market balance (locked and escrowed) for a given account + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2070,25 +2073,25 @@ USAGE: lotus chain command [command options] [arguments...] COMMANDS: - head Print chain head - get-block, getblock Get a block and print its details - read-obj Read the raw bytes of an object - delete-obj Delete an object from the chain blockstore - stat-obj Collect size and ipld link counts for objs - getmessage, get-message, get-msg Get and print a message by its cid - sethead, set-head manually set the local nodes head tipset (Caution: normally only used for recovery) - list, love View a segment of the chain - get Get chain DAG node by path - bisect bisect chain for an event - export export chain to a car file - slash-consensus Report consensus fault - gas-price Estimate gas prices - inspect-usage Inspect block space usage of a given tipset - decode decode various types - encode encode various types - disputer interact with the window post disputer - prune prune the stored chain state and perform garbage collection - help, h Shows a list of commands or help for one command + head Print chain head + get-block, getblock Get a block and print its details + read-obj Read the raw bytes of an object + delete-obj Delete an object from the chain blockstore + stat-obj Collect size and ipld link counts for objs + getmessage, get-message, get-msg Get and print a message by its cid + sethead, set-head manually set the local nodes head tipset (Caution: normally only used for recovery) + list, love View a segment of the chain + get Get chain DAG node by path + bisect bisect chain for an event + export export chain to a car file + slash-consensus Report consensus fault + gas-price Estimate gas prices + inspect-usage Inspect block space usage of a given tipset + decode decode various types + encode encode various types + disputer interact with the window post disputer + prune prune the stored chain state and perform garbage collection + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2154,6 +2157,7 @@ DESCRIPTION: When a base is provided it will be walked first, and all links visisted will be ignored when the passed in object is walked. + OPTIONS: --base value ignore links found in this obj @@ -2209,6 +2213,7 @@ DESCRIPTION: - hamt-address - cronevent - account-state + OPTIONS: --as-type value specify type to interpret output as @@ -2238,6 +2243,7 @@ DESCRIPTION: - lotus chain bisect 1 32000 '@Ha:t03/1' jq -e '.[2] > 100000' For special path elements see 'chain get' help + OPTIONS: --help, -h show help (default: false) @@ -2310,8 +2316,8 @@ USAGE: lotus chain decode command [command options] [arguments...] COMMANDS: - params Decode message params - help, h Shows a list of commands or help for one command + params Decode message params + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2341,8 +2347,8 @@ USAGE: lotus chain encode command [command options] [arguments...] COMMANDS: - params Encodes the given JSON params - help, h Shows a list of commands or help for one command + params Encodes the given JSON params + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2373,9 +2379,9 @@ USAGE: lotus chain disputer command [command options] [arguments...] COMMANDS: - start Start the window post disputer - dispute Send a specific DisputeWindowedPoSt message - help, h Shows a list of commands or help for one command + start Start the window post disputer + dispute Send a specific DisputeWindowedPoSt message + help, h Shows a list of commands or help for one command OPTIONS: --max-fee value Spend up to X FIL per DisputeWindowedPoSt message @@ -2419,7 +2425,6 @@ USAGE: lotus chain prune [command options] [arguments...] OPTIONS: - --move-to value specify new path for coldstore during moving gc --moving-gc use moving gc for garbage collecting the coldstore (default: false) --online-gc use online gc for garbage collecting the coldstore (default: false) --retention value specify state retention policy (default: -1) @@ -2435,10 +2440,10 @@ USAGE: lotus log command [command options] [arguments...] COMMANDS: - list List log systems - set-level Set log level - alerts Get alert states - help, h Shows a list of commands or help for one command + list List log systems + set-level Set log level + alerts Get alert states + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2484,9 +2489,10 @@ DESCRIPTION: GOLOG_LOG_FMT - Change output log format (json, nocolor) GOLOG_FILE - Write logs to file GOLOG_OUTPUT - Specify whether to output to file, stderr, stdout or a combination, i.e. file+stderr + OPTIONS: - --system value limit to log system (accepts multiple inputs) + --system value [ --system value ] limit to log system ``` @@ -2535,6 +2541,94 @@ OPTIONS: ``` +## lotus evm +``` +NAME: + lotus evm - Commands related to the Filecoin EVM runtime + +USAGE: + lotus evm command [command options] [arguments...] + +COMMANDS: + deploy Deploy an EVM smart contract and return its address + invoke Invoke an EVM smart contract using the specified CALLDATA + stat Print eth/filecoin addrs and code cid + call Simulate an eth contract call + contract-address Generate contract address from smart contract code + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help (default: false) + +``` + +### lotus evm deploy +``` +NAME: + lotus evm deploy - Deploy an EVM smart contract and return its address + +USAGE: + lotus evm deploy [command options] contract + +OPTIONS: + --from value optionally specify the account to use for sending the creation message + --hex use when input contract is in hex (default: false) + +``` + +### lotus evm invoke +``` +NAME: + lotus evm invoke - Invoke an EVM smart contract using the specified CALLDATA + +USAGE: + lotus evm invoke [command options] address calldata + +OPTIONS: + --from value optionally specify the account to use for sending the exec message + --value value optionally specify the value to be sent with the invokation message (default: 0) + +``` + +### lotus evm stat +``` +NAME: + lotus evm stat - Print eth/filecoin addrs and code cid + +USAGE: + lotus evm stat [command options] address + +OPTIONS: + --help, -h show help (default: false) + +``` + +### lotus evm call +``` +NAME: + lotus evm call - Simulate an eth contract call + +USAGE: + lotus evm call [command options] [from] [to] [params] + +OPTIONS: + --help, -h show help (default: false) + +``` + +### lotus evm contract-address +``` +NAME: + lotus evm contract-address - Generate contract address from smart contract code + +USAGE: + lotus evm contract-address [command options] [senderEthAddr] [salt] [contractHexPath] + +OPTIONS: + --help, -h show help (default: false) + +``` + ## lotus net ``` NAME: @@ -2544,23 +2638,23 @@ USAGE: lotus net command [command options] [arguments...] COMMANDS: - peers Print peers - ping Ping peers - connect Connect to a peer - disconnect Disconnect from a peer - listen List listen addresses - id Get node identity - find-peer, findpeer Find the addresses of a given peerID - scores Print peers' pubsub scores - reachability Print information about reachability from the internet - bandwidth Print bandwidth usage information - block Manage network connection gating rules - stat Report resource usage for a scope - limit Get or set resource limits for a scope - protect Add one or more peer IDs to the list of protected peer connections - unprotect Remove one or more peer IDs from the list of protected peer connections. - list-protected List the peer IDs with protected connection. - help, h Shows a list of commands or help for one command + peers Print peers + ping Ping peers + connect Connect to a peer + disconnect Disconnect from a peer + listen List listen addresses + id Get node identity + find-peer, findpeer Find the addresses of a given peerID + scores Print peers' pubsub scores + reachability Print information about reachability from the internet + bandwidth Print bandwidth usage information + block Manage network connection gating rules + stat Report resource usage for a scope + limit Get or set resource limits for a scope + protect Add one or more peer IDs to the list of protected peer connections + unprotect Remove one or more peer IDs from the list of protected peer connections. + list-protected List the peer IDs with protected connection. + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2700,10 +2794,10 @@ USAGE: lotus net block command [command options] [arguments...] COMMANDS: - add Add connection gating rules - remove Remove connection gating rules - list list connection gating rules - help, h Shows a list of commands or help for one command + add Add connection gating rules + remove Remove connection gating rules + list list connection gating rules + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2719,10 +2813,10 @@ USAGE: lotus net block add command [command options] [arguments...] COMMANDS: - peer Block a peer - ip Block an IP address - subnet Block an IP subnet - help, h Shows a list of commands or help for one command + peer Block a peer + ip Block an IP address + subnet Block an IP subnet + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2777,10 +2871,10 @@ USAGE: lotus net block remove command [command options] [arguments...] COMMANDS: - peer Unblock a peer - ip Unblock an IP address - subnet Unblock an IP subnet - help, h Shows a list of commands or help for one command + peer Unblock a peer + ip Unblock an IP address + subnet Unblock an IP subnet + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2857,6 +2951,7 @@ DESCRIPTION: - proto: -- reports the resource usage of a specific protocol. - peer: -- reports the resource usage of a specific peer. - all -- reports the resource usage for all currently active scopes. + OPTIONS: --json (default: false) @@ -2882,6 +2977,7 @@ DESCRIPTION: - peer: -- reports the resource usage of a specific peer. The limit is json-formatted, with the same structure as the limits file. + OPTIONS: --set set the limit for a scope (default: false) @@ -2936,13 +3032,13 @@ USAGE: lotus sync command [command options] [arguments...] COMMANDS: - status check sync status - wait Wait for sync to be complete - mark-bad Mark the given block as bad, will prevent syncing to a chain that contains it - unmark-bad Unmark the given block as bad, makes it possible to sync to a chain containing it - check-bad check if the given block was marked bad, and for what reason - checkpoint mark a certain tipset as checkpointed; the node will never fork away from this tipset - help, h Shows a list of commands or help for one command + status check sync status + wait Wait for sync to be complete + mark-bad Mark the given block as bad, will prevent syncing to a chain that contains it + unmark-bad Unmark the given block as bad, makes it possible to sync to a chain containing it + check-bad check if the given block was marked bad, and for what reason + checkpoint mark a certain tipset as checkpointed; the node will never fork away from this tipset + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) diff --git a/documentation/en/default-lotus-config.toml b/documentation/en/default-lotus-config.toml index 889b87e4e..41d7e6aca 100644 --- a/documentation/en/default-lotus-config.toml +++ b/documentation/en/default-lotus-config.toml @@ -98,6 +98,35 @@ # env var: LOTUS_PUBSUB_REMOTETRACER #RemoteTracer = "" + # Path to file that will be used to output tracer content in JSON format. + # If present tracer will save data to defined file. + # Format: file path + # + # type: string + # env var: LOTUS_PUBSUB_JSONTRACER + #JsonTracer = "" + + # Connection string for elasticsearch instance. + # If present tracer will save data to elasticsearch. + # Format: https://:@:/ + # + # type: string + # env var: LOTUS_PUBSUB_ELASTICSEARCHTRACER + #ElasticSearchTracer = "" + + # Name of elasticsearch index that will be used to save tracer data. + # This property is used only if ElasticSearchTracer propery is set. + # + # type: string + # env var: LOTUS_PUBSUB_ELASTICSEARCHINDEX + #ElasticSearchIndex = "" + + # Auth token that will be passed with logs to elasticsearch - used for weighted peers score. + # + # type: string + # env var: LOTUS_PUBSUB_TRACERSOURCEAUTH + #TracerSourceAuth = "" + [Client] # type: bool @@ -264,3 +293,71 @@ #Tracing = false +[Fevm] + # EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids. + # This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above. + # + # type: bool + # env var: LOTUS_FEVM_ENABLEETHRPC + #EnableEthRPC = false + + # EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days + # Set to 0 to keep all mappings + # + # type: int + # env var: LOTUS_FEVM_ETHTXHASHMAPPINGLIFETIMEDAYS + #EthTxHashMappingLifetimeDays = 0 + + [Fevm.Events] + # EnableEthRPC enables APIs that + # DisableRealTimeFilterAPI will disable the RealTimeFilterAPI that can create and query filters for actor events as they are emitted. + # The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag. + # + # type: bool + # env var: LOTUS_FEVM_EVENTS_DISABLEREALTIMEFILTERAPI + #DisableRealTimeFilterAPI = false + + # DisableHistoricFilterAPI will disable the HistoricFilterAPI that can create and query filters for actor events + # that occurred in the past. HistoricFilterAPI maintains a queryable index of events. + # The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag. + # + # type: bool + # env var: LOTUS_FEVM_EVENTS_DISABLEHISTORICFILTERAPI + #DisableHistoricFilterAPI = false + + # FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than + # this time become eligible for automatic deletion. + # + # type: Duration + # env var: LOTUS_FEVM_EVENTS_FILTERTTL + #FilterTTL = "24h0m0s" + + # MaxFilters specifies the maximum number of filters that may exist at any one time. + # + # type: int + # env var: LOTUS_FEVM_EVENTS_MAXFILTERS + #MaxFilters = 100 + + # MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter. + # + # type: int + # env var: LOTUS_FEVM_EVENTS_MAXFILTERRESULTS + #MaxFilterResults = 10000 + + # MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying + # the entire chain) + # + # type: uint64 + # env var: LOTUS_FEVM_EVENTS_MAXFILTERHEIGHTRANGE + #MaxFilterHeightRange = 2880 + + # DatabasePath is the full path to a sqlite database that will be used to index actor events to + # support the historic filter APIs. If the database does not exist it will be created. The directory containing + # the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as + # relative to the CWD (current working directory). + # + # type: string + # env var: LOTUS_FEVM_EVENTS_DATABASEPATH + #DatabasePath = "" + + diff --git a/documentation/en/default-lotus-miner-config.toml b/documentation/en/default-lotus-miner-config.toml index 939bac0cc..416531f98 100644 --- a/documentation/en/default-lotus-miner-config.toml +++ b/documentation/en/default-lotus-miner-config.toml @@ -98,6 +98,35 @@ # env var: LOTUS_PUBSUB_REMOTETRACER #RemoteTracer = "" + # Path to file that will be used to output tracer content in JSON format. + # If present tracer will save data to defined file. + # Format: file path + # + # type: string + # env var: LOTUS_PUBSUB_JSONTRACER + #JsonTracer = "" + + # Connection string for elasticsearch instance. + # If present tracer will save data to elasticsearch. + # Format: https://:@:/ + # + # type: string + # env var: LOTUS_PUBSUB_ELASTICSEARCHTRACER + #ElasticSearchTracer = "" + + # Name of elasticsearch index that will be used to save tracer data. + # This property is used only if ElasticSearchTracer propery is set. + # + # type: string + # env var: LOTUS_PUBSUB_ELASTICSEARCHINDEX + #ElasticSearchIndex = "" + + # Auth token that will be passed with logs to elasticsearch - used for weighted peers score. + # + # type: string + # env var: LOTUS_PUBSUB_TRACERSOURCEAUTH + #TracerSourceAuth = "" + [Subsystems] # type: bool diff --git a/documentation/misc/RELEASE_ISSUE_TEMPLATE.md b/documentation/misc/RELEASE_ISSUE_TEMPLATE.md index 8c3cce944..9ae46fe57 100644 --- a/documentation/misc/RELEASE_ISSUE_TEMPLATE.md +++ b/documentation/misc/RELEASE_ISSUE_TEMPLATE.md @@ -21,12 +21,14 @@ First steps: - [ ] Fork a new branch (`release/vX.Y.Z`) from `master` and make any further release related changes to this branch. If any "non-trivial" changes get added to the release, uncheck all the checkboxes and return to this stage. - - [ ] Bump the version in `build/version.go` in the `master` branch to `vX.Y.(Z+1)-dev` (bump from feature release) or `vX.(Y+1).0-dev` (bump from mandatory release) + - [ ] Bump the version in `build/version.go` in the `master` branch to `vX.Y.(Z+1)-dev` (bump from feature release) or `vX.(Y+1).0-dev` (bump from mandatory release). Run make gen and make docsgen-cli before committing changes Prepping an RC: -- [ ] version string in `build/version.go` has been updated (in the `release/vX.Y.Z` branch). +- [ ] version string in `build/version.go` has been updated (in the `release/vX.Y.Z` branch) - [ ] run `make gen && make docsgen-cli` +- [ ] Generate changelog using the script at scripts/mkreleaselog +- [ ] Add contents of generated text to lotus/CHANGELOG.md in addition to other details - [ ] tag commit with `vX.Y.Z-rcN` - [ ] cut a pre-release [here](https://github.com/filecoin-project/lotus/releases/new?prerelease=true) diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index 280c4f8b9..1bc8bf8b4 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit 280c4f8b94fd46dc824a5c827dece73ec7fe3efd +Subproject commit 1bc8bf8b482b2ef34cbce17bfc3a7ec68c047461 diff --git a/extern/test-vectors b/extern/test-vectors index d9a75a787..28b0c45ea 160000 --- a/extern/test-vectors +++ b/extern/test-vectors @@ -1 +1 @@ -Subproject commit d9a75a7873aee0db28b87e3970d2ea16a2f37c6a +Subproject commit 28b0c45eab4c302864af0aeaaff813625cfafe97 diff --git a/gateway/eth_sub.go b/gateway/eth_sub.go new file mode 100644 index 000000000..76d913983 --- /dev/null +++ b/gateway/eth_sub.go @@ -0,0 +1,71 @@ +package gateway + +import ( + "context" + "sync" + + "github.com/filecoin-project/go-jsonrpc" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types/ethtypes" +) + +type EthSubHandler struct { + queued map[ethtypes.EthSubscriptionID][]ethtypes.EthSubscriptionResponse + sinks map[ethtypes.EthSubscriptionID]func(context.Context, *ethtypes.EthSubscriptionResponse) error + + lk sync.Mutex +} + +func NewEthSubHandler() *EthSubHandler { + return &EthSubHandler{ + queued: make(map[ethtypes.EthSubscriptionID][]ethtypes.EthSubscriptionResponse), + sinks: make(map[ethtypes.EthSubscriptionID]func(context.Context, *ethtypes.EthSubscriptionResponse) error), + } +} + +func (e *EthSubHandler) AddSub(ctx context.Context, id ethtypes.EthSubscriptionID, sink func(context.Context, *ethtypes.EthSubscriptionResponse) error) error { + e.lk.Lock() + defer e.lk.Unlock() + + for _, p := range e.queued[id] { + p := p // copy + if err := sink(ctx, &p); err != nil { + return err + } + } + delete(e.queued, id) + e.sinks[id] = sink + return nil +} + +func (e *EthSubHandler) RemoveSub(id ethtypes.EthSubscriptionID) { + e.lk.Lock() + defer e.lk.Unlock() + + delete(e.sinks, id) + delete(e.queued, id) +} + +func (e *EthSubHandler) EthSubscription(ctx context.Context, r jsonrpc.RawParams) error { + p, err := jsonrpc.DecodeParams[ethtypes.EthSubscriptionResponse](r) + if err != nil { + return err + } + + e.lk.Lock() + + sink := e.sinks[p.SubscriptionID] + + if sink == nil { + e.queued[p.SubscriptionID] = append(e.queued[p.SubscriptionID], p) + e.lk.Unlock() + return nil + } + + e.lk.Unlock() + + return sink(ctx, &p) // todo track errors and auto-unsubscribe on rpc conn close? +} + +var _ api.EthSubscriber = (*EthSubHandler)(nil) diff --git a/gateway/handler.go b/gateway/handler.go index be824b430..54ab2467f 100644 --- a/gateway/handler.go +++ b/gateway/handler.go @@ -25,15 +25,21 @@ type perConnLimiterKeyType string const perConnLimiterKey perConnLimiterKeyType = "limiter" +type filterTrackerKeyType string + +const statefulCallTrackerKey filterTrackerKeyType = "statefulCallTracker" + // Handler returns a gateway http.Handler, to be mounted as-is on the server. func Handler(gwapi lapi.Gateway, api lapi.FullNode, rateLimit int64, connPerMinute int64, opts ...jsonrpc.ServerOption) (http.Handler, error) { m := mux.NewRouter() serveRpc := func(path string, hnd interface{}) { - rpcServer := jsonrpc.NewServer(append(opts, jsonrpc.WithServerErrors(lapi.RPCErrors))...) + rpcServer := jsonrpc.NewServer(append(opts, jsonrpc.WithReverseClient[lapi.EthSubscriberMethods]("Filecoin"), jsonrpc.WithServerErrors(lapi.RPCErrors))...) rpcServer.Register("Filecoin", hnd) rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover") + lapi.CreateEthRPCAliases(rpcServer) + m.Handle(path, rpcServer) } @@ -81,8 +87,12 @@ type RateLimiterHandler struct { } func (h RateLimiterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - r2 := r.WithContext(context.WithValue(r.Context(), perConnLimiterKey, h.limiter)) - h.handler.ServeHTTP(w, r2) + r = r.WithContext(context.WithValue(r.Context(), perConnLimiterKey, h.limiter)) + + // also add a filter tracker to the context + r = r.WithContext(context.WithValue(r.Context(), statefulCallTrackerKey, newStatefulCallTracker())) + + h.handler.ServeHTTP(w, r) } // this blocks new connections if there have already been too many. diff --git a/gateway/node.go b/gateway/node.go index 7e84092e3..90a6812b5 100644 --- a/gateway/node.go +++ b/gateway/node.go @@ -5,26 +5,25 @@ import ( "fmt" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "go.opencensus.io/stats" "golang.org/x/time/rate" - "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-jsonrpc" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/api" - apitypes "github.com/filecoin-project/lotus/api/types" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/lib/sigs" + "github.com/filecoin-project/lotus/chain/types/ethtypes" _ "github.com/filecoin-project/lotus/lib/sigs/bls" + _ "github.com/filecoin-project/lotus/lib/sigs/delegated" _ "github.com/filecoin-project/lotus/lib/sigs/secp" "github.com/filecoin-project/lotus/metrics" "github.com/filecoin-project/lotus/node/impl/full" @@ -87,13 +86,52 @@ type TargetAPI interface { StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (api.CirculatingSupply, error) - WalletBalance(context.Context, address.Address) (types.BigInt, error) //perm:read + WalletBalance(context.Context, address.Address) (types.BigInt, error) + + EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) + FilecoinAddressToEthAddress(ctx context.Context, filecoinAddress address.Address) (ethtypes.EthAddress, error) + EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) + EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) + EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) + EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) + EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) + EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) + EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) + EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) + EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) + EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) + EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) + EthChainId(ctx context.Context) (ethtypes.EthUint64, error) + NetVersion(ctx context.Context) (string, error) + NetListening(ctx context.Context) (bool, error) + EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) + EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) + EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) + EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) + EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) + EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) + EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) + EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) + EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) + EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) + EthNewFilter(ctx context.Context, filter *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) + EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) + EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) + EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) + EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) + EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) + Web3ClientVersion(ctx context.Context) (string, error) } var _ TargetAPI = *new(api.FullNode) // gateway depends on latest type Node struct { target TargetAPI + subHnd *EthSubHandler lookbackCap time.Duration stateWaitLookbackLimit abi.ChainEpoch rateLimiter *rate.Limiter @@ -110,7 +148,7 @@ var ( ) // NewNode creates a new gateway node. -func NewNode(api TargetAPI, lookbackCap time.Duration, stateWaitLookbackLimit abi.ChainEpoch, rateLimit int64, rateLimitTimeout time.Duration) *Node { +func NewNode(api TargetAPI, sHnd *EthSubHandler, lookbackCap time.Duration, stateWaitLookbackLimit abi.ChainEpoch, rateLimit int64, rateLimitTimeout time.Duration) *Node { var limit rate.Limit if rateLimit == 0 { limit = rate.Inf @@ -119,6 +157,7 @@ func NewNode(api TargetAPI, lookbackCap time.Duration, stateWaitLookbackLimit ab } return &Node{ target: api, + subHnd: sHnd, lookbackCap: lookbackCap, stateWaitLookbackLimit: stateWaitLookbackLimit, rateLimiter: rate.NewLimiter(limit, stateRateLimitTokens), @@ -183,462 +222,3 @@ func (gw *Node) limit(ctx context.Context, tokens int) error { } return nil } - -func (gw *Node) Discover(ctx context.Context) (apitypes.OpenRPCDocument, error) { - return build.OpenRPCDiscoverJSON_Gateway(), nil -} - -func (gw *Node) Version(ctx context.Context) (api.APIVersion, error) { - if err := gw.limit(ctx, basicRateLimitTokens); err != nil { - return api.APIVersion{}, err - } - return gw.target.Version(ctx) -} - -func (gw *Node) ChainGetParentMessages(ctx context.Context, c cid.Cid) ([]api.Message, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetParentMessages(ctx, c) -} - -func (gw *Node) ChainGetParentReceipts(ctx context.Context, c cid.Cid) ([]*types.MessageReceipt, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetParentReceipts(ctx, c) -} - -func (gw *Node) ChainGetBlockMessages(ctx context.Context, c cid.Cid) (*api.BlockMessages, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetBlockMessages(ctx, c) -} - -func (gw *Node) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return false, err - } - return gw.target.ChainHasObj(ctx, c) -} - -func (gw *Node) ChainHead(ctx context.Context) (*types.TipSet, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - - return gw.target.ChainHead(ctx) -} - -func (gw *Node) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetMessage(ctx, mc) -} - -func (gw *Node) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetTipSet(ctx, tsk) -} - -func (gw *Node) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipSetHeight(ctx, h, tsk); err != nil { - return nil, err - } - return gw.target.ChainGetTipSetByHeight(ctx, h, tsk) -} - -func (gw *Node) ChainGetTipSetAfterHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipSetHeight(ctx, h, tsk); err != nil { - return nil, err - } - return gw.target.ChainGetTipSetAfterHeight(ctx, h, tsk) -} - -func (gw *Node) checkTipSetHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) error { - var ts *types.TipSet - if tsk.IsEmpty() { - head, err := gw.target.ChainHead(ctx) - if err != nil { - return err - } - ts = head - } else { - gts, err := gw.target.ChainGetTipSet(ctx, tsk) - if err != nil { - return err - } - ts = gts - } - - // Check if the tipset key refers to gw tipset that's too far in the past - if err := gw.checkTipset(ts); err != nil { - return err - } - - // Check if the height is too far in the past - if err := gw.checkTipsetHeight(ts, h); err != nil { - return err - } - - return nil -} - -func (gw *Node) ChainGetNode(ctx context.Context, p string) (*api.IpldObject, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetNode(ctx, p) -} - -func (gw *Node) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainNotify(ctx) -} - -func (gw *Node) ChainGetPath(ctx context.Context, from, to types.TipSetKey) ([]*api.HeadChange, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, from); err != nil { - return nil, xerrors.Errorf("gateway: checking 'from' tipset: %w", err) - } - if err := gw.checkTipsetKey(ctx, to); err != nil { - return nil, xerrors.Errorf("gateway: checking 'to' tipset: %w", err) - } - return gw.target.ChainGetPath(ctx, from, to) -} - -func (gw *Node) ChainGetGenesis(ctx context.Context) (*types.TipSet, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetGenesis(ctx) -} - -func (gw *Node) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainReadObj(ctx, c) -} - -func (gw *Node) ChainPutObj(context.Context, blocks.Block) error { - return xerrors.New("not supported") -} - -func (gw *Node) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.GasEstimateMessageGas(ctx, msg, spec, tsk) -} - -func (gw *Node) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return cid.Cid{}, err - } - // TODO: additional anti-spam checks - return gw.target.MpoolPushUntrusted(ctx, sm) -} - -func (gw *Node) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) { - if err := gw.limit(ctx, walletRateLimitTokens); err != nil { - return types.BigInt{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return types.NewInt(0), err - } - return gw.target.MsigGetAvailableBalance(ctx, addr, tsk) -} - -func (gw *Node) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) { - if err := gw.limit(ctx, walletRateLimitTokens); err != nil { - return types.BigInt{}, err - } - if err := gw.checkTipsetKey(ctx, start); err != nil { - return types.NewInt(0), err - } - if err := gw.checkTipsetKey(ctx, end); err != nil { - return types.NewInt(0), err - } - return gw.target.MsigGetVested(ctx, addr, start, end) -} - -func (gw *Node) MsigGetVestingSchedule(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MsigVesting, error) { - if err := gw.limit(ctx, walletRateLimitTokens); err != nil { - return api.MsigVesting{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return api.MsigVesting{}, err - } - return gw.target.MsigGetVestingSchedule(ctx, addr, tsk) -} - -func (gw *Node) MsigGetPending(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.MsigTransaction, error) { - if err := gw.limit(ctx, walletRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.MsigGetPending(ctx, addr, tsk) -} - -func (gw *Node) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return address.Address{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return address.Undef, err - } - return gw.target.StateAccountKey(ctx, addr, tsk) -} - -func (gw *Node) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return api.DealCollateralBounds{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return api.DealCollateralBounds{}, err - } - return gw.target.StateDealProviderCollateralBounds(ctx, size, verified, tsk) -} - -func (gw *Node) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateGetActor(ctx, actor, tsk) -} - -func (gw *Node) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateListMiners(ctx, tsk) -} - -func (gw *Node) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return address.Address{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return address.Undef, err - } - return gw.target.StateLookupID(ctx, addr, tsk) -} - -func (gw *Node) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return api.MarketBalance{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return api.MarketBalance{}, err - } - return gw.target.StateMarketBalance(ctx, addr, tsk) -} - -func (gw *Node) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateMarketStorageDeal(ctx, dealId, tsk) -} - -func (gw *Node) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return network.VersionMax, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return network.VersionMax, err - } - return gw.target.StateNetworkVersion(ctx, tsk) -} - -func (gw *Node) StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if limit == api.LookbackNoLimit { - limit = gw.stateWaitLookbackLimit - } - if gw.stateWaitLookbackLimit != api.LookbackNoLimit && limit > gw.stateWaitLookbackLimit { - limit = gw.stateWaitLookbackLimit - } - if err := gw.checkTipsetKey(ctx, from); err != nil { - return nil, err - } - return gw.target.StateSearchMsg(ctx, from, msg, limit, allowReplaced) -} - -func (gw *Node) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if limit == api.LookbackNoLimit { - limit = gw.stateWaitLookbackLimit - } - if gw.stateWaitLookbackLimit != api.LookbackNoLimit && limit > gw.stateWaitLookbackLimit { - limit = gw.stateWaitLookbackLimit - } - return gw.target.StateWaitMsg(ctx, msg, confidence, limit, allowReplaced) -} - -func (gw *Node) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateReadState(ctx, actor, tsk) -} - -func (gw *Node) StateMinerPower(ctx context.Context, m address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateMinerPower(ctx, m, tsk) -} - -func (gw *Node) StateMinerFaults(ctx context.Context, m address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return bitfield.BitField{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return bitfield.BitField{}, err - } - return gw.target.StateMinerFaults(ctx, m, tsk) -} - -func (gw *Node) StateMinerRecoveries(ctx context.Context, m address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return bitfield.BitField{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return bitfield.BitField{}, err - } - return gw.target.StateMinerRecoveries(ctx, m, tsk) -} - -func (gw *Node) StateMinerInfo(ctx context.Context, m address.Address, tsk types.TipSetKey) (api.MinerInfo, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return api.MinerInfo{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return api.MinerInfo{}, err - } - return gw.target.StateMinerInfo(ctx, m, tsk) -} - -func (gw *Node) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) ([]api.Deadline, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateMinerDeadlines(ctx, m, tsk) -} - -func (gw *Node) StateMinerAvailableBalance(ctx context.Context, m address.Address, tsk types.TipSetKey) (types.BigInt, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return types.BigInt{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return types.BigInt{}, err - } - return gw.target.StateMinerAvailableBalance(ctx, m, tsk) -} - -func (gw *Node) StateMinerProvingDeadline(ctx context.Context, m address.Address, tsk types.TipSetKey) (*dline.Info, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateMinerProvingDeadline(ctx, m, tsk) -} - -func (gw *Node) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (abi.TokenAmount, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return abi.TokenAmount{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return abi.TokenAmount{}, err - } - return gw.target.StateCirculatingSupply(ctx, tsk) -} - -func (gw *Node) StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateSectorGetInfo(ctx, maddr, n, tsk) -} - -func (gw *Node) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateVerifiedClientStatus(ctx, addr, tsk) -} - -func (gw *Node) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return api.CirculatingSupply{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return api.CirculatingSupply{}, err - } - return gw.target.StateVMCirculatingSupplyInternal(ctx, tsk) -} - -func (gw *Node) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *crypto.Signature) (bool, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return false, err - } - return sigs.Verify(sig, k, msg) == nil, nil -} - -func (gw *Node) WalletBalance(ctx context.Context, k address.Address) (types.BigInt, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return types.BigInt{}, err - } - return gw.target.WalletBalance(ctx, k) -} diff --git a/gateway/node_test.go b/gateway/node_test.go index 805767dc6..aa33e8bfb 100644 --- a/gateway/node_test.go +++ b/gateway/node_test.go @@ -89,7 +89,7 @@ func TestGatewayAPIChainGetTipSetByHeight(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { mock := &mockGatewayDepsAPI{} - a := NewNode(mock, DefaultLookbackCap, DefaultStateWaitLookbackLimit, 0, time.Minute) + a := NewNode(mock, nil, DefaultLookbackCap, DefaultStateWaitLookbackLimit, 0, time.Minute) // Create tipsets from genesis up to tskh and return the highest ts := mock.createTipSets(tt.args.tskh, tt.args.genesisTS) @@ -245,7 +245,7 @@ func TestGatewayVersion(t *testing.T) { //stm: @GATEWAY_NODE_GET_VERSION_001 ctx := context.Background() mock := &mockGatewayDepsAPI{} - a := NewNode(mock, DefaultLookbackCap, DefaultStateWaitLookbackLimit, 0, time.Minute) + a := NewNode(mock, nil, DefaultLookbackCap, DefaultStateWaitLookbackLimit, 0, time.Minute) v, err := a.Version(ctx) require.NoError(t, err) @@ -256,7 +256,7 @@ func TestGatewayLimitTokensAvailable(t *testing.T) { ctx := context.Background() mock := &mockGatewayDepsAPI{} tokens := 3 - a := NewNode(mock, DefaultLookbackCap, DefaultStateWaitLookbackLimit, int64(tokens), time.Minute) + a := NewNode(mock, nil, DefaultLookbackCap, DefaultStateWaitLookbackLimit, int64(tokens), time.Minute) require.NoError(t, a.limit(ctx, tokens), "requests should not be limited when there are enough tokens available") } @@ -264,7 +264,7 @@ func TestGatewayLimitTokensNotAvailable(t *testing.T) { ctx := context.Background() mock := &mockGatewayDepsAPI{} tokens := 3 - a := NewNode(mock, DefaultLookbackCap, DefaultStateWaitLookbackLimit, int64(1), time.Millisecond) + a := NewNode(mock, nil, DefaultLookbackCap, DefaultStateWaitLookbackLimit, int64(1), time.Millisecond) var err error // try to be rate limited for i := 0; i <= 1000; i++ { diff --git a/gateway/proxy_eth.go b/gateway/proxy_eth.go new file mode 100644 index 000000000..838a9ba3f --- /dev/null +++ b/gateway/proxy_eth.go @@ -0,0 +1,585 @@ +package gateway + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "sync" + "time" + + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" +) + +func (gw *Node) Web3ClientVersion(ctx context.Context) (string, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return "", err + } + + return gw.target.Web3ClientVersion(ctx) +} + +func (gw *Node) EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) { + // gateway provides public API, so it can't hold user accounts + return []ethtypes.EthAddress{}, nil +} + +func (gw *Node) EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + return gw.target.EthBlockNumber(ctx) +} + +func (gw *Node) EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + head, err := gw.target.ChainHead(ctx) + if err != nil { + return 0, err + } + if err := gw.checkTipsetHeight(head, abi.ChainEpoch(blkNum)); err != nil { + return 0, err + } + + return gw.target.EthGetBlockTransactionCountByNumber(ctx, blkNum) +} + +func (gw *Node) tskByEthHash(ctx context.Context, blkHash ethtypes.EthHash) (types.TipSetKey, error) { + tskCid := blkHash.ToCid() + tskBlk, err := gw.target.ChainReadObj(ctx, tskCid) + if err != nil { + return types.EmptyTSK, err + } + tsk := new(types.TipSetKey) + if err := tsk.UnmarshalCBOR(bytes.NewReader(tskBlk)); err != nil { + return types.EmptyTSK, xerrors.Errorf("cannot unmarshal block into tipset key: %w", err) + } + + return *tsk, nil +} + +func (gw *Node) checkBlkHash(ctx context.Context, blkHash ethtypes.EthHash) error { + tsk, err := gw.tskByEthHash(ctx, blkHash) + if err != nil { + return err + } + + return gw.checkTipsetKey(ctx, tsk) +} + +func (gw *Node) checkBlkParam(ctx context.Context, blkParam string) error { + if blkParam == "earliest" { + // also not supported in node impl + return fmt.Errorf("block param \"earliest\" is not supported") + } + + switch blkParam { + case "pending", "latest": + // those will be recent enough, so we don't need to check + return nil + default: + var num ethtypes.EthUint64 + err := num.UnmarshalJSON([]byte(`"` + blkParam + `"`)) + if err != nil { + return fmt.Errorf("cannot parse block number: %v", err) + } + head, err := gw.target.ChainHead(ctx) + if err != nil { + return err + } + if err := gw.checkTipsetHeight(head, abi.ChainEpoch(num)); err != nil { + return err + } + } + + return nil +} + +func (gw *Node) EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + if err := gw.checkBlkHash(ctx, blkHash); err != nil { + return 0, err + } + + return gw.target.EthGetBlockTransactionCountByHash(ctx, blkHash) +} + +func (gw *Node) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthBlock{}, err + } + + if err := gw.checkBlkHash(ctx, blkHash); err != nil { + return ethtypes.EthBlock{}, err + } + + return gw.target.EthGetBlockByHash(ctx, blkHash, fullTxInfo) +} + +func (gw *Node) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthBlock{}, err + } + + if err := gw.checkBlkParam(ctx, blkNum); err != nil { + return ethtypes.EthBlock{}, err + } + + return gw.target.EthGetBlockByNumber(ctx, blkNum, fullTxInfo) +} + +func (gw *Node) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + return gw.target.EthGetTransactionByHash(ctx, txHash) +} + +func (gw *Node) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + return gw.target.EthGetTransactionHashByCid(ctx, cid) +} + +func (gw *Node) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + return gw.target.EthGetMessageCidByTransactionHash(ctx, txHash) +} + +func (gw *Node) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + if err := gw.checkBlkParam(ctx, blkOpt); err != nil { + return 0, err + } + + return gw.target.EthGetTransactionCount(ctx, sender, blkOpt) +} + +func (gw *Node) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + return gw.target.EthGetTransactionReceipt(ctx, txHash) +} + +func (gw *Node) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthTx{}, err + } + + if err := gw.checkBlkHash(ctx, blkHash); err != nil { + return ethtypes.EthTx{}, err + } + + return gw.target.EthGetTransactionByBlockHashAndIndex(ctx, blkHash, txIndex) +} + +func (gw *Node) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthTx{}, err + } + + head, err := gw.target.ChainHead(ctx) + if err != nil { + return ethtypes.EthTx{}, err + } + if err := gw.checkTipsetHeight(head, abi.ChainEpoch(blkNum)); err != nil { + return ethtypes.EthTx{}, err + } + + return gw.target.EthGetTransactionByBlockNumberAndIndex(ctx, blkNum, txIndex) +} + +func (gw *Node) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + if err := gw.checkBlkParam(ctx, blkOpt); err != nil { + return nil, err + } + + return gw.target.EthGetCode(ctx, address, blkOpt) +} + +func (gw *Node) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + if err := gw.checkBlkParam(ctx, blkParam); err != nil { + return nil, err + } + + return gw.target.EthGetStorageAt(ctx, address, position, blkParam) +} + +func (gw *Node) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthBigInt(big.Zero()), err + } + + if err := gw.checkBlkParam(ctx, blkParam); err != nil { + return ethtypes.EthBigInt(big.Zero()), err + } + + return gw.target.EthGetBalance(ctx, address, blkParam) +} + +func (gw *Node) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + return gw.target.EthChainId(ctx) +} + +func (gw *Node) NetVersion(ctx context.Context) (string, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return "", err + } + + return gw.target.NetVersion(ctx) +} + +func (gw *Node) NetListening(ctx context.Context) (bool, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return false, err + } + + return gw.target.NetListening(ctx) +} + +func (gw *Node) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + return gw.target.EthProtocolVersion(ctx) +} + +func (gw *Node) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthBigInt(big.Zero()), err + } + + return gw.target.EthGasPrice(ctx) +} + +var EthFeeHistoryMaxBlockCount = 128 // this seems to be expensive; todo: figure out what is a good number that works with everything + +func (gw *Node) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { + params, err := jsonrpc.DecodeParams[ethtypes.EthFeeHistoryParams](p) + if err != nil { + return ethtypes.EthFeeHistory{}, xerrors.Errorf("decoding params: %w", err) + } + + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthFeeHistory{}, err + } + + if err := gw.checkBlkParam(ctx, params.NewestBlkNum); err != nil { + return ethtypes.EthFeeHistory{}, err + } + + if params.BlkCount > ethtypes.EthUint64(EthFeeHistoryMaxBlockCount) { + return ethtypes.EthFeeHistory{}, fmt.Errorf("block count too high") + } + + return gw.target.EthFeeHistory(ctx, p) +} + +func (gw *Node) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthBigInt(big.Zero()), err + } + + return gw.target.EthMaxPriorityFeePerGas(ctx) +} + +func (gw *Node) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + // todo limit gas? to what? + return gw.target.EthEstimateGas(ctx, tx) +} + +func (gw *Node) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + if err := gw.checkBlkParam(ctx, blkParam); err != nil { + return nil, err + } + + // todo limit gas? to what? + return gw.target.EthCall(ctx, tx, blkParam) +} + +func (gw *Node) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthHash{}, err + } + + return gw.target.EthSendRawTransaction(ctx, rawTx) +} + +func (gw *Node) EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + if filter.FromBlock != nil { + if err := gw.checkBlkParam(ctx, *filter.FromBlock); err != nil { + return nil, err + } + } + if filter.ToBlock != nil { + if err := gw.checkBlkParam(ctx, *filter.ToBlock); err != nil { + return nil, err + } + } + if filter.BlockHash != nil { + if err := gw.checkBlkHash(ctx, *filter.BlockHash); err != nil { + return nil, err + } + } + + return gw.target.EthGetLogs(ctx, filter) +} + +/* FILTERS: Those are stateful.. figure out how to properly either bind them to users, or time out? */ + +func (gw *Node) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + ft := statefulCallFromContext(ctx) + ft.lk.Lock() + _, ok := ft.userFilters[id] + ft.lk.Unlock() + + if !ok { + return nil, nil + } + + return gw.target.EthGetFilterChanges(ctx, id) +} + +func (gw *Node) EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + ft := statefulCallFromContext(ctx) + ft.lk.Lock() + _, ok := ft.userFilters[id] + ft.lk.Unlock() + + if !ok { + return nil, nil + } + + return gw.target.EthGetFilterLogs(ctx, id) +} + +func (gw *Node) EthNewFilter(ctx context.Context, filter *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthFilterID{}, err + } + + return addUserFilterLimited(ctx, func() (ethtypes.EthFilterID, error) { + return gw.target.EthNewFilter(ctx, filter) + }) +} + +func (gw *Node) EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthFilterID{}, err + } + + return addUserFilterLimited(ctx, func() (ethtypes.EthFilterID, error) { + return gw.target.EthNewBlockFilter(ctx) + }) +} + +func (gw *Node) EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthFilterID{}, err + } + + return addUserFilterLimited(ctx, func() (ethtypes.EthFilterID, error) { + return gw.target.EthNewPendingTransactionFilter(ctx) + }) +} + +func (gw *Node) EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return false, err + } + + // check if the filter belongs to this connection + ft := statefulCallFromContext(ctx) + ft.lk.Lock() + defer ft.lk.Unlock() + + if _, ok := ft.userFilters[id]; !ok { + return false, nil + } + + ok, err := gw.target.EthUninstallFilter(ctx, id) + if err != nil { + return false, err + } + + delete(ft.userFilters, id) + return ok, nil +} + +func (gw *Node) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) { + // validate params + _, err := jsonrpc.DecodeParams[ethtypes.EthSubscribeParams](p) + if err != nil { + return ethtypes.EthSubscriptionID{}, xerrors.Errorf("decoding params: %w", err) + } + + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthSubscriptionID{}, err + } + + if gw.subHnd == nil { + return ethtypes.EthSubscriptionID{}, xerrors.New("subscription support not enabled") + } + + ethCb, ok := jsonrpc.ExtractReverseClient[api.EthSubscriberMethods](ctx) + if !ok { + return ethtypes.EthSubscriptionID{}, xerrors.Errorf("connection doesn't support callbacks") + } + + ft := statefulCallFromContext(ctx) + ft.lk.Lock() + defer ft.lk.Unlock() + + if len(ft.userSubscriptions) >= EthMaxFiltersPerConn { + return ethtypes.EthSubscriptionID{}, fmt.Errorf("too many subscriptions") + } + + sub, err := gw.target.EthSubscribe(ctx, p) + if err != nil { + return ethtypes.EthSubscriptionID{}, err + } + + err = gw.subHnd.AddSub(ctx, sub, func(ctx context.Context, response *ethtypes.EthSubscriptionResponse) error { + outParam, err := json.Marshal(response) + if err != nil { + return err + } + + return ethCb.EthSubscription(ctx, outParam) + }) + if err != nil { + return ethtypes.EthSubscriptionID{}, err + } + + ft.userSubscriptions[sub] = time.Now() + + return sub, err +} + +func (gw *Node) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return false, err + } + + // check if the filter belongs to this connection + ft := statefulCallFromContext(ctx) + ft.lk.Lock() + defer ft.lk.Unlock() + + if _, ok := ft.userSubscriptions[id]; !ok { + return false, nil + } + + ok, err := gw.target.EthUnsubscribe(ctx, id) + if err != nil { + return false, err + } + + delete(ft.userSubscriptions, id) + + if gw.subHnd != nil { + gw.subHnd.RemoveSub(id) + } + + return ok, nil +} + +var EthMaxFiltersPerConn = 16 // todo make this configurable + +func addUserFilterLimited(ctx context.Context, cb func() (ethtypes.EthFilterID, error)) (ethtypes.EthFilterID, error) { + ft := statefulCallFromContext(ctx) + ft.lk.Lock() + defer ft.lk.Unlock() + + if len(ft.userFilters) >= EthMaxFiltersPerConn { + return ethtypes.EthFilterID{}, fmt.Errorf("too many filters") + } + + id, err := cb() + if err != nil { + return id, err + } + + ft.userFilters[id] = time.Now() + + return id, nil +} + +func statefulCallFromContext(ctx context.Context) *statefulCallTracker { + return ctx.Value(statefulCallTrackerKey).(*statefulCallTracker) +} + +type statefulCallTracker struct { + lk sync.Mutex + + userFilters map[ethtypes.EthFilterID]time.Time + userSubscriptions map[ethtypes.EthSubscriptionID]time.Time +} + +// called per request (ws connection) +func newStatefulCallTracker() *statefulCallTracker { + return &statefulCallTracker{ + userFilters: make(map[ethtypes.EthFilterID]time.Time), + userSubscriptions: make(map[ethtypes.EthSubscriptionID]time.Time), + } +} diff --git a/gateway/proxy_fil.go b/gateway/proxy_fil.go new file mode 100644 index 000000000..1f6ee2ccc --- /dev/null +++ b/gateway/proxy_fil.go @@ -0,0 +1,482 @@ +package gateway + +import ( + "context" + + "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/network" + + "github.com/filecoin-project/lotus/api" + apitypes "github.com/filecoin-project/lotus/api/types" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/sigs" +) + +func (gw *Node) Discover(ctx context.Context) (apitypes.OpenRPCDocument, error) { + return build.OpenRPCDiscoverJSON_Gateway(), nil +} + +func (gw *Node) Version(ctx context.Context) (api.APIVersion, error) { + if err := gw.limit(ctx, basicRateLimitTokens); err != nil { + return api.APIVersion{}, err + } + return gw.target.Version(ctx) +} + +func (gw *Node) ChainGetParentMessages(ctx context.Context, c cid.Cid) ([]api.Message, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetParentMessages(ctx, c) +} + +func (gw *Node) ChainGetParentReceipts(ctx context.Context, c cid.Cid) ([]*types.MessageReceipt, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetParentReceipts(ctx, c) +} + +func (gw *Node) ChainGetBlockMessages(ctx context.Context, c cid.Cid) (*api.BlockMessages, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetBlockMessages(ctx, c) +} + +func (gw *Node) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return false, err + } + return gw.target.ChainHasObj(ctx, c) +} + +func (gw *Node) ChainHead(ctx context.Context) (*types.TipSet, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + + return gw.target.ChainHead(ctx) +} + +func (gw *Node) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetMessage(ctx, mc) +} + +func (gw *Node) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetTipSet(ctx, tsk) +} + +func (gw *Node) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipSetHeight(ctx, h, tsk); err != nil { + return nil, err + } + return gw.target.ChainGetTipSetByHeight(ctx, h, tsk) +} + +func (gw *Node) ChainGetTipSetAfterHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipSetHeight(ctx, h, tsk); err != nil { + return nil, err + } + return gw.target.ChainGetTipSetAfterHeight(ctx, h, tsk) +} + +func (gw *Node) checkTipSetHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) error { + var ts *types.TipSet + if tsk.IsEmpty() { + head, err := gw.target.ChainHead(ctx) + if err != nil { + return err + } + ts = head + } else { + gts, err := gw.target.ChainGetTipSet(ctx, tsk) + if err != nil { + return err + } + ts = gts + } + + // Check if the tipset key refers to gw tipset that's too far in the past + if err := gw.checkTipset(ts); err != nil { + return err + } + + // Check if the height is too far in the past + if err := gw.checkTipsetHeight(ts, h); err != nil { + return err + } + + return nil +} + +func (gw *Node) ChainGetNode(ctx context.Context, p string) (*api.IpldObject, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetNode(ctx, p) +} + +func (gw *Node) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainNotify(ctx) +} + +func (gw *Node) ChainGetPath(ctx context.Context, from, to types.TipSetKey) ([]*api.HeadChange, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, from); err != nil { + return nil, xerrors.Errorf("gateway: checking 'from' tipset: %w", err) + } + if err := gw.checkTipsetKey(ctx, to); err != nil { + return nil, xerrors.Errorf("gateway: checking 'to' tipset: %w", err) + } + return gw.target.ChainGetPath(ctx, from, to) +} + +func (gw *Node) ChainGetGenesis(ctx context.Context) (*types.TipSet, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetGenesis(ctx) +} + +func (gw *Node) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainReadObj(ctx, c) +} + +func (gw *Node) ChainPutObj(context.Context, blocks.Block) error { + return xerrors.New("not supported") +} + +func (gw *Node) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.GasEstimateMessageGas(ctx, msg, spec, tsk) +} + +func (gw *Node) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return cid.Cid{}, err + } + // TODO: additional anti-spam checks + return gw.target.MpoolPushUntrusted(ctx, sm) +} + +func (gw *Node) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) { + if err := gw.limit(ctx, walletRateLimitTokens); err != nil { + return types.BigInt{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return types.NewInt(0), err + } + return gw.target.MsigGetAvailableBalance(ctx, addr, tsk) +} + +func (gw *Node) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) { + if err := gw.limit(ctx, walletRateLimitTokens); err != nil { + return types.BigInt{}, err + } + if err := gw.checkTipsetKey(ctx, start); err != nil { + return types.NewInt(0), err + } + if err := gw.checkTipsetKey(ctx, end); err != nil { + return types.NewInt(0), err + } + return gw.target.MsigGetVested(ctx, addr, start, end) +} + +func (gw *Node) MsigGetVestingSchedule(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MsigVesting, error) { + if err := gw.limit(ctx, walletRateLimitTokens); err != nil { + return api.MsigVesting{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return api.MsigVesting{}, err + } + return gw.target.MsigGetVestingSchedule(ctx, addr, tsk) +} + +func (gw *Node) MsigGetPending(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.MsigTransaction, error) { + if err := gw.limit(ctx, walletRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.MsigGetPending(ctx, addr, tsk) +} + +func (gw *Node) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return address.Address{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return address.Undef, err + } + return gw.target.StateAccountKey(ctx, addr, tsk) +} + +func (gw *Node) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return api.DealCollateralBounds{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return api.DealCollateralBounds{}, err + } + return gw.target.StateDealProviderCollateralBounds(ctx, size, verified, tsk) +} + +func (gw *Node) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateGetActor(ctx, actor, tsk) +} + +func (gw *Node) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateListMiners(ctx, tsk) +} + +func (gw *Node) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return address.Address{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return address.Undef, err + } + return gw.target.StateLookupID(ctx, addr, tsk) +} + +func (gw *Node) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return api.MarketBalance{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return api.MarketBalance{}, err + } + return gw.target.StateMarketBalance(ctx, addr, tsk) +} + +func (gw *Node) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateMarketStorageDeal(ctx, dealId, tsk) +} + +func (gw *Node) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return network.VersionMax, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return network.VersionMax, err + } + return gw.target.StateNetworkVersion(ctx, tsk) +} + +func (gw *Node) StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if limit == api.LookbackNoLimit { + limit = gw.stateWaitLookbackLimit + } + if gw.stateWaitLookbackLimit != api.LookbackNoLimit && limit > gw.stateWaitLookbackLimit { + limit = gw.stateWaitLookbackLimit + } + if err := gw.checkTipsetKey(ctx, from); err != nil { + return nil, err + } + return gw.target.StateSearchMsg(ctx, from, msg, limit, allowReplaced) +} + +func (gw *Node) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if limit == api.LookbackNoLimit { + limit = gw.stateWaitLookbackLimit + } + if gw.stateWaitLookbackLimit != api.LookbackNoLimit && limit > gw.stateWaitLookbackLimit { + limit = gw.stateWaitLookbackLimit + } + return gw.target.StateWaitMsg(ctx, msg, confidence, limit, allowReplaced) +} + +func (gw *Node) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateReadState(ctx, actor, tsk) +} + +func (gw *Node) StateMinerPower(ctx context.Context, m address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateMinerPower(ctx, m, tsk) +} + +func (gw *Node) StateMinerFaults(ctx context.Context, m address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return bitfield.BitField{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return bitfield.BitField{}, err + } + return gw.target.StateMinerFaults(ctx, m, tsk) +} + +func (gw *Node) StateMinerRecoveries(ctx context.Context, m address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return bitfield.BitField{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return bitfield.BitField{}, err + } + return gw.target.StateMinerRecoveries(ctx, m, tsk) +} + +func (gw *Node) StateMinerInfo(ctx context.Context, m address.Address, tsk types.TipSetKey) (api.MinerInfo, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return api.MinerInfo{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return api.MinerInfo{}, err + } + return gw.target.StateMinerInfo(ctx, m, tsk) +} + +func (gw *Node) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) ([]api.Deadline, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateMinerDeadlines(ctx, m, tsk) +} + +func (gw *Node) StateMinerAvailableBalance(ctx context.Context, m address.Address, tsk types.TipSetKey) (types.BigInt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return types.BigInt{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return types.BigInt{}, err + } + return gw.target.StateMinerAvailableBalance(ctx, m, tsk) +} + +func (gw *Node) StateMinerProvingDeadline(ctx context.Context, m address.Address, tsk types.TipSetKey) (*dline.Info, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateMinerProvingDeadline(ctx, m, tsk) +} + +func (gw *Node) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (abi.TokenAmount, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return abi.TokenAmount{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return abi.TokenAmount{}, err + } + return gw.target.StateCirculatingSupply(ctx, tsk) +} + +func (gw *Node) StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateSectorGetInfo(ctx, maddr, n, tsk) +} + +func (gw *Node) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateVerifiedClientStatus(ctx, addr, tsk) +} + +func (gw *Node) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return api.CirculatingSupply{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return api.CirculatingSupply{}, err + } + return gw.target.StateVMCirculatingSupplyInternal(ctx, tsk) +} + +func (gw *Node) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *crypto.Signature) (bool, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return false, err + } + return sigs.Verify(sig, k, msg) == nil, nil +} + +func (gw *Node) WalletBalance(ctx context.Context, k address.Address) (types.BigInt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return types.BigInt{}, err + } + return gw.target.WalletBalance(ctx, k) +} diff --git a/gen/api/proxygen.go b/gen/api/proxygen.go index f756c0d0c..75fbc668c 100644 --- a/gen/api/proxygen.go +++ b/gen/api/proxygen.go @@ -259,7 +259,7 @@ func generate(path, pkg, outpkg, outfile string) error { if len(tf) != 2 { continue } - if tf[0] != "perm" { // todo: allow more tag types + if tf[0] != "perm" && tf[0] != "rpc_method" && tf[0] != "notify" { // todo: allow more tag types continue } info.Methods[mname].Tags[tf[0]] = tf @@ -302,12 +302,14 @@ type {{.Num}}Struct struct { {{range .Include}} {{.}}Struct {{end}} - Internal struct { + Internal {{.Num}}Methods +} + +type {{.Num}}Methods struct { {{range .Methods}} {{.Num}} func({{.NamedParams}}) ({{.Results}}) `+"`"+`{{range .Tags}}{{index . 0}}:"{{index . 1}}"{{end}}`+"`"+` {{end}} } -} type {{.Num}}Stub struct { {{range .Include}} diff --git a/gen/bundle/bundle.go b/gen/bundle/bundle.go index c7655157e..f57ced15b 100644 --- a/gen/bundle/bundle.go +++ b/gen/bundle/bundle.go @@ -2,6 +2,8 @@ package main import ( "os" + "strconv" + "strings" "text/template" "github.com/filecoin-project/lotus/build" @@ -20,6 +22,7 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet {{- range . }} { Network: {{printf "%q" .Network}}, Version: {{.Version}}, + {{if .BundleGitTag}} BundleGitTag: {{printf "%q" .BundleGitTag}}, {{end}} ManifestCid: MustParseCid({{printf "%q" .ManifestCid}}), Actors: map[string]cid.Cid { {{- range $name, $cid := .Actors }} @@ -31,12 +34,50 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet } `)) +func splitOverride(override string) (string, string) { + x := strings.Split(override, "=") + return x[0], x[1] +} + func main() { + // read metadata from the embedded bundle, includes all info except git tags metadata, err := build.ReadEmbeddedBuiltinActorsMetadata() if err != nil { panic(err) } + // IF args have been provided, extract git tag info from them, otherwise + // rely on previously embedded metadata for git tags. + if len(os.Args) > 1 { + // see ./build/actors/pack.sh + // (optional) expected args are: + // $(GOCC) run ./gen/bundle $(VERSION) $(RELEASE) $(RELEASE_OVERRIDES) + // overrides are in the format network_name=override + gitTag := os.Args[2] + packedActorsVersion, err := strconv.Atoi(os.Args[1][1:]) + if err != nil { + panic(err) + } + + overrides := map[string]string{} + for _, override := range os.Args[3:] { + k, v := splitOverride(override) + overrides[k] = v + } + for _, m := range metadata { + if int(m.Version) == packedActorsVersion { + override, ok := overrides[m.Network] + if ok { + m.BundleGitTag = override + } else { + m.BundleGitTag = gitTag + } + } else { + m.BundleGitTag = getOldGitTagFromEmbeddedMetadata(m) + } + } + } + fi, err := os.Create("./build/builtin_actors_gen.go") if err != nil { panic(err) @@ -48,3 +89,14 @@ func main() { panic(err) } } + +func getOldGitTagFromEmbeddedMetadata(m *build.BuiltinActorsMetadata) string { + for _, v := range build.EmbeddedBuiltinActorsMetadata { + // if we agree on the manifestCid for the previously embedded metadata, use the previously set tag + if m.Version == v.Version && m.Network == v.Network && m.ManifestCid == v.ManifestCid { + return m.BundleGitTag + } + } + + return "" +} diff --git a/gen/inlinegen-data.json b/gen/inlinegen-data.json index e767f990a..8384e749d 100644 --- a/gen/inlinegen-data.json +++ b/gen/inlinegen-data.json @@ -1,7 +1,7 @@ { - "actorVersions": [0, 2, 3, 4, 5, 6, 7, 8, 9], - "latestActorsVersion": 9, + "actorVersions": [0, 2, 3, 4, 5, 6, 7, 8, 9, 10], + "latestActorsVersion": 10, - "networkVersions": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], - "latestNetworkVersion": 17 + "networkVersions": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], + "latestNetworkVersion": 18 } diff --git a/gen/main.go b/gen/main.go index 439194ef4..a3891778a 100644 --- a/gen/main.go +++ b/gen/main.go @@ -27,13 +27,16 @@ func main() { types.Message{}, types.SignedMessage{}, types.MsgMeta{}, - types.Actor{}, - types.MessageReceipt{}, + types.ActorV4{}, + types.ActorV5{}, + // types.MessageReceipt{}, // Custom serde to deal with versioning. types.BlockMsg{}, types.ExpTipSet{}, types.BeaconEntry{}, types.StateRoot{}, types.StateInfo0{}, + types.Event{}, + types.EventEntry{}, ) if err != nil { fmt.Println(err) diff --git a/go.mod b/go.mod index a5ce1e3d8..55ee0d510 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ retract v1.14.0 // Accidentally force-pushed tag, use v1.14.1+ instead. require ( contrib.go.opencensus.io/exporter/prometheus v0.4.0 github.com/BurntSushi/toml v1.1.0 - github.com/DataDog/zstd v1.4.1 - github.com/GeertJohan/go.rice v1.0.2 + github.com/DataDog/zstd v1.4.5 + github.com/GeertJohan/go.rice v1.0.3 github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee github.com/Kubuxu/imtui v0.0.0-20210401140320-41663d68d0fa github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d @@ -16,13 +16,14 @@ require ( github.com/buger/goterm v1.0.3 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e github.com/containerd/cgroups v1.0.4 - github.com/coreos/go-systemd/v22 v22.3.2 + github.com/coreos/go-systemd/v22 v22.4.0 github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/dgraph-io/badger/v2 v2.2007.3 - github.com/docker/go-units v0.4.0 + github.com/docker/go-units v0.5.0 github.com/drand/drand v1.3.0 github.com/drand/kyber v1.1.7 github.com/dustin/go-humanize v1.0.0 + github.com/elastic/go-elasticsearch/v7 v7.14.0 github.com/elastic/go-sysinfo v1.7.0 github.com/elastic/gosigar v0.14.2 github.com/etclabscore/go-openrpc-reflect v0.0.36 @@ -30,6 +31,7 @@ require ( github.com/filecoin-project/dagstore v0.5.2 github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200910194244-f640612a1a1f github.com/filecoin-project/go-address v1.1.0 + github.com/filecoin-project/go-amt-ipld/v4 v4.0.0 github.com/filecoin-project/go-bitfield v0.2.4 github.com/filecoin-project/go-cbor-util v0.0.1 github.com/filecoin-project/go-commp-utils v0.1.3 @@ -37,16 +39,16 @@ require ( github.com/filecoin-project/go-data-transfer v1.15.2 github.com/filecoin-project/go-fil-commcid v0.1.0 github.com/filecoin-project/go-fil-commp-hashhash v0.1.0 - github.com/filecoin-project/go-fil-markets v1.25.0 - github.com/filecoin-project/go-jsonrpc v0.1.8 + github.com/filecoin-project/go-fil-markets v1.25.2 + github.com/filecoin-project/go-jsonrpc v0.2.1 github.com/filecoin-project/go-legs v0.4.4 github.com/filecoin-project/go-padreader v0.0.1 github.com/filecoin-project/go-paramfetch v0.0.4 - github.com/filecoin-project/go-state-types v0.10.0-alpha-2 + github.com/filecoin-project/go-state-types v0.10.0 github.com/filecoin-project/go-statemachine v1.0.2 github.com/filecoin-project/go-statestore v0.2.0 github.com/filecoin-project/go-storedcounter v0.1.0 - github.com/filecoin-project/index-provider v0.8.1 + github.com/filecoin-project/index-provider v0.9.1 github.com/filecoin-project/pubsub v1.0.0 github.com/filecoin-project/specs-actors v0.9.15 github.com/filecoin-project/specs-actors/v2 v2.3.6 @@ -60,10 +62,12 @@ require ( github.com/gbrlsnchs/jwt/v3 v3.0.1 github.com/gdamore/tcell/v2 v2.2.0 github.com/go-kit/kit v0.12.0 + github.com/go-openapi/spec v0.19.11 github.com/golang/mock v1.6.0 github.com/google/uuid v1.3.0 - github.com/gorilla/mux v1.7.4 + github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 + github.com/gregdhill/go-openrpc v0.0.0-20220114144539-ae6f44720487 github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026 github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e github.com/hashicorp/go-multierror v1.1.1 @@ -73,17 +77,15 @@ require ( github.com/icza/backscanner v0.0.0-20210726202459-ac2ffc679f94 github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab github.com/ipfs/bbloom v0.0.4 - github.com/ipfs/go-bitswap v0.10.2 - github.com/ipfs/go-block-format v0.0.3 github.com/ipfs/go-blockservice v0.4.0 - github.com/ipfs/go-cid v0.2.0 + github.com/ipfs/go-cid v0.3.2 github.com/ipfs/go-cidutil v0.1.0 - github.com/ipfs/go-datastore v0.5.1 + github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-badger2 v0.1.2 github.com/ipfs/go-ds-leveldb v0.5.0 github.com/ipfs/go-ds-measure v0.2.0 github.com/ipfs/go-fs-lock v0.0.7 - github.com/ipfs/go-graphsync v0.13.1 + github.com/ipfs/go-graphsync v0.13.2 github.com/ipfs/go-ipfs-blockstore v1.2.0 github.com/ipfs/go-ipfs-blocksutil v0.0.1 github.com/ipfs/go-ipfs-chunker v0.0.5 @@ -92,73 +94,76 @@ require ( github.com/ipfs/go-ipfs-exchange-offline v0.3.0 github.com/ipfs/go-ipfs-files v0.1.1 github.com/ipfs/go-ipfs-http-client v0.4.0 - github.com/ipfs/go-ipfs-routing v0.2.1 + github.com/ipfs/go-ipfs-routing v0.3.0 github.com/ipfs/go-ipfs-util v0.0.2 github.com/ipfs/go-ipld-cbor v0.0.6 github.com/ipfs/go-ipld-format v0.4.0 + github.com/ipfs/go-libipfs v0.4.1 github.com/ipfs/go-log/v2 v2.5.1 github.com/ipfs/go-merkledag v0.8.1 github.com/ipfs/go-metrics-interface v0.0.1 github.com/ipfs/go-metrics-prometheus v0.0.2 - github.com/ipfs/go-unixfs v0.3.1 + github.com/ipfs/go-unixfs v0.4.0 github.com/ipfs/go-unixfsnode v1.4.0 github.com/ipfs/interface-go-ipfs-core v0.7.0 github.com/ipld/go-car v0.4.0 github.com/ipld/go-car/v2 v2.5.0 - github.com/ipld/go-codec-dagpb v1.3.2 - github.com/ipld/go-ipld-prime v0.17.0 + github.com/ipld/go-codec-dagpb v1.5.0 + github.com/ipld/go-ipld-prime v0.20.0 github.com/ipld/go-ipld-selector-text-lite v0.0.1 github.com/kelseyhightower/envconfig v1.4.0 github.com/koalacxr/quantile v0.0.1 github.com/libp2p/go-buffer-pool v0.1.0 - github.com/libp2p/go-libp2p v0.22.0 + github.com/libp2p/go-libp2p v0.23.4 github.com/libp2p/go-libp2p-consensus v0.0.1 github.com/libp2p/go-libp2p-gorpc v0.4.0 github.com/libp2p/go-libp2p-kad-dht v0.18.0 - github.com/libp2p/go-libp2p-peerstore v0.8.0 - github.com/libp2p/go-libp2p-pubsub v0.8.0 + github.com/libp2p/go-libp2p-pubsub v0.8.2 github.com/libp2p/go-libp2p-raft v0.1.8 github.com/libp2p/go-libp2p-record v0.2.0 github.com/libp2p/go-libp2p-routing-helpers v0.2.3 github.com/libp2p/go-maddr-filter v0.1.0 github.com/libp2p/go-msgio v0.2.0 github.com/mattn/go-isatty v0.0.16 + github.com/mattn/go-sqlite3 v1.14.16 github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 github.com/mitchellh/go-homedir v1.1.0 - github.com/multiformats/go-base32 v0.0.4 - github.com/multiformats/go-multiaddr v0.6.0 + github.com/multiformats/go-base32 v0.1.0 + github.com/multiformats/go-multiaddr v0.8.0 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multibase v0.1.1 github.com/multiformats/go-multihash v0.2.1 github.com/multiformats/go-varint v0.0.6 github.com/open-rpc/meta-schema v0.0.0-20201029221707-1b72ef2ea333 github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e - github.com/prometheus/client_golang v1.12.1 + github.com/prometheus/client_golang v1.13.0 github.com/raulk/clock v1.1.0 github.com/raulk/go-watchdog v1.3.0 - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.1 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/urfave/cli/v2 v2.8.1 + github.com/urfave/cli/v2 v2.16.3 github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba - github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c + github.com/whyrusleeping/cbor-gen v0.0.0-20221021053955-c138aae13722 github.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 + github.com/xeipuuv/gojsonschema v1.2.0 github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 go.opencensus.io v0.23.0 - go.opentelemetry.io/otel v1.7.0 - go.opentelemetry.io/otel/bridge/opencensus v0.25.0 + go.opentelemetry.io/otel v1.11.1 + go.opentelemetry.io/otel/bridge/opencensus v0.33.0 go.opentelemetry.io/otel/exporters/jaeger v1.2.0 - go.opentelemetry.io/otel/sdk v1.2.0 + go.opentelemetry.io/otel/sdk v1.11.1 go.uber.org/fx v1.15.0 go.uber.org/multierr v1.8.0 - go.uber.org/zap v1.22.0 - golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 - golang.org/x/net v0.0.0-20220812174116-3211cb980234 - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac + go.uber.org/zap v1.23.0 + golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 + golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b + golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 + golang.org/x/sync v0.0.0-20220907140024-f12130a52804 + golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 + golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 golang.org/x/tools v0.1.12 - golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 gopkg.in/cheggaaa/pb.v1 v1.0.28 gotest.tools v2.2.0+incompatible ) @@ -174,16 +179,15 @@ require ( github.com/armon/go-metrics v0.3.9 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bep/debounce v1.2.0 // indirect + github.com/bep/debounce v1.2.1 // indirect github.com/boltdb/bolt v1.3.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cheekybits/genny v1.0.0 // indirect github.com/cilium/ebpf v0.4.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect github.com/cskr/pubsub v1.0.2 // indirect - github.com/daaku/go.zipexe v1.0.0 // indirect + github.com/daaku/go.zipexe v1.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect @@ -194,13 +198,12 @@ require ( github.com/etclabscore/go-jsonschema-walk v0.0.6 // indirect github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 // indirect github.com/filecoin-project/go-amt-ipld/v3 v3.1.0 // indirect - github.com/filecoin-project/go-amt-ipld/v4 v4.0.0 // indirect github.com/filecoin-project/go-commp-utils/nonffi v0.0.0-20220905160352-62059082a837 // indirect - github.com/filecoin-project/go-ds-versioning v0.1.1 // indirect + github.com/filecoin-project/go-ds-versioning v0.1.2 // indirect github.com/filecoin-project/go-hamt-ipld v0.1.5 // indirect github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 // indirect github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0 // indirect - github.com/filecoin-project/storetheindex v0.4.17 // indirect + github.com/filecoin-project/storetheindex v0.4.30-0.20221114113647-683091f8e893 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect @@ -212,7 +215,6 @@ require ( github.com/go-ole/go-ole v1.2.5 // indirect github.com/go-openapi/jsonpointer v0.19.3 // indirect github.com/go-openapi/jsonreference v0.19.4 // indirect - github.com/go-openapi/spec v0.19.11 // indirect github.com/go-openapi/swag v0.19.11 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect @@ -221,7 +223,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/go-cmp v0.5.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/hannahhoward/cbor-gen-for v0.0.0-20200817222906-ea96cece81f1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -231,18 +233,20 @@ require ( github.com/huin/goupnp v1.0.3 // indirect github.com/iancoleman/orderedmap v0.1.0 // indirect github.com/ipfs/go-bitfield v1.0.0 // indirect + github.com/ipfs/go-block-format v0.1.1 // indirect github.com/ipfs/go-filestore v1.2.0 // indirect github.com/ipfs/go-ipfs-cmds v0.7.0 // indirect github.com/ipfs/go-ipfs-config v0.18.0 // indirect github.com/ipfs/go-ipfs-delay v0.0.1 // indirect github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect - github.com/ipfs/go-ipfs-pq v0.0.2 // indirect + github.com/ipfs/go-ipfs-pq v0.0.3 // indirect github.com/ipfs/go-ipld-legacy v0.1.1 // indirect - github.com/ipfs/go-ipns v0.2.0 // indirect + github.com/ipfs/go-ipns v0.3.0 // indirect github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-path v0.3.0 // indirect - github.com/ipfs/go-peertaskqueue v0.7.1 // indirect - github.com/ipfs/go-verifcid v0.0.1 // indirect + github.com/ipfs/go-peertaskqueue v0.8.1 // indirect + github.com/ipfs/go-verifcid v0.0.2 // indirect + github.com/ipld/go-ipld-adl-hamt v0.0.0-20220616142416-9004dbd839e0 // indirect github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c // indirect @@ -254,29 +258,28 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/kilic/bls12-381 v0.0.0-20200820230200-6b2c19996391 // indirect - github.com/klauspost/compress v1.15.1 // indirect - github.com/klauspost/cpuid/v2 v2.1.0 // indirect + github.com/klauspost/compress v1.15.10 // indirect + github.com/klauspost/cpuid/v2 v2.1.1 // indirect github.com/koron/go-ssdp v0.0.3 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect github.com/libp2p/go-libp2p-connmgr v0.4.0 // indirect - github.com/libp2p/go-libp2p-core v0.20.0 // indirect - github.com/libp2p/go-libp2p-gostream v0.4.0 // indirect + github.com/libp2p/go-libp2p-core v0.20.1 // indirect + github.com/libp2p/go-libp2p-gostream v0.5.0 // indirect github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect github.com/libp2p/go-libp2p-noise v0.5.0 // indirect + github.com/libp2p/go-libp2p-peerstore v0.8.0 // indirect github.com/libp2p/go-libp2p-tls v0.5.0 // indirect github.com/libp2p/go-nat v0.1.0 // indirect github.com/libp2p/go-netroute v0.2.0 // indirect github.com/libp2p/go-openssl v0.1.0 // indirect github.com/libp2p/go-reuseport v0.2.0 // indirect - github.com/libp2p/go-yamux/v3 v3.1.2 // indirect - github.com/lucas-clemente/quic-go v0.28.1 // indirect + github.com/libp2p/go-yamux/v4 v4.0.0 // indirect + github.com/lucas-clemente/quic-go v0.29.1 // indirect github.com/lucasb-eyer/go-colorful v1.0.3 // indirect github.com/magefile/mage v1.9.0 // indirect github.com/mailru/easyjson v0.7.6 // indirect - github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect - github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect @@ -291,7 +294,7 @@ require ( github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multicodec v0.5.0 // indirect + github.com/multiformats/go-multicodec v0.8.0 // indirect github.com/multiformats/go-multistream v0.3.3 // indirect github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c // indirect github.com/nkovacs/streamquote v1.0.0 // indirect @@ -314,6 +317,7 @@ require ( github.com/sirupsen/logrus v1.8.1 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/twmb/murmur3 v1.1.6 // indirect github.com/uber/jaeger-client-go v2.25.0+incompatible // indirect github.com/ugorji/go/codec v1.2.6 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect @@ -322,16 +326,17 @@ require ( github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.12.1 // indirect - go.opentelemetry.io/otel/metric v0.25.0 // indirect - go.opentelemetry.io/otel/sdk/export/metric v0.25.0 // indirect - go.opentelemetry.io/otel/trace v1.7.0 // indirect + go.opentelemetry.io/otel/metric v0.33.0 // indirect + go.opentelemetry.io/otel/sdk/metric v0.33.0 // indirect + go.opentelemetry.io/otel/trace v1.11.1 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/dig v1.12.0 // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect - golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect diff --git a/go.sum b/go.sum index 30bd7d5b5..fa97634f2 100644 --- a/go.sum +++ b/go.sum @@ -51,12 +51,13 @@ github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= -github.com/GeertJohan/go.rice v1.0.2 h1:PtRw+Tg3oa3HYwiDBZyvOJ8LdIyf6lAovJJtr7YOAYk= -github.com/GeertJohan/go.rice v1.0.2/go.mod h1:af5vUNlDNkCjOZeSGFgIJxDje9qdjsO6hshx0gTmZt4= +github.com/GeertJohan/go.rice v1.0.3 h1:k5viR+xGtIhF61125vCE1cmJ5957RQGXG6dmbaWZSmI= +github.com/GeertJohan/go.rice v1.0.3/go.mod h1:XVdrU4pW00M4ikZed5q56tPf1v2KwnIKeIdc9CBYNt4= github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee h1:8doiS7ib3zi6/K172oDhSKU0dJ/miJramo9NITOMyZQ= github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee/go.mod h1:W0GbEAA4uFNYOGG2cJpmFJ04E6SD1NLELPYZB57/7AY= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= @@ -115,15 +116,14 @@ github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NR github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.2.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bep/debounce v1.2.0 h1:wXds8Kq8qRfwAOpAxHrJDbCXgC5aHSzgQb/0gKsHQqo= -github.com/bep/debounce v1.2.0/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= +github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= +github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= @@ -160,7 +160,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -186,6 +185,7 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA= github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -198,23 +198,24 @@ github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU= +github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= -github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= -github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= +github.com/daaku/go.zipexe v1.0.2 h1:Zg55YLYTr7M9wjKn8SY/WcpuuEi+kR2u4E8RhvpyXmk= +github.com/daaku/go.zipexe v1.0.2/go.mod h1:5xWogtqlYnfBXkSB1o9xysukNP9GTvaNkqzUZbt3Bw8= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -244,8 +245,9 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/drand/bls12-381 v0.3.2/go.mod h1:dtcLgPtYT38L3NO6mPDYH0nbpc5tjPassDqiniuAt4Y= github.com/drand/drand v1.3.0 h1:k/w/PtHzmlU6OmfoAqgirWyrJ4FZH8ESlJrsKF20UkM= github.com/drand/drand v1.3.0/go.mod h1:D6kAVlxufq1gi71YCGfzN455JrXF4Q272ZJEG975fzo= @@ -264,6 +266,8 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/go-elasticsearch/v7 v7.14.0 h1:extp3jos/rwJn3J+lgbaGlwAgs0TVsIHme00GyNAyX4= +github.com/elastic/go-elasticsearch/v7 v7.14.0/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4= github.com/elastic/go-sysinfo v1.7.0 h1:4vVvcfi255+8+TyQ7TYUTEK3A+G8v5FLE+ZKYL1z1Dg= github.com/elastic/go-sysinfo v1.7.0/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= @@ -320,15 +324,15 @@ github.com/filecoin-project/go-crypto v0.0.1 h1:AcvpSGGCgjaY8y1az6AMfKQWreF/pWO2 github.com/filecoin-project/go-crypto v0.0.1/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= github.com/filecoin-project/go-data-transfer v1.15.2 h1:PzqsFr2Q/onMGKrGh7TtRT0dKsJcVJrioJJnjnKmxlk= github.com/filecoin-project/go-data-transfer v1.15.2/go.mod h1:qXOJ3IF5dEJQHykXXTwcaRxu17bXAxr+LglXzkL6bZQ= -github.com/filecoin-project/go-ds-versioning v0.1.1 h1:JiyBqaQlwC+UM0WhcBtVEeT3XrX59mQhT8U3p7nu86o= -github.com/filecoin-project/go-ds-versioning v0.1.1/go.mod h1:C9/l9PnB1+mwPa26BBVpCjG/XQCB0yj/q5CK2J8X1I4= +github.com/filecoin-project/go-ds-versioning v0.1.2 h1:to4pTadv3IeV1wvgbCbN6Vqd+fu+7tveXgv/rCEZy6w= +github.com/filecoin-project/go-ds-versioning v0.1.2/go.mod h1:C9/l9PnB1+mwPa26BBVpCjG/XQCB0yj/q5CK2J8X1I4= github.com/filecoin-project/go-fil-commcid v0.0.0-20201016201715-d41df56b4f6a/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-commcid v0.1.0 h1:3R4ds1A9r6cr8mvZBfMYxTS88OqLYEo6roi+GiIeOh8= github.com/filecoin-project/go-fil-commcid v0.1.0/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-commp-hashhash v0.1.0 h1:imrrpZWEHRnNqqv0tN7LXep5bFEVOVmQWHJvl2mgsGo= github.com/filecoin-project/go-fil-commp-hashhash v0.1.0/go.mod h1:73S8WSEWh9vr0fDJVnKADhfIv/d6dCbAGaAGWbdJEI8= -github.com/filecoin-project/go-fil-markets v1.25.0 h1:zWkc1v84JL9KttiqOy2IIZB0jksIdAt1WLCdOP/KvAg= -github.com/filecoin-project/go-fil-markets v1.25.0/go.mod h1:3lzXZt5mRHTHAmZ10sUviiutaLVL57B99FgBU1MYqWY= +github.com/filecoin-project/go-fil-markets v1.25.2 h1:kVfgaamTC7dkn8KwS5zRJBNEBSNvVqdG3BCoDaUYuCI= +github.com/filecoin-project/go-fil-markets v1.25.2/go.mod h1:dc2oTPU6GH3Qk1nA+Er+hSX64rg+NVykkPIWFBYxcZU= github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM= @@ -336,8 +340,8 @@ github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0/go.mod h1:7aWZdaQ1b16BVoQUYR+ github.com/filecoin-project/go-hamt-ipld/v3 v3.0.1/go.mod h1:gXpNmr3oQx8l3o7qkGyDjJjYSRX7hp/FGOStdqrWyDI= github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0 h1:rVVNq0x6RGQIzCo1iiJlGFm9AGIZzeifggxtKMU7zmI= github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0/go.mod h1:bxmzgT8tmeVQA1/gvBwFmYdT8SOFUwB3ovSUfG1Ux0g= -github.com/filecoin-project/go-jsonrpc v0.1.8 h1:uXX/ikAk3Q4f/k8DRd9Zw+fWnfiYb5I+UI1tzlQgHog= -github.com/filecoin-project/go-jsonrpc v0.1.8/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= +github.com/filecoin-project/go-jsonrpc v0.2.1 h1:xfxkfIAO300sPiV59DnxnCb4sdTtWYlRz/TsP+ByT2E= +github.com/filecoin-project/go-jsonrpc v0.2.1/go.mod h1:jBSvPTl8V1N7gSTuCR4bis8wnQnIjHbRPpROol6iQKM= github.com/filecoin-project/go-legs v0.4.4 h1:mpMmAOOnamaz0CV9rgeKhEWA8j9kMC+f+UGCGrxKaZo= github.com/filecoin-project/go-legs v0.4.4/go.mod h1:JQ3hA6xpJdbR8euZ2rO0jkxaMxeidXf0LDnVuqPAe9s= github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20/go.mod h1:mPn+LRRd5gEKNAtc+r3ScpW2JRU/pj4NBKdADYWHiak= @@ -352,8 +356,8 @@ github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psS github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= github.com/filecoin-project/go-state-types v0.1.8/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= github.com/filecoin-project/go-state-types v0.1.10/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= -github.com/filecoin-project/go-state-types v0.10.0-alpha-2 h1:xz8+sXAuCMane7SkEYCtQjD/zYJ4n1d5bxwYNL8Thf0= -github.com/filecoin-project/go-state-types v0.10.0-alpha-2/go.mod h1:7ty480tvttEAqWKywhAaDCElk7ksTqEXtXWAzTSdEKo= +github.com/filecoin-project/go-state-types v0.10.0 h1:vsSThZIaPmOxNGG59+8D/HnlWRtlbdOjduH6ye+v8f0= +github.com/filecoin-project/go-state-types v0.10.0/go.mod h1:aLIas+W8BWAfpLWEPUOGMPBdhcVwoCG4pIQSQk26024= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v1.0.2 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc= github.com/filecoin-project/go-statemachine v1.0.2/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54= @@ -362,8 +366,8 @@ github.com/filecoin-project/go-statestore v0.2.0 h1:cRRO0aPLrxKQCZ2UOQbzFGn4WDNd github.com/filecoin-project/go-statestore v0.2.0/go.mod h1:8sjBYbS35HwPzct7iT4lIXjLlYyPor80aU7t7a/Kspo= github.com/filecoin-project/go-storedcounter v0.1.0 h1:Mui6wSUBC+cQGHbDUBcO7rfh5zQkWJM/CpAZa/uOuus= github.com/filecoin-project/go-storedcounter v0.1.0/go.mod h1:4ceukaXi4vFURIoxYMfKzaRF5Xv/Pinh2oTnoxpv+z8= -github.com/filecoin-project/index-provider v0.8.1 h1:ggoBWvMSWR91HZQCWfv8SZjoTGNyJBwNMLuN9bJZrbU= -github.com/filecoin-project/index-provider v0.8.1/go.mod h1:c/Ym5HtWPp9NQgNc9dgSBMpSNsZ/DE9FEi9qVubl5RM= +github.com/filecoin-project/index-provider v0.9.1 h1:Jnh9dviIHvQxZ2baNoYu3n8z6F9O62ksnVlyREgPyyM= +github.com/filecoin-project/index-provider v0.9.1/go.mod h1:NlHxQcy2iMGfUoUGUzrRxntcpiC50QSnvp68u2VTT40= github.com/filecoin-project/pubsub v1.0.0 h1:ZTmT27U07e54qV1mMiQo4HDr0buo8I1LDHBYLXlsNXM= github.com/filecoin-project/pubsub v1.0.0/go.mod h1:GkpB33CcUtUNrLPhJgfdy4FDx4OMNR9k+46DHx/Lqrg= github.com/filecoin-project/specs-actors v0.9.13/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao= @@ -384,8 +388,8 @@ github.com/filecoin-project/specs-actors/v7 v7.0.1 h1:w72xCxijK7xs1qzmJiw+WYJaVt github.com/filecoin-project/specs-actors/v7 v7.0.1/go.mod h1:tPLEYXoXhcpyLh69Ccq91SOuLXsPWjHiY27CzawjUEk= github.com/filecoin-project/specs-actors/v8 v8.0.1 h1:4u0tIRJeT5G7F05lwLRIsDnsrN+bJ5Ixj6h49Q7uE2Y= github.com/filecoin-project/specs-actors/v8 v8.0.1/go.mod h1:UYIPg65iPWoFw5NEftREdJwv9b/5yaLKdCgTvNI/2FA= -github.com/filecoin-project/storetheindex v0.4.17 h1:w0dVc954TGPukoVbidlYvn9Xt+wVhk5vBvrqeJiRo8I= -github.com/filecoin-project/storetheindex v0.4.17/go.mod h1:y2dL8C5D3PXi183hdxgGtM8vVYOZ1lg515tpl/D3tN8= +github.com/filecoin-project/storetheindex v0.4.30-0.20221114113647-683091f8e893 h1:6GCuzxLVHBzlz7y+FkbHh6n0UyoEGWqDwJKQPJoz7bE= +github.com/filecoin-project/storetheindex v0.4.30-0.20221114113647-683091f8e893/go.mod h1:S7590oDimBvXMUtzWsBXoshu9HtYKwtXl47zAK9rcP8= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= github.com/filecoin-project/test-vectors/schema v0.0.5/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= @@ -399,9 +403,11 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/gbrlsnchs/jwt/v3 v3.0.1 h1:lbUmgAKpxnClrKloyIwpxm4OuWeDl5wLk52G91ODPw4= @@ -445,6 +451,7 @@ github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwoh github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.4 h1:3Vw+rh13uq2JFNxgnMTGE1rnoieU9FmyE1gvnyylsYg= github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.7/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/spec v0.19.11 h1:ogU5q8dtp3MMPn59a9VRrPKVxvJHEs5P7yNMR5sNnis= github.com/go-openapi/spec v0.19.11/go.mod h1:vqK/dIdLGCosfvYsQV3WfC7N3TiZSnGY2RZKoFK7X28= @@ -458,6 +465,10 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packr/v2 v2.6.0/go.mod h1:sgEE1xNZ6G0FNN5xn9pevVu4nywaxHvgup67xisti08= github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -534,8 +545,9 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -564,20 +576,23 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk= github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregdhill/go-openrpc v0.0.0-20220114144539-ae6f44720487 h1:NyaWOSkqFK1d9o+HLfnMIGzrHuUUPeBNIZyi5Zoe/lY= +github.com/gregdhill/go-openrpc v0.0.0-20220114144539-ae6f44720487/go.mod h1:a1eRkbhd3DYpRH2lnuUsVG+QMTI+v0hGnsis8C9hMrA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= @@ -657,6 +672,7 @@ github.com/icza/backscanner v0.0.0-20210726202459-ac2ffc679f94 h1:9tcYMdi+7Rb1y0 github.com/icza/backscanner v0.0.0-20210726202459-ac2ffc679f94/go.mod h1:GYeBD1CF7AqnKZK+UCytLcY3G+UKo0ByXX/3xfdNyqQ= github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k= github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab h1:HqW4xhhynfjrtEiiSGcQUd6vrK23iMam1FO8rI7mwig= @@ -672,11 +688,11 @@ github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiL github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo= github.com/ipfs/go-bitswap v0.6.0/go.mod h1:Hj3ZXdOC5wBJvENtdqsixmzzRukqd8EHLxZLZc3mzRA= github.com/ipfs/go-bitswap v0.10.2 h1:B81RIwkTnIvSYT1ZCzxjYTeF0Ek88xa9r1AMpTfk+9Q= -github.com/ipfs/go-bitswap v0.10.2/go.mod h1:+fZEvycxviZ7c+5KlKwTzLm0M28g2ukCPqiuLfJk4KA= github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= -github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= +github.com/ipfs/go-block-format v0.1.1 h1:129vSO3zwbsYADcyQWcOYiuCpAqt462SFfqFHdFJhhI= +github.com/ipfs/go-block-format v0.1.1/go.mod h1:+McEIT+g52p+zz5xGAABGSOKrzmrdX97bc0USBdWPUs= github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So= github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= github.com/ipfs/go-blockservice v0.2.1/go.mod h1:k6SiwmgyYgs4M/qt+ww6amPeUH9EISLRBnvUurKJhi8= @@ -693,8 +709,9 @@ github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00/go.mod h1:plgt+Y5MnO github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o= -github.com/ipfs/go-cid v0.2.0 h1:01JTiihFq9en9Vz0lc0VDWvZe/uBonGpzo4THP0vcQ0= github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= +github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc= +github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw= github.com/ipfs/go-cidutil v0.1.0 h1:RW5hO7Vcf16dplUU60Hs0AKDkQAVPVplr7lk97CFL+Q= github.com/ipfs/go-cidutil v0.1.0/go.mod h1:e7OEVBMIv9JaOxt9zaGEmAoSlXW9jdFZ5lP/0PwcfpA= github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= @@ -707,8 +724,9 @@ github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13X github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= -github.com/ipfs/go-datastore v0.5.1 h1:WkRhLuISI+XPD0uk3OskB0fYFSyqK8Ob5ZYew9Qa1nQ= github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= +github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= +github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= @@ -732,8 +750,8 @@ github.com/ipfs/go-filestore v1.2.0/go.mod h1:HLJrCxRXquTeEEpde4lTLMaE/MYJZD7WHL github.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28L7zESmM= github.com/ipfs/go-fs-lock v0.0.7 h1:6BR3dajORFrFTkb5EpCUFIAypsoxpGpDSVUdFwzgL9U= github.com/ipfs/go-fs-lock v0.0.7/go.mod h1:Js8ka+FNYmgQRLrRXzU3CB/+Csr1BwrRilEcvYrHhhc= -github.com/ipfs/go-graphsync v0.13.1 h1:lWiP/WLycoPUYyj3IDEi1GJNP30kFuYOvimcfeuZyQs= -github.com/ipfs/go-graphsync v0.13.1/go.mod h1:y8e8G6CmZeL9Srvx1l15CtGiRdf3h5JdQuqPz/iYL0A= +github.com/ipfs/go-graphsync v0.13.2 h1:+7IjTrdg3+3iwtPXSkLoxvhaByS3+3b9NStMAowFqkw= +github.com/ipfs/go-graphsync v0.13.2/go.mod h1:TO1Y65spARny/t37hkid5xCpQJ6vR7A7VFTEUb0Z6eA= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= github.com/ipfs/go-ipfs-blockstore v0.2.1/go.mod h1:jGesd8EtCM3/zPgx+qr0/feTXGUeRai6adgwC+Q+JvE= @@ -775,12 +793,14 @@ github.com/ipfs/go-ipfs-http-client v0.4.0/go.mod h1:NXzPUKt/QVCuR74a8angJCGOSLP github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= -github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE= +github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3kERkRb4= github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= -github.com/ipfs/go-ipfs-routing v0.2.1 h1:E+whHWhJkdN9YeoHZNj5itzc+OR292AJ2uE9FFiW0BY= github.com/ipfs/go-ipfs-routing v0.2.1/go.mod h1:xiNNiwgjmLqPS1cimvAw6EyB9rkVDbiocA4yY+wRNLM= +github.com/ipfs/go-ipfs-routing v0.3.0 h1:9W/W3N+g+y4ZDeffSgqhgo7BsBSJwPMcyssET9OWevc= +github.com/ipfs/go-ipfs-routing v0.3.0/go.mod h1:dKqtTFIql7e1zYsEuWLyuOU+E0WJWW8JjbTPLParDWo= github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= @@ -800,8 +820,10 @@ github.com/ipfs/go-ipld-format v0.4.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxn github.com/ipfs/go-ipld-legacy v0.1.0/go.mod h1:86f5P/srAmh9GcIcWQR9lfFLZPrIyyXQeVlOWeeWEuI= github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2cdcc= github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= -github.com/ipfs/go-ipns v0.2.0 h1:BgmNtQhqOw5XEZ8RAfWEpK4DhqaYiuP6h71MhIp7xXU= -github.com/ipfs/go-ipns v0.2.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= +github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A= +github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= +github.com/ipfs/go-libipfs v0.4.1 h1:tyu3RRMKFQUyUQt5jyt5SmDnls93H4Tr3HifL50zihg= +github.com/ipfs/go-libipfs v0.4.1/go.mod h1:Ad8ybPqwCkl2cNiNUMvM/iaVc/5bwNpHu8RPZ5te1hw= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSIKjA= github.com/ipfs/go-log v1.0.1/go.mod h1:HuWlQttfN6FWNHRhlY5yMk/lW7evQC0HHGOxEwMRR8I= @@ -814,13 +836,13 @@ github.com/ipfs/go-log/v2 v2.0.1/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBW github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= -github.com/ipfs/go-log/v2 v2.0.8/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/ipfs/go-log/v2 v2.1.2/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72gynbe/g= github.com/ipfs/go-log/v2 v2.4.0/go.mod h1:nPZnh7Cj7lwS3LpRU5Mwr2ol1c2gXIEXuF6aywqrtmo= +github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= @@ -841,17 +863,20 @@ github.com/ipfs/go-path v0.3.0/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1X github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ= github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= -github.com/ipfs/go-peertaskqueue v0.7.1 h1:7PLjon3RZwRQMgOTvYccZ+mjzkmds/7YzSWKFlBAypE= github.com/ipfs/go-peertaskqueue v0.7.1/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= +github.com/ipfs/go-peertaskqueue v0.8.1 h1:YhxAs1+wxb5jk7RvS0LHdyiILpNmRIRnZVztekOF0pg= +github.com/ipfs/go-peertaskqueue v0.8.1/go.mod h1:Oxxd3eaK279FxeydSPPVGHzbwVeHjatZ2GA8XD+KbPU= github.com/ipfs/go-unixfs v0.2.2-0.20190827150610-868af2e9e5cb/go.mod h1:IwAAgul1UQIcNZzKPYZWOCijryFBeCV79cNubPzol+k= github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= -github.com/ipfs/go-unixfs v0.3.1 h1:LrfED0OGfG98ZEegO4/xiprx2O+yS+krCMQSp7zLVv8= github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o= +github.com/ipfs/go-unixfs v0.4.0 h1:qSyyxfB/OiDdWHYiSbyaqKC7zfSE/TFL0QdwkRjBm20= +github.com/ipfs/go-unixfs v0.4.0/go.mod h1:I7Nqtm06HgOOd+setAoCU6rf/HgVFHE+peeNuOv/5+g= github.com/ipfs/go-unixfsnode v1.1.2/go.mod h1:5dcE2x03pyjHk4JjamXmunTMzz+VUtqvPwZjIEkfV6s= github.com/ipfs/go-unixfsnode v1.4.0 h1:9BUxHBXrbNi8mWHc6j+5C580WJqtVw9uoeEKn4tMhwA= github.com/ipfs/go-unixfsnode v1.4.0/go.mod h1:qc7YFFZ8tABc58p62HnIYbUMwj9chhUuFWmxSokfePo= -github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= +github.com/ipfs/go-verifcid v0.0.2 h1:XPnUv0XmdH+ZIhLGKg6U2vaPaRDXb9urMyNVCE7uvTs= +github.com/ipfs/go-verifcid v0.0.2/go.mod h1:40cD9x1y4OWnFXbLNJYRe7MpNvWlMn3LZAG5Wb4xnPU= github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= github.com/ipfs/interface-go-ipfs-core v0.7.0 h1:7tb+2upz8oCcjIyjo1atdMk+P+u7wPmI+GksBlLE8js= github.com/ipfs/interface-go-ipfs-core v0.7.0/go.mod h1:lF27E/nnSPbylPqKVXGZghal2hzifs3MmjyiEjnc9FY= @@ -866,8 +891,10 @@ github.com/ipld/go-car/v2 v2.5.0/go.mod h1:jKjGOqoCj5zn6KjnabD6JbnCsMntqU2hLiU6b github.com/ipld/go-codec-dagpb v1.2.0/go.mod h1:6nBN7X7h8EOsEejZGqC7tej5drsdBAXbMHyBT+Fne5s= github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA= github.com/ipld/go-codec-dagpb v1.3.1/go.mod h1:ErNNglIi5KMur/MfFE/svtgQthzVvf+43MrzLbpcIZY= -github.com/ipld/go-codec-dagpb v1.3.2 h1:MZQUIjanHXXfDuYmtWYT8nFbqfFsZuyHClj6VDmSXr4= -github.com/ipld/go-codec-dagpb v1.3.2/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA= +github.com/ipld/go-codec-dagpb v1.5.0 h1:RspDRdsJpLfgCI0ONhTAnbHdySGD4t+LHSPK4X1+R0k= +github.com/ipld/go-codec-dagpb v1.5.0/go.mod h1:0yRIutEFD8o1DGVqw4RSHh+BUTlJA9XWldxaaWR/o4g= +github.com/ipld/go-ipld-adl-hamt v0.0.0-20220616142416-9004dbd839e0 h1:QAI/Ridj0+foHD6epbxmB4ugxz9B4vmNdYSmQLGa05E= +github.com/ipld/go-ipld-adl-hamt v0.0.0-20220616142416-9004dbd839e0/go.mod h1:odxGcpiQZLzP5+yGu84Ljo8y3EzCvNAQKEodHNsHLXA= github.com/ipld/go-ipld-prime v0.0.2-0.20191108012745-28a82f04c785/go.mod h1:bDDSvVz7vaK12FNvMeRYnpRFkSUPNQOiCYQezMD/P3w= github.com/ipld/go-ipld-prime v0.9.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= @@ -875,8 +902,9 @@ github.com/ipld/go-ipld-prime v0.10.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/ github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8= github.com/ipld/go-ipld-prime v0.14.0/go.mod h1:9ASQLwUFLptCov6lIYc70GRB4V7UTyLD0IJtrDJe6ZM= github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA= -github.com/ipld/go-ipld-prime v0.17.0 h1:+U2peiA3aQsE7mrXjD2nYZaZrCcakoz2Wge8K42Ld8g= github.com/ipld/go-ipld-prime v0.17.0/go.mod h1:aYcKm5TIvGfY8P3QBKz/2gKcLxzJ1zDaD+o0bOowhgs= +github.com/ipld/go-ipld-prime v0.20.0 h1:Ud3VwE9ClxpO2LkCYP7vWPc0Fo+dYdYzgxUJZ3uRG4g= +github.com/ipld/go-ipld-prime v0.20.0/go.mod h1:PzqZ/ZR981eKbgdr3y2DJYeD/8bgMawdGVlJDE8kK+M= github.com/ipld/go-ipld-prime-proto v0.0.0-20191113031812-e32bd156a1e5/go.mod h1:gcvzoEDBjwycpXt3LBE061wT9f46szXGHAmj9uoP6fU= github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73 h1:TsyATB2ZRRQGTwafJdgEUQkmjOExRV0DNokcihZxbnQ= github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY= @@ -907,6 +935,7 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= @@ -935,6 +964,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4ufZiIGv2nXn4gMxnfKV306n3mWXgNu/d2TqdTU= github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= +github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f/go.mod h1:XXfR6YFCRSrkEXbNlIyDsgXVNJWVUV30m/ebkVy9n6s= @@ -947,16 +977,20 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo= +github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0= -github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0= +github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/koalacxr/quantile v0.0.1 h1:wAW+SQ286Erny9wOjVww96t8ws+x5Zj6AKHDULUK+o0= github.com/koalacxr/quantile v0.0.1/go.mod h1:bGN/mCZLZ4lrSDHRQ6Lglj9chowGux8sGUIND+DQeD0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= @@ -967,10 +1001,11 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -1006,10 +1041,10 @@ github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qD github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= -github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= github.com/libp2p/go-libp2p v0.17.0/go.mod h1:Fkin50rsGdv5mm5BshBUtPRZknt9esfmYXBOYcwOTgw= -github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw= -github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4= +github.com/libp2p/go-libp2p v0.19.4/go.mod h1:MIt8y481VDhUe4ErWi1a4bvt/CjjFfOq6kZTothWIXY= +github.com/libp2p/go-libp2p v0.23.4 h1:hWi9XHSOVFR1oDWRk7rigfyA4XNMuYL20INNybP9LP8= +github.com/libp2p/go-libp2p v0.23.4/go.mod h1:s9DEa5NLR4g+LZS+md5uGU4emjMWFiqkZr6hBTY8UxI= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= @@ -1021,7 +1056,6 @@ github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRk github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= github.com/libp2p/go-libp2p-autonat v0.4.2/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-autonat v0.6.0/go.mod h1:bFC6kY8jwzNNWoqc8iGE57vsfwyJ/lP4O4DOV1e0B2o= github.com/libp2p/go-libp2p-autonat v0.7.0/go.mod h1:uPvPn6J7cN+LCfFwW5tpOYvAz5NvPTc4iBamTV/WDMg= github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= @@ -1033,6 +1067,7 @@ github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFk github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= +github.com/libp2p/go-libp2p-circuit v0.6.0/go.mod h1:kB8hY+zCpMeScyvFrKrGicRdid6vNXbunKE4rXATZ0M= github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= github.com/libp2p/go-libp2p-connmgr v0.3.0/go.mod h1:RVoyPjJm0J9Vd1m6qUN2Tn7kJm4rL1Ml20pFsFgPGik= github.com/libp2p/go-libp2p-connmgr v0.4.0 h1:q/KZUS1iMDIQckMZarMYwhQisJqiFPHAVC1c4DR3hDE= @@ -1070,8 +1105,10 @@ github.com/libp2p/go-libp2p-core v0.10.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQR github.com/libp2p/go-libp2p-core v0.11.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= github.com/libp2p/go-libp2p-core v0.12.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= github.com/libp2p/go-libp2p-core v0.13.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= -github.com/libp2p/go-libp2p-core v0.20.0 h1:PGKM74+T+O/FaZNARNW32i90RMBHCcgd/hkum2UQ5eY= -github.com/libp2p/go-libp2p-core v0.20.0/go.mod h1:6zR8H7CvQWgYLsbG4on6oLNSGcyKaYFSEYyDt51+bIY= +github.com/libp2p/go-libp2p-core v0.14.0/go.mod h1:tLasfcVdTXnixsLB0QYaT1syJOhsbrhG7q6pGrHtBg8= +github.com/libp2p/go-libp2p-core v0.15.1/go.mod h1:agSaboYM4hzB1cWekgVReqV5M4g5M+2eNNejV+1EEhs= +github.com/libp2p/go-libp2p-core v0.20.1 h1:fQz4BJyIFmSZAiTbKV8qoYhEH5Dtv/cVhZbG3Ib/+Cw= +github.com/libp2p/go-libp2p-core v0.20.1/go.mod h1:6zR8H7CvQWgYLsbG4on6oLNSGcyKaYFSEYyDt51+bIY= github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= @@ -1084,8 +1121,8 @@ github.com/libp2p/go-libp2p-discovery v0.6.0/go.mod h1:/u1voHt0tKIe5oIA1RHBKQLVC github.com/libp2p/go-libp2p-gorpc v0.4.0 h1:kxHg5C3IuXeOq5FHPGbMHwQzKDlTVeB/NDr0ndc8J/g= github.com/libp2p/go-libp2p-gorpc v0.4.0/go.mod h1:jux2Mb6BfUE1n58KbVCmWtqvpiZo0DDaKobKInf4s5o= github.com/libp2p/go-libp2p-gostream v0.3.1/go.mod h1:1V3b+u4Zhaq407UUY9JLCpboaeufAeVQbnvAt12LRsI= -github.com/libp2p/go-libp2p-gostream v0.4.0 h1:heduMMEB78yBqeEQv+P7Fn5X926MHC2jDIC7/7yLpYA= -github.com/libp2p/go-libp2p-gostream v0.4.0/go.mod h1:21DVGBcCQwRfEXZpCnZ2kG24QiEkBpEQvG53gYXE4u0= +github.com/libp2p/go-libp2p-gostream v0.5.0 h1:niNGTUrFoUDP/8jxMgu97zngMO+UGYBpVpbCKwIJBls= +github.com/libp2p/go-libp2p-gostream v0.5.0/go.mod h1:rXrb0CqfcRRxa7m3RSKORQiKiWgk3IPeXWda66ZXKsA= github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8= github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= @@ -1106,6 +1143,7 @@ github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= +github.com/libp2p/go-libp2p-mplex v0.5.0/go.mod h1:eLImPJLkj3iG5t5lq68w3Vm5NAQ5BcKwrrb2VmOYb3M= github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= @@ -1117,6 +1155,7 @@ github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCTh github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= github.com/libp2p/go-libp2p-noise v0.2.0/go.mod h1:IEbYhBBzGyvdLBoxxULL/SGbJARhUeqlO8lVSREYu2Q= github.com/libp2p/go-libp2p-noise v0.3.0/go.mod h1:JNjHbociDJKHD64KTkzGnzqJ0FEV5gHJa6AB00kbCNQ= +github.com/libp2p/go-libp2p-noise v0.4.0/go.mod h1:BzzY5pyzCYSyJbQy9oD8z5oP2idsafjt4/X42h9DjZU= github.com/libp2p/go-libp2p-noise v0.5.0 h1:gwJZ/3iH3MRnBrLIyr/YLdCOnmqfJMptlsFFUIc3j0Y= github.com/libp2p/go-libp2p-noise v0.5.0/go.mod h1:CYYpJ+T4pox1d1J/hhUVxuMf6b2s3c41hFUgS8/yFQw= github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= @@ -1139,12 +1178,13 @@ github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYc github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= github.com/libp2p/go-libp2p-pubsub v0.6.0/go.mod h1:nJv87QM2cU0w45KPR1rZicq+FmFIOD16zmT+ep1nOmg= -github.com/libp2p/go-libp2p-pubsub v0.8.0 h1:KygfDpaa9AeUPGCVcpVenpXNFauDn+5kBYu3EjcL3Tg= -github.com/libp2p/go-libp2p-pubsub v0.8.0/go.mod h1:e4kT+DYjzPUYGZeWk4I+oxCSYTXizzXii5LDRRhjKSw= +github.com/libp2p/go-libp2p-pubsub v0.8.2 h1:QLGUmkgKmwEVxVDYGsqc5t9CykOMY2Y21cXQHjR462I= +github.com/libp2p/go-libp2p-pubsub v0.8.2/go.mod h1:e4kT+DYjzPUYGZeWk4I+oxCSYTXizzXii5LDRRhjKSw= github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= github.com/libp2p/go-libp2p-quic-transport v0.13.0/go.mod h1:39/ZWJ1TW/jx1iFkKzzUg00W6tDJh73FC0xYudjr7Hc= -github.com/libp2p/go-libp2p-quic-transport v0.15.0/go.mod h1:wv4uGwjcqe8Mhjj7N/Ic0aKjA+/10UnMlSzLO0yRpYQ= github.com/libp2p/go-libp2p-quic-transport v0.15.2/go.mod h1:wv4uGwjcqe8Mhjj7N/Ic0aKjA+/10UnMlSzLO0yRpYQ= +github.com/libp2p/go-libp2p-quic-transport v0.16.0/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ= +github.com/libp2p/go-libp2p-quic-transport v0.17.0/go.mod h1:x4pw61P3/GRCcSLypcQJE/Q2+E9f4X+5aRcZLXf20LM= github.com/libp2p/go-libp2p-raft v0.1.8 h1:Fq0aWHbbhi6WJXf+yaOQeMzV+9UgkbHIIGyaJbH3vpo= github.com/libp2p/go-libp2p-raft v0.1.8/go.mod h1:+YDisn3uszb7vxshLgKoDdRGs79WSbHRgrOdrYqDPk4= github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= @@ -1152,6 +1192,7 @@ github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7 github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= +github.com/libp2p/go-libp2p-resource-manager v0.2.1/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY= github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= @@ -1170,6 +1211,8 @@ github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6syd github.com/libp2p/go-libp2p-swarm v0.5.0/go.mod h1:sU9i6BoHE0Ve5SKz3y9WfKrh8dUat6JknzUehFx8xW4= github.com/libp2p/go-libp2p-swarm v0.8.0/go.mod h1:sOMp6dPuqco0r0GHTzfVheVBh6UEL0L1lXUZ5ot2Fvc= github.com/libp2p/go-libp2p-swarm v0.9.0/go.mod h1:2f8d8uxTJmpeqHF/1ujjdXZp+98nNIbujVOMEZxCbZ8= +github.com/libp2p/go-libp2p-swarm v0.10.0/go.mod h1:71ceMcV6Rg/0rIQ97rsZWMzto1l9LnNquef+efcRbmA= +github.com/libp2p/go-libp2p-swarm v0.10.2/go.mod h1:Pdkq0QU5a+qu+oyqIV3bknMsnzk9lnNyKvB9acJ5aZs= github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= @@ -1182,10 +1225,14 @@ github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotl github.com/libp2p/go-libp2p-testing v0.4.2/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= github.com/libp2p/go-libp2p-testing v0.5.0/go.mod h1:QBk8fqIL1XNcno/l3/hhaIEn4aLRijpYOR+zVjjlh+A= github.com/libp2p/go-libp2p-testing v0.6.0/go.mod h1:QBk8fqIL1XNcno/l3/hhaIEn4aLRijpYOR+zVjjlh+A= +github.com/libp2p/go-libp2p-testing v0.7.0/go.mod h1:OLbdn9DbgdMwv00v+tlp1l3oe2Cl+FAjoWIA2pa0X6E= +github.com/libp2p/go-libp2p-testing v0.9.0/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= +github.com/libp2p/go-libp2p-testing v0.9.2/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= github.com/libp2p/go-libp2p-tls v0.3.0/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= github.com/libp2p/go-libp2p-tls v0.3.1/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= +github.com/libp2p/go-libp2p-tls v0.4.1/go.mod h1:EKCixHEysLNDlLUoKxv+3f/Lp90O2EXNjTr0UQDnrIw= github.com/libp2p/go-libp2p-tls v0.5.0 h1:aRNTeOI8Ljm1r4L2uMGxkMsVnyZoPwaqQqMw23qAsQs= github.com/libp2p/go-libp2p-tls v0.5.0/go.mod h1:1a4tq0xQSZ0kAkDkZVAppuP3SAIUHcnzi2djJ/2EN4I= github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= @@ -1199,6 +1246,8 @@ github.com/libp2p/go-libp2p-transport-upgrader v0.4.2/go.mod h1:NR8ne1VwfreD5VIW github.com/libp2p/go-libp2p-transport-upgrader v0.4.3/go.mod h1:bpkldbOWXMrXhpZbSV1mQxTrefOg2Fi+k1ClDSA4ppw= github.com/libp2p/go-libp2p-transport-upgrader v0.5.0/go.mod h1:Rc+XODlB3yce7dvFV4q/RmyJGsFcCZRkeZMu/Zdg0mo= github.com/libp2p/go-libp2p-transport-upgrader v0.6.0/go.mod h1:1e07y1ZSZdHo9HPbuU8IztM1Cj+DR5twgycb4pnRzRo= +github.com/libp2p/go-libp2p-transport-upgrader v0.7.0/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= +github.com/libp2p/go-libp2p-transport-upgrader v0.7.1/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8= github.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4= github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= @@ -1211,8 +1260,10 @@ github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelN github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= github.com/libp2p/go-libp2p-yamux v0.5.4/go.mod h1:tfrXbyaTqqSU654GTvK3ocnSZL3BuHoeTSqhcel1wsE= -github.com/libp2p/go-libp2p-yamux v0.6.0/go.mod h1:MRhd6mAYnFRnSISp4M8i0ClV/j+mWHo2mYLifWGw33k= github.com/libp2p/go-libp2p-yamux v0.7.0/go.mod h1:fMyA0CsPfHkIuBU0wjRGrCjTBFiXTXxG0k5M4ETv+08= +github.com/libp2p/go-libp2p-yamux v0.8.0/go.mod h1:yTkPgN2ib8FHyU1ZcVD7aelzyAqXXwEPbyx+aSKm9h8= +github.com/libp2p/go-libp2p-yamux v0.8.1/go.mod h1:rUozF8Jah2dL9LLGyBaBeTQeARdwhefMCTQVQt6QobE= +github.com/libp2p/go-libp2p-yamux v0.9.1/go.mod h1:wRc6wvyxQINFcKe7daL4BeQ02Iyp+wxyC8WCNfngBrA= github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= @@ -1225,6 +1276,7 @@ github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3 github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= +github.com/libp2p/go-mplex v0.4.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E= github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= @@ -1267,6 +1319,7 @@ github.com/libp2p/go-stream-muxer v0.1.0/go.mod h1:8JAVsjeRBCWwPoZeH0W1imLOcriqX github.com/libp2p/go-stream-muxer-multistream v0.1.1/go.mod h1:zmGdfkQ1AzOECIAcccoL8L//laqawOsO03zX8Sa+eGw= github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= +github.com/libp2p/go-stream-muxer-multistream v0.4.0/go.mod h1:nb+dGViZleRP4XcyHuZSVrJCBl55nRBOMmiSL/dyziw= github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19K427vCzQ+xHKH/o= github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= @@ -1275,6 +1328,8 @@ github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1 github.com/libp2p/go-tcp-transport v0.2.3/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= github.com/libp2p/go-tcp-transport v0.2.4/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= github.com/libp2p/go-tcp-transport v0.4.0/go.mod h1:0y52Rwrn4076xdJYu/51/qJIdxz+EWDAOG2S45sV3VI= +github.com/libp2p/go-tcp-transport v0.5.0/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= +github.com/libp2p/go-tcp-transport v0.5.1/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= github.com/libp2p/go-ws-transport v0.0.5/go.mod h1:Qbl4BxPfXXhhd/o0wcrgoaItHqA9tnZjoFZnxykuaXU= @@ -1283,6 +1338,7 @@ github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzl github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= github.com/libp2p/go-ws-transport v0.5.0/go.mod h1:I2juo1dNTbl8BKSBYo98XY85kU2xds1iamArLvl8kNg= +github.com/libp2p/go-ws-transport v0.6.0/go.mod h1:dXqtI9e2JV9FtF1NOtWVZSKXh5zXvnuwPXfj8GPBbYU= github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= @@ -1295,16 +1351,23 @@ github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/h github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs= -github.com/libp2p/go-yamux/v3 v3.1.2 h1:lNEy28MBk1HavUAlzKgShp+F6mn/ea1nDYWftZhFW9Q= +github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= +github.com/libp2p/go-yamux/v3 v3.0.2/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= +github.com/libp2p/go-yamux/v3 v3.1.1/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= github.com/libp2p/go-yamux/v3 v3.1.2/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= +github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= +github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= -github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU= -github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0= +github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= +github.com/lucas-clemente/quic-go v0.27.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= +github.com/lucas-clemente/quic-go v0.27.1/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= +github.com/lucas-clemente/quic-go v0.29.1 h1:Z+WMJ++qMLhvpFkRZA+jl3BTxUjm415YBmWanXB8zP0= +github.com/lucas-clemente/quic-go v0.29.1/go.mod h1:CTcNfLYJS2UuRNB+zcNlgvkjBhxX6Hm3WUxxAQx2mgE= github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg= @@ -1320,23 +1383,24 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs= github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= -github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= -github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ= -github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= +github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= +github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= +github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM= github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU= github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= +github.com/marten-seemann/webtransport-go v0.1.1 h1:TnyKp3pEXcDooTaNn4s9dYpMJ7kMnTp7k5h+SgYP/mc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -1359,6 +1423,8 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -1376,6 +1442,7 @@ github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7 github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= @@ -1414,8 +1481,9 @@ github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= @@ -1430,8 +1498,10 @@ github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4 github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc= -github.com/multiformats/go-multiaddr v0.6.0 h1:qMnoOPj2s8xxPU5kZ57Cqdr0hHhARz7mFsPMIiYNqzg= -github.com/multiformats/go-multiaddr v0.6.0/go.mod h1:F4IpaKZuPP360tOMn2Tpyu0At8w23aRyVqeK0DbFeGM= +github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM= +github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug= +github.com/multiformats/go-multiaddr v0.8.0 h1:aqjksEcqK+iD/Foe1RRFsGZh8+XFiGo7FgUCZlpv3LU= +github.com/multiformats/go-multiaddr v0.8.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= @@ -1455,8 +1525,10 @@ github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1 github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multicodec v0.3.1-0.20211210143421-a526f306ed2c/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= -github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs= +github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues= +github.com/multiformats/go-multicodec v0.8.0 h1:evBmgkbSQux+Ds2IgfhkO38Dl2GDtRW8/Rp6YiSHX/Q= +github.com/multiformats/go-multicodec v0.8.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= @@ -1475,6 +1547,7 @@ github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9 github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= +github.com/multiformats/go-multistream v0.3.0/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= github.com/multiformats/go-multistream v0.3.3 h1:d5PZpjwRgVlbwfdTDjife7XszfZd8KYWfROYFlGcR8o= github.com/multiformats/go-multistream v0.3.3/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= @@ -1520,8 +1593,8 @@ github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/open-rpc/meta-schema v0.0.0-20201029221707-1b72ef2ea333 h1:CznVS40zms0Dj5he4ERo+fRPtO0qxUk8lA8Xu3ddet0= github.com/open-rpc/meta-schema v0.0.0-20201029221707-1b72ef2ea333/go.mod h1:Ag6rSXkHIckQmjFBCweJEEt1mrTPBv8b9W4aU/NQWfI= @@ -1583,8 +1656,9 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1605,6 +1679,7 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9 github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.33.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/node_exporter v1.0.0-rc.0.0.20200428091818-01054558c289/go.mod h1:FGbBv5OPKjch+jNUJmEQpMZytIdyW0NdBtWFcfSKusc= @@ -1634,9 +1709,10 @@ github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= @@ -1687,8 +1763,8 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= -github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs= github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -1720,8 +1796,10 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -1730,12 +1808,15 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= +github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g= github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc= github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= @@ -1745,6 +1826,8 @@ github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= +github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v2.23.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v2.25.0+incompatible h1:IxcNZ7WRY1Y3G4poYlx24szfsn/3LvK9QHCq9oQw8+U= @@ -1763,8 +1846,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= -github.com/urfave/cli/v2 v2.8.1 h1:CGuYNZF9IKZY/rfBe3lJpccSoIY1ytfvmgQT90cNOl4= -github.com/urfave/cli/v2 v2.8.1/go.mod h1:Z41J9TPoffeoqP0Iza0YbAhGvymRdZAd2uPmZ5JxRdY= +github.com/urfave/cli/v2 v2.16.3 h1:gHoFIwpPjoyIMbJp/VFd+/vuD0dAgFK4B6DpEMFJfQk= +github.com/urfave/cli/v2 v2.16.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8= @@ -1772,7 +1855,8 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= -github.com/warpfork/go-testmark v0.10.0 h1:E86YlUMYfwIacEsQGlnTvjk1IgYkyTGjPhF0RnwTCmw= +github.com/warpfork/go-testmark v0.10.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= +github.com/warpfork/go-testmark v0.11.0 h1:J6LnV8KpceDvo7spaNU4+DauH2n1x+6RaO2rJrmpQ9U= github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= @@ -1799,8 +1883,8 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163/go.mod h1:f github.com/whyrusleeping/cbor-gen v0.0.0-20210118024343-169e9d70c0c2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20210303213153-67a261a1d291/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20220323183124-98fa8256a799/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= -github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c h1:6VPKXBDRt7mDUyiHx9X8ROnPYFDf3L7OfEuKCI5dZDI= -github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20221021053955-c138aae13722 h1:0HEhvpGQJ2Gd0ngPW83aduQQuF/V9v13+3zpSrR3lrA= +github.com/whyrusleeping/cbor-gen v0.0.0-20221021053955-c138aae13722/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= @@ -1818,6 +1902,12 @@ github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go. github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xorcare/golden v0.6.0/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ= github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 h1:oWgZJmC1DorFZDpfMfWg7xk29yEOZiXmo/wZl+utTI8= @@ -1830,6 +1920,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= github.com/zondax/hid v0.9.1 h1:gQe66rtmyZ8VeGFcOpbuH3r7erYtNEAezCAYu8LdkJo= github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= @@ -1856,34 +1947,30 @@ go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.6-0.20201102222123-380f4078db9f/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I= -go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= -go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= -go.opentelemetry.io/otel/bridge/opencensus v0.25.0 h1:18Ww8TpCEGes12HZJzB2nEbUglvMLzPxqgZypsrKiNc= -go.opentelemetry.io/otel/bridge/opencensus v0.25.0/go.mod h1:dkZDdaNwLlIutxK2Kc2m3jwW2M1ISaNf8/rOYVwuVHs= +go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= +go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.opentelemetry.io/otel/bridge/opencensus v0.33.0 h1:DnSFYr/VxUVwkHL0UoaMcxx74Jugb1HO0B08cYBmi0c= +go.opentelemetry.io/otel/bridge/opencensus v0.33.0/go.mod h1:gylOY4P2e7kPYc6T9M8XfQ5+RK4+evGorTOOy+gO4Nc= go.opentelemetry.io/otel/exporters/jaeger v1.2.0 h1:C/5Egj3MJBXRJi22cSl07suqPqtZLnLFmH//OxETUEc= go.opentelemetry.io/otel/exporters/jaeger v1.2.0/go.mod h1:KJLFbEMKTNPIfOxcg/WikIozEoKcPgJRz3Ce1vLlM8E= -go.opentelemetry.io/otel/internal/metric v0.25.0 h1:w/7RXe16WdPylaIXDgcYM6t/q0K5lXgSdZOEbIEyliE= -go.opentelemetry.io/otel/internal/metric v0.25.0/go.mod h1:Nhuw26QSX7d6n4duoqAFi5KOQR4AuzyMcl5eXOgwxtc= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/metric v0.25.0 h1:7cXOnCADUsR3+EOqxPaSKwhEuNu0gz/56dRN1hpIdKw= -go.opentelemetry.io/otel/metric v0.25.0/go.mod h1:E884FSpQfnJOMMUaq+05IWlJ4rjZpk2s/F1Ju+TEEm8= +go.opentelemetry.io/otel/metric v0.33.0 h1:xQAyl7uGEYvrLAiV/09iTJlp1pZnQ9Wl793qbVvED1E= +go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk v1.2.0 h1:wKN260u4DesJYhyjxDa7LRFkuhH7ncEVKU37LWcyNIo= go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U= -go.opentelemetry.io/otel/sdk/export/metric v0.25.0 h1:6UjAFmVB5Fza3K5qUJpYWGrk8QMPIqlSnya5FI46VBY= -go.opentelemetry.io/otel/sdk/export/metric v0.25.0/go.mod h1:Ej7NOa+WpN49EIcr1HMUYRvxXXCCnQCg2+ovdt2z8Pk= -go.opentelemetry.io/otel/sdk/metric v0.25.0 h1:J+Ta+4IAA5W9AdWhGQLfciEpavBqqSkBzTDeYvJLFNU= -go.opentelemetry.io/otel/sdk/metric v0.25.0/go.mod h1:G4xzj4LvC6xDDSsVXpvRVclQCbofGGg4ZU2VKKtDRfg= +go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= +go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys= +go.opentelemetry.io/otel/sdk/metric v0.33.0 h1:oTqyWfksgKoJmbrs2q7O7ahkJzt+Ipekihf8vhpa9qo= +go.opentelemetry.io/otel/sdk/metric v0.33.0/go.mod h1:xdypMeA21JBOvjjzDUtD0kzIcHO/SPez+a8HOzJPGp0= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0= -go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o= -go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= +go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= +go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1903,6 +1990,7 @@ go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= @@ -1919,8 +2007,9 @@ go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0= -go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= @@ -1943,6 +2032,7 @@ golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1963,9 +2053,11 @@ golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1979,8 +2071,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20210615023648-acb5c1269671/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc= golang.org/x/exp v0.0.0-20210714144626-1041f73d31d8/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 h1:rxKZ2gOnYxjfmakvUUqh9Gyb6KXfrj7JWTxORTYqb0E= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b h1:SCE/18RnFsLrjydh/R/s5EVvHoZprqEQUuoxK8q2Pc4= +golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -2007,6 +2099,7 @@ golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hM golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2070,12 +2163,13 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= -golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 h1:KafLifaRFIuSJ5C+7CyFJOF9haxKNC1CEIDk8GX6X0k= +golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -2097,8 +2191,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220907140024-f12130a52804 h1:0SH2R3f1b1VmIMG7BXbEZCBUu2dKmHschSmjqGUrW8A= +golang.org/x/sync v0.0.0-20220907140024-f12130a52804/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180202135801-37707fdb30a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2125,12 +2220,14 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190524152521-dbbf3f1254d4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2197,14 +2294,15 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211209171907-798191bca915/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2223,8 +2321,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ= +golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2241,6 +2339,7 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -2287,14 +2386,16 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -2402,6 +2503,7 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= diff --git a/itests/api_test.go b/itests/api_test.go index 2afbc0bd0..ff303df3e 100644 --- a/itests/api_test.go +++ b/itests/api_test.go @@ -307,5 +307,5 @@ func (ts *apiSuite) testNonGenesisMiner(t *testing.T) { tid, err := address.IDFromAddress(ta) require.NoError(t, err) - require.Equal(t, uint64(1001), tid) + require.Equal(t, uint64(1002), tid) // ETH0 is 1001 } diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go index 909b5691e..819340ea1 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go @@ -71,6 +71,7 @@ func runTestCCUpgrade(t *testing.T) *kit.TestFullNode { { si, err := client.StateSectorGetInfo(ctx, maddr, CCUpgrade, types.EmptyTSK) require.NoError(t, err) + require.NotNil(t, si) require.Less(t, 50000, int(si.Expiration)) } client.WaitForSectorActive(ctx, t, CCUpgrade, maddr) diff --git a/itests/contracts/AutoSelfDestruct.hex b/itests/contracts/AutoSelfDestruct.hex new file mode 100644 index 000000000..f5128bf30 --- /dev/null +++ b/itests/contracts/AutoSelfDestruct.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061001f61002460201b60201c565b61003d565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b60848061004b6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806383197ef014602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea26469706673582212208d48a69a112633756d84552847610df29b02ac89dd39e4e295066e99a45e809664736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/AutoSelfDestruct.sol b/itests/contracts/AutoSelfDestruct.sol new file mode 100644 index 000000000..bdb165f5d --- /dev/null +++ b/itests/contracts/AutoSelfDestruct.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.17; + +contract AutoSelfDestruct { + constructor() { + destroy(); + } + function destroy() public { + selfdestruct(payable(msg.sender)); + } +} diff --git a/itests/contracts/Blocktest.hex b/itests/contracts/Blocktest.hex new file mode 100644 index 000000000..2d477b3ff --- /dev/null +++ b/itests/contracts/Blocktest.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061024d806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806311dcda5214610067578063188ec356146100715780633e64a6961461008f57806342cbb15c146100ad578063564b81ef146100cb578063bfc6ac54146100e9575b600080fd5b61006f610107565b005b610079610117565b6040516100869190610165565b60405180910390f35b61009761011f565b6040516100a49190610165565b60405180910390f35b6100b5610127565b6040516100c29190610165565b60405180910390f35b6100d361012f565b6040516100e09190610165565b60405180910390f35b6100f1610137565b6040516100fe9190610199565b60405180910390f35b61013a461461011557600080fd5b565b600042905090565b600048905090565b600043905090565b600046905090565b600060014361014691906101e3565b40905090565b6000819050919050565b61015f8161014c565b82525050565b600060208201905061017a6000830184610156565b92915050565b6000819050919050565b61019381610180565b82525050565b60006020820190506101ae600083018461018a565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006101ee8261014c565b91506101f98361014c565b9250828203905081811115610211576102106101b4565b5b9291505056fea264697066735822122015a2d5fbebc013a5c3ece3d5bbf98707100b155793f6d340c3df6a736a3f1dfa64736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/Blocktest.sol b/itests/contracts/Blocktest.sol new file mode 100644 index 000000000..3fde0d56b --- /dev/null +++ b/itests/contracts/Blocktest.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.17; + +contract BlockTest { + + function testChainID() public view{ + require(block.chainid == 314); + } + + function getBlockhashPrevious() public view returns (bytes32) { + return blockhash(block.number-1); + } + + function getBasefee() public view returns (uint256){ + return block.basefee; + } + + function getBlockNumber() public view returns (uint256){ + return block.number; + } + function getTimestamp() public view returns (uint256){ + return block.timestamp; + } +} diff --git a/itests/contracts/Constructor.hex b/itests/contracts/Constructor.hex new file mode 100644 index 000000000..e46d5bcd1 --- /dev/null +++ b/itests/contracts/Constructor.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506103ca806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c806358f5ebb614610030575b600080fd5b61004a60048036038101906100459190610123565b610060565b6040516100579190610191565b60405180910390f35b60008082604051610070906100db565b61007a91906101bb565b604051809103906000f080158015610096573d6000803e3d6000fd5b5090507f3a5c468996b00310e3e82919e3af9cce21d49c40c39a2627a9f946e1a54d886232846040516100ca9291906101d6565b60405180910390a180915050919050565b6101958061020083390190565b600080fd5b6000819050919050565b610100816100ed565b811461010b57600080fd5b50565b60008135905061011d816100f7565b92915050565b600060208284031215610139576101386100e8565b5b60006101478482850161010e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061017b82610150565b9050919050565b61018b81610170565b82525050565b60006020820190506101a66000830184610182565b92915050565b6101b5816100ed565b82525050565b60006020820190506101d060008301846101ac565b92915050565b60006040820190506101eb6000830185610182565b6101f860208301846101ac565b939250505056fe608060405234801561001057600080fd5b506040516101953803806101958339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b60e0806100b56000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80638381f58a146037578063eeb4e367146051575b600080fd5b603d606b565b604051604891906091565b60405180910390f35b60576071565b604051606291906091565b60405180910390f35b60005481565b60008054905090565b6000819050919050565b608b81607a565b82525050565b600060208201905060a460008301846084565b9291505056fea2646970667358221220451c388f24a935fc5f5eef536207cbd982254ac8521d49937bb10e5079e3924164736f6c63430008110033a264697066735822122027da159d84a9bdcd5aff5755c4602f7099db638f7a95d715c76454c99511146f64736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/Constructor.sol b/itests/contracts/Constructor.sol new file mode 100644 index 000000000..a85d13269 --- /dev/null +++ b/itests/contracts/Constructor.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.2; + + +contract Test_contract { + uint256 public number; + + constructor(uint256 _number) { + number = _number; + } + + function get_number() public view returns (uint256) { + return number; + } +} + +contract App { + + event NewTest(address sender, uint256 number); + + function new_Test(uint256 number) + public + returns (address) + { + address mynew = address(new Test_contract({_number: number})); + emit NewTest(tx.origin, number); + return mynew; + } +} diff --git a/itests/contracts/Create2Factory.hex b/itests/contracts/Create2Factory.hex new file mode 100644 index 000000000..006874306 --- /dev/null +++ b/itests/contracts/Create2Factory.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506109fb806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80632b85ba3814610051578063732768dd146100815780637c3e4053146100b2578063bb29998e146100e2575b600080fd5b61006b60048036038101906100669190610473565b610112565b60405161007891906104e1565b60405180910390f35b61009b60048036038101906100969190610473565b61013f565b6040516100a9929190610517565b60405180910390f35b6100cc60048036038101906100c79190610473565b61027e565b6040516100d991906104e1565b60405180910390f35b6100fc60048036038101906100f7919061056c565b6102c0565b60405161010991906104e1565b60405180910390f35b6000816000819055506000806101278461013f565b915091508161013557600080fd5b8092505050919050565b60008060008360405160240161015591906105a8565b6040516020818303038152906040527f7c3e4053000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000803073ffffffffffffffffffffffffffffffffffffffff16836040516101fc9190610634565b600060405180830381855af49150503d8060008114610237576040519150601f19603f3d011682016040523d82523d6000602084013e61023c565b606091505b5091509150811561026e5760008180602001905181019061025d9190610689565b905082819550955050505050610279565b816000945094505050505b915091565b6000818260405161028e9061042b565b61029891906105a8565b8190604051809103906000f59050801580156102b8573d6000803e3d6000fd5b509050919050565b6000808290508073ffffffffffffffffffffffffffffffffffffffff166383197ef06040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561030e57600080fd5b505af1158015610322573d6000803e3d6000fd5b5050505060008173ffffffffffffffffffffffffffffffffffffffff166367e404ce6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610373573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039791906106cb565b905060006104128373ffffffffffffffffffffffffffffffffffffffff1663bfa0b1336040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061040d919061070d565b61013f565b509050801561042057600080fd5b819350505050919050565b61028b8061073b83390190565b600080fd5b6000819050919050565b6104508161043d565b811461045b57600080fd5b50565b60008135905061046d81610447565b92915050565b60006020828403121561048957610488610438565b5b60006104978482850161045e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006104cb826104a0565b9050919050565b6104db816104c0565b82525050565b60006020820190506104f660008301846104d2565b92915050565b60008115159050919050565b610511816104fc565b82525050565b600060408201905061052c6000830185610508565b61053960208301846104d2565b9392505050565b610549816104c0565b811461055457600080fd5b50565b60008135905061056681610540565b92915050565b60006020828403121561058257610581610438565b5b600061059084828501610557565b91505092915050565b6105a28161043d565b82525050565b60006020820190506105bd6000830184610599565b92915050565b600081519050919050565b600081905092915050565b60005b838110156105f75780820151818401526020810190506105dc565b60008484015250505050565b600061060e826105c3565b61061881856105ce565b93506106288185602086016105d9565b80840191505092915050565b60006106408284610603565b915081905092915050565b6000610656826104a0565b9050919050565b6106668161064b565b811461067157600080fd5b50565b6000815190506106838161065d565b92915050565b60006020828403121561069f5761069e610438565b5b60006106ad84828501610674565b91505092915050565b6000815190506106c581610540565b92915050565b6000602082840312156106e1576106e0610438565b5b60006106ef848285016106b6565b91505092915050565b60008151905061070781610447565b92915050565b60006020828403121561072357610722610438565b5b6000610731848285016106f8565b9150509291505056fe608060405234801561001057600080fd5b5060405161028b38038061028b833981810160405281019061003291906100ba565b326000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600181905550506100e7565b600080fd5b6000819050919050565b61009781610084565b81146100a257600080fd5b50565b6000815190506100b48161008e565b92915050565b6000602082840312156100d0576100cf61007f565b5b60006100de848285016100a5565b91505092915050565b610195806100f66000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806367e404ce1461004657806383197ef014610064578063bfa0b1331461006e575b600080fd5b61004e61008c565b60405161005b9190610110565b60405180910390f35b61006c6100b0565b005b6100766100c9565b6040516100839190610144565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b60015481565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100fa826100cf565b9050919050565b61010a816100ef565b82525050565b60006020820190506101256000830184610101565b92915050565b6000819050919050565b61013e8161012b565b82525050565b60006020820190506101596000830184610135565b9291505056fea26469706673582212208252a57fdfc00b722b7063f2d28dd8c5a36b469462c89da52bcf17ccdda2de6764736f6c63430008110033a26469706673582212200edf974d1735ee81f671df7e60300ab28168b8cb22cc3e59180ef743c4a526c964736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/Create2Factory.sol b/itests/contracts/Create2Factory.sol new file mode 100644 index 000000000..ffec40822 --- /dev/null +++ b/itests/contracts/Create2Factory.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.17; +contract Create2Factory { + + bytes32 savedSalt; + + // Returns the address of the newly deployed contract + function deploy( + bytes32 _salt + ) public returns (address) { + // This syntax is a newer way to invoke create2 without assembly, you just need to pass salt + // https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2 + savedSalt = _salt; + (bool success, address ret) = deployDelegateCall(_salt); + require(success); + return ret; + } + + function deployDelegateCall( + bytes32 _salt + ) public returns (bool, address) { + bytes memory data = abi.encodeWithSignature("_deploy(bytes32)", _salt); + (bool success, bytes memory returnedData) = address(this).delegatecall(data); + if(success){ + (address ret) = abi.decode(returnedData, (address)); + return (success, ret); + }else{ + return (success, address(0)); + } + } + + function _deploy(bytes32 _salt) public returns (address) { + // https://solidity-by-example.org/app/create1/ + // This syntax is a newer way to invoke create2 without assembly, you just need to pass salt + // https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2 + return address(new SelfDestruct{salt: _salt}(_salt)); + } + + function test(address _address) public returns (address){ + + // run destroy() on _address + SelfDestruct selfDestruct = SelfDestruct(_address); + selfDestruct.destroy(); + + //verify data can still be accessed + address ret = selfDestruct.sender(); + + // attempt and fail to deploy contract using salt + (bool success, ) = deployDelegateCall(selfDestruct.salt()); + require(!success); + + return ret; + } +} + +contract SelfDestruct { + address public sender; + bytes32 public salt; + constructor(bytes32 _salt) { + sender = tx.origin; + salt=_salt; + } + function destroy() public { + selfdestruct(payable(msg.sender)); + } +} + diff --git a/itests/contracts/DelegatecallActor.hex b/itests/contracts/DelegatecallActor.hex new file mode 100644 index 000000000..aed647407 --- /dev/null +++ b/itests/contracts/DelegatecallActor.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061018c806100206000396000f3fe6080604052600436106100345760003560e01c806361bc221a146100395780636466414b146100645780638ada066e14610080575b600080fd5b34801561004557600080fd5b5061004e6100ab565b60405161005b91906100dd565b60405180910390f35b61007e60048036038101906100799190610129565b6100b1565b005b34801561008c57600080fd5b506100956100bb565b6040516100a291906100dd565b60405180910390f35b60005481565b8060008190555050565b60008054905090565b6000819050919050565b6100d7816100c4565b82525050565b60006020820190506100f260008301846100ce565b92915050565b600080fd5b610106816100c4565b811461011157600080fd5b50565b600081359050610123816100fd565b92915050565b60006020828403121561013f5761013e6100f8565b5b600061014d84828501610114565b9150509291505056fea2646970667358221220cf4567855a30be48cde5cdbff495bdaa4052e2c4540678b97284af53a4e5dbd164736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/DelegatecallActor.sol b/itests/contracts/DelegatecallActor.sol new file mode 100644 index 000000000..8671f6298 --- /dev/null +++ b/itests/contracts/DelegatecallActor.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract DelegatecallActor { + uint public counter; + + function getCounter() public view returns (uint){ + return counter; + } + function setVars(uint _counter) public payable { + counter = _counter; + } +} diff --git a/itests/contracts/DelegatecallStorage.hex b/itests/contracts/DelegatecallStorage.hex new file mode 100644 index 000000000..966e9e906 --- /dev/null +++ b/itests/contracts/DelegatecallStorage.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061087e806100206000396000f3fe6080604052600436106100555760003560e01c80630712ede21461005a57806361bc221a1461008a5780637da3c3ab146100b55780638ada066e146100cc578063bed56f47146100f7578063d1e0f30814610127575b600080fd5b610074600480360381019061006f919061060f565b610157565b604051610081919061065e565b60405180910390f35b34801561009657600080fd5b5061009f610298565b6040516100ac919061065e565b60405180910390f35b3480156100c157600080fd5b506100ca61029e565b005b3480156100d857600080fd5b506100e16102e1565b6040516100ee919061065e565b60405180910390f35b610111600480360381019061010c919061060f565b6102ea565b60405161011e919061065e565b60405180910390f35b610141600480360381019061013c919061060f565b610431565b60405161014e919061065e565b60405180910390f35b6000808373ffffffffffffffffffffffffffffffffffffffff1683604051602401610182919061065e565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161020c91906106ea565b600060405180830381855af49150503d8060008114610247576040519150601f19603f3d011682016040523d82523d6000602084013e61024c565b606091505b505090506000610291576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102889061075e565b60405180910390fd5b5092915050565b60005481565b60006102df576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d69061075e565b60405180910390fd5b565b60008054905090565b6000808373ffffffffffffffffffffffffffffffffffffffff16848460405160240161031792919061078d565b6040516020818303038152906040527fbed56f47000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516103a191906106ea565b600060405180830381855af49150503d80600081146103dc576040519150601f19603f3d011682016040523d82523d6000602084013e6103e1565b606091505b5050905080610425576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161041c90610828565b60405180910390fd5b60005491505092915050565b6000808373ffffffffffffffffffffffffffffffffffffffff168360405160240161045c919061065e565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516104e691906106ea565b600060405180830381855af49150503d8060008114610521576040519150601f19603f3d011682016040523d82523d6000602084013e610526565b606091505b505090508061056a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056190610828565b60405180910390fd5b60005491505092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105a68261057b565b9050919050565b6105b68161059b565b81146105c157600080fd5b50565b6000813590506105d3816105ad565b92915050565b6000819050919050565b6105ec816105d9565b81146105f757600080fd5b50565b600081359050610609816105e3565b92915050565b6000806040838503121561062657610625610576565b5b6000610634858286016105c4565b9250506020610645858286016105fa565b9150509250929050565b610658816105d9565b82525050565b6000602082019050610673600083018461064f565b92915050565b600081519050919050565b600081905092915050565b60005b838110156106ad578082015181840152602081019050610692565b60008484015250505050565b60006106c482610679565b6106ce8185610684565b93506106de81856020860161068f565b80840191505092915050565b60006106f682846106b9565b915081905092915050565b600082825260208201905092915050565b7f696e74656e74696f6e616c6c79207468726f77696e67206572726f7200000000600082015250565b6000610748601c83610701565b915061075382610712565b602082019050919050565b600060208201905081810360008301526107778161073b565b9050919050565b6107878161059b565b82525050565b60006040820190506107a2600083018561077e565b6107af602083018461064f565b9392505050565b7f4572726f72206d6573736167653a2044656c656761746563616c6c206661696c60008201527f6564000000000000000000000000000000000000000000000000000000000000602082015250565b6000610812602283610701565b915061081d826107b6565b604082019050919050565b6000602082019050818103600083015261084181610805565b905091905056fea2646970667358221220b2a3ae7e2a9ffc78e3e2a7aadb2885435c5e51aa9d3f07372a0dffb6238aa1db64736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/DelegatecallStorage.sol b/itests/contracts/DelegatecallStorage.sol new file mode 100644 index 000000000..15e672082 --- /dev/null +++ b/itests/contracts/DelegatecallStorage.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract DelegatecallStorage { + uint public counter; + + function getCounter() public view returns (uint){ + return counter; + } + function setVars(address _contract, uint _counter) public payable returns (uint){ + (bool success, ) = _contract.delegatecall( + abi.encodeWithSignature("setVars(uint256)", _counter) + ); + require(success, 'Error message: Delegatecall failed'); + return counter; + } + function setVarsSelf(address _contract, uint _counter) public payable returns (uint){ + (bool success, ) = _contract.delegatecall( + abi.encodeWithSignature("setVarsSelf(address,uint256)", _contract, _counter) + ); + require(success, 'Error message: Delegatecall failed'); + return counter; + } + function setVarsRevert(address _contract, uint _counter) public payable returns (uint){ + (bool success, ) = _contract.delegatecall( + abi.encodeWithSignature("setVars(uint256)", _counter) + ); + require(false,"intentionally throwing error"); + } + function revert() public{ + require(false,"intentionally throwing error"); + } +} diff --git a/itests/contracts/DeployValueTest.hex b/itests/contracts/DeployValueTest.hex new file mode 100644 index 000000000..535704abf --- /dev/null +++ b/itests/contracts/DeployValueTest.hex @@ -0,0 +1 @@ +60806040523460405161001190610073565b6040518091039082f090508015801561002e573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061007f565b60c78061031683390190565b6102888061008e6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80630e3608df146100465780634313b53114610064578063b0d22c6214610082575b600080fd5b61004e6100a0565b60405161005b919061017d565b60405180910390f35b61006c610137565b60405161007991906101d9565b60405180910390f35b61008a61015b565b604051610097919061017d565b60405180910390f35b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561010e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101329190610225565b905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006007905090565b6000819050919050565b61017781610164565b82525050565b6000602082019050610192600083018461016e565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101c382610198565b9050919050565b6101d3816101b8565b82525050565b60006020820190506101ee60008301846101ca565b92915050565b600080fd5b61020281610164565b811461020d57600080fd5b50565b60008151905061021f816101f9565b92915050565b60006020828403121561023b5761023a6101f4565b5b600061024984828501610210565b9150509291505056fea2646970667358221220c24abd10dbe58d92bfe62cb351771fcdc45d54241a8ce7085f2a75179c67cd8a64736f6c63430008110033608060405260b5806100126000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806312065fe014602d575b600080fd5b60336047565b604051603e91906066565b60405180910390f35b600047905090565b6000819050919050565b606081604f565b82525050565b6000602082019050607960008301846059565b9291505056fea26469706673582212207123972a300833ee01aebf99e4bdf8ecf9f01c0d3dd776048bd41803c6855c0e64736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/DeployValueTest.sol b/itests/contracts/DeployValueTest.sol new file mode 100644 index 000000000..fe261b014 --- /dev/null +++ b/itests/contracts/DeployValueTest.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.17; + + + +contract DeployValueTest { + address public newContract; + + constructor() payable { + newContract = address(new NewContract{value: msg.value}()); + } + + function getConst() public view returns (uint) { + return 7; + } + + function getNewContractBalance() public view returns (uint) { + return NewContract(newContract).getBalance(); + } +} + +contract NewContract { + constructor() payable { + } + + function getBalance() public view returns (uint) { + return address(this).balance; + } +} diff --git a/itests/contracts/Errors.hex b/itests/contracts/Errors.hex new file mode 100644 index 000000000..64e4ea6df --- /dev/null +++ b/itests/contracts/Errors.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506102de806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80630abe88b61461005c57806358d4cbce1461006657806359be8c55146100705780638791bd331461007a578063c6dbcf2e14610084575b600080fd5b61006461008e565b005b61006e61009f565b005b6100786100a4565b005b6100826100df565b005b61008c610111565b005b600061009d5761009c61012a565b5b565b600080fd5b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100d6906101b6565b60405180910390fd5b6040517f09caebf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006001905060008082610125919061023e565b505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600082825260208201905092915050565b7f6d7920726561736f6e0000000000000000000000000000000000000000000000600082015250565b60006101a0600983610159565b91506101ab8261016a565b602082019050919050565b600060208201905081810360008301526101cf81610193565b9050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610249826101d6565b9150610254836101d6565b925082610264576102636101e0565b5b600160000383147f80000000000000000000000000000000000000000000000000000000000000008314161561029d5761029c61020f565b5b82820590509291505056fea26469706673582212207815355e9e7ced2b8168a953c364e82871c0fe326602bbb9106e6551aea673ed64736f6c63430008120033 \ No newline at end of file diff --git a/itests/contracts/Errors.sol b/itests/contracts/Errors.sol new file mode 100644 index 000000000..f9bcfbce2 --- /dev/null +++ b/itests/contracts/Errors.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract Errors { + error CustomError(); + + function failRevertEmpty() public { + revert(); + } + function failRevertReason() public { + revert("my reason"); + } + function failAssert() public { + assert(false); + } + function failDivZero() public { + int a = 1; + int b = 0; + a / b; + } + function failCustom() public { + revert CustomError(); + } +} diff --git a/itests/contracts/EventMatrix.hex b/itests/contracts/EventMatrix.hex new file mode 100644 index 000000000..be831e397 --- /dev/null +++ b/itests/contracts/EventMatrix.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506106af806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063c755553811610071578063c755553814610128578063cbfc3b5814610144578063cc6f8faf14610160578063cd5b6c3d1461017c578063e2a6147314610198578063fb62b28b146101b4576100a9565b80630919b8be146100ae5780636199074d146100ca57806366eef346146100e657806375091b1f146100f0578063a63ae81a1461010c575b600080fd5b6100c860048036038101906100c39190610483565b6101d0565b005b6100e460048036038101906100df91906104c3565b61020d565b005b6100ee610241565b005b61010a60048036038101906101059190610483565b61026f565b005b61012660048036038101906101219190610516565b6102ab565b005b610142600480360381019061013d9190610516565b6102e5565b005b61015e60048036038101906101599190610543565b610315565b005b61017a600480360381019061017591906104c3565b610358565b005b61019660048036038101906101919190610483565b610396565b005b6101b260048036038101906101ad9190610543565b6103c8565b005b6101ce60048036038101906101c991906104c3565b610408565b005b7f5469c6b769315f5668523937f05ca07d4cc87849432bc5f5907f1d90fa73b9f982826040516102019291906105b9565b60405180910390a15050565b8082847fb89dabcdb7ff41f1794c0da92f65ece6c19b6b0caeac5407b2a721efe27c080460405160405180910390a4505050565b7fc3f6f1c76bd4e74ee5782052b0b4f8bd5c50b86c3c5a2f52638e03066e50a91b60405160405180910390a1565b817f6709824ebe5f6e620ca3f4b02a3428e8ce2dc97c550816eaeeb3a342b214bd858260405161029f91906105e2565b60405180910390a25050565b7fc804e53d6048af1b3e6a352e246d5f3864fea9d635ace499e023a58c383b3a88816040516102da91906105e2565b60405180910390a150565b807f44a227a31429ab5eb00daf6611c6422f10571619f2267e0e149e9ebe6d2a5d0560405160405180910390a250565b7f28d45631a87b2a52a9625f8520fa37ff8c4d926cdf17042e241985da5cb7b8508484848460405161034a94939291906105fd565b60405180910390a150505050565b81837fcd5fe5fbc1d27b90036997224cea7aa565e3779622867265081f636b3a5ccb088360405161038991906105e2565b60405180910390a3505050565b80827f232f09cef3babc26e58d1cc1346c0a8bc626ffe600c9605b5d747783eda484a760405160405180910390a35050565b8183857f812e73dbcf7e267f27ecb1383bfc902a6650b41b6e7d03ac265108c369673d95846040516103fa91906105e2565b60405180910390a450505050565b7fd4d143faaf60340ad98e1f2c96fc26f5695834c21b5200edad339ee7e9a372cc83838360405161043b93929190610642565b60405180910390a1505050565b600080fd5b6000819050919050565b6104608161044d565b811461046b57600080fd5b50565b60008135905061047d81610457565b92915050565b6000806040838503121561049a57610499610448565b5b60006104a88582860161046e565b92505060206104b98582860161046e565b9150509250929050565b6000806000606084860312156104dc576104db610448565b5b60006104ea8682870161046e565b93505060206104fb8682870161046e565b925050604061050c8682870161046e565b9150509250925092565b60006020828403121561052c5761052b610448565b5b600061053a8482850161046e565b91505092915050565b6000806000806080858703121561055d5761055c610448565b5b600061056b8782880161046e565b945050602061057c8782880161046e565b935050604061058d8782880161046e565b925050606061059e8782880161046e565b91505092959194509250565b6105b38161044d565b82525050565b60006040820190506105ce60008301856105aa565b6105db60208301846105aa565b9392505050565b60006020820190506105f760008301846105aa565b92915050565b600060808201905061061260008301876105aa565b61061f60208301866105aa565b61062c60408301856105aa565b61063960608301846105aa565b95945050505050565b600060608201905061065760008301866105aa565b61066460208301856105aa565b61067160408301846105aa565b94935050505056fea26469706673582212201b2f4de851da592b926eb2cd07ccfbbd02270fde6dee2459ba942e5dcf5685d364736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/EventMatrix.sol b/itests/contracts/EventMatrix.sol new file mode 100644 index 000000000..f1d63c69e --- /dev/null +++ b/itests/contracts/EventMatrix.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.5.0; + +contract EventMatrix { + event EventZeroData(); + event EventOneData(uint a); + event EventTwoData(uint a, uint b); + event EventThreeData(uint a, uint b, uint c); + event EventFourData(uint a, uint b, uint c, uint d); + + event EventOneIndexed(uint indexed a); + event EventTwoIndexed(uint indexed a, uint indexed b); + event EventThreeIndexed(uint indexed a, uint indexed b, uint indexed c); + + event EventOneIndexedWithData(uint indexed a, uint b); + event EventTwoIndexedWithData(uint indexed a, uint indexed b, uint c); + event EventThreeIndexedWithData(uint indexed a, uint indexed b, uint indexed c, uint d); + + function logEventZeroData() public { + emit EventZeroData(); + } + function logEventOneData(uint a) public { + emit EventOneData(a); + } + function logEventTwoData(uint a, uint b) public { + emit EventTwoData(a,b); + } + function logEventThreeData(uint a, uint b, uint c) public { + emit EventThreeData(a,b,c); + } + function logEventFourData(uint a, uint b, uint c, uint d) public { + emit EventFourData(a,b,c,d); + } + function logEventOneIndexed(uint a) public { + emit EventOneIndexed(a); + } + function logEventTwoIndexed(uint a, uint b) public { + emit EventTwoIndexed(a,b); + } + function logEventThreeIndexed(uint a, uint b, uint c) public { + emit EventThreeIndexed(a,b,c); + } + function logEventOneIndexedWithData(uint a, uint b) public { + emit EventOneIndexedWithData(a,b); + } + function logEventTwoIndexedWithData(uint a, uint b, uint c) public { + emit EventTwoIndexedWithData(a,b,c); + } + function logEventThreeIndexedWithData(uint a, uint b, uint c, uint d) public { + emit EventThreeIndexedWithData(a,b,c,d); + } +} diff --git a/itests/contracts/ExternalRecursiveCallSimple.hex b/itests/contracts/ExternalRecursiveCallSimple.hex new file mode 100644 index 000000000..03d79fe2d --- /dev/null +++ b/itests/contracts/ExternalRecursiveCallSimple.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506101ee806100206000396000f3fe60806040526004361061001e5760003560e01c8063c38e07dd14610023575b600080fd5b61003d600480360381019061003891906100fe565b61003f565b005b60008111156100c0573073ffffffffffffffffffffffffffffffffffffffff1663c38e07dd600183610071919061015a565b6040518263ffffffff1660e01b815260040161008d919061019d565b600060405180830381600087803b1580156100a757600080fd5b505af11580156100bb573d6000803e3d6000fd5b505050505b50565b600080fd5b6000819050919050565b6100db816100c8565b81146100e657600080fd5b50565b6000813590506100f8816100d2565b92915050565b600060208284031215610114576101136100c3565b5b6000610122848285016100e9565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610165826100c8565b9150610170836100c8565b92508282039050818111156101885761018761012b565b5b92915050565b610197816100c8565b82525050565b60006020820190506101b2600083018461018e565b9291505056fea264697066735822122033d012e17f5d7a62bb724021b5c4e0d109aeb28d1cd5b5c0a0b1b801c0b5032164736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/ExternalRecursiveCallSimple.sol b/itests/contracts/ExternalRecursiveCallSimple.sol new file mode 100644 index 000000000..97a27811b --- /dev/null +++ b/itests/contracts/ExternalRecursiveCallSimple.sol @@ -0,0 +1,13 @@ + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract StackRecCallExp { + function exec1(uint256 r) public payable { + if(r > 0) { + StackRecCallExp(address(this)).exec1(r-1); + } + + return; + } +} diff --git a/itests/contracts/GasLimitSend.hex b/itests/contracts/GasLimitSend.hex new file mode 100644 index 000000000..ac4927d38 --- /dev/null +++ b/itests/contracts/GasLimitSend.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061027c806100206000396000f3fe6080604052600436106100385760003560e01c80630bc07a88146100435780633da767881461005a578063f0ba84401461008557610039565b5b6100416100c2565b005b34801561004f57600080fd5b506100586100c2565b005b34801561006657600080fd5b5061006f61010d565b60405161007c9190610156565b60405180910390f35b34801561009157600080fd5b506100ac60048036038101906100a791906101a2565b610119565b6040516100b99190610156565b60405180910390f35b60005b606481101561010a5760008190806001815401808255809150506001900390600052602060002001600090919091909150558080610102906101fe565b9150506100c5565b50565b60008080549050905090565b6000818154811061012957600080fd5b906000526020600020016000915090505481565b6000819050919050565b6101508161013d565b82525050565b600060208201905061016b6000830184610147565b92915050565b600080fd5b61017f8161013d565b811461018a57600080fd5b50565b60008135905061019c81610176565b92915050565b6000602082840312156101b8576101b7610171565b5b60006101c68482850161018d565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006102098261013d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361023b5761023a6101cf565b5b60018201905091905056fea2646970667358221220c56d78e0c60a01681eee1b76c95e7b214d16a512c944e31cfee71eb727c1e44064736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/GasLimitSend.sol b/itests/contracts/GasLimitSend.sol new file mode 100644 index 000000000..b5a91e14d --- /dev/null +++ b/itests/contracts/GasLimitSend.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract GasLimitTest { + address payable receiver; + constructor(){ + address mynew = address(new GasLimitTestReceiver()); + receiver = payable(mynew); + } + function send() public payable{ + receiver.transfer(msg.value); + } + function expensiveTest() public{ + GasLimitTestReceiver(receiver).expensive(); + } + function getDataLength() public returns (uint256) { + return GasLimitTestReceiver(receiver).getDataLength(); + } +} + +contract GasLimitTestReceiver { + uint256[] public data; + fallback() external payable { + expensive(); + } + function expensive() public{ + for (uint256 i = 0; i < 100; i++) { + data.push(i); + } + } + function getDataLength() public view returns (uint256) { + return data.length; + } +} diff --git a/itests/contracts/GasSendTest.hex b/itests/contracts/GasSendTest.hex new file mode 100644 index 000000000..b41be3463 --- /dev/null +++ b/itests/contracts/GasSendTest.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80630c55699c14602d575b600080fd5b60336047565b604051603e91906067565b60405180910390f35b60006007905090565b6000819050919050565b6061816050565b82525050565b6000602082019050607a6000830184605a565b9291505056fea2646970667358221220c0f2da1b01178b54afba1ddf14f30307a03cdb66f61b4e1dc342079561db009064736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/GasSendTest.sol b/itests/contracts/GasSendTest.sol new file mode 100644 index 000000000..b422bda26 --- /dev/null +++ b/itests/contracts/GasSendTest.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract GasLimitTestReceiver { + function x() public returns (uint256){ + return 7; + } +} + diff --git a/itests/contracts/GetDifficulty.hex b/itests/contracts/GetDifficulty.hex new file mode 100644 index 000000000..6d584b233 --- /dev/null +++ b/itests/contracts/GetDifficulty.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5060b58061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063b6baffe314602d575b600080fd5b60336047565b604051603e91906066565b60405180910390f35b600044905090565b6000819050919050565b606081604f565b82525050565b6000602082019050607960008301846059565b9291505056fea2646970667358221220c113f1abaabaed6a0324d363896b0d15a8bca7b9a540948a5be5b636a12a534f64736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/GetDifficulty.sol b/itests/contracts/GetDifficulty.sol new file mode 100644 index 000000000..155e7cfd1 --- /dev/null +++ b/itests/contracts/GetDifficulty.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.17; + +contract GetDifficulty { + function getDifficulty () public view returns (uint256) { + return block.difficulty; + } +} + diff --git a/itests/contracts/NotPayable.hex b/itests/contracts/NotPayable.hex new file mode 100644 index 000000000..c08070029 --- /dev/null +++ b/itests/contracts/NotPayable.hex @@ -0,0 +1 @@ +6080604052348015600f57600080fd5b50604780601d6000396000f3fe6080604052348015600f57600080fd5b00fea26469706673582212200cd38951eddebe3692dc8921afb65a04fbe64e10d5e261806330156459bf227264736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/NotPayable.sol b/itests/contracts/NotPayable.sol new file mode 100644 index 000000000..9b9a06e08 --- /dev/null +++ b/itests/contracts/NotPayable.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.17; + +//sending eth should fall because fallback is not payable +contract NotPayable { + fallback() external {} +} diff --git a/itests/contracts/RecCall.hex b/itests/contracts/RecCall.hex new file mode 100644 index 000000000..b8de20213 --- /dev/null +++ b/itests/contracts/RecCall.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061025b806100206000396000f3fe60806040526004361061001e5760003560e01c8063cb7786d714610023575b600080fd5b61003d60048036038101906100389190610129565b61003f565b005b600083036100d15760008111156100cc573073ffffffffffffffffffffffffffffffffffffffff1663cb7786d7838460018561007b91906101ab565b6040518463ffffffff1660e01b8152600401610099939291906101ee565b600060405180830381600087803b1580156100b357600080fd5b505af11580156100c7573d6000803e3d6000fd5b505050505b6100e9565b6100e86001846100e191906101ab565b838361003f565b5b505050565b600080fd5b6000819050919050565b610106816100f3565b811461011157600080fd5b50565b600081359050610123816100fd565b92915050565b600080600060608486031215610142576101416100ee565b5b600061015086828701610114565b935050602061016186828701610114565b925050604061017286828701610114565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006101b6826100f3565b91506101c1836100f3565b92508282039050818111156101d9576101d861017c565b5b92915050565b6101e8816100f3565b82525050565b600060608201905061020360008301866101df565b61021060208301856101df565b61021d60408301846101df565b94935050505056fea26469706673582212209a21ff59c642e2970917c07bf498271c2a6df8e3929677952c0c2d8031db15cc64736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/RecCall.sol b/itests/contracts/RecCall.sol new file mode 100644 index 000000000..f89611f0e --- /dev/null +++ b/itests/contracts/RecCall.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract StackRecCall { + function exec1(uint256 n, uint256 m, uint256 r) public payable { + if(n == 0) { + if(r > 0) { + StackRecCall(address(this)).exec1(m, m, r-1); + } + + return; + } + + exec1(n-1, m, r); + } +} diff --git a/itests/contracts/Recursive.hex b/itests/contracts/Recursive.hex new file mode 100644 index 000000000..b211aafd9 --- /dev/null +++ b/itests/contracts/Recursive.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506102d9806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063032cec451461005c57806372536f3c1461007a57806399fdb86e14610098578063d2aac3ea146100b6578063ec49254c146100d4575b600080fd5b610064610104565b60405161007191906101c7565b60405180910390f35b610082610115565b60405161008f91906101c7565b60405180910390f35b6100a0610126565b6040516100ad91906101c7565b60405180910390f35b6100be610137565b6040516100cb91906101c7565b60405180910390f35b6100ee60048036038101906100e99190610213565b610148565b6040516100fb91906101c7565b60405180910390f35b60006101106001610148565b905090565b6000610121600a610148565b905090565b60006101326002610148565b905090565b60006101436000610148565b905090565b6000808211156101a5577f3110e0ccd510fcbb471c933ad12161c459e8735b5bde2eea61a659c2e2f0a3cc8260405161018191906101c7565b60405180910390a161019e600183610199919061026f565b610148565b90506101a9565b8190505b919050565b6000819050919050565b6101c1816101ae565b82525050565b60006020820190506101dc60008301846101b8565b92915050565b600080fd5b6101f0816101ae565b81146101fb57600080fd5b50565b60008135905061020d816101e7565b92915050565b600060208284031215610229576102286101e2565b5b6000610237848285016101fe565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061027a826101ae565b9150610285836101ae565b925082820390508181111561029d5761029c610240565b5b9291505056fea26469706673582212206178e15eb87e2f766b94ec09a6a860878c93d72a31de225e1684da1755f917c764736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/Recursive.sol b/itests/contracts/Recursive.sol new file mode 100644 index 000000000..aa8fe62b0 --- /dev/null +++ b/itests/contracts/Recursive.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract Recursive { + event RecursiveCallEvent(uint256 count); + + function recursive10() public returns (uint256){ + return recursiveCall(10); + } + function recursive2() public returns (uint256){ + return recursiveCall(2); + } + function recursive1() public returns (uint256){ + return recursiveCall(1); + } + function recursive0() public returns (uint256){ + return recursiveCall(0); + } + function recursiveCall(uint256 count) public returns (uint256) { + if (count > 0) { + emit RecursiveCallEvent(count); + return recursiveCall(count-1); + } + return count; + } +} diff --git a/itests/contracts/RecursiveDelegeatecall.hex b/itests/contracts/RecursiveDelegeatecall.hex new file mode 100644 index 000000000..d8337c258 --- /dev/null +++ b/itests/contracts/RecursiveDelegeatecall.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50610459806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80633af3f24f1461003b578063ec49254c14610059575b600080fd5b610043610089565b6040516100509190610221565b60405180910390f35b610073600480360381019061006e919061026d565b61008f565b6040516100809190610221565b60405180910390f35b60005481565b60007faab69767807d0ab32f0099452739da31b76ecd3e8694bb49898829c8bf9d063582306040516100c29291906102db565b60405180910390a160016000808282546100dc9190610333565b9250508190555060018211156101ff576001826100f99190610367565b91506000803073ffffffffffffffffffffffffffffffffffffffff16846040516024016101269190610221565b6040516020818303038152906040527fec49254c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101b0919061040c565b600060405180830381855af49150503d80600081146101eb576040519150601f19603f3d011682016040523d82523d6000602084013e6101f0565b606091505b50915091508392505050610203565b8190505b919050565b6000819050919050565b61021b81610208565b82525050565b60006020820190506102366000830184610212565b92915050565b600080fd5b61024a81610208565b811461025557600080fd5b50565b60008135905061026781610241565b92915050565b6000602082840312156102835761028261023c565b5b600061029184828501610258565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102c58261029a565b9050919050565b6102d5816102ba565b82525050565b60006040820190506102f06000830185610212565b6102fd60208301846102cc565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061033e82610208565b915061034983610208565b925082820190508082111561036157610360610304565b5b92915050565b600061037282610208565b915061037d83610208565b925082820390508181111561039557610394610304565b5b92915050565b600081519050919050565b600081905092915050565b60005b838110156103cf5780820151818401526020810190506103b4565b60008484015250505050565b60006103e68261039b565b6103f081856103a6565b93506104008185602086016103b1565b80840191505092915050565b600061041882846103db565b91508190509291505056fea2646970667358221220e70fbbfaccd3fbb084623d6d06895fba1abc5fefc181215b56ab1e43db79c7fb64736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/RecursiveDelegeatecall.sol b/itests/contracts/RecursiveDelegeatecall.sol new file mode 100644 index 000000000..cd1b693c0 --- /dev/null +++ b/itests/contracts/RecursiveDelegeatecall.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.17; + +contract RecursiveDelegatecall { + event RecursiveCallEvent(uint256 count, address self); + uint256 public totalCalls; + + function recursiveCall(uint256 count) public returns (uint256) { + emit RecursiveCallEvent(count, address(this)); + totalCalls += 1; + if (count > 1) { + count -= 1; + (bool success, bytes memory returnedData) = address(this) + .delegatecall( + abi.encodeWithSignature("recursiveCall(uint256)", count) + ); + return count; + } + return count; + } +} diff --git a/itests/contracts/SelfDestruct.hex b/itests/contracts/SelfDestruct.hex new file mode 100644 index 000000000..c2f91b803 --- /dev/null +++ b/itests/contracts/SelfDestruct.hex @@ -0,0 +1 @@ +6080604052348015600f57600080fd5b5060848061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806383197ef014602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220d4aa109d42268586e7ce4f0fafb0ebbd04c412c6c7e8c387b009a08ecdff864264736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/SelfDestruct.sol b/itests/contracts/SelfDestruct.sol new file mode 100644 index 000000000..6c4ff9188 --- /dev/null +++ b/itests/contracts/SelfDestruct.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.17; + +contract SelfDestruct { + function destroy() public { + selfdestruct(payable(msg.sender)); + } +} diff --git a/itests/contracts/SimpleCoin.hex b/itests/contracts/SimpleCoin.hex new file mode 100644 index 000000000..8e11ab5b9 --- /dev/null +++ b/itests/contracts/SimpleCoin.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061051c806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610193919061047e565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104b2565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b925082820261046081610337565b915082820484148315176104775761047661040d565b5b5092915050565b600061048982610337565b915061049483610337565b92508282039050818111156104ac576104ab61040d565b5b92915050565b60006104bd82610337565b91506104c883610337565b92508282019050808211156104e0576104df61040d565b5b9291505056fea2646970667358221220050cdcfbe2911d041d2e6c355dbb6a0ca8ca70b500865bf33d9a2e5f4ac5a4e164736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/SimpleCoin.sol b/itests/contracts/SimpleCoin.sol new file mode 100644 index 000000000..5318b0cb8 --- /dev/null +++ b/itests/contracts/SimpleCoin.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.2; + +contract SimpleCoin { + mapping(address => uint256) balances; + + event Transfer(address indexed _from, address indexed _to, uint256 _value); + + constructor() { + balances[tx.origin] = 10000; + } + + function sendCoin(address receiver, uint256 amount) + public + returns (bool sufficient) + { + if (balances[msg.sender] < amount) return false; + balances[msg.sender] -= amount; + balances[receiver] += amount; + emit Transfer(msg.sender, receiver, amount); + return true; + } + + function getBalanceInEth(address addr) public view returns (uint256) { + return getBalance(addr) * 2; + } + + function getBalance(address addr) public view returns (uint256) { + return balances[addr]; + } +} diff --git a/itests/contracts/StackFunc.hex b/itests/contracts/StackFunc.hex new file mode 100644 index 000000000..1a3d1202e --- /dev/null +++ b/itests/contracts/StackFunc.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50610162806100206000396000f3fe60806040526004361061001e5760003560e01c8063c38e07dd14610023575b600080fd5b61003d6004803603810190610038919061009c565b61003f565b005b600081031561005e5761005d60018261005891906100f8565b61003f565b5b50565b600080fd5b6000819050919050565b61007981610066565b811461008457600080fd5b50565b60008135905061009681610070565b92915050565b6000602082840312156100b2576100b1610061565b5b60006100c084828501610087565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061010382610066565b915061010e83610066565b9250828203905081811115610126576101256100c9565b5b9291505056fea2646970667358221220ee8f18bfd33b1e0156cfe68e9071dd32960b370c7e63ec53c62dd48e28cb5d3b64736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/StackFunc.sol b/itests/contracts/StackFunc.sol new file mode 100644 index 000000000..7084901c6 --- /dev/null +++ b/itests/contracts/StackFunc.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract StackSelf { + function exec1(uint256 n) public payable { + if(n == 0) { + return; + } + + exec1(n-1); + } +} \ No newline at end of file diff --git a/itests/contracts/TestApp.hex b/itests/contracts/TestApp.hex new file mode 100644 index 000000000..bf1830071 --- /dev/null +++ b/itests/contracts/TestApp.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50612e80806100206000396000f3fe60806040523480156200001157600080fd5b5060043610620000a05760003560e01c8063883a8410116200006f578063883a84101462000181578063c483289114620001bb578063d65c239c14620001dd578063dc33b0041462000213578063eae185c4146200024b57620000a0565b806308eaae9614620000a5578063120f83c414620000db5780632db0de8514620001115780637f823290146200014b575b600080fd5b620000c36004803603810190620000bd919062001a74565b62000281565b604051620000d2919062001b1f565b60405180910390f35b620000f96004803603810190620000f3919062001b6d565b620005b4565b60405162000108919062001bb0565b60405180910390f35b6200012f600480360381019062000129919062001bcd565b62000600565b6040516200014295949392919062001c88565b60405180910390f35b62000169600480360381019062000163919062001cec565b620006d3565b60405162000178919062001f0c565b60405180910390f35b6200019f600480360381019062000199919062001f30565b62000d53565b604051620001b295949392919062001c88565b60405180910390f35b620001c562000e68565b604051620001d4919062001bb0565b60405180910390f35b620001fb6004803603810190620001f5919062001f77565b62000e72565b6040516200020a919062001f0c565b60405180910390f35b6200023160048036038101906200022b919062001b6d565b6200127e565b604051620002429392919062001fdb565b60405180910390f35b62000269600480360381019062000263919062001f77565b620012d5565b60405162000278919062001f0c565b60405180910390f35b600080838360405162000294906200176c565b620002a192919062002018565b604051809103906000f080158015620002be573d6000803e3d6000fd5b509050600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160149054906101000a900460ff16620003f4576200032181620016ba565b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548160ff0219169083151502179055506040820151816001019080519060200190620003e59291906200177a565b50606082015181600201559050505b600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600260003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206002016000828254620004ec91906200207b565b925050819055506000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060018060008282546200056a91906200207b565b925050819055507f1e91349225b89f401c5f81de959b2a1cbc472147eeefbf4e367a6b7d2dfcd3bc32604051620005a2919062001b1f565b60405180910390a18091505092915050565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201549050919050565b6000806000606060008086815481106200061f576200061e620020b6565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663909747956040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000695573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190620006c0919062002191565b9450945094509450945091939590929450565b606060008367ffffffffffffffff811115620006f457620006f3620018f2565b5b6040519080825280602002602001820160405280156200073157816020015b6200071d62001809565b815260200190600190039081620007135790505b50905060008390505b8481101562000d4757600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010184826200079391906200207b565b81548110620007a757620007a6620020b6565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828583620007e1919062002238565b81518110620007f557620007f4620020b6565b5b60200260200101516000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010184826200088391906200207b565b81548110620008975762000896620020b6565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632212dbc36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200090d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000933919062002273565b82858362000942919062002238565b81518110620009565762000955620020b6565b5b60200260200101516020018181525050600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018482620009b691906200207b565b81548110620009ca57620009c9620020b6565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a8d509ff6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000a40573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a669190620022a5565b82858362000a75919062002238565b8151811062000a895762000a88620020b6565b5b60200260200101516040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101848262000b1791906200207b565b8154811062000b2b5762000b2a620020b6565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630cb1851a6040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000ba1573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019062000bcc9190620022d7565b82858362000bdb919062002238565b8151811062000bef5762000bee620020b6565b5b602002602001015160600181905250600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101848262000c4e91906200207b565b8154811062000c625762000c61620020b6565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663eeb4e3676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000cd8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000cfe919062002273565b82858362000d0d919062002238565b8151811062000d215762000d20620020b6565b5b60200260200101516080018181525050808062000d3e9062002328565b9150506200073a565b50809150509392505050565b600080600060606000600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101868154811062000db35762000db2620020b6565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663909747956040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000e29573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019062000e54919062002191565b945094509450945094509295509295909350565b6000600154905090565b606060008367ffffffffffffffff81111562000e935762000e92620018f2565b5b60405190808252806020026020018201604052801562000ed057816020015b62000ebc62001809565b81526020019060019003908162000eb25790505b50905060008390505b848110156200127357600080858362000ef391906200207b565b8154811062000f075762000f06620020b6565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508083868462000f44919062002238565b8151811062000f585762000f57620020b6565b5b60200260200101516000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff16632212dbc36040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000fe2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001008919062002273565b83868462001017919062002238565b815181106200102b576200102a620020b6565b5b602002602001015160200181815250508073ffffffffffffffffffffffffffffffffffffffff1663a8d509ff6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001087573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620010ad9190620022a5565b838684620010bc919062002238565b81518110620010d057620010cf620020b6565b5b60200260200101516040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff16630cb1851a6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156200115a573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190620011859190620022d7565b83868462001194919062002238565b81518110620011a857620011a7620020b6565b5b6020026020010151606001819052508073ffffffffffffffffffffffffffffffffffffffff1663eeb4e3676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001203573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001229919062002273565b83868462001238919062002238565b815181106200124c576200124b620020b6565b5b602002602001015160800181815250505080806200126a9062002328565b91505062000ed9565b508091505092915050565b60026020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900460ff16908060020154905083565b606060008367ffffffffffffffff811115620012f657620012f5620018f2565b5b6040519080825280602002602001820160405280156200133357816020015b6200131f62001809565b815260200190600190039081620013155790505b50905060005b84811015620016af576000806001868460015462001358919062002238565b62001364919062002238565b62001370919062002238565b81548110620013845762001383620020b6565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905080838381518110620013c857620013c7620020b6565b5b60200260200101516000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff16632212dbc36040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001452573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001478919062002273565b8383815181106200148e576200148d620020b6565b5b602002602001015160200181815250508073ffffffffffffffffffffffffffffffffffffffff1663a8d509ff6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620014ea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620015109190620022a5565b838381518110620015265762001525620020b6565b5b60200260200101516040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff16630cb1851a6040518163ffffffff1660e01b8152600401600060405180830381865afa158015620015b0573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190620015db9190620022d7565b838381518110620015f157620015f0620020b6565b5b6020026020010151606001819052508073ffffffffffffffffffffffffffffffffffffffff1663eeb4e3676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200164c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001672919062002273565b838381518110620016885762001687620020b6565b5b60200260200101516080018181525050508080620016a69062002328565b91505062001339565b508091505092915050565b620016c462001864565b60606003839080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060405180608001604052808473ffffffffffffffffffffffffffffffffffffffff1681526020016001151581526020018281526020016000815250915050919050565b610ad5806200237683390190565b828054828255906000526020600020908101928215620017f6579160200282015b82811115620017f55782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906200179b565b5b509050620018059190620018a4565b5090565b6040518060a00160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001600081525090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160001515815260200160608152602001600081525090565b5b80821115620018bf576000816000905550600101620018a5565b5090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6200192c82620018e1565b810181811067ffffffffffffffff821117156200194e576200194d620018f2565b5b80604052505050565b600062001963620018c3565b905062001971828262001921565b919050565b600067ffffffffffffffff821115620019945762001993620018f2565b5b6200199f82620018e1565b9050602081019050919050565b82818337600083830152505050565b6000620019d2620019cc8462001976565b62001957565b905082815260208101848484011115620019f157620019f0620018dc565b5b620019fe848285620019ac565b509392505050565b600082601f83011262001a1e5762001a1d620018d7565b5b813562001a30848260208601620019bb565b91505092915050565b6000819050919050565b62001a4e8162001a39565b811462001a5a57600080fd5b50565b60008135905062001a6e8162001a43565b92915050565b6000806040838503121562001a8e5762001a8d620018cd565b5b600083013567ffffffffffffffff81111562001aaf5762001aae620018d2565b5b62001abd8582860162001a06565b925050602062001ad08582860162001a5d565b9150509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600062001b078262001ada565b9050919050565b62001b198162001afa565b82525050565b600060208201905062001b36600083018462001b0e565b92915050565b62001b478162001afa565b811462001b5357600080fd5b50565b60008135905062001b678162001b3c565b92915050565b60006020828403121562001b865762001b85620018cd565b5b600062001b968482850162001b56565b91505092915050565b62001baa8162001a39565b82525050565b600060208201905062001bc7600083018462001b9f565b92915050565b60006020828403121562001be65762001be5620018cd565b5b600062001bf68482850162001a5d565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101562001c3b57808201518184015260208101905062001c1e565b60008484015250505050565b600062001c548262001bff565b62001c60818562001c0a565b935062001c7281856020860162001c1b565b62001c7d81620018e1565b840191505092915050565b600060a08201905062001c9f600083018862001b0e565b62001cae602083018762001b9f565b62001cbd604083018662001b0e565b818103606083015262001cd1818562001c47565b905062001ce2608083018462001b9f565b9695505050505050565b60008060006060848603121562001d085762001d07620018cd565b5b600062001d188682870162001b56565b935050602062001d2b8682870162001a5d565b925050604062001d3e8682870162001a5d565b9150509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b62001d7f8162001afa565b82525050565b62001d908162001a39565b82525050565b600082825260208201905092915050565b600062001db48262001bff565b62001dc0818562001d96565b935062001dd281856020860162001c1b565b62001ddd81620018e1565b840191505092915050565b600060a08301600083015162001e02600086018262001d74565b50602083015162001e17602086018262001d85565b50604083015162001e2c604086018262001d74565b506060830151848203606086015262001e46828262001da7565b915050608083015162001e5d608086018262001d85565b508091505092915050565b600062001e76838362001de8565b905092915050565b6000602082019050919050565b600062001e988262001d48565b62001ea4818562001d53565b93508360208202850162001eb88562001d64565b8060005b8581101562001efa578484038952815162001ed8858262001e68565b945062001ee58362001e7e565b925060208a0199505060018101905062001ebc565b50829750879550505050505092915050565b6000602082019050818103600083015262001f28818462001e8b565b905092915050565b6000806040838503121562001f4a5762001f49620018cd565b5b600062001f5a8582860162001b56565b925050602062001f6d8582860162001a5d565b9150509250929050565b6000806040838503121562001f915762001f90620018cd565b5b600062001fa18582860162001a5d565b925050602062001fb48582860162001a5d565b9150509250929050565b60008115159050919050565b62001fd58162001fbe565b82525050565b600060608201905062001ff2600083018662001b0e565b62002001602083018562001fca565b62002010604083018462001b9f565b949350505050565b6000604082019050818103600083015262002034818562001c47565b905062002045602083018462001b9f565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000620020888262001a39565b9150620020958362001a39565b9250828201905080821115620020b057620020af6200204c565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081519050620020f68162001b3c565b92915050565b6000815190506200210d8162001a43565b92915050565b60006200212a620021248462001976565b62001957565b905082815260208101848484011115620021495762002148620018dc565b5b6200215684828562001c1b565b509392505050565b600082601f830112620021765762002175620018d7565b5b81516200218884826020860162002113565b91505092915050565b600080600080600060a08688031215620021b057620021af620018cd565b5b6000620021c088828901620020e5565b9550506020620021d388828901620020fc565b9450506040620021e688828901620020e5565b935050606086015167ffffffffffffffff8111156200220a5762002209620018d2565b5b62002218888289016200215e565b92505060806200222b88828901620020fc565b9150509295509295909350565b6000620022458262001a39565b9150620022528362001a39565b92508282039050818111156200226d576200226c6200204c565b5b92915050565b6000602082840312156200228c576200228b620018cd565b5b60006200229c84828501620020fc565b91505092915050565b600060208284031215620022be57620022bd620018cd565b5b6000620022ce84828501620020e5565b91505092915050565b600060208284031215620022f057620022ef620018cd565b5b600082015167ffffffffffffffff811115620023115762002310620018d2565b5b6200231f848285016200215e565b91505092915050565b6000620023358262001a39565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036200236a57620023696200204c565b5b60018201905091905056fe60806040523480156200001157600080fd5b5060405162000ad538038062000ad583398181016040528101906200003791906200026e565b32600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555042600081905550816002908162000090919062000515565b50806003819055505050620005fc565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6200010982620000be565b810181811067ffffffffffffffff821117156200012b576200012a620000cf565b5b80604052505050565b600062000140620000a0565b90506200014e8282620000fe565b919050565b600067ffffffffffffffff821115620001715762000170620000cf565b5b6200017c82620000be565b9050602081019050919050565b60005b83811015620001a95780820151818401526020810190506200018c565b60008484015250505050565b6000620001cc620001c68462000153565b62000134565b905082815260208101848484011115620001eb57620001ea620000b9565b5b620001f884828562000189565b509392505050565b600082601f830112620002185762000217620000b4565b5b81516200022a848260208601620001b5565b91505092915050565b6000819050919050565b620002488162000233565b81146200025457600080fd5b50565b60008151905062000268816200023d565b92915050565b60008060408385031215620002885762000287620000aa565b5b600083015167ffffffffffffffff811115620002a957620002a8620000af565b5b620002b78582860162000200565b9250506020620002ca8582860162000257565b9150509250929050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200032757607f821691505b6020821081036200033d576200033c620002df565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620003a77fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000368565b620003b3868362000368565b95508019841693508086168417925050509392505050565b6000819050919050565b6000620003f6620003f0620003ea8462000233565b620003cb565b62000233565b9050919050565b6000819050919050565b6200041283620003d5565b6200042a6200042182620003fd565b84845462000375565b825550505050565b600090565b6200044162000432565b6200044e81848462000407565b505050565b5b8181101562000476576200046a60008262000437565b60018101905062000454565b5050565b601f821115620004c5576200048f8162000343565b6200049a8462000358565b81016020851015620004aa578190505b620004c2620004b98562000358565b83018262000453565b50505b505050565b600082821c905092915050565b6000620004ea60001984600802620004ca565b1980831691505092915050565b6000620005058383620004d7565b9150826002028217905092915050565b6200052082620002d4565b67ffffffffffffffff8111156200053c576200053b620000cf565b5b6200054882546200030e565b620005558282856200047a565b600060209050601f8311600181146200058d576000841562000578578287015190505b620005848582620004f7565b865550620005f4565b601f1984166200059d8662000343565b60005b82811015620005c757848901518255600182019150602085019450602081019050620005a0565b86831015620005e75784890151620005e3601f891682620004d7565b8355505b6001600288020188555050505b505050505050565b6104c9806200060c6000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80630cb1851a1461005c5780632212dbc31461007a5780639097479514610098578063a8d509ff146100ba578063eeb4e367146100d8575b600080fd5b6100646100f6565b6040516100719190610327565b60405180910390f35b610082610188565b60405161008f9190610362565b60405180910390f35b6100a0610191565b6040516100b19594939291906103be565b60405180910390f35b6100c2610263565b6040516100cf9190610418565b60405180910390f35b6100e061028d565b6040516100ed9190610362565b60405180910390f35b60606002805461010590610462565b80601f016020809104026020016040519081016040528092919081815260200182805461013190610462565b801561017e5780601f106101535761010080835404028352916020019161017e565b820191906000526020600020905b81548152906001019060200180831161016157829003601f168201915b5050505050905090565b60008054905090565b60008060006060600030600054600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660026003548180546101d290610462565b80601f01602080910402602001604051908101604052809291908181526020018280546101fe90610462565b801561024b5780601f106102205761010080835404028352916020019161024b565b820191906000526020600020905b81548152906001019060200180831161022e57829003601f168201915b50505050509150945094509450945094509091929394565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000600354905090565b600081519050919050565b600082825260208201905092915050565b60005b838110156102d15780820151818401526020810190506102b6565b60008484015250505050565b6000601f19601f8301169050919050565b60006102f982610297565b61030381856102a2565b93506103138185602086016102b3565b61031c816102dd565b840191505092915050565b6000602082019050818103600083015261034181846102ee565b905092915050565b6000819050919050565b61035c81610349565b82525050565b60006020820190506103776000830184610353565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103a88261037d565b9050919050565b6103b88161039d565b82525050565b600060a0820190506103d360008301886103af565b6103e06020830187610353565b6103ed60408301866103af565b81810360608301526103ff81856102ee565b905061040e6080830184610353565b9695505050505050565b600060208201905061042d60008301846103af565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061047a57607f821691505b60208210810361048d5761048c610433565b5b5091905056fea264697066735822122096ba86e2c854094a9f7774cf59534923c219cc0ab6e812963e86557d6743467c64736f6c63430008110033a2646970667358221220b58cd7b4415159e845caf380c6ffa231afa779fa9b6af3b83d7b80ca521527a464736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/TestApp.sol b/itests/contracts/TestApp.sol new file mode 100644 index 000000000..072eb7a61 --- /dev/null +++ b/itests/contracts/TestApp.sol @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.2; +pragma experimental ABIEncoderV2; + +contract Test_contract { + uint256 timestamp; + address sender; + string text; + uint256 number; + + constructor(string memory _text, uint256 _number) { + sender = tx.origin; + timestamp = block.timestamp; + text = _text; + number = _number; + } + + function getall() + public + view + returns ( + address, + uint256, + address, + string memory, + uint256 + ) + { + return (address(this), timestamp, sender, text, number); + } + + function get_timestamp() public view returns (uint256) { + return timestamp; + } + + function get_sender() public view returns (address) { + return sender; + } + + function get_text() public view returns (string memory) { + return text; + } + + function get_number() public view returns (uint256) { + return number; + } +} + +contract App { + address[] Test_list; + uint256 Test_list_length; + + function get_Test_list_length() public view returns (uint256) { + return Test_list_length; + } + + struct Test_getter { + address _address; + uint256 timestamp; + address sender; + string text; + uint256 number; + } + + function get_Test_N(uint256 index) + public + view + returns ( + address, + uint256, + address, + string memory, + uint256 + ) + { + return Test_contract(Test_list[index]).getall(); + } + + function get_first_Test_N(uint256 count, uint256 offset) + public + view + returns (Test_getter[] memory) + { + Test_getter[] memory getters = new Test_getter[](count); + for (uint256 i = offset; i < count; i++) { + Test_contract myTest = Test_contract(Test_list[i + offset]); + getters[i - offset]._address = address(myTest); + getters[i - offset].timestamp = myTest.get_timestamp(); + getters[i - offset].sender = myTest.get_sender(); + getters[i - offset].text = myTest.get_text(); + getters[i - offset].number = myTest.get_number(); + } + return getters; + } + + function get_last_Test_N(uint256 count, uint256 offset) + public + view + returns (Test_getter[] memory) + { + Test_getter[] memory getters = new Test_getter[](count); + for (uint256 i = 0; i < count; i++) { + Test_contract myTest = + Test_contract(Test_list[Test_list_length - i - offset - 1]); + getters[i]._address = address(myTest); + + getters[i].timestamp = myTest.get_timestamp(); + getters[i].sender = myTest.get_sender(); + getters[i].text = myTest.get_text(); + getters[i].number = myTest.get_number(); + } + return getters; + } + + function get_Test_user_length(address user) public view returns (uint256) { + return user_map[user].Test_list_length; + } + + function get_Test_user_N(address user, uint256 index) + public + view + returns ( + address, + uint256, + address, + string memory, + uint256 + ) + { + return Test_contract(user_map[user].Test_list[index]).getall(); + } + + function get_last_Test_user_N( + address user, + uint256 count, + uint256 offset + ) public view returns (Test_getter[] memory) { + Test_getter[] memory getters = new Test_getter[](count); + + for (uint256 i = offset; i < count; i++) { + getters[i - offset]._address = user_map[user].Test_list[i + offset]; + getters[i - offset].timestamp = Test_contract( + user_map[user].Test_list[i + offset] + ) + .get_timestamp(); + getters[i - offset].sender = Test_contract( + user_map[user].Test_list[i + offset] + ) + .get_sender(); + getters[i - offset].text = Test_contract( + user_map[user].Test_list[i + offset] + ) + .get_text(); + getters[i - offset].number = Test_contract( + user_map[user].Test_list[i + offset] + ) + .get_number(); + } + return getters; + } + + struct UserInfo { + address owner; + bool exists; + address[] Test_list; + uint256 Test_list_length; + } + mapping(address => UserInfo) public user_map; + address[] UserInfoList; + uint256 UserInfoListLength; + + event NewTest(address sender); + + function new_Test(string memory text, uint256 number) + public + returns (address) + { + address mynew = + address(new Test_contract({_text: text, _number: number})); + + if (!user_map[tx.origin].exists) { + user_map[tx.origin] = create_user_on_new_Test(mynew); + } + user_map[tx.origin].Test_list.push(mynew); + + user_map[tx.origin].Test_list_length += 1; + + Test_list.push(mynew); + Test_list_length += 1; + + emit NewTest(tx.origin); + + return mynew; + } + + function create_user_on_new_Test(address addr) + private + returns (UserInfo memory) + { + address[] memory Test_list_; + + UserInfoList.push(addr); + return + UserInfo({ + exists: true, + owner: addr, + Test_list: Test_list_, + Test_list_length: 0 + }); + } +} diff --git a/itests/contracts/TransparentUpgradeableProxy.hex b/itests/contracts/TransparentUpgradeableProxy.hex new file mode 100644 index 000000000..d3430beee --- /dev/null +++ b/itests/contracts/TransparentUpgradeableProxy.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061256c806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200003a5760003560e01c806320965255146200003f578063f8a8fd6d1462000061575b600080fd5b620000496200006d565b604051620000589190620002a6565b60405180910390f35b6200006b62000234565b005b6000806040516200007e9062000253565b604051809103906000f0801580156200009b573d6000803e3d6000fd5b509050600081604051620000af9062000261565b620000bb919062000308565b604051809103906000f080158015620000d8573d6000803e3d6000fd5b5090506000604051620000eb906200026f565b604051809103906000f08015801562000108573d6000803e3d6000fd5b5090508173ffffffffffffffffffffffffffffffffffffffff16633659cfe6826040518263ffffffff1660e01b815260040162000146919062000308565b600060405180830381600087803b1580156200016157600080fd5b505af115801562000176573d6000803e3d6000fd5b5050505060006040516200018a906200027d565b604051809103906000f080158015620001a7573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff16633ccc0522846040518263ffffffff1660e01b8152600401620001e5919062000308565b6020604051808303816000875af115801562000205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022b91906200035b565b94505050505090565b6200023e6200006d565b6000146200025157620002506200038d565b5b565b6103f780620003bd83390190565b61174480620007b483390190565b6103ef8062001ef883390190565b61025080620022e783390190565b6000819050919050565b620002a0816200028b565b82525050565b6000602082019050620002bd600083018462000295565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620002f082620002c3565b9050919050565b6200030281620002e3565b82525050565b60006020820190506200031f6000830184620002f7565b92915050565b600080fd5b62000335816200028b565b81146200034157600080fd5b50565b60008151905062000355816200032a565b92915050565b60006020828403121562000374576200037362000325565b5b6000620003848482850162000344565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fdfe608060405234801561001057600080fd5b506103d7806100206000396000f3fe608060405234801561001057600080fd5b50600436106100455760003560e01c8063209652551461004e578063552410771461006c5780638129fc1c1461008857610046565b5b600180819055005b610056610092565b6040516100639190610218565b60405180910390f35b61008660048036038101906100819190610264565b61009c565b005b6100906100a6565b005b6000600154905090565b8060018190555050565b60008060019054906101000a900460ff161590508080156100d75750600160008054906101000a900460ff1660ff16105b8061010457506100e6306101dc565b1580156101035750600160008054906101000a900460ff1660ff16145b5b610143576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161013a90610314565b60405180910390fd5b60016000806101000a81548160ff021916908360ff1602179055508015610180576001600060016101000a81548160ff0219169083151502179055505b80156101d95760008060016101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249860016040516101d09190610386565b60405180910390a15b50565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b610212816101ff565b82525050565b600060208201905061022d6000830184610209565b92915050565b600080fd5b610241816101ff565b811461024c57600080fd5b50565b60008135905061025e81610238565b92915050565b60006020828403121561027a57610279610233565b5b60006102888482850161024f565b91505092915050565b600082825260208201905092915050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b60006102fe602e83610291565b9150610309826102a2565b604082019050919050565b6000602082019050818103600083015261032d816102f1565b9050919050565b6000819050919050565b600060ff82169050919050565b6000819050919050565b600061037061036b61036684610334565b61034b565b61033e565b9050919050565b61038081610355565b82525050565b600060208201905061039b6000830184610377565b9291505056fea2646970667358221220934a8ba055f2e0df7da7dde7999f38a4972809a218a2a064683da10ad547f1fd64736f6c63430008110033608060405260405162001744380380620017448339818101604052810190620000299190620005c7565b80604051806020016040528060008152506200004e828260006200006860201b60201c565b50506200006133620000ab60201b60201c565b50620008fd565b62000079836200010960201b60201c565b600082511180620000875750805b15620000a657620000a483836200016060201b620003361760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000dc6200019660201b60201c565b82604051620000ed9291906200060a565b60405180910390a16200010681620001fa60201b60201c565b50565b6200011a81620002ea60201b60201c565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b60606200018e83836040518060600160405280602781526020016200171d60279139620003c060201b60201c565b905092915050565b6000620001d17fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b6200045260201b620003631760201c565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036200026c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200026390620006be565b60405180910390fd5b80620002a67fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b6200045260201b620003631760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b62000300816200045c60201b6200036d1760201c565b62000342576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620003399062000756565b60405180910390fd5b806200037c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200045260201b620003631760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051620003ec9190620007f1565b600060405180830381855af49150503d806000811462000429576040519150601f19603f3d011682016040523d82523d6000602084013e6200042e565b606091505b509150915062000447868383876200047f60201b60201c565b925050509392505050565b6000819050919050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60608315620004ef576000835103620004e657620004a3856200045c60201b60201c565b620004e5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620004dc906200085a565b60405180910390fd5b5b82905062000502565b6200050183836200050a60201b60201c565b5b949350505050565b6000825111156200051e5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620005549190620008d9565b60405180910390fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200058f8262000562565b9050919050565b620005a18162000582565b8114620005ad57600080fd5b50565b600081519050620005c18162000596565b92915050565b600060208284031215620005e057620005df6200055d565b5b6000620005f084828501620005b0565b91505092915050565b620006048162000582565b82525050565b6000604082019050620006216000830185620005f9565b620006306020830184620005f9565b9392505050565b600082825260208201905092915050565b7f455243313936373a206e65772061646d696e20697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000620006a660268362000637565b9150620006b38262000648565b604082019050919050565b60006020820190508181036000830152620006d98162000697565b9050919050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b60006200073e602d8362000637565b91506200074b82620006e0565b604082019050919050565b6000602082019050818103600083015262000771816200072f565b9050919050565b600081519050919050565b600081905092915050565b60005b83811015620007ae57808201518184015260208101905062000791565b60008484015250505050565b6000620007c78262000778565b620007d3818562000783565b9350620007e58185602086016200078e565b80840191505092915050565b6000620007ff8284620007ba565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b600062000842601d8362000637565b91506200084f826200080a565b602082019050919050565b60006020820190508181036000830152620008758162000833565b9050919050565b600081519050919050565b6000601f19601f8301169050919050565b6000620008a5826200087c565b620008b1818562000637565b9350620008c38185602086016200078e565b620008ce8162000887565b840191505092915050565b60006020820190508181036000830152620008f5818462000898565b905092915050565b610e10806200090d6000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100675780634f1ef286146100835780635c60da1b1461009f5780638f283970146100bd578063f851a440146100d95761005d565b3661005d5761005b6100f7565b005b6100656100f7565b005b610081600480360381019061007c9190610916565b610111565b005b61009d600480360381019061009891906109a8565b61017f565b005b6100a761021c565b6040516100b49190610a17565b60405180910390f35b6100d760048036038101906100d29190610916565b61027b565b005b6100e16102d7565b6040516100ee9190610a17565b60405180910390f35b6100ff610390565b61010f61010a61040f565b61041e565b565b610119610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16036101735761015361049b565b61016e816040518060200160405280600081525060006104aa565b61017c565b61017b6100f7565b5b50565b610187610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff160361020e576102098383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505060016104aa565b610217565b6102166100f7565b5b505050565b6000610226610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff160361026f5761026061049b565b61026861040f565b9050610278565b6102776100f7565b5b90565b610283610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16036102cb576102bd61049b565b6102c6816104d6565b6102d4565b6102d36100f7565b5b50565b60006102e1610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff160361032a5761031b61049b565b610323610444565b9050610333565b6103326100f7565b5b90565b606061035b8383604051806060016040528060278152602001610db460279139610522565b905092915050565b6000819050919050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b610398610444565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603610405576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103fc90610adb565b60405180910390fd5b61040d6105a8565b565b60006104196105aa565b905090565b3660008037600080366000845af43d6000803e806000811461043f573d6000f35b3d6000fd5b60006104727fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b610363565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600034146104a857600080fd5b565b6104b383610601565b6000825111806104c05750805b156104d1576104cf8383610336565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6104ff610444565b8260405161050e929190610afb565b60405180910390a161051f81610650565b50565b60606000808573ffffffffffffffffffffffffffffffffffffffff168560405161054c9190610b95565b600060405180830381855af49150503d8060008114610587576040519150601f19603f3d011682016040523d82523d6000602084013e61058c565b606091505b509150915061059d86838387610730565b925050509392505050565b565b60006105d87f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b610363565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b61060a816107a5565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036106bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106b690610c1e565b60405180910390fd5b806106ec7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360001b610363565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6060831561079257600083510361078a5761074a8561036d565b610789576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161078090610c8a565b60405180910390fd5b5b82905061079d565b61079c838361085e565b5b949350505050565b6107ae8161036d565b6107ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107e490610d1c565b60405180910390fd5b8061081a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b610363565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000825111156108715781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108a59190610d91565b60405180910390fd5b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006108e3826108b8565b9050919050565b6108f3816108d8565b81146108fe57600080fd5b50565b600081359050610910816108ea565b92915050565b60006020828403121561092c5761092b6108ae565b5b600061093a84828501610901565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261096857610967610943565b5b8235905067ffffffffffffffff81111561098557610984610948565b5b6020830191508360018202830111156109a1576109a061094d565b5b9250929050565b6000806000604084860312156109c1576109c06108ae565b5b60006109cf86828701610901565b935050602084013567ffffffffffffffff8111156109f0576109ef6108b3565b5b6109fc86828701610952565b92509250509250925092565b610a11816108d8565b82525050565b6000602082019050610a2c6000830184610a08565b92915050565b600082825260208201905092915050565b7f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60008201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760208201527f6574000000000000000000000000000000000000000000000000000000000000604082015250565b6000610ac5604283610a32565b9150610ad082610a43565b606082019050919050565b60006020820190508181036000830152610af481610ab8565b9050919050565b6000604082019050610b106000830185610a08565b610b1d6020830184610a08565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610b58578082015181840152602081019050610b3d565b60008484015250505050565b6000610b6f82610b24565b610b798185610b2f565b9350610b89818560208601610b3a565b80840191505092915050565b6000610ba18284610b64565b915081905092915050565b7f455243313936373a206e65772061646d696e20697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000610c08602683610a32565b9150610c1382610bac565b604082019050919050565b60006020820190508181036000830152610c3781610bfb565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000610c74601d83610a32565b9150610c7f82610c3e565b602082019050919050565b60006020820190508181036000830152610ca381610c67565b9050919050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b6000610d06602d83610a32565b9150610d1182610caa565b604082019050919050565b60006020820190508181036000830152610d3581610cf9565b9050919050565b600081519050919050565b6000601f19601f8301169050919050565b6000610d6382610d3c565b610d6d8185610a32565b9350610d7d818560208601610b3a565b610d8681610d47565b840191505092915050565b60006020820190508181036000830152610dab8184610d58565b90509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220e09e1af8aa595ace2cac727dfa78b8a1c201fdfb2f2b3364541017dec279304b64736f6c63430008110033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564608060405234801561001057600080fd5b506103cf806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063209652551461004657806355241077146100645780638129fc1c14610080575b600080fd5b61004e61008a565b60405161005b9190610210565b60405180910390f35b61007e6004803603810190610079919061025c565b610094565b005b61008861009e565b005b6000600154905090565b8060018190555050565b60008060019054906101000a900460ff161590508080156100cf5750600160008054906101000a900460ff1660ff16105b806100fc57506100de306101d4565b1580156100fb5750600160008054906101000a900460ff1660ff16145b5b61013b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101329061030c565b60405180910390fd5b60016000806101000a81548160ff021916908360ff1602179055508015610178576001600060016101000a81548160ff0219169083151502179055505b80156101d15760008060016101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249860016040516101c8919061037e565b60405180910390a15b50565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b61020a816101f7565b82525050565b60006020820190506102256000830184610201565b92915050565b600080fd5b610239816101f7565b811461024457600080fd5b50565b60008135905061025681610230565b92915050565b6000602082840312156102725761027161022b565b5b600061028084828501610247565b91505092915050565b600082825260208201905092915050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b60006102f6602e83610289565b91506103018261029a565b604082019050919050565b60006020820190508181036000830152610325816102e9565b9050919050565b6000819050919050565b600060ff82169050919050565b6000819050919050565b600061036861036361035e8461032c565b610343565b610336565b9050919050565b6103788161034d565b82525050565b6000602082019050610393600083018461036f565b9291505056fea2646970667358221220f2a2169e9ff5b35281e8323276adc729174eda42cfb39d55a7943efc6c70485164736f6c63430008110033608060405234801561001057600080fd5b50610230806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80633ccc052214610030575b600080fd5b61004a60048036038101906100459190610140565b610060565b6040516100579190610186565b60405180910390f35b6000808290508073ffffffffffffffffffffffffffffffffffffffff1663209652556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100d591906101cd565b915050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061010d826100e2565b9050919050565b61011d81610102565b811461012857600080fd5b50565b60008135905061013a81610114565b92915050565b600060208284031215610156576101556100dd565b5b60006101648482850161012b565b91505092915050565b6000819050919050565b6101808161016d565b82525050565b600060208201905061019b6000830184610177565b92915050565b6101aa8161016d565b81146101b557600080fd5b50565b6000815190506101c7816101a1565b92915050565b6000602082840312156101e3576101e26100dd565b5b60006101f1848285016101b8565b9150509291505056fea2646970667358221220b98dab0efb759c0eea90d951be7f01d309e1c04588076d429d10680bddf1351864736f6c63430008110033a264697066735822122024666606126645f287960fe9548cc80d17258ad514d74180c7af0e1ee954bd4364736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/TransparentUpgradeableProxy.sol b/itests/contracts/TransparentUpgradeableProxy.sol new file mode 100644 index 000000000..5bb3d0e5d --- /dev/null +++ b/itests/contracts/TransparentUpgradeableProxy.sol @@ -0,0 +1,590 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +abstract contract Initializable { + uint8 private _initialized; + + bool private _initializing; + + event Initialized(uint8 version); + + modifier initializer() { + bool isTopLevelCall = !_initializing; + require( + (isTopLevelCall && _initialized < 1) || + (!Address.isContract(address(this)) && _initialized == 1), + "Initializable: contract is already initialized" + ); + _initialized = 1; + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(1); + } + } + + modifier reinitializer(uint8 version) { + require( + !_initializing && _initialized < version, + "Initializable: contract is already initialized" + ); + _initialized = version; + _initializing = true; + _; + _initializing = false; + emit Initialized(version); + } + + modifier onlyInitializing() { + require(_initializing, "Initializable: contract is not initializing"); + _; + } + + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized != type(uint8).max) { + _initialized = type(uint8).max; + emit Initialized(type(uint8).max); + } + } + + function _getInitializedVersion() internal view returns (uint8) { + return _initialized; + } + + function _isInitializing() internal view returns (bool) { + return _initializing; + } +} + +contract Implementation4 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } + + fallback() external { + _value = 1; + } +} + +contract Implementation2 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } +} + +abstract contract Proxy { + function _delegate(address implementation) internal virtual { + assembly { + calldatacopy(0, 0, calldatasize()) + + let result := delegatecall( + gas(), + implementation, + 0, + calldatasize(), + 0, + 0 + ) + + returndatacopy(0, 0, returndatasize()) + + switch result + case 0 { + revert(0, returndatasize()) + } + default { + return(0, returndatasize()) + } + } + } + + function _implementation() internal view virtual returns (address); + + function _fallback() internal virtual { + _beforeFallback(); + _delegate(_implementation()); + } + + fallback() external payable virtual { + _fallback(); + } + + receive() external payable virtual { + _fallback(); + } + + function _beforeFallback() internal virtual {} +} + +interface IBeacon { + function implementation() external view returns (address); +} + +interface IERC1822Proxiable { + function proxiableUUID() external view returns (bytes32); +} + +library Address { + function isContract(address account) internal view returns (bool) { + return account.code.length > 0; + } + + function sendValue(address payable recipient, uint256 amount) internal { + require( + address(this).balance >= amount, + "Address: insufficient balance" + ); + + (bool success, ) = recipient.call{value: amount}(""); + require( + success, + "Address: unable to send value, recipient may have reverted" + ); + } + + function functionCall( + address target, + bytes memory data + ) internal returns (bytes memory) { + return + functionCallWithValue( + target, + data, + 0, + "Address: low-level call failed" + ); + } + + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return + functionCallWithValue( + target, + data, + value, + "Address: low-level call with value failed" + ); + } + + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require( + address(this).balance >= value, + "Address: insufficient balance for call" + ); + (bool success, bytes memory returndata) = target.call{value: value}( + data + ); + return + verifyCallResultFromTarget( + target, + success, + returndata, + errorMessage + ); + } + + function functionStaticCall( + address target, + bytes memory data + ) internal view returns (bytes memory) { + return + functionStaticCall( + target, + data, + "Address: low-level static call failed" + ); + } + + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + (bool success, bytes memory returndata) = target.staticcall(data); + return + verifyCallResultFromTarget( + target, + success, + returndata, + errorMessage + ); + } + + function functionDelegateCall( + address target, + bytes memory data + ) internal returns (bytes memory) { + return + functionDelegateCall( + target, + data, + "Address: low-level delegate call failed" + ); + } + + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + (bool success, bytes memory returndata) = target.delegatecall(data); + return + verifyCallResultFromTarget( + target, + success, + returndata, + errorMessage + ); + } + + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata, + string memory errorMessage + ) internal view returns (bytes memory) { + if (success) { + if (returndata.length == 0) { + require(isContract(target), "Address: call to non-contract"); + } + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + function _revert( + bytes memory returndata, + string memory errorMessage + ) private pure { + if (returndata.length > 0) { + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } +} + +library StorageSlot { + struct AddressSlot { + address value; + } + + struct BooleanSlot { + bool value; + } + + struct Bytes32Slot { + bytes32 value; + } + + struct Uint256Slot { + uint256 value; + } + + function getAddressSlot( + bytes32 slot + ) internal pure returns (AddressSlot storage r) { + assembly { + r.slot := slot + } + } + + function getBooleanSlot( + bytes32 slot + ) internal pure returns (BooleanSlot storage r) { + assembly { + r.slot := slot + } + } + + function getBytes32Slot( + bytes32 slot + ) internal pure returns (Bytes32Slot storage r) { + assembly { + r.slot := slot + } + } + + function getUint256Slot( + bytes32 slot + ) internal pure returns (Uint256Slot storage r) { + assembly { + r.slot := slot + } + } +} + +abstract contract ERC1967Upgrade { + bytes32 private constant _ROLLBACK_SLOT = + 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; + + bytes32 internal constant _IMPLEMENTATION_SLOT = + 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + event Upgraded(address indexed implementation); + + function _getImplementation() internal view returns (address) { + return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; + } + + function _setImplementation(address newImplementation) private { + require( + Address.isContract(newImplementation), + "ERC1967: new implementation is not a contract" + ); + StorageSlot + .getAddressSlot(_IMPLEMENTATION_SLOT) + .value = newImplementation; + } + + function _upgradeTo(address newImplementation) internal { + _setImplementation(newImplementation); + emit Upgraded(newImplementation); + } + + function _upgradeToAndCall( + address newImplementation, + bytes memory data, + bool forceCall + ) internal { + _upgradeTo(newImplementation); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(newImplementation, data); + } + } + + function _upgradeToAndCallUUPS( + address newImplementation, + bytes memory data, + bool forceCall + ) internal { + if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { + _setImplementation(newImplementation); + } else { + try IERC1822Proxiable(newImplementation).proxiableUUID() returns ( + bytes32 slot + ) { + require( + slot == _IMPLEMENTATION_SLOT, + "ERC1967Upgrade: unsupported proxiableUUID" + ); + } catch { + revert("ERC1967Upgrade: new implementation is not UUPS"); + } + _upgradeToAndCall(newImplementation, data, forceCall); + } + } + + bytes32 internal constant _ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + event AdminChanged(address previousAdmin, address newAdmin); + + function _getAdmin() internal view returns (address) { + return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; + } + + function _setAdmin(address newAdmin) private { + require( + newAdmin != address(0), + "ERC1967: new admin is the zero address" + ); + StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; + } + + function _changeAdmin(address newAdmin) internal { + emit AdminChanged(_getAdmin(), newAdmin); + _setAdmin(newAdmin); + } + + bytes32 internal constant _BEACON_SLOT = + 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; + + event BeaconUpgraded(address indexed beacon); + + function _getBeacon() internal view returns (address) { + return StorageSlot.getAddressSlot(_BEACON_SLOT).value; + } + + function _setBeacon(address newBeacon) private { + require( + Address.isContract(newBeacon), + "ERC1967: new beacon is not a contract" + ); + require( + Address.isContract(IBeacon(newBeacon).implementation()), + "ERC1967: beacon implementation is not a contract" + ); + StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; + } + + function _upgradeBeaconToAndCall( + address newBeacon, + bytes memory data, + bool forceCall + ) internal { + _setBeacon(newBeacon); + emit BeaconUpgraded(newBeacon); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall( + IBeacon(newBeacon).implementation(), + data + ); + } + } +} + +contract ERC1967Proxy is Proxy, ERC1967Upgrade { + constructor(address _logic, bytes memory _data) payable { + _upgradeToAndCall(_logic, _data, false); + } + + function _implementation() + internal + view + virtual + override + returns (address impl) + { + return ERC1967Upgrade._getImplementation(); + } +} + +contract TransparentUpgradeableProxy is ERC1967Proxy { + constructor(address _logic) payable ERC1967Proxy(_logic, "") { + _changeAdmin(msg.sender); + } + + modifier ifAdmin() { + if (msg.sender == _getAdmin()) { + _; + } else { + _fallback(); + } + } + + function admin() external payable ifAdmin returns (address admin_) { + _requireZeroValue(); + admin_ = _getAdmin(); + } + + function implementation() + external + payable + ifAdmin + returns (address implementation_) + { + _requireZeroValue(); + implementation_ = _implementation(); + } + + function changeAdmin(address newAdmin) external payable virtual ifAdmin { + _requireZeroValue(); + _changeAdmin(newAdmin); + } + + function upgradeTo(address newImplementation) external payable ifAdmin { + _requireZeroValue(); + _upgradeToAndCall(newImplementation, bytes(""), false); + } + + function upgradeToAndCall( + address newImplementation, + bytes calldata data + ) external payable ifAdmin { + _upgradeToAndCall(newImplementation, data, true); + } + + function _admin() internal view virtual returns (address) { + return _getAdmin(); + } + + function _beforeFallback() internal virtual override { + require( + msg.sender != _getAdmin(), + "TransparentUpgradeableProxy: admin cannot fallback to proxy target" + ); + super._beforeFallback(); + } + + function _requireZeroValue() private { + require(msg.value == 0); + } +} + +contract TestHelper { + function getValue(address proxyAddress) public returns (uint256) { + Implementation2 proxyInstance2 = Implementation2(proxyAddress); + return proxyInstance2.getValue(); + } +} + +contract TransparentUpgradeableProxyTestRunner { + function test() public { + assert(0 == getValue()); + } + + function getValue() public returns (uint256) { + Implementation4 instance4 = new Implementation4(); + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(instance4) + ); + Implementation2 instance2 = new Implementation2(); + proxy.upgradeTo(address(instance2)); + //use helper because proxy admin can't call getValue() + TestHelper h = new TestHelper(); + return h.getValue(address(proxy)); + } +} diff --git a/itests/contracts/ValueSender.hex b/itests/contracts/ValueSender.hex new file mode 100644 index 000000000..ed69dacdb --- /dev/null +++ b/itests/contracts/ValueSender.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506106dc806100206000396000f3fe60806040526004361061002d5760003560e01c8063dbdc275d14610072578063fd75295a1461009d5761006d565b3661006d577f34fb9cb8f63eaccc6c0beefc202db703e529c3bf9ce83f485b398af7fd679308333460405161006392919061020f565b60405180910390a1005b600080fd5b34801561007e57600080fd5b506100876100b9565b6040516100949190610238565b60405180910390f35b6100b760048036038101906100b29190610296565b610125565b005b6000806040516100c8906101a8565b604051809103906000f0801580156100e4573d6000803e3d6000fd5b5090507f8db3b20eed31d927a4f613b5c11765212e129cf726d025649650665569ea683b816040516101169190610238565b60405180910390a18091505090565b7f34fb9cb8f63eaccc6c0beefc202db703e529c3bf9ce83f485b398af7fd6793088134604051610156929190610322565b60405180910390a18073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f193505050501580156101a4573d6000803e3d6000fd5b5050565b61035b8061034c83390190565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101e0826101b5565b9050919050565b6101f0816101d5565b82525050565b6000819050919050565b610209816101f6565b82525050565b600060408201905061022460008301856101e7565b6102316020830184610200565b9392505050565b600060208201905061024d60008301846101e7565b92915050565b600080fd5b6000610263826101b5565b9050919050565b61027381610258565b811461027e57600080fd5b50565b6000813590506102908161026a565b92915050565b6000602082840312156102ac576102ab610253565b5b60006102ba84828501610281565b91505092915050565b6000819050919050565b60006102e86102e36102de846101b5565b6102c3565b6101b5565b9050919050565b60006102fa826102cd565b9050919050565b600061030c826102ef565b9050919050565b61031c81610301565b82525050565b60006040820190506103376000830185610313565b6103446020830184610200565b939250505056fe608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102fb806100606000396000f3fe60806040526004361061002d5760003560e01c806337cb6570146100725780639cb8a26a1461007c5761006d565b3661006d577fe1494f56a1ccfd8c7361f2ca5b8fd2b1a2fe11773821ac29534f09f4a0637d603334604051610063929190610214565b60405180910390a1005b600080fd5b61007a610093565b005b34801561008857600080fd5b50610091610155565b005b7f76cff203b0794a9e9013657ecb172f2d6e8de5941fd11a6bfbc0fb6014a5f07960008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16476040516100e492919061029c565b60405180910390a160008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015610152573d6000803e3d6000fd5b50565b7f1cbd47e7b0f55dc1a45ba8ebada53eaa1712b3e3e86f49a12c008ff22334569060405160405180910390a160008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101e5826101ba565b9050919050565b6101f5816101da565b82525050565b6000819050919050565b61020e816101fb565b82525050565b600060408201905061022960008301856101ec565b6102366020830184610205565b9392505050565b6000819050919050565b600061026261025d610258846101ba565b61023d565b6101ba565b9050919050565b600061027482610247565b9050919050565b600061028682610269565b9050919050565b6102968161027b565b82525050565b60006040820190506102b1600083018561028d565b6102be6020830184610205565b939250505056fea2646970667358221220bdf21908b1c91973a8440fe81130e0077cf83c8f8e9a053d8a0c3063391aa40764736f6c63430008110033a26469706673582212202e514fe078dfcf4f1142a088c57cfa71ada74d72ee0cc4a46b7e1141cdbaeeed64736f6c63430008110033 \ No newline at end of file diff --git a/itests/contracts/ValueSender.sol b/itests/contracts/ValueSender.sol new file mode 100644 index 000000000..1be682b25 --- /dev/null +++ b/itests/contracts/ValueSender.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.17; + +contract A { + event LogCreateB(address _bAddress); + event LogSendEthA(address _bAddress, uint _value); + event LogReceiveEthA(address _bAddress, uint _value); + + // Function to create a new instance of contract B and return its address + function createB() public returns (address) { + address bAddress = address(new B()); + emit LogCreateB(bAddress); + return bAddress; + } + + // Payable method to accept eth and an address for B and send the eth to B + function sendEthToB(address payable _bAddress) public payable { + emit LogSendEthA(_bAddress, msg.value); + _bAddress.transfer(msg.value); + } + + // Payable function to accept the eth + receive() external payable { + emit LogSendEthA(msg.sender, msg.value); + } +} + +contract B { + event LogSelfDestruct(); + event LogSendEthToA(address _to, uint _value); + event LogReceiveEth(address from, uint value); + address payable creator; + + constructor(){ + creator = payable(msg.sender); + } + + // Payable function to accept the eth + receive() external payable { + emit LogReceiveEth(msg.sender, msg.value); + } + + // Method to send ether to contract A + function sendEthToA() public payable { + emit LogSendEthToA(creator,address(this).balance); + creator.transfer(address(this).balance); + } + + // Self destruct method to send eth to its creator + function selfDestruct() public { + emit LogSelfDestruct(); + selfdestruct(creator); + } +} diff --git a/itests/contracts/compile.sh b/itests/contracts/compile.sh new file mode 100644 index 000000000..31bff4b68 --- /dev/null +++ b/itests/contracts/compile.sh @@ -0,0 +1,23 @@ +set -eu +set -o pipefail + +#use the solc compiler https://docs.soliditylang.org/en/v0.8.17/installing-solidity.html +# to compile all of the .sol files to their corresponding evm binary files stored as .hex +# solc outputs to stdout a format that we just want to grab the last line of and then remove the trailing newline on that line + +find . -maxdepth 1 -name \*.sol -print0 | + xargs -0 -I{} bash -euc -o pipefail 'solc --bin {} |tail -n1 | tr -d "\n" > $(echo {} | sed -e s/.sol$/.hex/)' + + + +#for these contracts we have 2 contracts in the same solidity file +#this command grabs the correct bytecode for us +for filename in Constructor TestApp ValueSender Create2Factory DeployValueTest; do + echo $filename + solc --bin $filename.sol | tail -n5|head -n1 | tr -d "\n" > $filename.hex +done + +for filename in TransparentUpgradeableProxy ; do + echo $filename + solc --bin $filename.sol | tail -n1| tr -d "\n" > $filename.hex +done diff --git a/itests/contracts/events.asm b/itests/contracts/events.asm new file mode 100644 index 000000000..ab96fcedd --- /dev/null +++ b/itests/contracts/events.asm @@ -0,0 +1,47 @@ +# https://github.com/filecoin-project/builtin-actors/blob/b1ba61053de2ceaddd5116e87823d20a8f5e38d7/actors/evm/tests/events.rs +# method dispatch: +# - 0x00000000 -> log_zero_data +# - 0x00000001 -> log_zero_nodata +# - 0x00000002 -> log_four_data +%dispatch_begin() +%dispatch(0x00, log_zero_data) +%dispatch(0x01, log_zero_nodata) +%dispatch(0x02, log_four_data) +%dispatch_end() +#### log a zero topic event with data +log_zero_data: +jumpdest +push8 0x1122334455667788 +push1 0x00 +mstore +push1 0x08 +push1 0x18 ## index 24 into memory as mstore writes a full word +log0 +push1 0x00 +push1 0x00 +return +#### log a zero topic event with no data +log_zero_nodata: +jumpdest +push1 0x00 +push1 0x00 +log0 +push1 0x00 +push1 0x00 +return +#### log a four topic event with data +log_four_data: +jumpdest +push8 0x1122334455667788 +push1 0x00 +mstore +push4 0x4444 +push3 0x3333 +push2 0x2222 +push2 0x1111 +push1 0x08 +push1 0x18 ## index 24 into memory as mstore writes a full word +log4 +push1 0x00 +push1 0x00 +return diff --git a/itests/contracts/events.bin b/itests/contracts/events.bin new file mode 100644 index 000000000..31abec334 --- /dev/null +++ b/itests/contracts/events.bin @@ -0,0 +1 @@ +63000000678063000000116000396000f360003560e01c80600014601f578060011460365780600214604157600080fd5b67112233445566778860005260086018a060006000f35b60006000a060006000f35b67112233445566778860005263000044446200333361222261111160086018a460006000f3 \ No newline at end of file diff --git a/itests/deals_padding_test.go b/itests/deals_padding_test.go index 3535a1227..aaca45360 100644 --- a/itests/deals_padding_test.go +++ b/itests/deals_padding_test.go @@ -33,7 +33,7 @@ func TestDealPadding(t *testing.T) { dh := kit.NewDealHarness(t, client, miner, miner) ctx := context.Background() - client.WaitTillChain(ctx, kit.BlockMinedBy(miner.ActorAddr)) + client.WaitTillChain(ctx, kit.BlocksMinedByAll(miner.ActorAddr)) // Create a random file, would originally be a 256-byte sector res, inFile := client.CreateImportFile(ctx, 1, 200) diff --git a/itests/deals_partial_retrieval_dm-level_test.go b/itests/deals_partial_retrieval_dm-level_test.go index f56d64026..246541229 100644 --- a/itests/deals_partial_retrieval_dm-level_test.go +++ b/itests/deals_partial_retrieval_dm-level_test.go @@ -10,8 +10,8 @@ import ( "testing" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/ipld/go-car" textselector "github.com/ipld/go-ipld-selector-text-lite" "github.com/stretchr/testify/require" diff --git a/itests/deals_partial_retrieval_test.go b/itests/deals_partial_retrieval_test.go index 0bbf23da0..e2dae9aff 100644 --- a/itests/deals_partial_retrieval_test.go +++ b/itests/deals_partial_retrieval_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/ipld/go-car" "github.com/stretchr/testify/require" "golang.org/x/xerrors" diff --git a/itests/deals_power_test.go b/itests/deals_power_test.go index 1ca28c6fd..57483cde7 100644 --- a/itests/deals_power_test.go +++ b/itests/deals_power_test.go @@ -52,7 +52,7 @@ func TestFirstDealEnablesMining(t *testing.T) { providerMined := make(chan struct{}) go func() { - _ = client.WaitTillChain(ctx, kit.BlockMinedBy(provider.ActorAddr)) + _ = client.WaitTillChain(ctx, kit.BlocksMinedByAll(provider.ActorAddr)) close(providerMined) }() diff --git a/itests/decode_params_test.go b/itests/decode_params_test.go new file mode 100644 index 000000000..6a4a8c681 --- /dev/null +++ b/itests/decode_params_test.go @@ -0,0 +1,124 @@ +// stm: #integration +package itests + +import ( + "bytes" + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/builtin/v10/eam" + "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/cli" +) + +type marshalable interface { + cbor.Marshaler + cbor.Unmarshaler +} + +type testCase struct { + ActorKey string + MethodNum abi.MethodNum + retVal marshalable +} + +// Used './lotus state replay --show-trace ' to get params/return to decode. +func TestDecodeParams(t *testing.T) { + testCborBytes := abi.CborBytes([]byte{1, 2, 3}) + + testCases := []testCase{ + { + ActorKey: manifest.EvmKey, + MethodNum: builtin.MethodsEVM.InvokeContract, + retVal: &testCborBytes, + }, + { + ActorKey: manifest.EamKey, + MethodNum: builtin.MethodsEAM.CreateExternal, + retVal: &testCborBytes, + }, + } + + for _, _tc := range testCases { + tc := _tc + t.Run(tc.ActorKey+" "+tc.MethodNum.String(), func(t *testing.T) { + av, err := actorstypes.VersionForNetwork(build.TestNetworkVersion) + require.NoError(t, err) + actorCodeCid, found := actors.GetActorCodeID(av, tc.ActorKey) + require.True(t, found) + + buf := bytes.NewBuffer(nil) + if err := tc.retVal.MarshalCBOR(buf); err != nil { + t.Fatal(err) + } + + paramString, err := cli.JsonParams(actorCodeCid, tc.MethodNum, buf.Bytes()) + require.NoError(t, err) + + jsonParams, err := json.MarshalIndent(tc.retVal, "", " ") + require.NoError(t, err) + require.Equal(t, string(jsonParams), paramString) + }) + } +} + +func TestDecodeReturn(t *testing.T) { + testCborBytes := abi.CborBytes([]byte{1, 2, 3}) + + robustAddr, err := address.NewIDAddress(12345) + require.NoError(t, err) + + //ethAddr, err := ethtypes.ParseEthAddress("d4c5fb16488Aa48081296299d54b0c648C9333dA") + //require.NoError(t, err) + + testReturn := eam.CreateExternalReturn{ + ActorID: 12345, + RobustAddress: &robustAddr, + EthAddress: [20]byte{}, + } + + testCases := []testCase{ + { + ActorKey: manifest.EvmKey, + MethodNum: builtin.MethodsEVM.InvokeContract, + retVal: &testCborBytes, + }, + { + ActorKey: manifest.EamKey, + MethodNum: builtin.MethodsEAM.CreateExternal, + retVal: &testReturn, + }, + } + + for _, _tc := range testCases { + tc := _tc + t.Run(tc.ActorKey+" "+tc.MethodNum.String(), func(t *testing.T) { + av, err := actorstypes.VersionForNetwork(build.TestNetworkVersion) + require.NoError(t, err) + actorCodeCid, found := actors.GetActorCodeID(av, tc.ActorKey) + require.True(t, found) + + buf := bytes.NewBuffer(nil) + if err := tc.retVal.MarshalCBOR(buf); err != nil { + t.Fatal(err) + } + + returnString, err := cli.JsonReturn(actorCodeCid, tc.MethodNum, buf.Bytes()) + require.NoError(t, err) + + jsonReturn, err := json.MarshalIndent(tc.retVal, "", " ") + require.NoError(t, err) + require.Equal(t, string(jsonReturn), returnString) + }) + } +} diff --git a/itests/eth_account_abstraction_test.go b/itests/eth_account_abstraction_test.go new file mode 100644 index 000000000..8d92d0a04 --- /dev/null +++ b/itests/eth_account_abstraction_test.go @@ -0,0 +1,370 @@ +package itests + +import ( + "context" + "encoding/hex" + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + builtin2 "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/builtin/v10/eam" + "github.com/filecoin-project/go-state-types/exitcode" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/chain/wallet/key" + "github.com/filecoin-project/lotus/itests/kit" +) + +// TestEthAccountAbstraction goes over the placeholder creation and promotion workflow: +// - an placeholder is created when it receives a message +// - the placeholder turns into an EOA when it sends a message +func TestEthAccountAbstraction(t *testing.T) { + kit.QuietMiningLogs() + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + secpKey, err := key.GenerateKey(types.KTDelegated) + require.NoError(t, err) + + placeholderAddress, err := client.WalletImport(ctx, &secpKey.KeyInfo) + require.NoError(t, err) + + // create an placeholder actor at the target address + msgCreatePlaceholder := &types.Message{ + From: client.DefaultKey.Address, + To: placeholderAddress, + Value: abi.TokenAmount(types.MustParseFIL("100")), + } + smCreatePlaceholder, err := client.MpoolPushMessage(ctx, msgCreatePlaceholder, nil) + require.NoError(t, err) + mLookup, err := client.StateWaitMsg(ctx, smCreatePlaceholder.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(t, err) + + require.True(t, mLookup.Receipt.ExitCode.IsSuccess()) + + // confirm the placeholder is an placeholder + placeholderActor, err := client.StateGetActor(ctx, placeholderAddress, types.EmptyTSK) + require.NoError(t, err) + + require.Equal(t, uint64(0), placeholderActor.Nonce) + require.True(t, builtin.IsPlaceholderActor(placeholderActor.Code)) + require.Equal(t, msgCreatePlaceholder.Value, placeholderActor.Balance) + + // send a message from the placeholder address + msgFromPlaceholder := &types.Message{ + From: placeholderAddress, + // self-send because an "eth tx payload" can't be to a filecoin address? + To: placeholderAddress, + Method: builtin2.MethodsEVM.InvokeContract, + } + msgFromPlaceholder, err = client.GasEstimateMessageGas(ctx, msgFromPlaceholder, nil, types.EmptyTSK) + require.NoError(t, err) + + txArgs, err := ethtypes.EthTxArgsFromUnsignedEthMessage(msgFromPlaceholder) + require.NoError(t, err) + + digest, err := txArgs.ToRlpUnsignedMsg() + require.NoError(t, err) + + siggy, err := client.WalletSign(ctx, placeholderAddress, digest) + require.NoError(t, err) + + smFromPlaceholderCid, err := client.MpoolPush(ctx, &types.SignedMessage{Message: *msgFromPlaceholder, Signature: *siggy}) + require.NoError(t, err) + + mLookup, err = client.StateWaitMsg(ctx, smFromPlaceholderCid, 3, api.LookbackNoLimit, true) + require.NoError(t, err) + require.True(t, mLookup.Receipt.ExitCode.IsSuccess()) + + // confirm ugly Placeholder duckling has turned into a beautiful EthAccount swan + + eoaActor, err := client.StateGetActor(ctx, placeholderAddress, types.EmptyTSK) + require.NoError(t, err) + + require.False(t, builtin.IsPlaceholderActor(eoaActor.Code)) + require.True(t, builtin.IsEthAccountActor(eoaActor.Code)) + require.Equal(t, uint64(1), eoaActor.Nonce) + + // Send another message, it should succeed without any code CID changes + + msgFromPlaceholder = &types.Message{ + From: placeholderAddress, + To: placeholderAddress, + Method: builtin2.MethodsEVM.InvokeContract, + Nonce: 1, + } + + msgFromPlaceholder, err = client.GasEstimateMessageGas(ctx, msgFromPlaceholder, nil, types.EmptyTSK) + require.NoError(t, err) + + txArgs, err = ethtypes.EthTxArgsFromUnsignedEthMessage(msgFromPlaceholder) + require.NoError(t, err) + + digest, err = txArgs.ToRlpUnsignedMsg() + require.NoError(t, err) + + siggy, err = client.WalletSign(ctx, placeholderAddress, digest) + require.NoError(t, err) + + smFromPlaceholderCid, err = client.MpoolPush(ctx, &types.SignedMessage{Message: *msgFromPlaceholder, Signature: *siggy}) + require.NoError(t, err) + + mLookup, err = client.StateWaitMsg(ctx, smFromPlaceholderCid, 3, api.LookbackNoLimit, true) + require.NoError(t, err) + require.True(t, mLookup.Receipt.ExitCode.IsSuccess()) + + // confirm no changes in code CID + + eoaActor, err = client.StateGetActor(ctx, placeholderAddress, types.EmptyTSK) + require.NoError(t, err) + require.Equal(t, uint64(2), eoaActor.Nonce) + + require.False(t, builtin.IsPlaceholderActor(eoaActor.Code)) + require.True(t, builtin.IsEthAccountActor(eoaActor.Code)) +} + +// Tests that an placeholder turns into an EthAccout even if the message fails +func TestEthAccountAbstractionFailure(t *testing.T) { + kit.QuietMiningLogs() + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + secpKey, err := key.GenerateKey(types.KTDelegated) + require.NoError(t, err) + + placeholderAddress, err := client.WalletImport(ctx, &secpKey.KeyInfo) + require.NoError(t, err) + + // create a placeholder actor at the target address + msgCreatePlaceholder := &types.Message{ + From: client.DefaultKey.Address, + To: placeholderAddress, + Value: abi.TokenAmount(types.MustParseFIL("100")), + Method: builtin2.MethodsEVM.InvokeContract, + } + smCreatePlaceholder, err := client.MpoolPushMessage(ctx, msgCreatePlaceholder, nil) + require.NoError(t, err) + mLookup, err := client.StateWaitMsg(ctx, smCreatePlaceholder.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(t, err) + require.True(t, mLookup.Receipt.ExitCode.IsSuccess()) + + // confirm the placeholder is an placeholder + placeholderActor, err := client.StateGetActor(ctx, placeholderAddress, types.EmptyTSK) + require.NoError(t, err) + + require.Equal(t, uint64(0), placeholderActor.Nonce) + require.True(t, builtin.IsPlaceholderActor(placeholderActor.Code)) + require.Equal(t, msgCreatePlaceholder.Value, placeholderActor.Balance) + + // send a message from the placeholder address + msgFromPlaceholder := &types.Message{ + From: placeholderAddress, + To: placeholderAddress, + Value: abi.TokenAmount(types.MustParseFIL("20")), + Method: builtin2.MethodsEVM.InvokeContract, + } + msgFromPlaceholder, err = client.GasEstimateMessageGas(ctx, msgFromPlaceholder, nil, types.EmptyTSK) + require.NoError(t, err) + + msgFromPlaceholder.Value = abi.TokenAmount(types.MustParseFIL("1000")) + txArgs, err := ethtypes.EthTxArgsFromUnsignedEthMessage(msgFromPlaceholder) + require.NoError(t, err) + + digest, err := txArgs.ToRlpUnsignedMsg() + require.NoError(t, err) + + siggy, err := client.WalletSign(ctx, placeholderAddress, digest) + require.NoError(t, err) + + smFromPlaceholderCid, err := client.MpoolPush(ctx, &types.SignedMessage{Message: *msgFromPlaceholder, Signature: *siggy}) + require.NoError(t, err) + + mLookup, err = client.StateWaitMsg(ctx, smFromPlaceholderCid, 3, api.LookbackNoLimit, true) + require.NoError(t, err) + // message should have failed because we didn't have enough $$$ + require.Equal(t, exitcode.SysErrInsufficientFunds, mLookup.Receipt.ExitCode) + + // BUT, ugly Placeholder duckling should have turned into a beautiful EthAccount swan anyway + + eoaActor, err := client.StateGetActor(ctx, placeholderAddress, types.EmptyTSK) + require.NoError(t, err) + + require.False(t, builtin.IsPlaceholderActor(eoaActor.Code)) + require.True(t, builtin.IsEthAccountActor(eoaActor.Code)) + require.Equal(t, uint64(1), eoaActor.Nonce) + + // Send a valid message now, it should succeed without any code CID changes + + msgFromPlaceholder = &types.Message{ + From: placeholderAddress, + To: placeholderAddress, + Nonce: 1, + Value: abi.NewTokenAmount(1), + Method: builtin2.MethodsEVM.InvokeContract, + } + + msgFromPlaceholder, err = client.GasEstimateMessageGas(ctx, msgFromPlaceholder, nil, types.EmptyTSK) + require.NoError(t, err) + + txArgs, err = ethtypes.EthTxArgsFromUnsignedEthMessage(msgFromPlaceholder) + require.NoError(t, err) + + digest, err = txArgs.ToRlpUnsignedMsg() + require.NoError(t, err) + + siggy, err = client.WalletSign(ctx, placeholderAddress, digest) + require.NoError(t, err) + + smFromPlaceholderCid, err = client.MpoolPush(ctx, &types.SignedMessage{Message: *msgFromPlaceholder, Signature: *siggy}) + require.NoError(t, err) + + mLookup, err = client.StateWaitMsg(ctx, smFromPlaceholderCid, 3, api.LookbackNoLimit, true) + require.NoError(t, err) + require.True(t, mLookup.Receipt.ExitCode.IsSuccess()) + + // confirm no changes in code CID + + eoaActor, err = client.StateGetActor(ctx, placeholderAddress, types.EmptyTSK) + require.NoError(t, err) + require.Equal(t, uint64(2), eoaActor.Nonce) + + require.False(t, builtin.IsPlaceholderActor(eoaActor.Code)) + require.True(t, builtin.IsEthAccountActor(eoaActor.Code)) +} + +// Tests that f4 addresess that aren't placeholders/ethaccounts can't be top-level senders +func TestEthAccountAbstractionFailsFromEvmActor(t *testing.T) { + kit.QuietMiningLogs() + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // create a new Ethereum account + key, ethAddr, deployer := client.EVM().NewAccount() + + // send some funds to the f410 address + kit.SendFunds(ctx, t, client, deployer, types.FromFil(10)) + + // install a contract from the placeholder + contractHex, err := os.ReadFile("./contracts/SimpleCoin.hex") + require.NoError(t, err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + + gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + From: ðAddr, + Data: contract, + }) + require.NoError(t, err) + + maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) + require.NoError(t, err) + + tx := ethtypes.EthTxArgs{ + ChainID: build.Eip155ChainId, + Value: big.Zero(), + Nonce: 0, + MaxFeePerGas: types.NanoFil, + MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas), + GasLimit: int(gaslimit), + Input: contract, + V: big.Zero(), + R: big.Zero(), + S: big.Zero(), + } + + client.EVM().SignTransaction(&tx, key.PrivateKey) + + client.EVM().SubmitTransaction(ctx, &tx) + + smsg, err := tx.ToSignedMessage() + require.NoError(t, err) + + ml, err := client.StateWaitMsg(ctx, smsg.Cid(), 1, api.LookbackNoLimit, true) + require.NoError(t, err) + require.True(t, ml.Receipt.ExitCode.IsSuccess()) + + // Get contract address, assert it's an EVM actor + contractAddr, err := client.EVM().ComputeContractAddress(ethAddr, 0).ToFilecoinAddress() + require.NoError(t, err) + + client.AssertActorType(ctx, contractAddr, "evm") + + msgFromContract := &types.Message{ + From: contractAddr, + To: contractAddr, + } + + _, err = client.GasEstimateMessageGas(ctx, msgFromContract, nil, types.EmptyTSK) + require.Error(t, err, "expected gas estimation to fail") + require.Contains(t, err.Error(), "SysErrSenderInvalid") +} + +func TestEthAccountManagerPermissions(t *testing.T) { + kit.QuietMiningLogs() + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // setup f1/f3/f4 accounts + + wsp, err := client.WalletNew(ctx, types.KTSecp256k1) + require.NoError(t, err) + + wbl, err := client.WalletNew(ctx, types.KTBLS) + require.NoError(t, err) + + wdl, err := client.WalletNew(ctx, types.KTDelegated) + require.NoError(t, err) + + def := client.DefaultKey.Address + + // send some funds + client.ExpectSend(ctx, def, wsp, types.FromFil(10), "") + client.ExpectSend(ctx, def, wbl, types.FromFil(10), "") + client.ExpectSend(ctx, def, wdl, types.FromFil(10), "") + require.NoError(t, err) + + // make sure that EAM only allows CreateExternal to be called by accounts + client.ExpectSend(ctx, wsp, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create, &eam.CreateParams{Nonce: 0})) + client.ExpectSend(ctx, wbl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create, &eam.CreateParams{Nonce: 0})) + client.ExpectSend(ctx, wdl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create, &eam.CreateParams{Nonce: 0})) + + client.ExpectSend(ctx, wsp, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create2, &eam.Create2Params{})) + client.ExpectSend(ctx, wbl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create2, &eam.Create2Params{})) + client.ExpectSend(ctx, wdl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create2, &eam.Create2Params{})) + + contractHex, err := os.ReadFile("contracts/SimpleCoin.hex") + require.NoError(t, err) + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + contractParams := abi.CborBytes(contract) + + client.ExpectSend(ctx, wsp, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "", client.MakeSendCall(builtin2.MethodsEAM.CreateExternal, &contractParams)) + client.ExpectSend(ctx, wbl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "", client.MakeSendCall(builtin2.MethodsEAM.CreateExternal, &contractParams)) + client.ExpectSend(ctx, wdl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "", client.MakeSendCall(builtin2.MethodsEAM.CreateExternal, &contractParams)) +} diff --git a/itests/eth_api_test.go b/itests/eth_api_test.go new file mode 100644 index 000000000..32949cc71 --- /dev/null +++ b/itests/eth_api_test.go @@ -0,0 +1,89 @@ +package itests + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/builtin" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/chain/wallet/key" + "github.com/filecoin-project/lotus/itests/kit" +) + +func TestEthAddressToFilecoinAddress(t *testing.T) { + // Disable EthRPC to confirm that this method does NOT need the EthEnableRPC config set to true + client, _, _ := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.DisableEthRPC()) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + secpKey, err := key.GenerateKey(types.KTDelegated) + require.NoError(t, err) + + filecoinKeyAddr, err := client.WalletImport(ctx, &secpKey.KeyInfo) + require.NoError(t, err) + + ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(filecoinKeyAddr) + require.NoError(t, err) + + apiFilAddr, err := client.EthAddressToFilecoinAddress(ctx, ethAddr) + require.NoError(t, err) + + require.Equal(t, filecoinKeyAddr, apiFilAddr) + + filecoinIdArr := builtin.StorageMarketActorAddr + ethAddr, err = ethtypes.EthAddressFromFilecoinAddress(filecoinIdArr) + require.NoError(t, err) + + apiFilAddr, err = client.EthAddressToFilecoinAddress(ctx, ethAddr) + require.NoError(t, err) + + require.Equal(t, filecoinIdArr, apiFilAddr) + +} + +func TestFilecoinAddressToEthAddress(t *testing.T) { + // Disable EthRPC to confirm that this method does NOT need the EthEnableRPC config set to true + client, _, _ := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.DisableEthRPC()) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + secpDelegatedKey, err := key.GenerateKey(types.KTDelegated) + require.NoError(t, err) + + filecoinKeyAddr, err := client.WalletImport(ctx, &secpDelegatedKey.KeyInfo) + require.NoError(t, err) + + ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(filecoinKeyAddr) + require.NoError(t, err) + + apiEthAddr, err := client.FilecoinAddressToEthAddress(ctx, filecoinKeyAddr) + require.NoError(t, err) + + require.Equal(t, ethAddr, apiEthAddr) + + filecoinIdArr := builtin.StorageMarketActorAddr + ethAddr, err = ethtypes.EthAddressFromFilecoinAddress(filecoinIdArr) + require.NoError(t, err) + + apiEthAddr, err = client.FilecoinAddressToEthAddress(ctx, filecoinIdArr) + require.NoError(t, err) + + require.Equal(t, ethAddr, apiEthAddr) + + secpKey, err := key.GenerateKey(types.KTSecp256k1) + require.NoError(t, err) + + filecoinSecpAddr, err := client.WalletImport(ctx, &secpKey.KeyInfo) + require.NoError(t, err) + + _, err = client.FilecoinAddressToEthAddress(ctx, filecoinSecpAddr) + + require.ErrorContains(t, err, ethtypes.ErrInvalidAddress.Error()) +} diff --git a/itests/eth_balance_test.go b/itests/eth_balance_test.go new file mode 100644 index 000000000..d5f151227 --- /dev/null +++ b/itests/eth_balance_test.go @@ -0,0 +1,135 @@ +package itests + +import ( + "context" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" +) + +func TestEthGetBalanceExistingF4address(t *testing.T) { + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + _, ethAddr, deployer := client.EVM().NewAccount() + + fundAmount := types.FromFil(0) + // send some funds to the f410 address + kit.SendFunds(ctx, t, client, deployer, fundAmount) + + balance, err := client.EthGetBalance(ctx, ethAddr, "latest") + require.NoError(t, err) + require.Equal(t, balance, ethtypes.EthBigInt{Int: fundAmount.Int}) +} + +func TestEthGetBalanceNonExistentF4address(t *testing.T) { + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + _, ethAddr, _ := client.EVM().NewAccount() + + balance, err := client.EthGetBalance(ctx, ethAddr, "latest") + require.NoError(t, err) + require.Equal(t, balance, ethtypes.EthBigIntZero) +} + +func TestEthGetBalanceExistentIDMaskedAddr(t *testing.T) { + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + faddr, err := client.WalletDefaultAddress(ctx) + require.NoError(t, err) + fid, err := client.StateLookupID(ctx, faddr, types.EmptyTSK) + require.NoError(t, err) + + ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(fid) + require.NoError(t, err) + + balance, err := client.WalletBalance(ctx, fid) + require.NoError(t, err) + + ebal, err := client.EthGetBalance(ctx, ethAddr, "latest") + require.NoError(t, err) + require.Equal(t, ebal, ethtypes.EthBigInt{Int: balance.Int}) +} + +func TestEthGetBalanceBuiltinActor(t *testing.T) { + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Address for market actor + fid, err := address.NewFromString("f05") + require.NoError(t, err) + + kit.SendFunds(ctx, t, client, fid, abi.TokenAmount{Int: big.NewInt(10).Int}) + + ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(fid) + require.NoError(t, err) + + ebal, err := client.EthGetBalance(ctx, ethAddr, "latest") + require.NoError(t, err) + require.Equal(t, ethtypes.EthBigInt{Int: big.NewInt(10).Int}, ebal) +} + +func TestEthBalanceCorrectLookup(t *testing.T) { + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + _, ethAddr, filAddr := client.EVM().NewAccount() + + val := int64(100) + + smsg, err := client.MpoolPushMessage(ctx, &types.Message{ + To: filAddr, + From: client.DefaultKey.Address, + Value: abi.NewTokenAmount(val), + }, nil) + require.NoError(t, err) + + ml, err := client.StateWaitMsg(ctx, smsg.Cid(), 3, api.LookbackNoLimit, false) + require.NoError(t, err) + require.True(t, ml.Receipt.ExitCode.IsSuccess()) + + bal, err := client.EVM().EthGetBalance(ctx, ethAddr, strconv.FormatInt(int64(ml.Height-2), 10)) + require.NoError(t, err) + require.Equal(t, int64(0), bal.Int64()) + + bal, err = client.EVM().EthGetBalance(ctx, ethAddr, strconv.FormatInt(int64(ml.Height-1), 10)) + require.NoError(t, err) + require.Equal(t, val, bal.Int64()) + + bal, err = client.EVM().EthGetBalance(ctx, ethAddr, strconv.FormatInt(int64(ml.Height), 10)) + require.NoError(t, err) + require.Equal(t, val, bal.Int64()) +} diff --git a/itests/eth_block_hash_test.go b/itests/eth_block_hash_test.go new file mode 100644 index 000000000..ac6506bb2 --- /dev/null +++ b/itests/eth_block_hash_test.go @@ -0,0 +1,65 @@ +package itests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/itests/kit" +) + +// TestEthBlockHashesCorrect_MultiBlockTipset validates that blocks retrieved through +// EthGetBlockByNumber are identical to blocks retrieved through +// EthGetBlockByHash, when using the block hash returned by the former. +// +// Specifically, it checks the system behaves correctly with multiblock tipsets. +// +// Catches regressions around https://github.com/filecoin-project/lotus/issues/10061. +func TestEthBlockHashesCorrect_MultiBlockTipset(t *testing.T) { + // miner is connected to the first node, and we want to observe the chain + // from the second node. + blocktime := 100 * time.Millisecond + n1, m1, m2, ens := kit.EnsembleOneTwo(t, + kit.MockProofs(), + kit.ThroughRPC(), + ) + ens.InterconnectAll().BeginMining(blocktime) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + n1.WaitTillChain(ctx, kit.HeightAtLeast(abi.ChainEpoch(25))) + defer cancel() + + var n2 kit.TestFullNode + ens.FullNode(&n2, kit.ThroughRPC()).Start().Connect(n2, n1) + + // find the first tipset where all miners mined a block. + ctx, cancel = context.WithTimeout(context.Background(), 1*time.Minute) + n2.WaitTillChain(ctx, kit.BlocksMinedByAll(m1.ActorAddr, m2.ActorAddr)) + defer cancel() + + head, err := n2.ChainHead(context.Background()) + require.NoError(t, err) + + // let the chain run a little bit longer to minimise the chance of reorgs + n2.WaitTillChain(ctx, kit.HeightAtLeast(head.Height()+50)) + + head, err = n2.ChainHead(context.Background()) + require.NoError(t, err) + + for i := 1; i <= int(head.Height()); i++ { + hex := fmt.Sprintf("0x%x", i) + + ethBlockA, err := n2.EthGetBlockByNumber(ctx, hex, true) + require.NoError(t, err) + + ethBlockB, err := n2.EthGetBlockByHash(ctx, ethBlockA.Hash, true) + require.NoError(t, err) + + require.Equal(t, ethBlockA, ethBlockB) + } +} diff --git a/itests/eth_bytecode_test.go b/itests/eth_bytecode_test.go new file mode 100644 index 000000000..a8a75e83f --- /dev/null +++ b/itests/eth_bytecode_test.go @@ -0,0 +1,95 @@ +package itests + +import ( + "context" + "encoding/hex" + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" +) + +// TestGetCodeAndNonce ensures that GetCode and GetTransactionCount return the correct results for: +// 1. Placeholders. +// 2. Non-existent actors. +// 3. Normal EVM actors. +// 4. Self-destructed EVM actors. +func TestGetCodeAndNonce(t *testing.T) { + kit.QuietMiningLogs() + + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Accounts should have empty code, empty nonce. + { + // A random eth address should have no code. + _, ethAddr, filAddr := client.EVM().NewAccount() + bytecode, err := client.EVM().EthGetCode(ctx, ethAddr, "latest") + require.NoError(t, err) + require.Empty(t, bytecode) + + // Nonce should also be zero + nonce, err := client.EVM().EthGetTransactionCount(ctx, ethAddr, "latest") + require.NoError(t, err) + require.Zero(t, nonce) + + // send some funds to the account. + kit.SendFunds(ctx, t, client, filAddr, types.FromFil(10)) + + // The code should still be empty, target is now a placeholder. + bytecode, err = client.EVM().EthGetCode(ctx, ethAddr, "latest") + require.NoError(t, err) + require.Empty(t, bytecode) + + // Nonce should still be zero. + nonce, err = client.EVM().EthGetTransactionCount(ctx, ethAddr, "latest") + require.NoError(t, err) + require.Zero(t, nonce) + } + + // Check contract code. + { + // install a contract + contractHex, err := os.ReadFile("./contracts/SelfDestruct.hex") + require.NoError(t, err) + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + createReturn := client.EVM().DeployContract(ctx, client.DefaultKey.Address, contract) + contractAddr := createReturn.EthAddress + contractFilAddr := *createReturn.RobustAddress + + // The newly deployed contract should not be empty. + bytecode, err := client.EVM().EthGetCode(ctx, contractAddr, "latest") + require.NoError(t, err) + require.NotEmpty(t, bytecode) + + // Nonce should be one. + nonce, err := client.EVM().EthGetTransactionCount(ctx, contractAddr, "latest") + require.NoError(t, err) + require.Equal(t, ethtypes.EthUint64(1), nonce) + + // Destroy it. + _, _, err = client.EVM().InvokeContractByFuncName(ctx, client.DefaultKey.Address, contractFilAddr, "destroy()", nil) + require.NoError(t, err) + + // The code should be empty again. + bytecode, err = client.EVM().EthGetCode(ctx, contractAddr, "latest") + require.NoError(t, err) + require.Empty(t, bytecode) + + // Nonce should go back to zero + nonce, err = client.EVM().EthGetTransactionCount(ctx, contractAddr, "latest") + require.NoError(t, err) + require.Zero(t, nonce) + } + +} diff --git a/itests/eth_config_test.go b/itests/eth_config_test.go new file mode 100644 index 000000000..8b74d011a --- /dev/null +++ b/itests/eth_config_test.go @@ -0,0 +1,62 @@ +// stm: #integration +package itests + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/node/impl/full" +) + +func TestEthFilterAPIDisabledViaConfig(t *testing.T) { + ctx := context.Background() + + kit.QuietMiningLogs() + + // pass kit.DisableEthRPC() so RealTimeFilterAPI will not be enabled + client, _, _ := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.DisableEthRPC()) + + _, err := client.EthNewPendingTransactionFilter(ctx) + require.NotNil(t, err) + require.Equal(t, err.Error(), full.ErrModuleDisabled.Error()) + + _, err = client.EthGetLogs(ctx, ðtypes.EthFilterSpec{}) + require.NotNil(t, err) + require.Equal(t, err.Error(), full.ErrModuleDisabled.Error()) + + _, err = client.EthGetFilterChanges(ctx, ethtypes.EthFilterID{}) + require.NotNil(t, err) + require.Equal(t, err.Error(), full.ErrModuleDisabled.Error()) + + _, err = client.EthGetFilterLogs(ctx, ethtypes.EthFilterID{}) + require.NotNil(t, err) + require.Equal(t, err.Error(), full.ErrModuleDisabled.Error()) + + _, err = client.EthNewFilter(ctx, ðtypes.EthFilterSpec{}) + require.NotNil(t, err) + require.Equal(t, err.Error(), full.ErrModuleDisabled.Error()) + + _, err = client.EthNewBlockFilter(ctx) + require.NotNil(t, err) + require.Equal(t, err.Error(), full.ErrModuleDisabled.Error()) + + _, err = client.EthNewPendingTransactionFilter(ctx) + require.NotNil(t, err) + require.Equal(t, err.Error(), full.ErrModuleDisabled.Error()) + + _, err = client.EthUninstallFilter(ctx, ethtypes.EthFilterID{}) + require.NotNil(t, err) + require.Equal(t, err.Error(), full.ErrModuleDisabled.Error()) + + _, err = client.EthSubscribe(ctx, []byte("{}")) + require.NotNil(t, err) + require.Equal(t, err.Error(), full.ErrModuleDisabled.Error()) + + _, err = client.EthUnsubscribe(ctx, ethtypes.EthSubscriptionID{}) + require.NotNil(t, err) + require.Equal(t, err.Error(), full.ErrModuleDisabled.Error()) +} diff --git a/itests/eth_conformance_test.go b/itests/eth_conformance_test.go new file mode 100644 index 000000000..8a367d6b1 --- /dev/null +++ b/itests/eth_conformance_test.go @@ -0,0 +1,514 @@ +package itests + +import ( + "bytes" + "context" + "encoding/binary" + "encoding/hex" + "encoding/json" + "os" + "strings" + "testing" + "time" + + "github.com/go-openapi/spec" + "github.com/gregdhill/go-openrpc/parse" + orpctypes "github.com/gregdhill/go-openrpc/types" + manet "github.com/multiformats/go-multiaddr/net" + "github.com/stretchr/testify/require" + "github.com/xeipuuv/gojsonschema" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/chain/wallet/key" + "github.com/filecoin-project/lotus/itests/kit" +) + +// TODO generate this using reflection. It's the same as the EthAPI except every return value is a json.RawMessage +type ethAPIRaw struct { + EthAccounts func(context.Context) (json.RawMessage, error) + EthBlockNumber func(context.Context) (json.RawMessage, error) + EthCall func(context.Context, ethtypes.EthCall, string) (json.RawMessage, error) + EthChainId func(context.Context) (json.RawMessage, error) + EthEstimateGas func(context.Context, ethtypes.EthCall) (json.RawMessage, error) + EthFeeHistory func(context.Context, ethtypes.EthUint64, string, []float64) (json.RawMessage, error) + EthGasPrice func(context.Context) (json.RawMessage, error) + EthGetBalance func(context.Context, ethtypes.EthAddress, string) (json.RawMessage, error) + EthGetBlockByHash func(context.Context, ethtypes.EthHash, bool) (json.RawMessage, error) + EthGetBlockByNumber func(context.Context, string, bool) (json.RawMessage, error) + EthGetBlockTransactionCountByHash func(context.Context, ethtypes.EthHash) (json.RawMessage, error) + EthGetBlockTransactionCountByNumber func(context.Context, ethtypes.EthUint64) (json.RawMessage, error) + EthGetCode func(context.Context, ethtypes.EthAddress, string) (json.RawMessage, error) + EthGetFilterChanges func(context.Context, ethtypes.EthFilterID) (json.RawMessage, error) + EthGetFilterLogs func(context.Context, ethtypes.EthFilterID) (json.RawMessage, error) + EthGetLogs func(context.Context, *ethtypes.EthFilterSpec) (json.RawMessage, error) + EthGetStorageAt func(context.Context, ethtypes.EthAddress, ethtypes.EthBytes, string) (json.RawMessage, error) + EthGetTransactionByBlockHashAndIndex func(context.Context, ethtypes.EthHash, ethtypes.EthUint64) (json.RawMessage, error) + EthGetTransactionByBlockNumberAndIndex func(context.Context, ethtypes.EthUint64, ethtypes.EthUint64) (json.RawMessage, error) + EthGetTransactionByHash func(context.Context, *ethtypes.EthHash) (json.RawMessage, error) + EthGetTransactionCount func(context.Context, ethtypes.EthAddress, string) (json.RawMessage, error) + EthGetTransactionReceipt func(context.Context, ethtypes.EthHash) (json.RawMessage, error) + EthMaxPriorityFeePerGas func(context.Context) (json.RawMessage, error) + EthNewBlockFilter func(context.Context) (json.RawMessage, error) + EthNewFilter func(context.Context, *ethtypes.EthFilterSpec) (json.RawMessage, error) + EthNewPendingTransactionFilter func(context.Context) (json.RawMessage, error) + EthSendRawTransaction func(context.Context, ethtypes.EthBytes) (json.RawMessage, error) + EthSubscribe func(context.Context, string, *ethtypes.EthSubscriptionParams) (json.RawMessage, error) + EthUninstallFilter func(context.Context, ethtypes.EthFilterID) (json.RawMessage, error) + EthUnsubscribe func(context.Context, ethtypes.EthSubscriptionID) (json.RawMessage, error) +} + +func TestEthOpenRPCConformance(t *testing.T) { + kit.QuietAllLogsExcept("events", "messagepool") + + // specs/eth_openrpc.json is built from https://github.com/ethereum/execution-apis + specJSON, err := os.ReadFile("specs/eth_openrpc.json") + require.NoError(t, err) + + specParsed := orpctypes.NewOpenRPCSpec1() + err = json.Unmarshal(specJSON, specParsed) + require.NoError(t, err) + parse.GetTypes(specParsed, specParsed.Objects) + + schemas := make(map[string]spec.Schema) + for _, method := range specParsed.Methods { + if method.Result != nil { + schemas[method.Name] = method.Result.Schema + } + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.WithEthRPC()) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + contractHex, err := os.ReadFile("contracts/EventMatrix.hex") + require.NoError(t, err) + + // strip any trailing newlines from the file + contractHex = bytes.TrimRight(contractHex, "\n") + + contractBin, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + + senderKey, senderEthAddr, senderFilAddr := client.EVM().NewAccount() + _, receiverEthAddr, _ := client.EVM().NewAccount() + kit.SendFunds(ctx, t, client, senderFilAddr, types.FromFil(1000)) + + deployerAddr, err := client.EVM().WalletDefaultAddress(ctx) + require.NoError(t, err) + + pendingTransactionFilterID, err := client.EthNewPendingTransactionFilter(ctx) + require.NoError(t, err) + + blockFilterID, err := client.EthNewBlockFilter(ctx) + require.NoError(t, err) + + filterAllLogs := kit.NewEthFilterBuilder().FromBlockEpoch(0).Filter() + + logFilterID, err := client.EthNewFilter(ctx, filterAllLogs) + require.NoError(t, err) + + uninstallableFilterID, err := client.EthNewFilter(ctx, filterAllLogs) + require.NoError(t, err) + + rawSignedEthTx := createRawSignedEthTx(ctx, t, client, senderEthAddr, receiverEthAddr, senderKey, contractBin) + + result := client.EVM().DeployContract(ctx, deployerAddr, contractBin) + contractAddr, err := address.NewIDAddress(result.ActorID) + require.NoError(t, err) + + contractEthAddr := ethtypes.EthAddress(result.EthAddress) + + messageWithEvents, blockHashWithMessage, blockNumberWithMessage := waitForMessageWithEvents(ctx, t, client, deployerAddr, contractAddr) + + // create a json-rpc client that returns raw json responses + var ethapi ethAPIRaw + + netAddr, err := manet.ToNetAddr(client.ListenAddr) + require.NoError(t, err) + rpcAddr := "ws://" + netAddr.String() + "/rpc/v1" + + closer, err := jsonrpc.NewClient(ctx, rpcAddr, "Filecoin", ðapi, nil) + require.NoError(t, err) + defer closer() + + testCases := []struct { + method string + variant string // suffix applied to the test name to distinguish different variants of a method call + call func(*ethAPIRaw) (json.RawMessage, error) + skipReason string + }{ + // Alphabetical order + + { + method: "eth_accounts", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthAccounts(context.Background()) + }, + }, + + { + method: "eth_blockNumber", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthBlockNumber(context.Background()) + }, + }, + + { + method: "eth_call", + variant: "latest", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthCall(context.Background(), ethtypes.EthCall{ + From: &senderEthAddr, + Data: contractBin, + }, "latest") + }, + }, + + { + method: "eth_chainId", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthChainId(context.Background()) + }, + }, + + { + method: "eth_estimateGas", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthEstimateGas(context.Background(), ethtypes.EthCall{ + From: &senderEthAddr, + Data: contractBin, + }) + }, + }, + + { + method: "eth_feeHistory", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthFeeHistory(context.Background(), ethtypes.EthUint64(2), "latest", nil) + }, + }, + + { + method: "eth_gasPrice", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGasPrice(context.Background()) + }, + }, + + { + method: "eth_getBalance", + variant: "blocknumber", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetBalance(context.Background(), contractEthAddr, "0x0") + }, + }, + + { + method: "eth_getBlockByHash", + variant: "txhashes", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetBlockByHash(context.Background(), blockHashWithMessage, false) + }, + }, + + { + method: "eth_getBlockByHash", + variant: "txfull", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetBlockByHash(context.Background(), blockHashWithMessage, true) + }, + }, + + { + method: "eth_getBlockByNumber", + variant: "earliest", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetBlockByNumber(context.Background(), "earliest", true) + }, + skipReason: "earliest block is not supported", + }, + + { + method: "eth_getBlockByNumber", + variant: "pending", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetBlockByNumber(context.Background(), "pending", true) + }, + }, + + { + method: "eth_getBlockByNumber", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetBlockByNumber(context.Background(), blockNumberWithMessage.Hex(), true) + }, + }, + + { + method: "eth_getBlockTransactionCountByHash", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetBlockTransactionCountByHash(context.Background(), blockHashWithMessage) + }, + }, + + { + method: "eth_getBlockTransactionCountByNumber", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetBlockTransactionCountByNumber(context.Background(), blockNumberWithMessage) + }, + }, + + { + method: "eth_getCode", + variant: "blocknumber", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetCode(context.Background(), contractEthAddr, blockNumberWithMessage.Hex()) + }, + }, + + { + method: "eth_getFilterChanges", + variant: "pendingtransaction", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return a.EthGetFilterChanges(ctx, pendingTransactionFilterID) + }, + }, + + { + method: "eth_getFilterChanges", + variant: "block", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return a.EthGetFilterChanges(ctx, blockFilterID) + }, + }, + + { + method: "eth_getFilterChanges", + variant: "logs", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return a.EthGetFilterChanges(ctx, logFilterID) + }, + }, + + { + method: "eth_getFilterLogs", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return a.EthGetFilterLogs(ctx, logFilterID) + }, + }, + + { + method: "eth_getLogs", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetLogs(context.Background(), filterAllLogs) + }, + }, + + { + method: "eth_getStorageAt", + variant: "blocknumber", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetStorageAt(context.Background(), contractEthAddr, ethtypes.EthBytes{0}, "0x0") + }, + }, + + { + method: "eth_getTransactionByBlockHashAndIndex", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetTransactionByBlockHashAndIndex(context.Background(), blockHashWithMessage, ethtypes.EthUint64(0)) + }, + skipReason: "unimplemented", + }, + + { + method: "eth_getTransactionByBlockNumberAndIndex", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetTransactionByBlockNumberAndIndex(context.Background(), blockNumberWithMessage, ethtypes.EthUint64(0)) + }, + skipReason: "unimplemented", + }, + + { + method: "eth_getTransactionByHash", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetTransactionByHash(context.Background(), &messageWithEvents) + }, + }, + + { + method: "eth_getTransactionCount", + variant: "blocknumber", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetTransactionCount(context.Background(), senderEthAddr, blockNumberWithMessage.Hex()) + }, + }, + + { + method: "eth_getTransactionReceipt", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthGetTransactionReceipt(context.Background(), messageWithEvents) + }, + }, + + { + method: "eth_maxPriorityFeePerGas", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthMaxPriorityFeePerGas(context.Background()) + }, + }, + + { + method: "eth_newBlockFilter", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthNewBlockFilter(context.Background()) + }, + }, + + { + method: "eth_newFilter", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthNewFilter(context.Background(), filterAllLogs) + }, + }, + + { + method: "eth_newPendingTransactionFilter", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthNewPendingTransactionFilter(context.Background()) + }, + }, + + { + method: "eth_sendRawTransaction", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return ethapi.EthSendRawTransaction(context.Background(), rawSignedEthTx) + }, + }, + { + method: "eth_uninstallFilter", + call: func(a *ethAPIRaw) (json.RawMessage, error) { + return a.EthUninstallFilter(ctx, uninstallableFilterID) + }, + }, + } + + for _, tc := range testCases { + tc := tc + name := tc.method + if tc.variant != "" { + name += "_" + tc.variant + } + t.Run(name, func(t *testing.T) { + if tc.skipReason != "" { + t.Skipf(tc.skipReason) + } + + schema, ok := schemas[tc.method] + require.True(t, ok, "method not found in openrpc spec") + + resp, err := tc.call(ðapi) + require.NoError(t, err) + + respJson, err := json.Marshal(resp) + require.NoError(t, err) + + loader := gojsonschema.NewGoLoader(schema) + resploader := gojsonschema.NewBytesLoader(respJson) + result, err := gojsonschema.Validate(loader, resploader) + require.NoError(t, err) + + if !result.Valid() { + if len(result.Errors()) == 1 && strings.Contains(result.Errors()[0].String(), "Must validate one and only one schema (oneOf)") { + // Ignore this error, since it seems the openrpc spec can't handle it + // New transaction and block filters have the same schema: an array of 32 byte hashes + return + } + + niceRespJson, err := json.MarshalIndent(resp, "", " ") + if err == nil { + t.Logf("response was %s", niceRespJson) + } + + schemaJson, err := json.MarshalIndent(schema, "", " ") + if err == nil { + t.Logf("schema was %s", schemaJson) + } + + // check against https://www.jsonschemavalidator.net/ + + for _, desc := range result.Errors() { + t.Logf("- %s\n", desc) + } + + t.Errorf("response did not validate") + } + }) + } +} + +func createRawSignedEthTx(ctx context.Context, t *testing.T, client *kit.TestFullNode, senderEthAddr ethtypes.EthAddress, receiverEthAddr ethtypes.EthAddress, senderKey *key.Key, contractBin []byte) []byte { + gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + From: &senderEthAddr, + Data: contractBin, + }) + require.NoError(t, err) + + maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) + require.NoError(t, err) + + tx := ethtypes.EthTxArgs{ + ChainID: build.Eip155ChainId, + Value: big.NewInt(100), + Nonce: 0, + To: &receiverEthAddr, + MaxFeePerGas: types.NanoFil, + MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas), + GasLimit: int(gaslimit), + V: big.Zero(), + R: big.Zero(), + S: big.Zero(), + } + + client.EVM().SignTransaction(&tx, senderKey.PrivateKey) + signed, err := tx.ToRlpSignedMsg() + require.NoError(t, err) + return signed +} + +func waitForMessageWithEvents(ctx context.Context, t *testing.T, client *kit.TestFullNode, sender address.Address, target address.Address) (ethtypes.EthHash, ethtypes.EthHash, ethtypes.EthUint64) { + vals := []uint64{44, 27, 19, 12} + inputData := []byte{} + for _, v := range vals { + buf := make([]byte, 32) + binary.BigEndian.PutUint64(buf[24:], v) + inputData = append(inputData, buf...) + } + + // send a message that exercises event logs + ret, err := client.EVM().InvokeSolidity(ctx, sender, target, kit.EventMatrixContract.Fn["logEventThreeIndexedWithData"], inputData) + require.NoError(t, err) + require.True(t, ret.Receipt.ExitCode.IsSuccess(), "contract execution failed") + + msgHash, err := client.EthGetTransactionHashByCid(ctx, ret.Message) + require.NoError(t, err) + require.NotNil(t, msgHash) + + ts, err := client.ChainGetTipSet(ctx, ret.TipSet) + require.NoError(t, err) + + blockNumber := ethtypes.EthUint64(ts.Height()) + + tsCid, err := ts.Key().Cid() + require.NoError(t, err) + + blockHash, err := ethtypes.EthHashFromCid(tsCid) + require.NoError(t, err) + return *msgHash, blockHash, blockNumber +} diff --git a/itests/eth_deploy_test.go b/itests/eth_deploy_test.go new file mode 100644 index 000000000..bbdadb1d5 --- /dev/null +++ b/itests/eth_deploy_test.go @@ -0,0 +1,254 @@ +package itests + +import ( + "context" + "encoding/hex" + "encoding/json" + "os" + "reflect" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/require" + "golang.org/x/crypto/sha3" + + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" + gstStore "github.com/filecoin-project/go-state-types/store" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/evm" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" +) + +// TestDeployment smoke tests the deployment of a contract via the +// Ethereum JSON-RPC endpoint, from an EEOA. +func TestDeployment(t *testing.T) { + // TODO::FVM @raulk the contract installation and invocation can be lifted into utility methods + // He who writes the second test, shall do that. + // kit.QuietMiningLogs() + + // reasonable blocktime so that the tx sits in the mpool for a bit during the test. + // although this is non-deterministic... + blockTime := 1 * time.Second + client, _, ens := kit.EnsembleMinimal( + t, + kit.MockProofs(), + kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // install contract + contractHex, err := os.ReadFile("./contracts/SimpleCoin.hex") + require.NoError(t, err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + + // create a new Ethereum account + key, ethAddr, deployer := client.EVM().NewAccount() + + // send some funds to the f410 address + kit.SendFunds(ctx, t, client, deployer, types.FromFil(10)) + + // verify balances. + bal := client.EVM().AssertAddressBalanceConsistent(ctx, deployer) + require.Equal(t, types.FromFil(10), bal) + + // verify the deployer address is an Placeholder. + client.AssertActorType(ctx, deployer, manifest.PlaceholderKey) + + gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + From: ðAddr, + Data: contract, + }) + require.NoError(t, err) + + maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) + require.NoError(t, err) + + // now deploy a contract from the placeholder, and validate it went well + tx := ethtypes.EthTxArgs{ + ChainID: build.Eip155ChainId, + Value: big.Zero(), + Nonce: 0, + MaxFeePerGas: types.NanoFil, + MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas), + GasLimit: int(gaslimit), + Input: contract, + V: big.Zero(), + R: big.Zero(), + S: big.Zero(), + } + + client.EVM().SignTransaction(&tx, key.PrivateKey) + + pendingFilter, err := client.EthNewPendingTransactionFilter(ctx) + require.NoError(t, err) + + hash := client.EVM().SubmitTransaction(ctx, &tx) + + mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash) + require.NoError(t, err) + require.NotNil(t, mpoolTx) + + // require that the hashes are identical + require.Equal(t, hash, mpoolTx.Hash) + + // these fields should be nil because the tx hasn't landed on chain. + // TODO::FVM @raulk We can either skip the assertion if the msg has already + // landed, or pause mining between the embryo creation and this assertion. + require.Nil(t, mpoolTx.BlockNumber) + require.Nil(t, mpoolTx.BlockHash) + require.Nil(t, mpoolTx.TransactionIndex) + + changes, err := client.EthGetFilterChanges(ctx, pendingFilter) + require.NoError(t, err) + require.Len(t, changes.Results, 1) + require.Equal(t, hash.String(), changes.Results[0]) + + var receipt *api.EthTxReceipt + for i := 0; i < 20; i++ { + // TODO::FVM @raulk The right time to exit this loop isn't after + // 20 iterations, but when StateWaitMsg returns -- let's wait on that + // event while continuing to make this assertion + receipt, err = client.EthGetTransactionReceipt(ctx, hash) + if err != nil || receipt == nil { + time.Sleep(500 * time.Millisecond) + continue + } + break + } + require.NoError(t, err) + require.NotNil(t, receipt) + // logs must be an empty array, not a nil value, to avoid tooling compatibility issues + require.Empty(t, receipt.Logs) + // a correctly formed logs bloom, albeit empty, has 256 zeroes + require.Len(t, receipt.LogsBloom, 256) + require.Equal(t, ethtypes.EthBytes(make([]byte, 256)), receipt.LogsBloom) + + // Success. + require.EqualValues(t, ethtypes.EthUint64(0x1), receipt.Status) + + // Verify that the chain transaction now has new fields set. + chainTx, err := client.EthGetTransactionByHash(ctx, &hash) + require.NoError(t, err) + + // require that the hashes are identical + require.Equal(t, hash, chainTx.Hash) + require.NotNil(t, chainTx.BlockNumber) + require.Greater(t, uint64(*chainTx.BlockNumber), uint64(0)) + require.NotNil(t, chainTx.BlockHash) + require.NotEmpty(t, *chainTx.BlockHash) + require.NotNil(t, chainTx.TransactionIndex) + require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction + + // should return error with non-existent block hash + nonExistentHash, err := ethtypes.ParseEthHash("0x62a80aa9262a3e1d3db0706af41c8535257b6275a283174cabf9d108d8946059") + require.Nil(t, err) + _, err = client.EthGetBlockByHash(ctx, nonExistentHash, false) + require.NotNil(t, err) + + // verify block information + block1, err := client.EthGetBlockByHash(ctx, *chainTx.BlockHash, false) + require.Nil(t, err) + require.Equal(t, block1.Hash, *chainTx.BlockHash) + require.Equal(t, block1.Number, *chainTx.BlockNumber) + for _, tx := range block1.Transactions { + _, ok := tx.(string) + require.True(t, ok) + } + require.Contains(t, block1.Transactions, hash.String()) + + // make sure the block got from EthGetBlockByNumber is the same + blkNum := strconv.FormatInt(int64(*chainTx.BlockNumber), 10) + block2, err := client.EthGetBlockByNumber(ctx, blkNum, false) + require.Nil(t, err) + require.True(t, reflect.DeepEqual(block1, block2)) + + // should be able to get the block using latest as well + block3, err := client.EthGetBlockByNumber(ctx, "latest", false) + require.Nil(t, err) + require.True(t, reflect.DeepEqual(block2, block3)) + + // verify that the block contains full tx objects + block4, err := client.EthGetBlockByHash(ctx, *chainTx.BlockHash, true) + require.Nil(t, err) + require.Equal(t, block4.Hash, *chainTx.BlockHash) + require.Equal(t, block4.Number, *chainTx.BlockNumber) + + // the call went through json-rpc and the response was unmarshaled + // into map[string]interface{}, so it has to be converted into ethtypes.EthTx + var foundTx *ethtypes.EthTx + for _, obj := range block4.Transactions { + j, err := json.Marshal(obj) + require.Nil(t, err) + + var tx ethtypes.EthTx + err = json.Unmarshal(j, &tx) + require.Nil(t, err) + + if tx.Hash == chainTx.Hash { + foundTx = &tx + } + } + require.NotNil(t, foundTx) + require.True(t, reflect.DeepEqual(*foundTx, *chainTx)) + + // make sure the block got from EthGetBlockByNumber is the same + block5, err := client.EthGetBlockByNumber(ctx, blkNum, true) + require.Nil(t, err) + require.True(t, reflect.DeepEqual(block4, block5)) + + // Verify that the deployer is now an account. + client.AssertActorType(ctx, deployer, manifest.EthAccountKey) + + // Verify that the nonce was incremented. + nonce, err := client.MpoolGetNonce(ctx, deployer) + require.NoError(t, err) + require.EqualValues(t, 1, nonce) + + // Verify that the deployer is now an account. + client.AssertActorType(ctx, deployer, manifest.EthAccountKey) + + // Get contract address. + contractAddr, err := client.EVM().ComputeContractAddress(ethAddr, 0).ToFilecoinAddress() + require.NoError(t, err) + + client.AssertActorType(ctx, contractAddr, "evm") + + // Check bytecode and bytecode hash match. + contractAct, err := client.StateGetActor(ctx, contractAddr, types.EmptyTSK) + require.NoError(t, err) + + bs := blockstore.NewAPIBlockstore(client) + ctxStore := gstStore.WrapBlockStore(ctx, bs) + + evmSt, err := evm.Load(ctxStore, contractAct) + require.NoError(t, err) + + byteCodeCid, err := evmSt.GetBytecodeCID() + require.NoError(t, err) + + byteCode, err := bs.Get(ctx, byteCodeCid) + require.NoError(t, err) + + byteCodeHashChain, err := evmSt.GetBytecodeHash() + require.NoError(t, err) + + hasher := sha3.NewLegacyKeccak256() + hasher.Write(byteCode.RawData()) + byteCodeHash := hasher.Sum(nil) + require.Equal(t, byteCodeHashChain[:], byteCodeHash) + + byteCodeSt, err := evmSt.GetBytecode() + require.NoError(t, err) + require.Equal(t, byteCode.RawData(), byteCodeSt) +} diff --git a/itests/eth_fee_history_test.go b/itests/eth_fee_history_test.go new file mode 100644 index 000000000..72302f298 --- /dev/null +++ b/itests/eth_fee_history_test.go @@ -0,0 +1,100 @@ +package itests + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-jsonrpc" + + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/lib/result" +) + +func TestEthFeeHistory(t *testing.T) { + require := require.New(t) + + kit.QuietAllLogsExcept() + + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Wait for the network to create 20 blocks + client.WaitTillChain(ctx, kit.HeightAtLeast(20)) + + history, err := client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{5, "0x10"}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(6, len(history.BaseFeePerGas)) + require.Equal(5, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock) + require.Nil(history.Reward) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{"5", "0x10"}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(6, len(history.BaseFeePerGas)) + require.Equal(5, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock) + require.Nil(history.Reward) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{"0x10", "0x12"}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(17, len(history.BaseFeePerGas)) + require.Equal(16, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(18-16+1), history.OldestBlock) + require.Nil(history.Reward) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{5, "0x10"}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(6, len(history.BaseFeePerGas)) + require.Equal(5, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock) + require.Nil(history.Reward) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{5, "10"}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(6, len(history.BaseFeePerGas)) + require.Equal(5, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock) + require.Nil(history.Reward) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{5, "10", &[]float64{25, 50, 75}}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(6, len(history.BaseFeePerGas)) + require.Equal(5, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock) + require.NotNil(history.Reward) + require.Equal(5, len(*history.Reward)) + for _, arr := range *history.Reward { + require.Equal(3, len(arr)) + } + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{1025, "10", &[]float64{25, 50, 75}}), + ).Assert(require.NoError)) + require.Error(err) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{5, "10", &[]float64{}}), + ).Assert(require.NoError)) + require.NoError(err) +} diff --git a/itests/eth_filter_test.go b/itests/eth_filter_test.go new file mode 100644 index 000000000..1104bec13 --- /dev/null +++ b/itests/eth_filter_test.go @@ -0,0 +1,2305 @@ +package itests + +import ( + "bytes" + "context" + "encoding/binary" + "encoding/hex" + "encoding/json" + "fmt" + "math/bits" + "os" + "sort" + "strconv" + "strings" + "testing" + "time" + + "github.com/ipfs/go-cid" + "github.com/stretchr/testify/require" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" + res "github.com/filecoin-project/lotus/lib/result" +) + +func TestEthNewPendingTransactionFilter(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + kit.QuietAllLogsExcept("events", "messagepool") + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.WithEthRPC()) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + // create a new address where to send funds. + addr, err := client.WalletNew(ctx, types.KTBLS) + require.NoError(t, err) + + // get the existing balance from the default wallet to then split it. + bal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + + // install filter + filterID, err := client.EthNewPendingTransactionFilter(ctx) + require.NoError(t, err) + + const iterations = 100 + + // we'll send half our balance (saving the other half for gas), + // in `iterations` increments. + toSend := big.Div(bal, big.NewInt(2)) + each := big.Div(toSend, big.NewInt(iterations)) + + waitAllCh := make(chan struct{}) + go func() { + headChangeCh, err := client.ChainNotify(ctx) + require.NoError(t, err) + <-headChangeCh // skip hccurrent + + defer func() { + close(waitAllCh) + }() + + count := 0 + for { + select { + case <-ctx.Done(): + return + case headChanges := <-headChangeCh: + for _, change := range headChanges { + if change.Type == store.HCApply { + msgs, err := client.ChainGetMessagesInTipset(ctx, change.Val.Key()) + require.NoError(t, err) + count += len(msgs) + if count == iterations { + return + } + } + } + } + } + }() + + var sms []*types.SignedMessage + for i := 0; i < iterations; i++ { + msg := &types.Message{ + From: client.DefaultKey.Address, + To: addr, + Value: each, + } + + sm, err := client.MpoolPushMessage(ctx, msg, nil) + require.NoError(t, err) + require.EqualValues(t, i, sm.Message.Nonce) + + sms = append(sms, sm) + } + + select { + case <-waitAllCh: + case <-ctx.Done(): + t.Errorf("timeout waiting to pack messages") + } + + expected := make(map[string]bool) + for _, sm := range sms { + hash, err := ethtypes.EthHashFromCid(sm.Cid()) + require.NoError(t, err) + expected[hash.String()] = false + } + + // collect filter results + res, err := client.EthGetFilterChanges(ctx, filterID) + require.NoError(t, err) + + // expect to have seen iteration number of mpool messages + require.Equal(t, iterations, len(res.Results), "expected %d tipsets to have been executed", iterations) + + require.Equal(t, len(res.Results), len(expected), "expected number of filter results to equal number of messages") + + for _, txid := range res.Results { + expected[txid.(string)] = true + } + + for _, found := range expected { + require.True(t, found) + } +} + +func TestEthNewPendingTransactionSub(t *testing.T) { + require := require.New(t) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + kit.QuietAllLogsExcept("events", "messagepool") + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.WithEthRPC()) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + // create a new address where to send funds. + addr, err := client.WalletNew(ctx, types.KTBLS) + require.NoError(err) + + // get the existing balance from the default wallet to then split it. + bal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(err) + + // install filter + subId, err := client.EthSubscribe(ctx, res.Wrap[jsonrpc.RawParams](json.Marshal(ethtypes.EthSubscribeParams{EventType: "newPendingTransactions"})).Assert(require.NoError)) + require.NoError(err) + + var subResponses []ethtypes.EthSubscriptionResponse + err = client.EthSubRouter.AddSub(ctx, subId, func(ctx context.Context, resp *ethtypes.EthSubscriptionResponse) error { + subResponses = append(subResponses, *resp) + return nil + }) + require.NoError(err) + + const iterations = 100 + + // we'll send half our balance (saving the other half for gas), + // in `iterations` increments. + toSend := big.Div(bal, big.NewInt(2)) + each := big.Div(toSend, big.NewInt(iterations)) + + waitAllCh := make(chan struct{}) + go func() { + headChangeCh, err := client.ChainNotify(ctx) + require.NoError(err) + <-headChangeCh // skip hccurrent + + defer func() { + close(waitAllCh) + }() + + count := 0 + for { + select { + case <-ctx.Done(): + return + case headChanges := <-headChangeCh: + for _, change := range headChanges { + if change.Type == store.HCApply { + msgs, err := client.ChainGetMessagesInTipset(ctx, change.Val.Key()) + require.NoError(err) + count += len(msgs) + if count == iterations { + return + } + } + } + } + } + }() + + var sms []*types.SignedMessage + for i := 0; i < iterations; i++ { + msg := &types.Message{ + From: client.DefaultKey.Address, + To: addr, + Value: each, + } + + sm, err := client.MpoolPushMessage(ctx, msg, nil) + require.NoError(err) + require.EqualValues(i, sm.Message.Nonce) + + sms = append(sms, sm) + } + + select { + case <-waitAllCh: + case <-ctx.Done(): + t.Errorf("timeout waiting to pack messages") + } + + expected := make(map[string]bool) + for _, sm := range sms { + hash, err := ethtypes.EthHashFromCid(sm.Cid()) + require.NoError(err) + expected[hash.String()] = false + } + + // expect to have seen iteration number of mpool messages + require.Equal(len(subResponses), len(expected), "expected number of filter results to equal number of messages") + + for _, txid := range subResponses { + expected[txid.Result.(string)] = true + } + + for _, found := range expected { + require.True(found) + } +} + +func TestEthNewBlockFilter(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + kit.QuietAllLogsExcept("events", "messagepool") + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.WithEthRPC()) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + // create a new address where to send funds. + addr, err := client.WalletNew(ctx, types.KTBLS) + require.NoError(t, err) + + // get the existing balance from the default wallet to then split it. + bal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + + // install filter + filterID, err := client.EthNewBlockFilter(ctx) + require.NoError(t, err) + + const iterations = 30 + + // we'll send half our balance (saving the other half for gas), + // in `iterations` increments. + toSend := big.Div(bal, big.NewInt(2)) + each := big.Div(toSend, big.NewInt(iterations)) + + waitAllCh := make(chan struct{}) + tipsetChan := make(chan *types.TipSet, iterations) + go func() { + headChangeCh, err := client.ChainNotify(ctx) + require.NoError(t, err) + <-headChangeCh // skip hccurrent + + defer func() { + close(tipsetChan) + close(waitAllCh) + }() + + count := 0 + for { + select { + case <-ctx.Done(): + return + case headChanges := <-headChangeCh: + for _, change := range headChanges { + if change.Type == store.HCApply || change.Type == store.HCRevert { + count++ + tipsetChan <- change.Val + if count == iterations { + return + } + } + } + } + } + }() + + for i := 0; i < iterations; i++ { + msg := &types.Message{ + From: client.DefaultKey.Address, + To: addr, + Value: each, + } + + sm, err := client.MpoolPushMessage(ctx, msg, nil) + require.NoError(t, err) + require.EqualValues(t, i, sm.Message.Nonce) + } + + select { + case <-waitAllCh: + case <-ctx.Done(): + t.Errorf("timeout waiting to pack messages") + } + + expected := make(map[string]bool) + for ts := range tipsetChan { + c, err := ts.Key().Cid() + require.NoError(t, err) + hash, err := ethtypes.EthHashFromCid(c) + require.NoError(t, err) + expected[hash.String()] = false + } + + // collect filter results + res, err := client.EthGetFilterChanges(ctx, filterID) + require.NoError(t, err) + + // expect to have seen iteration number of tipsets + require.Equal(t, iterations, len(res.Results), "expected %d tipsets to have been executed", iterations) + + require.Equal(t, len(res.Results), len(expected), "expected number of filter results to equal number of tipsets") + + for _, blockhash := range res.Results { + expected[blockhash.(string)] = true + } + + for _, found := range expected { + require.True(t, found, "expected all tipsets to be present in filter results") + } +} + +func TestEthNewFilterDefaultSpec(t *testing.T) { + require := require.New(t) + + kit.QuietAllLogsExcept("events", "messagepool") + + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.WithEthRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // install contract + contractHex, err := os.ReadFile("contracts/events.bin") + require.NoError(err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(err) + + fromAddr, err := client.WalletDefaultAddress(ctx) + require.NoError(err) + + result := client.EVM().DeployContract(ctx, fromAddr, contract) + + idAddr, err := address.NewIDAddress(result.ActorID) + require.NoError(err) + t.Logf("actor ID address is %s", idAddr) + + // install filter + filterID, err := client.EthNewFilter(ctx, ðtypes.EthFilterSpec{}) + require.NoError(err) + + const iterations = 3 + ethContractAddr, received := invokeLogFourData(t, client, iterations) + + // collect filter results + res, err := client.EthGetFilterChanges(ctx, filterID) + require.NoError(err) + + // expect to have seen iteration number of events + require.Equal(iterations, len(res.Results)) + + expected := []ExpectedEthLog{ + { + Address: ethContractAddr, + Topics: []ethtypes.EthHash{ + paddedEthHash([]byte{0x11, 0x11}), + paddedEthHash([]byte{0x22, 0x22}), + paddedEthHash([]byte{0x33, 0x33}), + paddedEthHash([]byte{0x44, 0x44}), + }, + Data: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, + }, + { + Address: ethContractAddr, + Topics: []ethtypes.EthHash{ + paddedEthHash([]byte{0x11, 0x11}), + paddedEthHash([]byte{0x22, 0x22}), + paddedEthHash([]byte{0x33, 0x33}), + paddedEthHash([]byte{0x44, 0x44}), + }, + Data: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, + }, + { + Address: ethContractAddr, + Topics: []ethtypes.EthHash{ + paddedEthHash([]byte{0x11, 0x11}), + paddedEthHash([]byte{0x22, 0x22}), + paddedEthHash([]byte{0x33, 0x33}), + paddedEthHash([]byte{0x44, 0x44}), + }, + Data: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, + }, + } + + elogs, err := parseEthLogsFromFilterResult(res) + require.NoError(err) + AssertEthLogs(t, elogs, expected, received) +} + +func TestEthGetLogsBasic(t *testing.T) { + require := require.New(t) + kit.QuietAllLogsExcept("events", "messagepool") + + blockTime := 100 * time.Millisecond + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + invocations := 1 + ethContractAddr, received := invokeLogFourData(t, client, invocations) + + // Build filter spec + spec := kit.NewEthFilterBuilder(). + FromBlockEpoch(0). + Topic1OneOf(paddedEthHash([]byte{0x11, 0x11})). + Filter() + + expected := []ExpectedEthLog{ + { + Address: ethContractAddr, + Topics: []ethtypes.EthHash{ + paddedEthHash([]byte{0x11, 0x11}), + paddedEthHash([]byte{0x22, 0x22}), + paddedEthHash([]byte{0x33, 0x33}), + paddedEthHash([]byte{0x44, 0x44}), + }, + Data: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, + }, + } + + // Use filter + res, err := client.EthGetLogs(ctx, spec) + require.NoError(err) + + elogs, err := parseEthLogsFromFilterResult(res) + require.NoError(err) + AssertEthLogs(t, elogs, expected, received) +} + +func TestEthSubscribeLogsNoTopicSpec(t *testing.T) { + require := require.New(t) + + kit.QuietAllLogsExcept("events", "messagepool") + + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // install contract + contractHex, err := os.ReadFile("contracts/events.bin") + require.NoError(err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(err) + + fromAddr, err := client.WalletDefaultAddress(ctx) + require.NoError(err) + + result := client.EVM().DeployContract(ctx, fromAddr, contract) + + idAddr, err := address.NewIDAddress(result.ActorID) + require.NoError(err) + t.Logf("actor ID address is %s", idAddr) + + // install filter + subId, err := client.EthSubscribe(ctx, res.Wrap[jsonrpc.RawParams](json.Marshal(ethtypes.EthSubscribeParams{EventType: "logs"})).Assert(require.NoError)) + require.NoError(err) + + var subResponses []ethtypes.EthSubscriptionResponse + err = client.EthSubRouter.AddSub(ctx, subId, func(ctx context.Context, resp *ethtypes.EthSubscriptionResponse) error { + subResponses = append(subResponses, *resp) + return nil + }) + require.NoError(err) + + const iterations = 10 + ethContractAddr, messages := invokeLogFourData(t, client, iterations) + + expected := make([]ExpectedEthLog, iterations) + for i := range expected { + expected[i] = ExpectedEthLog{ + Address: ethContractAddr, + Topics: []ethtypes.EthHash{ + paddedEthHash([]byte{0x11, 0x11}), + paddedEthHash([]byte{0x22, 0x22}), + paddedEthHash([]byte{0x33, 0x33}), + paddedEthHash([]byte{0x44, 0x44}), + }, + Data: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, + } + } + + elogs, err := parseEthLogsFromSubscriptionResponses(subResponses) + require.NoError(err) + AssertEthLogs(t, elogs, expected, messages) +} + +func TestTxReceiptBloom(t *testing.T) { + blockTime := 50 * time.Millisecond + client, _, ens := kit.EnsembleMinimal( + t, + kit.MockProofs(), + kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, "contracts/EventMatrix.hex") + + _, ml, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "logEventZeroData()", nil) + require.NoError(t, err) + + th, err := client.EthGetTransactionHashByCid(ctx, ml.Message) + require.NoError(t, err) + require.NotNil(t, th) + + receipt, err := client.EthGetTransactionReceipt(ctx, *th) + require.NoError(t, err) + require.NotNil(t, receipt) + require.Len(t, receipt.Logs, 1) + + // computed by calling EventMatrix/logEventZeroData in remix + // note this only contains topic bits + matchMask := "0x00000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + maskBytes, err := hex.DecodeString(matchMask[2:]) + require.NoError(t, err) + + bitsSet := 0 + for i, maskByte := range maskBytes { + bitsSet += bits.OnesCount8(receipt.LogsBloom[i]) + + if maskByte > 0 { + require.True(t, maskByte&receipt.LogsBloom[i] > 0) + } + } + + // 3 bits from the topic, 3 bits from the address + require.Equal(t, 6, bitsSet) +} + +func TestEthGetLogs(t *testing.T) { + require := require.New(t) + kit.QuietAllLogsExcept("events", "messagepool") + + blockTime := 100 * time.Millisecond + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Set up the test fixture with a standard list of invocations + contract1, contract2, invocations := prepareEventMatrixInvocations(ctx, t, client) + testCases := getCombinationFilterTestCases(contract1, contract2, "0x0") + + messages := invokeAndWaitUntilAllOnChain(t, client, invocations) + + for _, tc := range testCases { + tc := tc // appease the lint despot + t.Run(tc.name, func(t *testing.T) { + res, err := client.EthGetLogs(ctx, tc.spec) + require.NoError(err) + + elogs, err := parseEthLogsFromFilterResult(res) + require.NoError(err) + AssertEthLogs(t, elogs, tc.expected, messages) + }) + } +} + +func TestEthGetFilterChanges(t *testing.T) { + require := require.New(t) + kit.QuietAllLogsExcept("events", "messagepool") + + blockTime := 100 * time.Millisecond + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Set up the test fixture with a standard list of invocations + contract1, contract2, invocations := prepareEventMatrixInvocations(ctx, t, client) + + // Get the test cases + testCases := getCombinationFilterTestCases(contract1, contract2, "latest") + + testFilters := map[string]ethtypes.EthFilterID{} + // Create all the filters + for _, tc := range testCases { + filterID, err := client.EthNewFilter(ctx, tc.spec) + require.NoError(err) + testFilters[tc.name] = filterID + } + + // Perform all the invocations + messages := invokeAndWaitUntilAllOnChain(t, client, invocations) + + for _, tc := range testCases { + tc := tc // appease the lint despot + t.Run(tc.name, func(t *testing.T) { + filterID, ok := testFilters[tc.name] + require.True(ok) + + // Look for events that the filter has accumulated + res, err := client.EthGetFilterChanges(ctx, filterID) + require.NoError(err) + + elogs, err := parseEthLogsFromFilterResult(res) + require.NoError(err) + AssertEthLogs(t, elogs, tc.expected, messages) + }) + } +} + +func TestEthSubscribeLogs(t *testing.T) { + require := require.New(t) + kit.QuietAllLogsExcept("events", "messagepool") + + blockTime := 100 * time.Millisecond + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Set up the test fixture with a standard list of invocations + contract1, contract2, invocations := prepareEventMatrixInvocations(ctx, t, client) + + // Get the test cases + testCases := getTopicFilterTestCases(contract1, contract2, "latest") + + testResponses := map[string]chan ethtypes.EthSubscriptionResponse{} + + // Create all the filters + for _, tc := range testCases { + // subscribe to topics in filter + subParam, err := json.Marshal(ethtypes.EthSubscribeParams{ + EventType: "logs", + Params: ðtypes.EthSubscriptionParams{ + Topics: tc.spec.Topics, + Address: tc.spec.Address, + }, + }) + require.NoError(err) + + subId, err := client.EthSubscribe(ctx, subParam) + require.NoError(err) + + responseCh := make(chan ethtypes.EthSubscriptionResponse, len(invocations)) + testResponses[tc.name] = responseCh + + err = client.EthSubRouter.AddSub(ctx, subId, func(ctx context.Context, resp *ethtypes.EthSubscriptionResponse) error { + responseCh <- *resp + return nil + }) + require.NoError(err) + } + + // Perform all the invocations + messages := invokeAndWaitUntilAllOnChain(t, client, invocations) + + // wait a little for subscriptions to gather results + time.Sleep(blockTime * 6) + + for _, tc := range testCases { + tc := tc // appease the lint despot + t.Run(tc.name, func(t *testing.T) { + responseCh, ok := testResponses[tc.name] + require.True(ok) + + // don't expect any more responses + close(responseCh) + + var elogs []*ethtypes.EthLog + for resp := range responseCh { + rmap, ok := resp.Result.(map[string]interface{}) + require.True(ok, "expected subscription result entry to be map[string]interface{}, but was %T", resp.Result) + + elog, err := ParseEthLog(rmap) + require.NoError(err) + + elogs = append(elogs, elog) + } + AssertEthLogs(t, elogs, tc.expected, messages) + }) + } +} + +func TestEthGetFilterLogs(t *testing.T) { + require := require.New(t) + kit.QuietAllLogsExcept("events", "messagepool") + + blockTime := 100 * time.Millisecond + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Set up the test fixture with a standard list of invocations + contract1, contract2, invocations := prepareEventMatrixInvocations(ctx, t, client) + + // Get the test cases + testCases := getCombinationFilterTestCases(contract1, contract2, "latest") + + testFilters := map[string]ethtypes.EthFilterID{} + // Create all the filters + for _, tc := range testCases { + filterID, err := client.EthNewFilter(ctx, tc.spec) + require.NoError(err) + testFilters[tc.name] = filterID + } + + // Perform all the invocations + messages := invokeAndWaitUntilAllOnChain(t, client, invocations) + + for _, tc := range testCases { + tc := tc // appease the lint despot + t.Run(tc.name, func(t *testing.T) { + filterID, ok := testFilters[tc.name] + require.True(ok) + + // Look for events that the filter has accumulated + res, err := client.EthGetFilterLogs(ctx, filterID) + require.NoError(err) + + elogs, err := parseEthLogsFromFilterResult(res) + require.NoError(err) + AssertEthLogs(t, elogs, tc.expected, messages) + }) + } +} + +func TestEthGetLogsWithBlockRanges(t *testing.T) { + require := require.New(t) + kit.QuietAllLogsExcept("events", "messagepool") + + blockTime := 100 * time.Millisecond + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Set up the test fixture with a standard list of invocations + _, _, messages := invokeEventMatrix(ctx, t, client) + + // Organize expected logs into three partitions for range testing + expectedByHeight := map[abi.ChainEpoch][]ExpectedEthLog{} + distinctHeights := map[abi.ChainEpoch]bool{} + + // Select events for partitioning + for _, m := range messages { + if bytes.Equal(m.invocation.Selector, kit.EventMatrixContract.Fn["logEventTwoIndexedWithData"]) { + addr := getEthAddress(ctx, t, client, m.invocation.Target) + args := unpackUint64Values(m.invocation.Data) + require.Equal(3, len(args), "logEventTwoIndexedWithData should have 3 arguments") + + distinctHeights[m.ts.Height()] = true + expectedByHeight[m.ts.Height()] = append(expectedByHeight[m.ts.Height()], ExpectedEthLog{ + Address: addr, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(args[0]), + uint64EthHash(args[1]), + }, + Data: paddedUint64(args[2]), + }) + } + } + + // Divide heights into 3 partitions, they don't have to be equal + require.True(len(distinctHeights) >= 3, "expected slice should divisible into three partitions") + heights := make([]abi.ChainEpoch, 0, len(distinctHeights)) + for h := range distinctHeights { + heights = append(heights, h) + } + sort.Slice(heights, func(i, j int) bool { + return heights[i] < heights[j] + }) + heightsPerPartition := len(heights) / 3 + + type partition struct { + start abi.ChainEpoch + end abi.ChainEpoch + expected []ExpectedEthLog + } + + var partition1, partition2, partition3 partition + + partition1.start = heights[0] + partition1.end = heights[heightsPerPartition-1] + for e := partition1.start; e <= partition1.end; e++ { + exp, ok := expectedByHeight[e] + if !ok { + continue + } + partition1.expected = append(partition1.expected, exp...) + } + t.Logf("partition1 from %d to %d with %d expected", partition1.start, partition1.end, len(partition1.expected)) + require.True(len(partition1.expected) > 0, "partition should have events") + + partition2.start = heights[heightsPerPartition] + partition2.end = heights[heightsPerPartition*2-1] + for e := partition2.start; e <= partition2.end; e++ { + exp, ok := expectedByHeight[e] + if !ok { + continue + } + partition2.expected = append(partition2.expected, exp...) + } + t.Logf("partition2 from %d to %d with %d expected", partition2.start, partition2.end, len(partition2.expected)) + require.True(len(partition2.expected) > 0, "partition should have events") + + partition3.start = heights[heightsPerPartition*2] + partition3.end = heights[len(heights)-1] + for e := partition3.start; e <= partition3.end; e++ { + exp, ok := expectedByHeight[e] + if !ok { + continue + } + partition3.expected = append(partition3.expected, exp...) + } + t.Logf("partition3 from %d to %d with %d expected", partition3.start, partition3.end, len(partition3.expected)) + require.True(len(partition3.expected) > 0, "partition should have events") + + // these are the topics we selected for partitioning earlier + topics := []ethtypes.EthHash{kit.EventMatrixContract.Ev["EventTwoIndexedWithData"]} + + union := func(lists ...[]ExpectedEthLog) []ExpectedEthLog { + ret := []ExpectedEthLog{} + for _, list := range lists { + ret = append(ret, list...) + } + return ret + } + + testCases := []struct { + name string + spec *ethtypes.EthFilterSpec + expected []ExpectedEthLog + }{ + { + name: "find all events from genesis", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(0).Topic1OneOf(topics...).Filter(), + expected: union(partition1.expected, partition2.expected, partition3.expected), + }, + + { + name: "find all from start of partition1", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(partition1.start).Topic1OneOf(topics...).Filter(), + expected: union(partition1.expected, partition2.expected, partition3.expected), + }, + + { + name: "find all from start of partition2", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(partition2.start).Topic1OneOf(topics...).Filter(), + expected: union(partition2.expected, partition3.expected), + }, + + { + name: "find all from start of partition3", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(partition3.start).Topic1OneOf(topics...).Filter(), + expected: union(partition3.expected), + }, + + { + name: "find none after end of partition3", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(partition3.end + 1).Topic1OneOf(topics...).Filter(), + expected: nil, + }, + + { + name: "find all events from genesis to end of partition1", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(0).ToBlockEpoch(partition1.end).Topic1OneOf(topics...).Filter(), + expected: union(partition1.expected), + }, + + { + name: "find all events from genesis to end of partition2", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(0).ToBlockEpoch(partition2.end).Topic1OneOf(topics...).Filter(), + expected: union(partition1.expected, partition2.expected), + }, + + { + name: "find all events from genesis to end of partition3", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(0).ToBlockEpoch(partition3.end).Topic1OneOf(topics...).Filter(), + expected: union(partition1.expected, partition2.expected, partition3.expected), + }, + + { + name: "find none from genesis to start of partition1", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(0).ToBlockEpoch(partition1.start - 1).Topic1OneOf(topics...).Filter(), + expected: nil, + }, + + { + name: "find all events in partition1", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(partition1.start).ToBlockEpoch(partition1.end).Topic1OneOf(topics...).Filter(), + expected: union(partition1.expected), + }, + + { + name: "find all events in partition2", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(partition2.start).ToBlockEpoch(partition2.end).Topic1OneOf(topics...).Filter(), + expected: union(partition2.expected), + }, + + { + name: "find all events in partition3", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(partition3.start).ToBlockEpoch(partition3.end).Topic1OneOf(topics...).Filter(), + expected: union(partition3.expected), + }, + + { + name: "find all events from earliest to end of partition1", + spec: kit.NewEthFilterBuilder().FromBlock("earliest").ToBlockEpoch(partition1.end).Topic1OneOf(topics...).Filter(), + expected: union(partition1.expected), + }, + + { + name: "find all events from start of partition3 to latest", + spec: kit.NewEthFilterBuilder().FromBlockEpoch(partition3.start).ToBlock("latest").Topic1OneOf(topics...).Filter(), + expected: union(partition3.expected), + }, + + { + name: "find all events from earliest to latest", + spec: kit.NewEthFilterBuilder().FromBlock("earliest").ToBlock("latest").Topic1OneOf(topics...).Filter(), + expected: union(partition1.expected, partition2.expected, partition3.expected), + }, + } + + for _, tc := range testCases { + tc := tc // appease the lint despot + t.Run(tc.name, func(t *testing.T) { + res, err := client.EthGetLogs(ctx, tc.spec) + require.NoError(err) + + elogs, err := parseEthLogsFromFilterResult(res) + require.NoError(err) + AssertEthLogs(t, elogs, tc.expected, messages) + }) + } +} + +func TestEthNewFilterMergesHistoricWithRealtime(t *testing.T) { + require := require.New(t) + + kit.QuietAllLogsExcept("events", "messagepool") + + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + sender, contract := client.EVM().DeployContractFromFilename(ctx, kit.EventMatrixContract.Filename) + + // generate some events before the creation of the filter + preInvocations := []Invocation{ + { + Sender: sender, + Target: contract, + Selector: kit.EventMatrixContract.Fn["logEventOneData"], + Data: packUint64Values(1), + }, + { + Sender: sender, + Target: contract, + Selector: kit.EventMatrixContract.Fn["logEventOneIndexed"], + Data: packUint64Values(2), + }, + } + + messages := invokeAndWaitUntilAllOnChain(t, client, preInvocations) + + // now install filter + spec := kit.NewEthFilterBuilder().FromBlock("earliest").Filter() + + filterID, err := client.EthNewFilter(ctx, spec) + require.NoError(err) + + // generate some events after the creation of the filter + postInvocations := []Invocation{ + { + Sender: sender, + Target: contract, + Selector: kit.EventMatrixContract.Fn["logEventOneData"], + Data: packUint64Values(3), + }, + { + Sender: sender, + Target: contract, + Selector: kit.EventMatrixContract.Fn["logEventOneIndexed"], + Data: packUint64Values(4), + }, + } + + postMessages := invokeAndWaitUntilAllOnChain(t, client, postInvocations) + for k, v := range postMessages { + messages[k] = v + } + + // collect filter results + res, err := client.EthGetFilterChanges(ctx, filterID) + require.NoError(err) + + ethContractAddr := getEthAddress(ctx, t, client, contract) + + // expect to see 2 messages from before the filter was installed and 2 after + expected := []ExpectedEthLog{ + { + Address: ethContractAddr, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneData"], + }, + Data: paddedUint64(1), + }, + { + Address: ethContractAddr, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexed"], + uint64EthHash(2), + }, + }, + { + Address: ethContractAddr, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneData"], + }, + Data: paddedUint64(3), + }, + { + Address: ethContractAddr, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexed"], + uint64EthHash(4), + }, + }, + } + + elogs, err := parseEthLogsFromFilterResult(res) + require.NoError(err) + AssertEthLogs(t, elogs, expected, messages) +} + +// ------------------------------------------------------------------------------- +// end of tests +// ------------------------------------------------------------------------------- + +type msgInTipset struct { + invocation Invocation // the solidity invocation that generated this message + msg api.Message + events []types.Event // events extracted from receipt + ts *types.TipSet + reverted bool +} + +func getEthAddress(ctx context.Context, t *testing.T, client *kit.TestFullNode, addr address.Address) ethtypes.EthAddress { + head, err := client.ChainHead(ctx) + require.NoError(t, err) + + actor, err := client.StateGetActor(ctx, addr, head.Key()) + require.NoError(t, err) + require.NotNil(t, actor.Address) + ethContractAddr, err := ethtypes.EthAddressFromFilecoinAddress(*actor.Address) + require.NoError(t, err) + return ethContractAddr +} + +type Invocation struct { + Sender address.Address + Target address.Address + Selector []byte // function selector + Data []byte + MinHeight abi.ChainEpoch // minimum chain height that must be reached before invoking +} + +func invokeAndWaitUntilAllOnChain(t *testing.T, client *kit.TestFullNode, invocations []Invocation) map[ethtypes.EthHash]msgInTipset { + require := require.New(t) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + msgChan := make(chan msgInTipset, len(invocations)) + + waitAllCh := make(chan struct{}) + waitForFirstHeadChange := make(chan struct{}) + go func() { + headChangeCh, err := client.ChainNotify(ctx) + require.NoError(err) + select { + case <-ctx.Done(): + return + case <-headChangeCh: // skip hccurrent + } + + close(waitForFirstHeadChange) + + defer func() { + close(msgChan) + close(waitAllCh) + }() + + count := 0 + for { + select { + case <-ctx.Done(): + return + case headChanges := <-headChangeCh: + for _, change := range headChanges { + if change.Type == store.HCApply || change.Type == store.HCRevert { + msgs, err := client.ChainGetMessagesInTipset(ctx, change.Val.Key()) + require.NoError(err) + + count += len(msgs) + for _, m := range msgs { + select { + case msgChan <- msgInTipset{msg: m, ts: change.Val, reverted: change.Type == store.HCRevert}: + default: + } + } + + if count == len(invocations) { + return + } + } + } + } + } + }() + + select { + case <-waitForFirstHeadChange: + case <-ctx.Done(): + t.Fatalf("timeout waiting for first head change") + } + + eventMap := map[cid.Cid][]types.Event{} + invocationMap := map[cid.Cid]Invocation{} + for _, inv := range invocations { + if inv.MinHeight > 0 { + for { + ts, err := client.ChainHead(ctx) + require.NoError(err) + if ts.Height() >= inv.MinHeight { + break + } + select { + case <-ctx.Done(): + t.Fatalf("context cancelled") + case <-time.After(100 * time.Millisecond): + } + } + } + ret, err := client.EVM().InvokeSolidity(ctx, inv.Sender, inv.Target, inv.Selector, inv.Data) + require.NoError(err) + require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed") + + invocationMap[ret.Message] = inv + + require.NotNil(t, ret.Receipt.EventsRoot, "no event root on receipt") + + evs := client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot) + eventMap[ret.Message] = evs + } + + select { + case <-waitAllCh: + case <-ctx.Done(): + t.Fatalf("timeout waiting to pack messages") + } + + received := make(map[ethtypes.EthHash]msgInTipset) + for m := range msgChan { + inv, ok := invocationMap[m.msg.Cid] + require.True(ok) + m.invocation = inv + + evs, ok := eventMap[m.msg.Cid] + require.True(ok) + m.events = evs + + eh, err := client.EthGetTransactionHashByCid(ctx, m.msg.Cid) + require.NoError(err) + received[*eh] = m + } + require.Equal(len(invocations), len(received), "all messages on chain") + + return received +} + +func invokeLogFourData(t *testing.T, client *kit.TestFullNode, iterations int) (ethtypes.EthAddress, map[ethtypes.EthHash]msgInTipset) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, kit.EventsContract.Filename) + + invocations := make([]Invocation, iterations) + for i := range invocations { + invocations[i] = Invocation{ + Sender: fromAddr, + Target: idAddr, + Selector: kit.EventsContract.Fn["log_four_data"], + Data: nil, + } + } + + messages := invokeAndWaitUntilAllOnChain(t, client, invocations) + + ethAddr := getEthAddress(ctx, t, client, idAddr) + + return ethAddr, messages +} + +func prepareEventMatrixInvocations(ctx context.Context, t *testing.T, client *kit.TestFullNode) (ethtypes.EthAddress, ethtypes.EthAddress, []Invocation) { + sender1, contract1 := client.EVM().DeployContractFromFilename(ctx, kit.EventMatrixContract.Filename) + sender2, contract2 := client.EVM().DeployContractFromFilename(ctx, kit.EventMatrixContract.Filename) + + invocations := []Invocation{ + // log EventZeroData() + // topic1: hash(EventZeroData) + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventZeroData"], + Data: nil, + }, + + // log EventOneData(23) + // topic1: hash(EventOneData) + // data: 23 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventOneData"], + Data: packUint64Values(23), + }, + + // log EventOneIndexed(44) + // topic1: hash(EventOneIndexed) + // topic2: 44 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventOneIndexed"], + Data: packUint64Values(44), + }, + + // log EventTwoIndexed(44,19) from contract2 + // topic1: hash(EventTwoIndexed) + // topic2: 44 + // topic3: 19 + { + Sender: sender2, + Target: contract2, + Selector: kit.EventMatrixContract.Fn["logEventTwoIndexed"], + Data: packUint64Values(44, 19), + }, + + // log EventOneData(44) + // topic1: hash(EventOneData) + // data: 44 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventOneData"], + Data: packUint64Values(44), + }, + + // log EventTwoData(555,666) + // topic1: hash(EventTwoData) + // data: 555,666 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventTwoData"], + Data: packUint64Values(555, 666), + }, + + // log EventZeroData() from contract2 + // topic1: hash(EventZeroData) + { + Sender: sender2, + Target: contract2, + Selector: kit.EventMatrixContract.Fn["logEventZeroData"], + Data: nil, + }, + + // log EventThreeData(1,2,3) + // topic1: hash(EventTwoData) + // data: 1,2,3 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventThreeData"], + Data: packUint64Values(1, 2, 3), + }, + + // log EventThreeIndexed(44,27,19) from contract2 + // topic1: hash(EventThreeIndexed) + // topic2: 44 + // topic3: 27 + // topic4: 19 + { + Sender: sender1, + Target: contract2, + Selector: kit.EventMatrixContract.Fn["logEventThreeIndexed"], + Data: packUint64Values(44, 27, 19), + }, + + // log EventOneIndexedWithData(44,19) + // topic1: hash(EventOneIndexedWithData) + // topic2: 44 + // data: 19 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventOneIndexedWithData"], + Data: packUint64Values(44, 19), + }, + + // log EventOneIndexedWithData(46,12) + // topic1: hash(EventOneIndexedWithData) + // topic2: 46 + // data: 12 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventOneIndexedWithData"], + Data: packUint64Values(46, 12), + }, + + // log EventTwoIndexedWithData(44,27,19) + // topic1: hash(EventTwoIndexedWithData) + // topic2: 44 + // topic3: 27 + // data: 19 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventTwoIndexedWithData"], + Data: packUint64Values(44, 27, 19), + }, + + // log EventThreeIndexedWithData(44,27,19,12) + // topic1: hash(EventThreeIndexedWithData) + // topic2: 44 + // topic3: 27 + // topic4: 19 + // data: 12 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventThreeIndexedWithData"], + Data: packUint64Values(44, 27, 19, 12), + }, + + // log EventOneIndexedWithData(50,9) + // topic1: hash(EventOneIndexedWithData) + // topic2: 50 + // data: 9 + { + Sender: sender2, + Target: contract2, + Selector: kit.EventMatrixContract.Fn["logEventOneIndexedWithData"], + Data: packUint64Values(50, 9), + }, + + // log EventTwoIndexedWithData(46,27,19) + // topic1: hash(EventTwoIndexedWithData) + // topic2: 46 + // topic3: 27 + // data: 19 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventTwoIndexedWithData"], + Data: packUint64Values(46, 27, 19), + }, + + // log EventTwoIndexedWithData(46,14,19) + // topic1: hash(EventTwoIndexedWithData) + // topic2: 46 + // topic3: 14 + // data: 19 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventTwoIndexedWithData"], + Data: packUint64Values(46, 14, 19), + }, + // log EventTwoIndexed(44,19) from contract1 + // topic1: hash(EventTwoIndexed) + // topic2: 44 + // topic3: 19 + { + Sender: sender1, + Target: contract1, + Selector: kit.EventMatrixContract.Fn["logEventTwoIndexed"], + Data: packUint64Values(40, 20), + }, + } + + ethAddr1 := getEthAddress(ctx, t, client, contract1) + ethAddr2 := getEthAddress(ctx, t, client, contract2) + + return ethAddr1, ethAddr2, invocations +} + +func invokeEventMatrix(ctx context.Context, t *testing.T, client *kit.TestFullNode) (ethtypes.EthAddress, ethtypes.EthAddress, map[ethtypes.EthHash]msgInTipset) { + ethAddr1, ethAddr2, invocations := prepareEventMatrixInvocations(ctx, t, client) + messages := invokeAndWaitUntilAllOnChain(t, client, invocations) + return ethAddr1, ethAddr2, messages +} + +type filterTestCase struct { + name string + spec *ethtypes.EthFilterSpec + expected []ExpectedEthLog +} + +// getTopicFilterTestCases returns filter test cases that only include topic criteria +func getTopicFilterTestCases(contract1, contract2 ethtypes.EthAddress, fromBlock string) []filterTestCase { + return []filterTestCase{ + { + name: "find all EventZeroData events", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic1OneOf(kit.EventMatrixContract.Ev["EventZeroData"]).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventZeroData"], + }, + Data: nil, + }, + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventZeroData"], + }, + Data: nil, + }, + }, + }, + { + name: "find all EventOneData events", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic1OneOf(kit.EventMatrixContract.Ev["EventOneData"]).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneData"], + }, + Data: packUint64Values(23), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneData"], + }, + Data: packUint64Values(44), + }, + }, + }, + { + name: "find all EventTwoData events", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic1OneOf(kit.EventMatrixContract.Ev["EventTwoData"]).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoData"], + }, + Data: packUint64Values(555, 666), + }, + }, + }, + { + name: "find all EventThreeData events", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic1OneOf(kit.EventMatrixContract.Ev["EventThreeData"]).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventThreeData"], + }, + Data: packUint64Values(1, 2, 3), + }, + }, + }, + { + name: "find all EventOneIndexed events", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic1OneOf(kit.EventMatrixContract.Ev["EventOneIndexed"]).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexed"], + uint64EthHash(44), + }, + Data: nil, + }, + }, + }, + { + name: "find all EventTwoIndexed events", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic1OneOf(kit.EventMatrixContract.Ev["EventTwoIndexed"]).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexed"], + uint64EthHash(44), + uint64EthHash(19), + }, + Data: nil, + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexed"], + uint64EthHash(40), + uint64EthHash(20), + }, + Data: nil, + }, + }, + }, + { + name: "find all EventThreeIndexed events", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic1OneOf(kit.EventMatrixContract.Ev["EventThreeIndexed"]).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventThreeIndexed"], + uint64EthHash(44), + uint64EthHash(27), + uint64EthHash(19), + }, + Data: nil, + }, + }, + }, + { + name: "find all EventOneIndexedWithData events", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic1OneOf(kit.EventMatrixContract.Ev["EventOneIndexedWithData"]).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(44), + }, + Data: paddedUint64(19), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(46), + }, + Data: paddedUint64(12), + }, + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(50), + }, + Data: paddedUint64(9), + }, + }, + }, + { + name: "find all EventTwoIndexedWithData events", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic1OneOf(kit.EventMatrixContract.Ev["EventTwoIndexedWithData"]).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(44), + uint64EthHash(27), + }, + Data: paddedUint64(19), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(46), + uint64EthHash(27), + }, + Data: paddedUint64(19), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(46), + uint64EthHash(14), + }, + Data: paddedUint64(19), + }, + }, + }, + { + name: "find all EventThreeIndexedWithData events", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic1OneOf(kit.EventMatrixContract.Ev["EventThreeIndexedWithData"]).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventThreeIndexedWithData"], + uint64EthHash(44), + uint64EthHash(27), + uint64EthHash(19), + }, + Data: paddedUint64(12), + }, + }, + }, + + { + name: "find all events with topic2 of 44", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic2OneOf(uint64EthHash(44)).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexed"], + uint64EthHash(44), + }, + Data: nil, + }, + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexed"], + uint64EthHash(44), + uint64EthHash(19), + }, + Data: nil, + }, + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventThreeIndexed"], + uint64EthHash(44), + uint64EthHash(27), + uint64EthHash(19), + }, + Data: nil, + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(44), + }, + Data: paddedUint64(19), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(44), + uint64EthHash(27), + }, + Data: paddedUint64(19), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventThreeIndexedWithData"], + uint64EthHash(44), + uint64EthHash(27), + uint64EthHash(19), + }, + Data: paddedUint64(12), + }, + }, + }, + { + name: "find all events with topic2 of 46", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic2OneOf(uint64EthHash(46)).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(46), + }, + Data: paddedUint64(12), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(46), + uint64EthHash(27), + }, + Data: paddedUint64(19), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(46), + uint64EthHash(14), + }, + Data: paddedUint64(19), + }, + }, + }, + { + name: "find all events with topic2 of 50", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic2OneOf(uint64EthHash(50)).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(50), + }, + Data: paddedUint64(9), + }, + }, + }, + { + name: "find all events with topic2 of 46 or 50", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).Topic2OneOf(uint64EthHash(46), uint64EthHash(50)).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(46), + }, + Data: paddedUint64(12), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(46), + uint64EthHash(27), + }, + Data: paddedUint64(19), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(46), + uint64EthHash(14), + }, + Data: paddedUint64(19), + }, + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(50), + }, + Data: paddedUint64(9), + }, + }, + }, + + { + name: "find all events with topic1 of EventTwoIndexedWithData and topic3 of 27", + spec: kit.NewEthFilterBuilder(). + FromBlockEpoch(0). + Topic1OneOf(kit.EventMatrixContract.Ev["EventTwoIndexedWithData"]). + Topic3OneOf(uint64EthHash(27)). + Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(44), + uint64EthHash(27), + }, + Data: paddedUint64(19), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(46), + uint64EthHash(27), + }, + Data: paddedUint64(19), + }, + }, + }, + + { + name: "find all events with topic1 of EventTwoIndexedWithData or EventOneIndexed and topic2 of 44", + spec: kit.NewEthFilterBuilder(). + FromBlockEpoch(0). + Topic1OneOf((kit.EventMatrixContract.Ev["EventTwoIndexedWithData"]), kit.EventMatrixContract.Ev["EventOneIndexed"]). + Topic2OneOf(uint64EthHash(44)). + Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexedWithData"], + uint64EthHash(44), + uint64EthHash(27), + }, + Data: paddedUint64(19), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexed"], + uint64EthHash(44), + }, + Data: nil, + }, + }, + }, + } +} + +// getAddressFilterTestCases returns filter test cases include address criteria +func getAddressFilterTestCases(contract1, contract2 ethtypes.EthAddress, fromBlock string) []filterTestCase { + return []filterTestCase{ + { + name: "find all events from contract2", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).AddressOneOf(contract2).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventZeroData"], + }, + Data: nil, + }, + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventThreeIndexed"], + uint64EthHash(44), + uint64EthHash(27), + uint64EthHash(19), + }, + Data: nil, + }, + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexed"], + uint64EthHash(44), + uint64EthHash(19), + }, + Data: nil, + }, + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(50), + }, + Data: paddedUint64(9), + }, + }, + }, + + { + name: "find all events with topic2 of 44 from contract2", + spec: kit.NewEthFilterBuilder().FromBlock(fromBlock).AddressOneOf(contract2).Topic2OneOf(paddedEthHash(paddedUint64(44))).Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventThreeIndexed"], + uint64EthHash(44), + uint64EthHash(27), + uint64EthHash(19), + }, + Data: nil, + }, + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventTwoIndexed"], + uint64EthHash(44), + uint64EthHash(19), + }, + Data: nil, + }, + }, + }, + + { + name: "find all EventOneIndexedWithData events from contract1 or contract2", + spec: kit.NewEthFilterBuilder(). + FromBlockEpoch(0). + AddressOneOf(contract1, contract2). + Topic1OneOf(kit.EventMatrixContract.Ev["EventOneIndexedWithData"]). + Filter(), + + expected: []ExpectedEthLog{ + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(44), + }, + Data: paddedUint64(19), + }, + { + Address: contract1, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(46), + }, + Data: paddedUint64(12), + }, + { + Address: contract2, + Topics: []ethtypes.EthHash{ + kit.EventMatrixContract.Ev["EventOneIndexedWithData"], + uint64EthHash(50), + }, + Data: paddedUint64(9), + }, + }, + }, + } +} + +func getCombinationFilterTestCases(contract1, contract2 ethtypes.EthAddress, fromBlock string) []filterTestCase { + topicCases := getTopicFilterTestCases(contract1, contract2, fromBlock) + addressCases := getAddressFilterTestCases(contract1, contract2, fromBlock) + + return append(topicCases, addressCases...) +} + +type ExpectedEthLog struct { + // Address is the address of the actor that produced the event log. + Address ethtypes.EthAddress `json:"address"` + + // List of topics associated with the event log. + Topics []ethtypes.EthHash `json:"topics"` + + // Data is the value of the event log, excluding topics + Data ethtypes.EthBytes `json:"data"` +} + +func AssertEthLogs(t *testing.T, actual []*ethtypes.EthLog, expected []ExpectedEthLog, messages map[ethtypes.EthHash]msgInTipset) { + t.Helper() + require := require.New(t) + + t.Logf("got %d ethlogs, wanted %d", len(actual), len(expected)) + + formatTopics := func(topics []ethtypes.EthHash) string { + ss := make([]string, len(topics)) + for i := range topics { + ss[i] = fmt.Sprintf("%d:%s", i, topics[i]) + } + return strings.Join(ss, ",") + } + + expectedMatched := map[int]bool{} + + for _, elog := range actual { + msg, exists := messages[elog.TransactionHash] + require.True(exists, "message not seen on chain") + + tsCid, err := msg.ts.Key().Cid() + require.NoError(err) + + tsCidHash, err := ethtypes.EthHashFromCid(tsCid) + require.NoError(err) + + require.Equal(tsCidHash, elog.BlockHash, "block hash matches tipset key") + + // Try and match the received log against an expected log + matched := false + LoopExpected: + for i, want := range expected { + // each expected log must match only once + if expectedMatched[i] { + continue + } + + if elog.Address != want.Address { + continue + } + + if len(elog.Topics) != len(want.Topics) { + continue + } + + for j := range elog.Topics { + if elog.Topics[j] != want.Topics[j] { + continue LoopExpected + } + } + + if !bytes.Equal(elog.Data, want.Data) { + continue + } + + expectedMatched[i] = true + matched = true + break + } + + if !matched { + var buf strings.Builder + buf.WriteString(fmt.Sprintf("found unexpected log at height %d:\n", msg.ts.Height())) + buf.WriteString(fmt.Sprintf(" address: %s\n", elog.Address)) + buf.WriteString(fmt.Sprintf(" topics: %s\n", formatTopics(elog.Topics))) + buf.WriteString(fmt.Sprintf(" data: %x\n", elog.Data)) + buf.WriteString("original events from receipt were:\n") + for i, ev := range msg.events { + buf.WriteString(fmt.Sprintf("event %d\n", i)) + buf.WriteString(fmt.Sprintf(" emitter: %v\n", ev.Emitter)) + for _, en := range ev.Entries { + buf.WriteString(fmt.Sprintf(" %s=%x\n", en.Key, en.Value)) + } + } + + t.Errorf(buf.String()) + } + } + + for i := range expected { + if _, ok := expectedMatched[i]; !ok { + var buf strings.Builder + buf.WriteString(fmt.Sprintf("did not find expected log with index %d:\n", i)) + buf.WriteString(fmt.Sprintf(" address: %s\n", expected[i].Address)) + buf.WriteString(fmt.Sprintf(" topics: %s\n", formatTopics(expected[i].Topics))) + buf.WriteString(fmt.Sprintf(" data: %x\n", expected[i].Data)) + t.Errorf(buf.String()) + } + } +} + +func parseEthLogsFromSubscriptionResponses(subResponses []ethtypes.EthSubscriptionResponse) ([]*ethtypes.EthLog, error) { + elogs := make([]*ethtypes.EthLog, 0, len(subResponses)) + for i := range subResponses { + rmap, ok := subResponses[i].Result.(map[string]interface{}) + if !ok { + return nil, xerrors.Errorf("expected subscription result entry to be map[string]interface{}, but was %T", subResponses[i].Result) + } + + elog, err := ParseEthLog(rmap) + if err != nil { + return nil, err + } + elogs = append(elogs, elog) + } + + return elogs, nil +} + +func parseEthLogsFromFilterResult(res *ethtypes.EthFilterResult) ([]*ethtypes.EthLog, error) { + elogs := make([]*ethtypes.EthLog, 0, len(res.Results)) + + for _, r := range res.Results { + rmap, ok := r.(map[string]interface{}) + if !ok { + return nil, xerrors.Errorf("expected filter result entry to be map[string]interface{}, but was %T", r) + } + + elog, err := ParseEthLog(rmap) + if err != nil { + return nil, err + } + elogs = append(elogs, elog) + } + + return elogs, nil +} + +func ParseEthLog(in map[string]interface{}) (*ethtypes.EthLog, error) { + el := ðtypes.EthLog{} + + ethHash := func(k string, v interface{}) (ethtypes.EthHash, error) { + s, ok := v.(string) + if !ok { + return ethtypes.EthHash{}, xerrors.Errorf(k + " not a string") + } + return ethtypes.ParseEthHash(s) + } + + ethUint64 := func(k string, v interface{}) (ethtypes.EthUint64, error) { + s, ok := v.(string) + if !ok { + return 0, xerrors.Errorf(k + " not a string") + } + parsedInt, err := strconv.ParseUint(strings.Replace(s, "0x", "", -1), 16, 64) + if err != nil { + return 0, err + } + return ethtypes.EthUint64(parsedInt), nil + } + + var err error + for k, v := range in { + switch k { + case "removed": + b, ok := v.(bool) + if ok { + el.Removed = b + continue + } + s, ok := v.(string) + if !ok { + return nil, xerrors.Errorf(k + ": not a string") + } + el.Removed, err = strconv.ParseBool(s) + if err != nil { + return nil, xerrors.Errorf("%s: %w", k, err) + } + case "address": + s, ok := v.(string) + if !ok { + return nil, xerrors.Errorf(k + ": not a string") + } + el.Address, err = ethtypes.ParseEthAddress(s) + if err != nil { + return nil, xerrors.Errorf("%s: %w", k, err) + } + case "logIndex": + el.LogIndex, err = ethUint64(k, v) + if err != nil { + return nil, xerrors.Errorf("%s: %w", k, err) + } + case "transactionIndex": + el.TransactionIndex, err = ethUint64(k, v) + if err != nil { + return nil, xerrors.Errorf("%s: %w", k, err) + } + case "blockNumber": + el.BlockNumber, err = ethUint64(k, v) + if err != nil { + return nil, xerrors.Errorf("%s: %w", k, err) + } + case "transactionHash": + el.TransactionHash, err = ethHash(k, v) + if err != nil { + return nil, xerrors.Errorf("%s: %w", k, err) + } + case "blockHash": + el.BlockHash, err = ethHash(k, v) + if err != nil { + return nil, xerrors.Errorf("%s: %w", k, err) + } + case "data": + s, ok := v.(string) + if !ok { + return nil, xerrors.Errorf(k + ": not a string") + } + data, err := hex.DecodeString(s[2:]) + if err != nil { + return nil, xerrors.Errorf("%s: %w", k, err) + } + el.Data = data + + case "topics": + s, ok := v.(string) + if ok { + topic, err := hex.DecodeString(s[2:]) + if err != nil { + return nil, xerrors.Errorf("%s: %w", k, err) + } + el.Topics = append(el.Topics, paddedEthHash(topic)) + continue + } + + sl, ok := v.([]interface{}) + if !ok { + return nil, xerrors.Errorf(k + ": not a slice") + } + for _, s := range sl { + topic, err := hex.DecodeString(s.(string)[2:]) + if err != nil { + return nil, xerrors.Errorf("%s: %w", k, err) + } + el.Topics = append(el.Topics, paddedEthHash(topic)) + } + } + } + + return el, err +} + +func paddedUint64(v uint64) ethtypes.EthBytes { + buf := make([]byte, 32) + binary.BigEndian.PutUint64(buf[24:], v) + return buf +} + +func uint64EthHash(v uint64) ethtypes.EthHash { + var buf ethtypes.EthHash + binary.BigEndian.PutUint64(buf[24:], v) + return buf +} + +func paddedEthHash(orig []byte) ethtypes.EthHash { + if len(orig) > 32 { + panic("exceeds EthHash length") + } + var ret ethtypes.EthHash + needed := 32 - len(orig) + copy(ret[needed:], orig) + return ret +} + +func packUint64Values(vals ...uint64) []byte { + ret := []byte{} + for _, v := range vals { + buf := paddedUint64(v) + ret = append(ret, buf...) + } + return ret +} + +func unpackUint64Values(data []byte) []uint64 { + if len(data)%32 != 0 { + panic("data length not a multiple of 32") + } + + var vals []uint64 + for i := 0; i < len(data); i += 32 { + v := binary.BigEndian.Uint64(data[i+24 : i+32]) + vals = append(vals, v) + } + return vals +} diff --git a/itests/eth_hash_lookup_test.go b/itests/eth_hash_lookup_test.go new file mode 100644 index 000000000..37d069796 --- /dev/null +++ b/itests/eth_hash_lookup_test.go @@ -0,0 +1,510 @@ +package itests + +import ( + "context" + "encoding/hex" + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" +) + +// TestTransactionHashLookup tests to see if lotus correctly stores a mapping from ethereum transaction hash to +// Filecoin Message Cid +func TestTransactionHashLookup(t *testing.T) { + kit.QuietMiningLogs() + + blocktime := 1 * time.Second + client, _, ens := kit.EnsembleMinimal( + t, + kit.MockProofs(), + kit.ThroughRPC(), + ) + ens.InterconnectAll().BeginMining(blocktime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // install contract + contractHex, err := os.ReadFile("./contracts/SimpleCoin.hex") + require.NoError(t, err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + + // create a new Ethereum account + key, ethAddr, deployer := client.EVM().NewAccount() + + // send some funds to the f410 address + kit.SendFunds(ctx, t, client, deployer, types.FromFil(10)) + + gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + From: ðAddr, + Data: contract, + }) + require.NoError(t, err) + + maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) + require.NoError(t, err) + + // now deploy a contract from the embryo, and validate it went well + tx := ethtypes.EthTxArgs{ + ChainID: build.Eip155ChainId, + Value: big.Zero(), + Nonce: 0, + MaxFeePerGas: types.NanoFil, + MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas), + GasLimit: int(gaslimit), + Input: contract, + V: big.Zero(), + R: big.Zero(), + S: big.Zero(), + } + + client.EVM().SignTransaction(&tx, key.PrivateKey) + + rawTxHash, err := tx.TxHash() + require.NoError(t, err) + + hash := client.EVM().SubmitTransaction(ctx, &tx) + require.Equal(t, rawTxHash, hash) + + mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash) + require.NoError(t, err) + require.Equal(t, hash, mpoolTx.Hash) + + // Wait for message to land on chain + var receipt *api.EthTxReceipt + for i := 0; i < 20; i++ { + receipt, err = client.EthGetTransactionReceipt(ctx, hash) + if err != nil || receipt == nil { + time.Sleep(blocktime) + continue + } + break + } + require.NoError(t, err) + require.NotNil(t, receipt) + + // Verify that the chain transaction now has new fields set. + chainTx, err := client.EthGetTransactionByHash(ctx, &hash) + require.NoError(t, err) + require.Equal(t, hash, chainTx.Hash) + + // require that the hashes are identical + require.Equal(t, hash, chainTx.Hash) + require.NotNil(t, chainTx.BlockNumber) + require.Greater(t, uint64(*chainTx.BlockNumber), uint64(0)) + require.NotNil(t, chainTx.BlockHash) + require.NotEmpty(t, *chainTx.BlockHash) + require.NotNil(t, chainTx.TransactionIndex) + require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction +} + +// TestTransactionHashLookupBlsFilecoinMessage tests to see if lotus can find a BLS Filecoin Message using the transaction hash +func TestTransactionHashLookupBlsFilecoinMessage(t *testing.T) { + kit.QuietMiningLogs() + + blocktime := 1 * time.Second + client, _, ens := kit.EnsembleMinimal( + t, + kit.MockProofs(), + kit.ThroughRPC(), + ) + ens.InterconnectAll().BeginMining(blocktime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // get the existing balance from the default wallet to then split it. + bal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + + // create a new address where to send funds. + addr, err := client.WalletNew(ctx, types.KTBLS) + require.NoError(t, err) + + toSend := big.Div(bal, big.NewInt(2)) + msg := &types.Message{ + From: client.DefaultKey.Address, + To: addr, + Value: toSend, + } + + sm, err := client.MpoolPushMessage(ctx, msg, nil) + require.NoError(t, err) + + hash, err := ethtypes.EthHashFromCid(sm.Message.Cid()) + require.NoError(t, err) + + mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash) + require.NoError(t, err) + require.Equal(t, hash, mpoolTx.Hash) + + // Wait for message to land on chain + var receipt *api.EthTxReceipt + for i := 0; i < 20; i++ { + receipt, err = client.EthGetTransactionReceipt(ctx, hash) + if err != nil || receipt == nil { + time.Sleep(blocktime) + continue + } + break + } + require.NoError(t, err) + require.NotNil(t, receipt) + require.Equal(t, hash, receipt.TransactionHash) + + // Verify that the chain transaction now has new fields set. + chainTx, err := client.EthGetTransactionByHash(ctx, &hash) + require.NoError(t, err) + require.Equal(t, hash, chainTx.Hash) + + // require that the hashes are identical + require.Equal(t, hash, chainTx.Hash) + require.NotNil(t, chainTx.BlockNumber) + require.Greater(t, uint64(*chainTx.BlockNumber), uint64(0)) + require.NotNil(t, chainTx.BlockHash) + require.NotEmpty(t, *chainTx.BlockHash) + require.NotNil(t, chainTx.TransactionIndex) + require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction +} + +// TestTransactionHashLookupSecpFilecoinMessage tests to see if lotus can find a Secp Filecoin Message using the transaction hash +func TestTransactionHashLookupSecpFilecoinMessage(t *testing.T) { + kit.QuietMiningLogs() + + blocktime := 1 * time.Second + client, _, ens := kit.EnsembleMinimal( + t, + kit.MockProofs(), + kit.ThroughRPC(), + ) + ens.InterconnectAll().BeginMining(blocktime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // get the existing balance from the default wallet to then split it. + bal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + + // create a new address where to send funds. + addr, err := client.WalletNew(ctx, types.KTSecp256k1) + require.NoError(t, err) + + toSend := big.Div(bal, big.NewInt(2)) + setupMsg := &types.Message{ + From: client.DefaultKey.Address, + To: addr, + Value: toSend, + } + + setupSmsg, err := client.MpoolPushMessage(ctx, setupMsg, nil) + require.NoError(t, err) + + _, err = client.StateWaitMsg(ctx, setupSmsg.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(t, err) + + // Send message for secp account + secpMsg := &types.Message{ + From: addr, + To: client.DefaultKey.Address, + Value: big.Div(toSend, big.NewInt(2)), + } + + secpSmsg, err := client.MpoolPushMessage(ctx, secpMsg, nil) + require.NoError(t, err) + + hash, err := ethtypes.EthHashFromCid(secpSmsg.Cid()) + require.NoError(t, err) + + mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash) + require.NoError(t, err) + require.Equal(t, hash, mpoolTx.Hash) + + _, err = client.StateWaitMsg(ctx, secpSmsg.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(t, err) + + receipt, err := client.EthGetTransactionReceipt(ctx, hash) + require.NoError(t, err) + require.NotNil(t, receipt) + require.Equal(t, hash, receipt.TransactionHash) + + // Verify that the chain transaction now has new fields set. + chainTx, err := client.EthGetTransactionByHash(ctx, &hash) + require.NoError(t, err) + require.Equal(t, hash, chainTx.Hash) + + // require that the hashes are identical + require.Equal(t, hash, chainTx.Hash) + require.NotNil(t, chainTx.BlockNumber) + require.Greater(t, uint64(*chainTx.BlockNumber), uint64(0)) + require.NotNil(t, chainTx.BlockHash) + require.NotEmpty(t, *chainTx.BlockHash) + require.NotNil(t, chainTx.TransactionIndex) + require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction +} + +// TestTransactionHashLookupSecpFilecoinMessage tests to see if lotus can find a Secp Filecoin Message using the transaction hash +func TestTransactionHashLookupNonexistentMessage(t *testing.T) { + kit.QuietMiningLogs() + + blocktime := 1 * time.Second + client, _, ens := kit.EnsembleMinimal( + t, + kit.MockProofs(), + kit.ThroughRPC(), + ) + ens.InterconnectAll().BeginMining(blocktime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + cid := build.MustParseCid("bafk2bzacecapjnxnyw4talwqv5ajbtbkzmzqiosztj5cb3sortyp73ndjl76e") + + // We shouldn't be able to return a hash for this fake cid + chainHash, err := client.EthGetTransactionHashByCid(ctx, cid) + require.NoError(t, err) + require.Nil(t, chainHash) + + calculatedHash, err := ethtypes.EthHashFromCid(cid) + require.NoError(t, err) + + // We shouldn't be able to return a cid for this fake hash + chainCid, err := client.EthGetMessageCidByTransactionHash(ctx, &calculatedHash) + require.NoError(t, err) + require.Nil(t, chainCid) +} + +func TestEthGetMessageCidByTransactionHashEthTx(t *testing.T) { + kit.QuietMiningLogs() + + blocktime := 1 * time.Second + client, _, ens := kit.EnsembleMinimal( + t, + kit.MockProofs(), + kit.ThroughRPC(), + ) + ens.InterconnectAll().BeginMining(blocktime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // install contract + contractHex, err := os.ReadFile("./contracts/SimpleCoin.hex") + require.NoError(t, err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + + // create a new Ethereum account + key, ethAddr, deployer := client.EVM().NewAccount() + + // send some funds to the f410 address + kit.SendFunds(ctx, t, client, deployer, types.FromFil(10)) + + gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + From: ðAddr, + Data: contract, + }) + require.NoError(t, err) + + maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) + require.NoError(t, err) + + // now deploy a contract from the embryo, and validate it went well + tx := ethtypes.EthTxArgs{ + ChainID: build.Eip155ChainId, + Value: big.Zero(), + Nonce: 0, + MaxFeePerGas: types.NanoFil, + MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas), + GasLimit: int(gaslimit), + Input: contract, + V: big.Zero(), + R: big.Zero(), + S: big.Zero(), + } + + client.EVM().SignTransaction(&tx, key.PrivateKey) + + sender, err := tx.Sender() + require.NoError(t, err) + + unsignedMessage, err := tx.ToUnsignedMessage(sender) + require.NoError(t, err) + + rawTxHash, err := tx.TxHash() + require.NoError(t, err) + + hash := client.EVM().SubmitTransaction(ctx, &tx) + require.Equal(t, rawTxHash, hash) + + mpoolCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash) + require.NoError(t, err) + require.NotNil(t, mpoolCid) + + mpoolTx, err := client.ChainGetMessage(ctx, *mpoolCid) + require.NoError(t, err) + require.NotNil(t, mpoolTx) + require.Equal(t, *unsignedMessage, *mpoolTx) + + // Wait for message to land on chain + var receipt *api.EthTxReceipt + for i := 0; i < 20; i++ { + receipt, err = client.EthGetTransactionReceipt(ctx, hash) + if err != nil || receipt == nil { + time.Sleep(blocktime) + continue + } + break + } + require.NoError(t, err) + require.NotNil(t, receipt) + + chainCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash) + require.NoError(t, err) + require.NotNil(t, chainCid) + + chainTx, err := client.ChainGetMessage(ctx, *mpoolCid) + require.NoError(t, err) + require.NotNil(t, chainTx) + require.Equal(t, *unsignedMessage, *chainTx) +} + +func TestEthGetMessageCidByTransactionHashSecp(t *testing.T) { + kit.QuietMiningLogs() + + blocktime := 1 * time.Second + client, _, ens := kit.EnsembleMinimal( + t, + kit.MockProofs(), + kit.ThroughRPC(), + ) + ens.InterconnectAll().BeginMining(blocktime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // get the existing balance from the default wallet to then split it. + bal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + + // create a new address where to send funds. + addr, err := client.WalletNew(ctx, types.KTSecp256k1) + require.NoError(t, err) + + toSend := big.Div(bal, big.NewInt(2)) + setupMsg := &types.Message{ + From: client.DefaultKey.Address, + To: addr, + Value: toSend, + } + + setupSmsg, err := client.MpoolPushMessage(ctx, setupMsg, nil) + require.NoError(t, err) + + _, err = client.StateWaitMsg(ctx, setupSmsg.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(t, err) + + // Send message for secp account + secpMsg := &types.Message{ + From: addr, + To: client.DefaultKey.Address, + Value: big.Div(toSend, big.NewInt(2)), + } + + secpSmsg, err := client.MpoolPushMessage(ctx, secpMsg, nil) + require.NoError(t, err) + + hash, err := ethtypes.EthHashFromCid(secpSmsg.Cid()) + require.NoError(t, err) + + mpoolCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash) + require.NoError(t, err) + require.NotNil(t, mpoolCid) + + mpoolTx, err := client.ChainGetMessage(ctx, *mpoolCid) + require.NoError(t, err) + require.NotNil(t, mpoolTx) + require.Equal(t, secpSmsg.Message, *mpoolTx) + + _, err = client.StateWaitMsg(ctx, secpSmsg.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(t, err) + + chainCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash) + require.NoError(t, err) + require.NotNil(t, chainCid) + + chainTx, err := client.ChainGetMessage(ctx, *mpoolCid) + require.NoError(t, err) + require.NotNil(t, chainTx) + require.Equal(t, secpSmsg.Message, *chainTx) +} + +func TestEthGetMessageCidByTransactionHashBLS(t *testing.T) { + kit.QuietMiningLogs() + + blocktime := 1 * time.Second + client, _, ens := kit.EnsembleMinimal( + t, + kit.MockProofs(), + kit.ThroughRPC(), + ) + ens.InterconnectAll().BeginMining(blocktime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // get the existing balance from the default wallet to then split it. + bal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + + // create a new address where to send funds. + addr, err := client.WalletNew(ctx, types.KTBLS) + require.NoError(t, err) + + toSend := big.Div(bal, big.NewInt(2)) + msg := &types.Message{ + From: client.DefaultKey.Address, + To: addr, + Value: toSend, + } + + sm, err := client.MpoolPushMessage(ctx, msg, nil) + require.NoError(t, err) + + hash, err := ethtypes.EthHashFromCid(sm.Cid()) + require.NoError(t, err) + + mpoolCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash) + require.NoError(t, err) + require.NotNil(t, mpoolCid) + + mpoolTx, err := client.ChainGetMessage(ctx, *mpoolCid) + require.NoError(t, err) + require.NotNil(t, mpoolTx) + require.Equal(t, sm.Message, *mpoolTx) + + _, err = client.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(t, err) + + chainCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash) + require.NoError(t, err) + require.NotNil(t, chainCid) + + chainTx, err := client.ChainGetMessage(ctx, *mpoolCid) + require.NoError(t, err) + require.NotNil(t, chainTx) + require.Equal(t, sm.Message, *chainTx) +} diff --git a/itests/eth_transactions_test.go b/itests/eth_transactions_test.go new file mode 100644 index 000000000..9afeb7bd5 --- /dev/null +++ b/itests/eth_transactions_test.go @@ -0,0 +1,314 @@ +package itests + +import ( + "context" + "encoding/hex" + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" +) + +func TestValueTransferValidSignature(t *testing.T) { + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // install contract + contractHex, err := os.ReadFile("./contracts/SimpleCoin.hex") + require.NoError(t, err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + + // create a new Ethereum account + key, ethAddr, deployer := client.EVM().NewAccount() + _, ethAddr2, _ := client.EVM().NewAccount() + + kit.SendFunds(ctx, t, client, deployer, types.FromFil(1000)) + + gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + From: ðAddr, + Data: contract, + }) + require.NoError(t, err) + + maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) + require.NoError(t, err) + + tx := ethtypes.EthTxArgs{ + ChainID: build.Eip155ChainId, + Value: big.NewInt(100), + Nonce: 0, + To: ðAddr2, + MaxFeePerGas: types.NanoFil, + MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas), + GasLimit: int(gaslimit), + V: big.Zero(), + R: big.Zero(), + S: big.Zero(), + } + + client.EVM().SignTransaction(&tx, key.PrivateKey) + // Mangle signature + tx.V.Int.Xor(tx.V.Int, big.NewInt(1).Int) + + signed, err := tx.ToRlpSignedMsg() + require.NoError(t, err) + // Submit transaction with bad signature + _, err = client.EVM().EthSendRawTransaction(ctx, signed) + require.Error(t, err) + + // Submit transaction with valid signature + client.EVM().SignTransaction(&tx, key.PrivateKey) + hash := client.EVM().SubmitTransaction(ctx, &tx) + + receipt, err := waitForEthTxReceipt(ctx, client, hash) + require.NoError(t, err) + require.NotNil(t, receipt) + + // Success. + require.EqualValues(t, ethtypes.EthUint64(0x1), receipt.Status) + + ethTx, err := client.EthGetTransactionByHash(ctx, &hash) + require.Nil(t, err) + require.EqualValues(t, ethAddr, ethTx.From) + require.EqualValues(t, ethAddr2, *ethTx.To) + require.EqualValues(t, tx.ChainID, ethTx.ChainID) + require.EqualValues(t, tx.Nonce, ethTx.Nonce) + require.EqualValues(t, hash, ethTx.Hash) + require.EqualValues(t, tx.Value, ethTx.Value) + require.EqualValues(t, 2, ethTx.Type) + require.EqualValues(t, ethtypes.EthBytes{}, ethTx.Input) + require.EqualValues(t, tx.GasLimit, ethTx.Gas) + require.EqualValues(t, tx.MaxFeePerGas, ethTx.MaxFeePerGas) + require.EqualValues(t, tx.MaxPriorityFeePerGas, ethTx.MaxPriorityFeePerGas) + require.EqualValues(t, tx.V, ethTx.V) + require.EqualValues(t, tx.R, ethTx.R) + require.EqualValues(t, tx.S, ethTx.S) +} + +func TestLegacyTransaction(t *testing.T) { + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // This is a legacy style transaction obtained from etherscan + // Tx details: https://etherscan.io/getRawTx?tx=0x0763262208d89efeeb50c8bb05b50c537903fe9d7bdef3b223fd1f5f69f69b32 + txBytes, err := hex.DecodeString("f86f830131cf8504a817c800825208942cf1e5a8250ded8835694ebeb90cfa0237fcb9b1882ec4a5251d1100008026a0f5f8d2244d619e211eeb634acd1bea0762b7b4c97bba9f01287c82bfab73f911a015be7982898aa7cc6c6f27ff33e999e4119d6cd51330353474b98067ff56d930") + require.NoError(t, err) + _, err = client.EVM().EthSendRawTransaction(ctx, txBytes) + require.ErrorContains(t, err, "legacy transaction is not supported") +} + +func TestContractDeploymentValidSignature(t *testing.T) { + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // install contract + contractHex, err := os.ReadFile("./contracts/SimpleCoin.hex") + require.NoError(t, err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + + // create a new Ethereum account + key, ethAddr, deployer := client.EVM().NewAccount() + + // send some funds to the f410 address + kit.SendFunds(ctx, t, client, deployer, types.FromFil(10)) + + // verify the deployer address is a placeholder. + client.AssertActorType(ctx, deployer, manifest.PlaceholderKey) + + tx, err := deployContractTx(ctx, client, ethAddr, contract) + require.NoError(t, err) + + client.EVM().SignTransaction(tx, key.PrivateKey) + // Mangle signature + tx.V.Int.Xor(tx.V.Int, big.NewInt(1).Int) + + signed, err := tx.ToRlpSignedMsg() + require.NoError(t, err) + // Submit transaction with bad signature + _, err = client.EVM().EthSendRawTransaction(ctx, signed) + require.Error(t, err) + + // Submit transaction with valid signature + client.EVM().SignTransaction(tx, key.PrivateKey) + hash := client.EVM().SubmitTransaction(ctx, tx) + + receipt, err := waitForEthTxReceipt(ctx, client, hash) + require.NoError(t, err) + require.NotNil(t, receipt) + + // Success. + require.EqualValues(t, ethtypes.EthUint64(0x1), receipt.Status) + + // Verify that the deployer is now an account. + client.AssertActorType(ctx, deployer, manifest.EthAccountKey) + + // Verify that the nonce was incremented. + nonce, err := client.MpoolGetNonce(ctx, deployer) + require.NoError(t, err) + require.EqualValues(t, 1, nonce) + + // Verify that the deployer is now an account. + client.AssertActorType(ctx, deployer, manifest.EthAccountKey) +} + +func TestContractInvocation(t *testing.T) { + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // install contract + contractHex, err := os.ReadFile("./contracts/SimpleCoin.hex") + require.NoError(t, err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + + // create a new Ethereum account + key, ethAddr, deployer := client.EVM().NewAccount() + // send some funds to the f410 address + kit.SendFunds(ctx, t, client, deployer, types.FromFil(10)) + + // DEPLOY CONTRACT + tx, err := deployContractTx(ctx, client, ethAddr, contract) + require.NoError(t, err) + + client.EVM().SignTransaction(tx, key.PrivateKey) + hash := client.EVM().SubmitTransaction(ctx, tx) + + receipt, err := waitForEthTxReceipt(ctx, client, hash) + require.NoError(t, err) + require.NotNil(t, receipt) + require.EqualValues(t, ethtypes.EthUint64(0x1), receipt.Status) + + // Get contract address. + contractAddr := client.EVM().ComputeContractAddress(ethAddr, 0) + + // INVOKE CONTRACT + + // Params + // entry point for getBalance - f8b2cb4f + // address - ff00000000000000000000000000000000000064 + params, err := hex.DecodeString("f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064") + require.NoError(t, err) + + gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + From: ðAddr, + To: &contractAddr, + Data: params, + }) + require.NoError(t, err) + + maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) + require.NoError(t, err) + + invokeTx := ethtypes.EthTxArgs{ + ChainID: build.Eip155ChainId, + To: &contractAddr, + Value: big.Zero(), + Nonce: 1, + MaxFeePerGas: types.NanoFil, + MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas), + GasLimit: int(gaslimit), + Input: params, + V: big.Zero(), + R: big.Zero(), + S: big.Zero(), + } + + client.EVM().SignTransaction(&invokeTx, key.PrivateKey) + // Mangle signature + invokeTx.V.Int.Xor(invokeTx.V.Int, big.NewInt(1).Int) + + signed, err := invokeTx.ToRlpSignedMsg() + require.NoError(t, err) + // Submit transaction with bad signature + _, err = client.EVM().EthSendRawTransaction(ctx, signed) + require.Error(t, err) + + // Submit transaction with valid signature + client.EVM().SignTransaction(&invokeTx, key.PrivateKey) + hash = client.EVM().SubmitTransaction(ctx, &invokeTx) + + receipt, err = waitForEthTxReceipt(ctx, client, hash) + require.NoError(t, err) + require.NotNil(t, receipt) + + // Success. + require.EqualValues(t, ethtypes.EthUint64(0x1), receipt.Status) +} + +func deployContractTx(ctx context.Context, client *kit.TestFullNode, ethAddr ethtypes.EthAddress, contract []byte) (*ethtypes.EthTxArgs, error) { + gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + From: ðAddr, + Data: contract, + }) + if err != nil { + return nil, err + } + + maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) + if err != nil { + return nil, err + } + + // now deploy a contract from the embryo, and validate it went well + return ðtypes.EthTxArgs{ + ChainID: build.Eip155ChainId, + Value: big.Zero(), + Nonce: 0, + MaxFeePerGas: types.NanoFil, + MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas), + GasLimit: int(gaslimit), + Input: contract, + V: big.Zero(), + R: big.Zero(), + S: big.Zero(), + }, nil +} + +func waitForEthTxReceipt(ctx context.Context, client *kit.TestFullNode, hash ethtypes.EthHash) (*api.EthTxReceipt, error) { + var receipt *api.EthTxReceipt + var err error + for i := 0; i < 10000000000; i++ { + receipt, err = client.EthGetTransactionReceipt(ctx, hash) + if err != nil || receipt == nil { + time.Sleep(500 * time.Millisecond) + continue + } + break + } + return receipt, err +} diff --git a/itests/fevm_address_test.go b/itests/fevm_address_test.go new file mode 100644 index 000000000..9eaac4647 --- /dev/null +++ b/itests/fevm_address_test.go @@ -0,0 +1,180 @@ +package itests + +import ( + "bytes" + "context" + "encoding/hex" + "os" + "testing" + + "github.com/stretchr/testify/require" + "golang.org/x/crypto/sha3" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + builtintypes "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/builtin/v10/eam" + "github.com/filecoin-project/go-state-types/exitcode" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" +) + +func effectiveEthAddressForCreate(t *testing.T, sender address.Address) ethtypes.EthAddress { + switch sender.Protocol() { + case address.SECP256K1, address.BLS: + hasher := sha3.NewLegacyKeccak256() + hasher.Write(sender.Bytes()) + addr, err := ethtypes.CastEthAddress(hasher.Sum(nil)[12:]) + require.NoError(t, err) + return addr + case address.Delegated: + addr, err := ethtypes.EthAddressFromFilecoinAddress(sender) + require.NoError(t, err) + return addr + default: + require.FailNow(t, "unsupported protocol %d", sender.Protocol()) + } + panic("unreachable") +} + +func createAndDeploy(ctx context.Context, t *testing.T, client *kit.TestFullNode, fromAddr address.Address, contract []byte) *api.MsgLookup { + // Create and deploy evm actor + + method := builtintypes.MethodsEAM.CreateExternal + contractParams := abi.CborBytes(contract) + params, actorsErr := actors.SerializeParams(&contractParams) + require.NoError(t, actorsErr) + + createMsg := &types.Message{ + To: builtintypes.EthereumAddressManagerActorAddr, + From: fromAddr, + Value: big.Zero(), + Method: method, + Params: params, + } + smsg, err := client.MpoolPushMessage(ctx, createMsg, nil) + require.NoError(t, err) + + wait, err := client.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false) + require.NoError(t, err) + require.Equal(t, exitcode.Ok, wait.Receipt.ExitCode) + return wait +} + +func getEthAddressTX(ctx context.Context, t *testing.T, client *kit.TestFullNode, wait *api.MsgLookup, ethAddr ethtypes.EthAddress) ethtypes.EthAddress { + // Check if eth address returned from CreateExternal is the same as eth address predicted at the start + var createExternalReturn eam.CreateExternalReturn + err := createExternalReturn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)) + require.NoError(t, err) + + createdEthAddr, err := ethtypes.CastEthAddress(createExternalReturn.EthAddress[:]) + require.NoError(t, err) + return createdEthAddr +} + +func TestAddressCreationBeforeDeploy(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + // install contract + contractHex, err := os.ReadFile("contracts/SimpleCoin.hex") + require.NoError(t, err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + + fromAddr, err := client.WalletDefaultAddress(ctx) + require.NoError(t, err) + + // We hash the f1/f3 address into the EVM's address space when deploying contracts from + // accounts. + effectiveEvmAddress := effectiveEthAddressForCreate(t, fromAddr) + ethAddr := client.EVM().ComputeContractAddress(effectiveEvmAddress, 1) + + contractFilAddr, err := ethAddr.ToFilecoinAddress() + require.NoError(t, err) + + //transfer half the wallet balance + bal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + sendAmount := big.Div(bal, big.NewInt(2)) + client.EVM().TransferValueOrFail(ctx, fromAddr, contractFilAddr, sendAmount) + + // Check if actor at new address is a placeholder actor + actor, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK) + require.NoError(t, err) + require.True(t, builtin.IsPlaceholderActor(actor.Code)) + + // Create and deploy evm actor + wait := createAndDeploy(ctx, t, client, fromAddr, contract) + + // Check if eth address returned from CreateExternal is the same as eth address predicted at the start + createdEthAddr := getEthAddressTX(ctx, t, client, wait, ethAddr) + require.Equal(t, ethAddr, createdEthAddr) + + // Check if newly deployed actor still has funds + actorPostCreate, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK) + require.NoError(t, err) + require.Equal(t, actorPostCreate.Balance, sendAmount) + require.True(t, builtin.IsEvmActor(actorPostCreate.Code)) + +} + +func TestDeployAddressMultipleTimes(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + // install contract + contractHex, err := os.ReadFile("contracts/SimpleCoin.hex") + require.NoError(t, err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(t, err) + + fromAddr, err := client.WalletDefaultAddress(ctx) + require.NoError(t, err) + + // We hash the f1/f3 address into the EVM's address space when deploying contracts from + // accounts. + effectiveEvmAddress := effectiveEthAddressForCreate(t, fromAddr) + ethAddr := client.EVM().ComputeContractAddress(effectiveEvmAddress, 1) + + contractFilAddr, err := ethAddr.ToFilecoinAddress() + require.NoError(t, err) + + // Send contract address small funds to init + sendAmount := big.NewInt(2) + client.EVM().TransferValueOrFail(ctx, fromAddr, contractFilAddr, sendAmount) + + // Check if actor at new address is a placeholder actor + actor, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK) + require.NoError(t, err) + require.True(t, builtin.IsPlaceholderActor(actor.Code)) + + // Create and deploy evm actor + wait := createAndDeploy(ctx, t, client, fromAddr, contract) + + // Check if eth address returned from CreateExternal is the same as eth address predicted at the start + createdEthAddr := getEthAddressTX(ctx, t, client, wait, ethAddr) + require.Equal(t, ethAddr, createdEthAddr) + + // Check if newly deployed actor still has funds + actorPostCreate, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK) + require.NoError(t, err) + require.Equal(t, actorPostCreate.Balance, sendAmount) + require.True(t, builtin.IsEvmActor(actorPostCreate.Code)) + + // Create and deploy evm actor + wait = createAndDeploy(ctx, t, client, fromAddr, contract) + + // Check that this time eth address returned from CreateExternal is not the same as eth address predicted at the start + createdEthAddr = getEthAddressTX(ctx, t, client, wait, ethAddr) + require.NotEqual(t, ethAddr, createdEthAddr) + +} diff --git a/itests/fevm_events_test.go b/itests/fevm_events_test.go new file mode 100644 index 000000000..458ac3470 --- /dev/null +++ b/itests/fevm_events_test.go @@ -0,0 +1,87 @@ +package itests + +import ( + "context" + "encoding/hex" + "fmt" + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" +) + +// TestFEVMEvents does a basic events smoke test. +func TestFEVMEvents(t *testing.T) { + require := require.New(t) + + kit.QuietMiningLogs() + + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // install contract + // See https://github.com/filecoin-project/builtin-actors/blob/next/actors/evm/tests/events.rs#L12 + contractHex, err := os.ReadFile("contracts/events.bin") + require.NoError(err) + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(err) + + fromAddr, err := client.WalletDefaultAddress(ctx) + require.NoError(err) + + result := client.EVM().DeployContract(ctx, fromAddr, contract) + + idAddr, err := address.NewIDAddress(result.ActorID) + require.NoError(err) + t.Logf("actor ID address is %s", idAddr) + + var ( + earliest = "earliest" + latest = "latest" + ) + + // Install a filter. + filter, err := client.EthNewFilter(ctx, ðtypes.EthFilterSpec{ + FromBlock: &earliest, + ToBlock: &latest, + }) + require.NoError(err) + + // No logs yet. + res, err := client.EthGetFilterLogs(ctx, filter) + require.NoError(err) + require.Empty(res.Results) + + // log a zero topic event with data + ret, err := client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x00}, nil) + require.NoError(err) + require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed") + require.NotNil(ret.Receipt.EventsRoot) + fmt.Println(ret) + fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot)) + + // log a zero topic event with no data + ret, err = client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x01}, nil) + require.NoError(err) + require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed") + fmt.Println(ret) + fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot)) + + // log a four topic event with data + ret, err = client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x02}, nil) + require.NoError(err) + require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed") + fmt.Println(ret) + fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot)) +} diff --git a/itests/fevm_test.go b/itests/fevm_test.go new file mode 100644 index 000000000..b93cc824d --- /dev/null +++ b/itests/fevm_test.go @@ -0,0 +1,1013 @@ +package itests + +import ( + "bytes" + "context" + "crypto/rand" + "encoding/binary" + "encoding/hex" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/big" + builtintypes "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/go-state-types/manifest" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" +) + +// convert a simple byte array into input data which is a left padded 32 byte array +func inputDataFromArray(input []byte) []byte { + inputData := make([]byte, 32) + copy(inputData[32-len(input):], input[:]) + return inputData +} + +// convert a "from" address into input data which is a left padded 32 byte array +func inputDataFromFrom(ctx context.Context, t *testing.T, client *kit.TestFullNode, from address.Address) []byte { + fromId, err := client.StateLookupID(ctx, from, types.EmptyTSK) + require.NoError(t, err) + + senderEthAddr, err := ethtypes.EthAddressFromFilecoinAddress(fromId) + require.NoError(t, err) + inputData := make([]byte, 32) + copy(inputData[32-len(senderEthAddr):], senderEthAddr[:]) + return inputData +} + +func decodeOutputToUint64(output []byte) (uint64, error) { + var result uint64 + buf := bytes.NewReader(output[len(output)-8:]) + err := binary.Read(buf, binary.BigEndian, &result) + return result, err +} +func buildInputFromuint64(number uint64) []byte { + // Convert the number to a binary uint64 array + binaryNumber := make([]byte, 8) + binary.BigEndian.PutUint64(binaryNumber, number) + return inputDataFromArray(binaryNumber) +} + +// recursive delegate calls that fail due to gas limits are currently getting to 229 iterations +// before running out of gas +func recursiveDelegatecallFail(ctx context.Context, t *testing.T, client *kit.TestFullNode, filename string, count uint64) { + expectedIterationsBeforeFailing := int(220) + fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename) + t.Log("recursion count - ", count) + inputData := buildInputFromuint64(count) + _, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", inputData) + + require.NoError(t, err) + + result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "totalCalls()", []byte{}) + require.NoError(t, err) + + resultUint, err := decodeOutputToUint64(result) + require.NoError(t, err) + + require.NotEqual(t, int(resultUint), int(count)) + require.Equal(t, expectedIterationsBeforeFailing, int(resultUint)) +} +func recursiveDelegatecallSuccess(ctx context.Context, t *testing.T, client *kit.TestFullNode, filename string, count uint64) { + t.Log("Count - ", count) + + fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename) + inputData := buildInputFromuint64(count) + _, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", inputData) + require.NoError(t, err) + + result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "totalCalls()", []byte{}) + require.NoError(t, err) + + resultUint, err := decodeOutputToUint64(result) + require.NoError(t, err) + + require.Equal(t, int(count), int(resultUint)) +} + +// TestFEVMRecursive does a basic fevm contract installation and invocation +func TestFEVMRecursive(t *testing.T) { + callCounts := []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 230, 330} + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + filename := "contracts/Recursive.hex" + fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename) + + // Successful calls + for _, callCount := range callCounts { + callCount := callCount // linter unhappy unless callCount is local to loop + t.Run(fmt.Sprintf("TestFEVMRecursive%d", callCount), func(t *testing.T) { + _, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", buildInputFromuint64(callCount)) + require.NoError(t, err) + }) + } + +} + +func TestFEVMRecursiveFail(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + filename := "contracts/Recursive.hex" + fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename) + + // Unsuccessful calls + failCallCounts := []uint64{340, 400, 600, 850, 1000} + for _, failCallCount := range failCallCounts { + failCallCount := failCallCount // linter unhappy unless callCount is local to loop + t.Run(fmt.Sprintf("TestFEVMRecursiveFail%d", failCallCount), func(t *testing.T) { + _, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", buildInputFromuint64(failCallCount)) + require.Error(t, err) + require.Equal(t, exitcode.ExitCode(37), wait.Receipt.ExitCode) + }) + } +} + +func TestFEVMRecursive1(t *testing.T) { + callCount := 1 + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + filename := "contracts/Recursive.hex" + fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename) + _, ret, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursive1()", []byte{}) + require.NoError(t, err) + events := client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot) + require.Equal(t, callCount, len(events)) +} +func TestFEVMRecursive2(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + filename := "contracts/Recursive.hex" + fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename) + _, ret, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursive2()", []byte{}) + require.NoError(t, err) + events := client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot) + require.Equal(t, 2, len(events)) +} + +// TestFEVMRecursiveDelegatecallCount tests the maximum delegatecall recursion depth. It currently +// succeeds succeeds up to 237 times. +func TestFEVMRecursiveDelegatecallCount(t *testing.T) { + + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + highestSuccessCount := uint64(225) + + filename := "contracts/RecursiveDelegeatecall.hex" + recursiveDelegatecallSuccess(ctx, t, client, filename, uint64(1)) + recursiveDelegatecallSuccess(ctx, t, client, filename, uint64(2)) + recursiveDelegatecallSuccess(ctx, t, client, filename, uint64(10)) + recursiveDelegatecallSuccess(ctx, t, client, filename, uint64(100)) + recursiveDelegatecallSuccess(ctx, t, client, filename, highestSuccessCount) + + recursiveDelegatecallFail(ctx, t, client, filename, highestSuccessCount+1) + recursiveDelegatecallFail(ctx, t, client, filename, uint64(1000)) + recursiveDelegatecallFail(ctx, t, client, filename, uint64(10000000)) + +} + +// TestFEVMBasic does a basic fevm contract installation and invocation +func TestFEVMBasic(t *testing.T) { + + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + filename := "contracts/SimpleCoin.hex" + // install contract + fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename) + + // invoke the contract with owner + { + inputData := inputDataFromFrom(ctx, t, client, fromAddr) + result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData) + require.NoError(t, err) + + expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000002710") + require.NoError(t, err) + require.Equal(t, result, expectedResult) + } + + // invoke the contract with non owner + { + inputData := inputDataFromFrom(ctx, t, client, fromAddr) + inputData[31]++ // change the pub address to one that has 0 balance by modifying the last byte of the address + result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData) + require.NoError(t, err) + + expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000") + require.NoError(t, err) + require.Equal(t, result, expectedResult) + } +} + +// TestFEVMETH0 tests that the ETH0 actor is in genesis +func TestFEVMETH0(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + eth0id, err := address.NewIDAddress(1001) + require.NoError(t, err) + + client.AssertActorType(ctx, eth0id, manifest.EthAccountKey) + + act, err := client.StateGetActor(ctx, eth0id, types.EmptyTSK) + require.NoError(t, err) + + eth0Addr, err := address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, make([]byte, 20)) + require.NoError(t, err) + require.Equal(t, *act.Address, eth0Addr) +} + +// TestFEVMDelegateCall deploys two contracts and makes a delegate call transaction +func TestFEVMDelegateCall(t *testing.T) { + + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract Actor + filenameActor := "contracts/DelegatecallActor.hex" + fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + //install contract Storage + filenameStorage := "contracts/DelegatecallStorage.hex" + fromAddrStorage, storageAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage) + require.Equal(t, fromAddr, fromAddrStorage) + + //call Contract Storage which makes a delegatecall to contract Actor + //this contract call sets the "counter" variable to 7, from default value 0 + inputDataContract := inputDataFromFrom(ctx, t, client, actorAddr) + inputDataValue := inputDataFromArray([]byte{7}) + inputData := append(inputDataContract, inputDataValue...) + + //verify that the returned value of the call to setvars is 7 + result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "setVars(address,uint256)", inputData) + require.NoError(t, err) + expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000007") + require.NoError(t, err) + require.Equal(t, result, expectedResult) + + //test the value is 7 a second way by calling the getter + result, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "getCounter()", []byte{}) + require.NoError(t, err) + require.Equal(t, result, expectedResult) + + //test the value is 0 via calling the getter on the Actor contract + result, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "getCounter()", []byte{}) + require.NoError(t, err) + expectedResultActor, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000") + require.NoError(t, err) + require.Equal(t, result, expectedResultActor) + + // The implementation's storage should not have been updated. + actorAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(actorAddr) + require.NoError(t, err) + value, err := client.EVM().EthGetStorageAt(ctx, actorAddrEth, nil, "latest") + require.NoError(t, err) + require.Equal(t, ethtypes.EthBytes(make([]byte, 32)), value) + + // The storage actor's storage _should_ have been updated + storageAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(storageAddr) + require.NoError(t, err) + value, err = client.EVM().EthGetStorageAt(ctx, storageAddrEth, nil, "latest") + require.NoError(t, err) + require.Equal(t, ethtypes.EthBytes(expectedResult), value) +} + +// TestFEVMDelegateCallRevert makes a delegatecall action and then calls revert. +// the state should not have changed because of the revert +func TestFEVMDelegateCallRevert(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract Actor + filenameActor := "contracts/DelegatecallActor.hex" + fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + //install contract Storage + filenameStorage := "contracts/DelegatecallStorage.hex" + fromAddrStorage, storageAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage) + require.Equal(t, fromAddr, fromAddrStorage) + + //call Contract Storage which makes a delegatecall to contract Actor + //this contract call sets the "counter" variable to 7, from default value 0 + + inputDataContract := inputDataFromFrom(ctx, t, client, actorAddr) + inputDataValue := inputDataFromArray([]byte{7}) + inputData := append(inputDataContract, inputDataValue...) + + //verify that the returned value of the call to setvars is 7 + _, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "setVarsRevert(address,uint256)", inputData) + require.Error(t, err) + require.Equal(t, exitcode.ExitCode(33), wait.Receipt.ExitCode) + + //test the value is 0 via calling the getter and was not set to 7 + expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000") + require.NoError(t, err) + result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "getCounter()", []byte{}) + require.NoError(t, err) + require.Equal(t, result, expectedResult) + + //test the value is 0 via calling the getter on the Actor contract + result, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "getCounter()", []byte{}) + require.NoError(t, err) + require.Equal(t, result, expectedResult) +} + +// TestFEVMSimpleRevert makes a call that is a simple revert +func TestFEVMSimpleRevert(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract Actor + filenameStorage := "contracts/DelegatecallStorage.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage) + + //call revert + _, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "revert()", []byte{}) + + require.Equal(t, wait.Receipt.ExitCode, exitcode.ExitCode(33)) + require.Error(t, err) +} + +// TestFEVMSelfDestruct creates a contract that just has a self destruct feature and calls it +func TestFEVMSelfDestruct(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract Actor + filenameStorage := "contracts/SelfDestruct.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage) + + //call destroy + _, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{}) + require.NoError(t, err) + + //call destroy a second time and also no error + _, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{}) + require.NoError(t, err) +} + +// TestFEVMTestApp deploys a fairly complex app contract and confirms it works as expected +func TestFEVMTestApp(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract Actor + filenameStorage := "contracts/TestApp.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage) + + inputData, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000066162636465660000000000000000000000000000000000000000000000000000") // sending string "abcdef" and int 7 - constructed using remix + require.NoError(t, err) + _, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "new_Test(string,uint256)", inputData) + require.NoError(t, err) + + inputData, err = hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000") + require.NoError(t, err) + + _, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "get_Test_N(uint256)", inputData) + require.NoError(t, err) + +} + +// TestFEVMTestApp creates a contract that just has a self destruct feature and calls it +func TestFEVMTestConstructor(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract Actor + filenameStorage := "contracts/Constructor.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage) + + //input = uint256{7}. set value and confirm tx success + inputData, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000007") + require.NoError(t, err) + _, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "new_Test(uint256)", inputData) + require.NoError(t, err) + +} + +// TestFEVMAutoSelfDestruct creates a contract that just has a self destruct feature and calls it +func TestFEVMAutoSelfDestruct(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract Actor + filenameStorage := "contracts/AutoSelfDestruct.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage) + + //call destroy + _, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{}) + require.NoError(t, err) +} + +// TestFEVMTestApp creates a contract that just has a self destruct feature and calls it +func TestFEVMTestSendToContract(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + bal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + + //install contract TestApp + filenameStorage := "contracts/SelfDestruct.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage) + + //transfer half balance to contract + + sendAmount := big.Div(bal, big.NewInt(2)) + client.EVM().TransferValueOrFail(ctx, fromAddr, contractAddr, sendAmount) + + //call self destruct which should return balance + _, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{}) + require.NoError(t, err) + + finalBalanceMinimum := types.FromFil(uint64(99_999_999)) // 100 million FIL - 1 FIL for gas upper bounds + finalBal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + require.Equal(t, true, finalBal.GreaterThan(finalBalanceMinimum)) +} + +// creates a contract that would fail when tx are sent to it +// on eth but on fevm it succeeds +// example failing on testnet https://goerli.etherscan.io/address/0x2ff1525e060169dbf97b9461758c8f701f107cd2 +func TestFEVMTestNotPayable(t *testing.T) { + + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + fromAddr := client.DefaultKey.Address + t.Log("from - ", fromAddr) + + //create contract A + filenameStorage := "contracts/NotPayable.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage) + sendAmount := big.NewInt(10_000_000) + + client.EVM().TransferValueOrFail(ctx, fromAddr, contractAddr, sendAmount) + +} + +// tx to non function succeeds +func TestFEVMSendCall(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract + filenameActor := "contracts/GasSendTest.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + _, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "x()", []byte{}) + require.NoError(t, err) +} + +// creates a contract that would fail when tx are sent to it +// on eth but on fevm it succeeds +// example on goerli of tx failing https://goerli.etherscan.io/address/0xec037bdc9a79420985a53a49fdae3ccf8989909b +func TestFEVMSendGasLimit(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract + filenameActor := "contracts/GasLimitSend.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + //send $ to contract + //transfer 1 attoFIL to contract + sendAmount := big.MustFromString("1") + + client.EVM().TransferValueOrFail(ctx, fromAddr, contractAddr, sendAmount) + _, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "getDataLength()", []byte{}) + require.NoError(t, err) + +} + +// TestFEVMDelegateCall deploys the two contracts in TestFEVMDelegateCall but instead of A calling B, A calls A which should cause A to cause A in an infinite loop and should give a reasonable error +func TestFEVMDelegateCallRecursiveFail(t *testing.T) { + //TODO change the gas limit of this invocation and confirm that the number of errors is + // different + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract Actor + filenameActor := "contracts/DelegatecallStorage.hex" + fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + //any data will do for this test that fails + inputDataContract := inputDataFromFrom(ctx, t, client, actorAddr) + inputDataValue := inputDataFromArray([]byte{7}) + inputData := append(inputDataContract, inputDataValue...) + + //verify that we run out of gas then revert. + _, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "setVarsSelf(address,uint256)", inputData) + require.Error(t, err) + require.Equal(t, exitcode.ExitCode(33), wait.Receipt.ExitCode) + + //assert no fatal errors but still there are errors:: + errorAny := "fatal error" + require.NotContains(t, err.Error(), errorAny) +} + +// TestFEVMTestSendValueThroughContracts creates A and B contract and exchanges value +// and self destructs and accounts for value sent +func TestFEVMTestSendValueThroughContractsAndDestroy(t *testing.T) { + + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + fromAddr := client.DefaultKey.Address + t.Log("from - ", fromAddr) + + //create contract A + filenameStorage := "contracts/ValueSender.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage) + + //create contract B + ret, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "createB()", []byte{}) + require.NoError(t, err) + + ethAddr, err := ethtypes.CastEthAddress(ret[12:]) + require.NoError(t, err) + contractBAddress, err := ethAddr.ToFilecoinAddress() + require.NoError(t, err) + t.Log("contractBAddress - ", contractBAddress) + + //self destruct contract B + _, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractBAddress, "selfDestruct()", []byte{}) + require.NoError(t, err) + +} + +func TestEVMRpcDisable(t *testing.T) { + client, _, _ := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.DisableEthRPC()) + + _, err := client.EthBlockNumber(context.Background()) + require.ErrorContains(t, err, "module disabled, enable with Fevm.EnableEthRPC") +} + +// TestFEVMRecursiveFuncCall deploys a contract and makes a recursive function calls +func TestFEVMRecursiveFuncCall(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract Actor + filenameActor := "contracts/StackFunc.hex" + fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + testN := func(n int, ex exitcode.ExitCode) func(t *testing.T) { + return func(t *testing.T) { + inputData := make([]byte, 32) + binary.BigEndian.PutUint64(inputData[24:], uint64(n)) + client.EVM().InvokeContractByFuncNameExpectExit(ctx, fromAddr, actorAddr, "exec1(uint256)", inputData, ex) + } + } + + t.Run("n=0", testN(0, exitcode.Ok)) + t.Run("n=1", testN(1, exitcode.Ok)) + t.Run("n=20", testN(20, exitcode.Ok)) + t.Run("n=200", testN(200, exitcode.Ok)) + t.Run("n=507", testN(507, exitcode.Ok)) + t.Run("n=508", testN(508, exitcode.ExitCode(37))) // 37 means stack overflow +} + +// TestFEVMRecursiveActorCall deploys a contract and makes a recursive actor calls +func TestFEVMRecursiveActorCall(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract Actor + filenameActor := "contracts/RecCall.hex" + fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + testN := func(n, r int, ex exitcode.ExitCode) func(t *testing.T) { + return func(t *testing.T) { + inputData := make([]byte, 32*3) + binary.BigEndian.PutUint64(inputData[24:], uint64(n)) + binary.BigEndian.PutUint64(inputData[32+24:], uint64(n)) + binary.BigEndian.PutUint64(inputData[32+32+24:], uint64(r)) + + client.EVM().InvokeContractByFuncNameExpectExit(ctx, fromAddr, actorAddr, "exec1(uint256,uint256,uint256)", inputData, ex) + } + } + + t.Run("n=0,r=1", testN(0, 1, exitcode.Ok)) + t.Run("n=1,r=1", testN(1, 1, exitcode.Ok)) + t.Run("n=20,r=1", testN(20, 1, exitcode.Ok)) + t.Run("n=200,r=1", testN(200, 1, exitcode.Ok)) + t.Run("n=251,r=1", testN(251, 1, exitcode.Ok)) + + t.Run("n=252,r=1-fails", testN(252, 1, exitcode.ExitCode(37))) // 37 means stack overflow + + t.Run("n=0,r=10", testN(0, 10, exitcode.Ok)) + t.Run("n=1,r=10", testN(1, 10, exitcode.Ok)) + t.Run("n=20,r=10", testN(20, 10, exitcode.Ok)) + t.Run("n=200,r=10", testN(200, 10, exitcode.Ok)) + t.Run("n=251,r=10", testN(251, 10, exitcode.Ok)) + + t.Run("n=252,r=10-fails", testN(252, 10, exitcode.ExitCode(37))) + + t.Run("n=0,r=32", testN(0, 32, exitcode.Ok)) + t.Run("n=1,r=32", testN(1, 32, exitcode.Ok)) + t.Run("n=20,r=32", testN(20, 32, exitcode.Ok)) + t.Run("n=200,r=32", testN(200, 32, exitcode.Ok)) + t.Run("n=251,r=32", testN(251, 32, exitcode.Ok)) + + t.Run("n=0,r=252", testN(0, 252, exitcode.Ok)) + t.Run("n=251,r=166", testN(251, 166, exitcode.Ok)) + + t.Run("n=0,r=253-fails", testN(0, 253, exitcode.ExitCode(33))) // 33 means transaction reverted + t.Run("n=251,r=167-fails", testN(251, 167, exitcode.ExitCode(33))) +} + +// TestFEVMRecursiveActorCallEstimate +func TestFEVMRecursiveActorCallEstimate(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract Actor + filenameActor := "contracts/ExternalRecursiveCallSimple.hex" + _, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + contractAddr, err := ethtypes.EthAddressFromFilecoinAddress(actorAddr) + require.NoError(t, err) + + // create a new Ethereum account + key, ethAddr, ethFilAddr := client.EVM().NewAccount() + kit.SendFunds(ctx, t, client, ethFilAddr, types.FromFil(1000)) + + makeParams := func(r int) []byte { + funcSignature := "exec1(uint256)" + entryPoint := kit.CalcFuncSignature(funcSignature) + + inputData := make([]byte, 32) + binary.BigEndian.PutUint64(inputData[24:], uint64(r)) + + params := append(entryPoint, inputData...) + + return params + } + + testN := func(r int) func(t *testing.T) { + return func(t *testing.T) { + t.Logf("running with %d recursive calls", r) + + params := makeParams(r) + gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + From: ðAddr, + To: &contractAddr, + Data: params, + }) + require.NoError(t, err) + require.LessOrEqual(t, int64(gaslimit), build.BlockGasLimit) + + t.Logf("EthEstimateGas GasLimit=%d", gaslimit) + + maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) + require.NoError(t, err) + + nonce, err := client.MpoolGetNonce(ctx, ethFilAddr) + require.NoError(t, err) + + tx := ðtypes.EthTxArgs{ + ChainID: build.Eip155ChainId, + To: &contractAddr, + Value: big.Zero(), + Nonce: int(nonce), + MaxFeePerGas: types.NanoFil, + MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas), + GasLimit: int(gaslimit), + Input: params, + V: big.Zero(), + R: big.Zero(), + S: big.Zero(), + } + + client.EVM().SignTransaction(tx, key.PrivateKey) + hash := client.EVM().SubmitTransaction(ctx, tx) + + smsg, err := tx.ToSignedMessage() + require.NoError(t, err) + + _, err = client.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false) + require.NoError(t, err) + + receipt, err := client.EthGetTransactionReceipt(ctx, hash) + require.NoError(t, err) + require.NotNil(t, receipt) + + t.Logf("Receipt GasUsed=%d", receipt.GasUsed) + t.Logf("Ratio %0.2f", float64(receipt.GasUsed)/float64(gaslimit)) + t.Logf("Overestimate %0.2f", ((float64(gaslimit)/float64(receipt.GasUsed))-1)*100) + + require.EqualValues(t, ethtypes.EthUint64(1), receipt.Status) + } + } + + t.Run("n=1", testN(1)) + t.Run("n=2", testN(2)) + t.Run("n=3", testN(3)) + t.Run("n=4", testN(4)) + t.Run("n=5", testN(5)) + t.Run("n=10", testN(10)) + t.Run("n=20", testN(20)) + t.Run("n=30", testN(30)) + t.Run("n=40", testN(40)) + t.Run("n=50", testN(50)) + t.Run("n=100", testN(100)) +} + +// TestFEVM deploys a contract while sending value to it +func TestFEVMDeployWithValue(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //testValue is the amount sent when the contract is created + //at the end we check that the new contract has a balance of testValue + testValue := big.NewInt(20) + + // deploy DeployValueTest which creates NewContract + // testValue is sent to DeployValueTest and that amount is + // also sent to NewContract + filenameActor := "contracts/DeployValueTest.hex" + fromAddr, idAddr := client.EVM().DeployContractFromFilenameWithValue(ctx, filenameActor, testValue) + + //call getNewContractBalance to find the value of NewContract + ret, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getNewContractBalance()", []byte{}) + require.NoError(t, err) + + contractBalance, err := decodeOutputToUint64(ret) + require.NoError(t, err) + + //require balance of NewContract is testValue + require.Equal(t, testValue.Uint64(), contractBalance) +} + +func TestFEVMDestroyCreate2(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //deploy create2 factory contract + filename := "contracts/Create2Factory.hex" + fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename) + + //construct salt for create2 + salt := make([]byte, 32) + _, err := rand.Read(salt) + require.NoError(t, err) + + //deploy contract using create2 factory + selfDestructAddress, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "deploy(bytes32)", salt) + require.NoError(t, err) + + //convert to filecoin actor address so we can call InvokeContractByFuncName + ea, err := ethtypes.CastEthAddress(selfDestructAddress[12:]) + require.NoError(t, err) + selfDestructAddressActor, err := ea.ToFilecoinAddress() + require.NoError(t, err) + + //read sender property from contract + ret, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, selfDestructAddressActor, "sender()", []byte{}) + require.NoError(t, err) + + //assert contract has correct data + ethFromAddr := inputDataFromFrom(ctx, t, client, fromAddr) + require.Equal(t, ethFromAddr, ret) + + //run test() which 1.calls sefldestruct 2. verifies sender() is the correct value 3. attempts and fails to deploy via create2 + testSenderAddress, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "test(address)", selfDestructAddress) + require.NoError(t, err) + require.Equal(t, testSenderAddress, ethFromAddr) + + //read sender() but get response of 0x0 because of self destruct + senderAfterDestroy, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, selfDestructAddressActor, "sender()", []byte{}) + require.NoError(t, err) + require.Equal(t, []byte{}, senderAfterDestroy) + + // deploy new contract at same address usign same salt + newAddressSelfDestruct, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "deploy(bytes32)", salt) + require.NoError(t, err) + require.Equal(t, newAddressSelfDestruct, selfDestructAddress) + + //verify sender() property is correct + senderSecondCall, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, selfDestructAddressActor, "sender()", []byte{}) + require.NoError(t, err) + + //assert contract has correct data + require.Equal(t, ethFromAddr, senderSecondCall) + +} + +func TestFEVMBareTransferTriggersSmartContractLogic(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + // This contract emits an event on receiving value. + filename := "contracts/ValueSender.hex" + _, contractAddr := client.EVM().DeployContractFromFilename(ctx, filename) + + accctKey, accntEth, accntFil := client.EVM().NewAccount() + kit.SendFunds(ctx, t, client, accntFil, types.FromFil(10)) + + contractEth, err := ethtypes.EthAddressFromFilecoinAddress(contractAddr) + require.NoError(t, err) + + gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + From: &accntEth, + To: &contractEth, + Value: ethtypes.EthBigInt(big.NewInt(100)), + }) + require.NoError(t, err) + + maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) + require.NoError(t, err) + + tx := ethtypes.EthTxArgs{ + ChainID: build.Eip155ChainId, + Value: big.NewInt(100), + Nonce: 0, + To: &contractEth, + MaxFeePerGas: types.NanoFil, + MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas), + GasLimit: int(gaslimit), + V: big.Zero(), + R: big.Zero(), + S: big.Zero(), + } + + client.EVM().SignTransaction(&tx, accctKey.PrivateKey) + + hash := client.EVM().SubmitTransaction(ctx, &tx) + + var receipt *api.EthTxReceipt + for i := 0; i < 1000; i++ { + receipt, err = client.EthGetTransactionReceipt(ctx, hash) + require.NoError(t, err) + if receipt != nil { + break + } + time.Sleep(500 * time.Millisecond) + } + + // The receive() function emits one log, that's how we know we hit it. + require.Len(t, receipt.Logs, 1) +} + +func TestFEVMProxyUpgradeable(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install transparently upgradeable proxy + proxyFilename := "contracts/TransparentUpgradeableProxy.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, proxyFilename) + + _, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "test()", []byte{}) + require.NoError(t, err) +} + +func TestFEVMGetBlockDifficulty(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract + filenameActor := "contracts/GetDifficulty.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + ret, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "getDifficulty()", []byte{}) + require.NoError(t, err) + require.Equal(t, len(ret), 32) +} + +func TestFEVMTestCorrectChainID(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract + filenameActor := "contracts/Blocktest.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + //run test + _, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "testChainID()", []byte{}) + require.NoError(t, err) +} + +func TestFEVMGetChainPropertiesBlockTimestamp(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract + filenameActor := "contracts/Blocktest.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + // block number check + ret, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "getTimestamp()", []byte{}) + require.NoError(t, err) + + timestampFromSolidity, err := decodeOutputToUint64(ret) + require.NoError(t, err) + + ethBlock := client.EVM().GetEthBlockFromWait(ctx, wait) + + require.Equal(t, ethBlock.Timestamp, ethtypes.EthUint64(timestampFromSolidity)) +} + +func TestFEVMGetChainPropertiesBlockNumber(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract + filenameActor := "contracts/Blocktest.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + // block number check + ret, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "getBlockNumber()", []byte{}) + require.NoError(t, err) + + blockHeightFromSolidity, err := decodeOutputToUint64(ret) + require.NoError(t, err) + + ethBlock := client.EVM().GetEthBlockFromWait(ctx, wait) + + require.Equal(t, ethBlock.Number, ethtypes.EthUint64(blockHeightFromSolidity)) +} + +func TestFEVMGetChainPropertiesBlockHash(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract + filenameActor := "contracts/Blocktest.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + //block hash check + ret, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "getBlockhashPrevious()", []byte{}) + expectedBlockHash := hex.EncodeToString(ret) + require.NoError(t, err) + + ethBlock := client.EVM().GetEthBlockFromWait(ctx, wait) + //in solidity we get the parent block hash because the current block hash doesnt exist at that execution context yet + //so we compare the parent hash here in the test + require.Equal(t, "0x"+expectedBlockHash, ethBlock.ParentHash.String()) +} + +func TestFEVMGetChainPropertiesBaseFee(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + //install contract + filenameActor := "contracts/Blocktest.hex" + fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor) + + ret, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "getBasefee()", []byte{}) + require.NoError(t, err) + baseFeeRet, err := decodeOutputToUint64(ret) + require.NoError(t, err) + + ethBlock := client.EVM().GetEthBlockFromWait(ctx, wait) + + require.Equal(t, ethBlock.BaseFeePerGas, ethtypes.EthBigInt(big.NewInt(int64(baseFeeRet)))) +} + +func TestFEVMErrorParsing(t *testing.T) { + ctx, cancel, client := kit.SetupFEVMTest(t) + defer cancel() + + e := client.EVM() + + _, contractAddr := e.DeployContractFromFilename(ctx, "contracts/Errors.hex") + contractAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(contractAddr) + require.NoError(t, err) + customError := ethtypes.EthBytes(kit.CalcFuncSignature("CustomError()")).String() + for sig, expected := range map[string]string{ + "failRevertEmpty()": "none", + "failRevertReason()": "Error(my reason)", + "failAssert()": "Assert()", + "failDivZero()": "DivideByZero()", + "failCustom()": customError, + } { + sig := sig + expected := fmt.Sprintf("exit 33, revert reason: %s, vm error", expected) + t.Run(sig, func(t *testing.T) { + entryPoint := kit.CalcFuncSignature(sig) + t.Run("EthCall", func(t *testing.T) { + _, err := e.EthCall(ctx, ethtypes.EthCall{ + To: &contractAddrEth, + Data: entryPoint, + }, "latest") + require.ErrorContains(t, err, expected) + }) + t.Run("EthEstimateGas", func(t *testing.T) { + _, err := e.EthEstimateGas(ctx, ethtypes.EthCall{ + To: &contractAddrEth, + Data: entryPoint, + }) + require.ErrorContains(t, err, expected) + }) + }) + } +} diff --git a/itests/gas_estimation_test.go b/itests/gas_estimation_test.go index 42cad8611..24013c885 100644 --- a/itests/gas_estimation_test.go +++ b/itests/gas_estimation_test.go @@ -2,16 +2,23 @@ package itests import ( "context" + "math" "testing" "time" "github.com/stretchr/testify/require" + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/builtin/account" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/itests/kit" ) @@ -37,8 +44,9 @@ func TestEstimateGasNoFunds(t *testing.T) { sm, err := client.MpoolPushMessage(ctx, msg, nil) require.NoError(t, err) - _, err = client.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true) + ret, err := client.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true) require.NoError(t, err) + require.True(t, ret.Receipt.ExitCode.IsSuccess()) // Make sure we can estimate gas even if we have no funds. msg2 := &types.Message{ @@ -52,3 +60,110 @@ func TestEstimateGasNoFunds(t *testing.T) { require.NoError(t, err) require.NotZero(t, limit) } + +// Make sure that we correctly calculate the inclusion cost. Especially, make sure the FVM and Lotus +// agree and that: +// 1. The FVM will never charge _less_ than the inclusion cost. +// 2. The FVM will never fine a storage provider for including a message that costs exactly the +// inclusion cost. +func TestEstimateInclusion(t *testing.T) { + ctx := context.Background() + + kit.QuietMiningLogs() + + // We need this to be "correct" in this test so that lotus can get the correct gas value + // (which, unfortunately, looks at the height and not the current network version). + oldPrices := vm.Prices + vm.Prices = map[abi.ChainEpoch]vm.Pricelist{ + 0: oldPrices[build.UpgradeHyggeHeight], + } + t.Cleanup(func() { vm.Prices = oldPrices }) + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs()) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + // First, try sending a message that should have no fees beyond the inclusion cost. I.e., it + // does absolutely nothing: + msg := &types.Message{ + From: client.DefaultKey.Address, + To: client.DefaultKey.Address, + Value: big.Zero(), + GasLimit: 0, + GasFeeCap: abi.NewTokenAmount(10000), + GasPremium: big.Zero(), + } + + burntBefore, err := client.WalletBalance(ctx, builtin.BurntFundsActorAddr) + require.NoError(t, err) + balanceBefore, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + + // Sign the message and compute the correct inclusion cost. + var smsg *types.SignedMessage + for i := 0; ; i++ { + var err error + smsg, err = client.WalletSignMessage(ctx, client.DefaultKey.Address, msg) + require.NoError(t, err) + estimatedGas := vm.PricelistByEpoch(math.MaxInt).OnChainMessage(smsg.ChainLength()).Total() + if estimatedGas == msg.GasLimit { + break + } + // Try 10 times to get the right gas value. + require.Less(t, i, 10, "unable to estimate gas: %s != %s", estimatedGas, msg.GasLimit) + msg.GasLimit = estimatedGas + } + + cid, err := client.MpoolPush(ctx, smsg) + require.NoError(t, err) + ret, err := client.StateWaitMsg(ctx, cid, 3, api.LookbackNoLimit, true) + require.NoError(t, err) + require.True(t, ret.Receipt.ExitCode.IsSuccess()) + require.Equal(t, msg.GasLimit, ret.Receipt.GasUsed) + + // Then try sending a message of the same size that tries to create an actor. This should + // get successfully included, but fail with out of gas: + + // Mutate the last byte to get a new address of the same length. + toBytes := msg.To.Bytes() + toBytes[len(toBytes)-1] += 1 //nolint:golint + newAddr, err := address.NewFromBytes(toBytes) + require.NoError(t, err) + + msg.Nonce = 1 + msg.To = newAddr + smsg, err = client.WalletSignMessage(ctx, client.DefaultKey.Address, msg) + require.NoError(t, err) + + cid, err = client.MpoolPush(ctx, smsg) + require.NoError(t, err) + ret, err = client.StateWaitMsg(ctx, cid, 3, api.LookbackNoLimit, true) + require.NoError(t, err) + require.Equal(t, ret.Receipt.ExitCode, exitcode.SysErrOutOfGas) + require.Equal(t, msg.GasLimit, ret.Receipt.GasUsed) + + // Now make sure that the client is the only contributor to the burnt funds actor (the + // miners should not have been fined for either message). + + burntAfter, err := client.WalletBalance(ctx, builtin.BurntFundsActorAddr) + require.NoError(t, err) + balanceAfter, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + + burnt := big.Sub(burntAfter, burntBefore) + spent := big.Sub(balanceBefore, balanceAfter) + + require.Equal(t, burnt, spent) + + // Finally, try to submit a message with too little gas. This should fail. + + msg.Nonce = 2 + msg.To = msg.From + msg.GasLimit -= 1 //nolint:golint + + smsg, err = client.WalletSignMessage(ctx, client.DefaultKey.Address, msg) + require.NoError(t, err) + + _, err = client.MpoolPush(ctx, smsg) + require.ErrorContains(t, err, "will not be included in a block") + require.ErrorContains(t, err, "cannot be less than the cost of storing a message") +} diff --git a/itests/gateway_test.go b/itests/gateway_test.go index b9c861bf3..d20b3bd1a 100644 --- a/itests/gateway_test.go +++ b/itests/gateway_test.go @@ -290,7 +290,7 @@ func startNodes( ens.InterconnectAll().BeginMining(blocktime) // Create a gateway server in front of the full node - gwapi := gateway.NewNode(full, lookbackCap, stateWaitLookbackLimit, 0, time.Minute) + gwapi := gateway.NewNode(full, nil, lookbackCap, stateWaitLookbackLimit, 0, time.Minute) handler, err := gateway.Handler(gwapi, full, 0, 0) require.NoError(t, err) diff --git a/itests/kit/ensemble.go b/itests/kit/ensemble.go index 956d243a3..6d4ca1c12 100644 --- a/itests/kit/ensemble.go +++ b/itests/kit/ensemble.go @@ -47,6 +47,7 @@ import ( "github.com/filecoin-project/lotus/chain/wallet/key" "github.com/filecoin-project/lotus/cmd/lotus-seed/seed" "github.com/filecoin-project/lotus/cmd/lotus-worker/sealworker" + "github.com/filecoin-project/lotus/gateway" "github.com/filecoin-project/lotus/genesis" "github.com/filecoin-project/lotus/markets/idxprov" "github.com/filecoin-project/lotus/markets/idxprov/idxprov_test" @@ -210,7 +211,7 @@ func (n *Ensemble) FullNode(full *TestFullNode, opts ...NodeOpt) *Ensemble { n.genesis.accounts = append(n.genesis.accounts, genacc) } - *full = TestFullNode{t: n.t, options: options, DefaultKey: key} + *full = TestFullNode{t: n.t, options: options, DefaultKey: key, EthSubRouter: gateway.NewEthSubHandler()} n.inactive.fullnodes = append(n.inactive.fullnodes, full) return n @@ -708,6 +709,7 @@ func (n *Ensemble) Start() *Ensemble { scfg.Storage.AllowPreCommit1 = false scfg.Storage.AllowPreCommit2 = false scfg.Storage.AllowCommit = false + scfg.Storage.AllowUnseal = false } scfg.Storage.Assigner = assigner diff --git a/itests/kit/ensemble_opts_nv.go b/itests/kit/ensemble_opts_nv.go index 64bed559b..67dcbfd2e 100644 --- a/itests/kit/ensemble_opts_nv.go +++ b/itests/kit/ensemble_opts_nv.go @@ -49,12 +49,12 @@ func LatestActorsAt(upgradeHeight abi.ChainEpoch) EnsembleOpt { }) /* inline-gen start */ return UpgradeSchedule(stmgr.Upgrade{ - Network: network.Version16, + Network: network.Version17, Height: -1, }, stmgr.Upgrade{ - Network: network.Version17, + Network: network.Version18, Height: upgradeHeight, - Migration: filcns.UpgradeActorsV9, + Migration: filcns.UpgradeActorsV10, }) /* inline-gen end */ } diff --git a/itests/kit/evm.go b/itests/kit/evm.go new file mode 100644 index 000000000..a2ab5bb6f --- /dev/null +++ b/itests/kit/evm.go @@ -0,0 +1,459 @@ +package kit + +import ( + "bytes" + "context" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "os" + "testing" + "time" + + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" + "github.com/multiformats/go-varint" + "github.com/stretchr/testify/require" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/crypto/sha3" + + "github.com/filecoin-project/go-address" + amt4 "github.com/filecoin-project/go-amt-ipld/v4" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + builtintypes "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/builtin/v10/eam" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/exitcode" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/chain/wallet/key" + "github.com/filecoin-project/lotus/lib/sigs" +) + +// EVM groups EVM-related actions. +type EVM struct{ *TestFullNode } + +func (f *TestFullNode) EVM() *EVM { + return &EVM{f} +} + +func (e *EVM) DeployContractWithValue(ctx context.Context, sender address.Address, bytecode []byte, value big.Int) eam.CreateReturn { + require := require.New(e.t) + + method := builtintypes.MethodsEAM.CreateExternal + initcode := abi.CborBytes(bytecode) + params, errActors := actors.SerializeParams(&initcode) + require.NoError(errActors) + + msg := &types.Message{ + To: builtintypes.EthereumAddressManagerActorAddr, + From: sender, + Value: value, + Method: method, + Params: params, + } + + e.t.Log("sending create message") + smsg, err := e.MpoolPushMessage(ctx, msg, nil) + require.NoError(err) + + e.t.Log("waiting for message to execute") + wait, err := e.StateWaitMsg(ctx, smsg.Cid(), 3, 0, false) + require.NoError(err) + + require.True(wait.Receipt.ExitCode.IsSuccess(), "contract installation failed") + + var result eam.CreateReturn + r := bytes.NewReader(wait.Receipt.Return) + err = result.UnmarshalCBOR(r) + require.NoError(err) + + return result +} +func (e *EVM) DeployContract(ctx context.Context, sender address.Address, bytecode []byte) eam.CreateReturn { + return e.DeployContractWithValue(ctx, sender, bytecode, big.Zero()) +} + +func (e *EVM) DeployContractFromFilenameWithValue(ctx context.Context, binFilename string, value big.Int) (address.Address, address.Address) { + contractHex, err := os.ReadFile(binFilename) + require.NoError(e.t, err) + + // strip any trailing newlines from the file + contractHex = bytes.TrimRight(contractHex, "\n") + + contract, err := hex.DecodeString(string(contractHex)) + require.NoError(e.t, err) + + fromAddr, err := e.WalletDefaultAddress(ctx) + require.NoError(e.t, err) + + result := e.DeployContractWithValue(ctx, fromAddr, contract, value) + + idAddr, err := address.NewIDAddress(result.ActorID) + require.NoError(e.t, err) + return fromAddr, idAddr +} +func (e *EVM) DeployContractFromFilename(ctx context.Context, binFilename string) (address.Address, address.Address) { + return e.DeployContractFromFilenameWithValue(ctx, binFilename, big.Zero()) +} + +func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte) (*api.MsgLookup, error) { + params := append(selector, inputData...) + var buffer bytes.Buffer + err := cbg.WriteByteArray(&buffer, params) + if err != nil { + return nil, err + } + params = buffer.Bytes() + + msg := &types.Message{ + To: target, + From: sender, + Value: big.Zero(), + Method: builtintypes.MethodsEVM.InvokeContract, + GasLimit: build.BlockGasLimit, // note: we hardcode block gas limit due to slightly broken gas estimation - https://github.com/filecoin-project/lotus/issues/10041 + Params: params, + } + + e.t.Log("sending invoke message") + smsg, err := e.MpoolPushMessage(ctx, msg, nil) + if err != nil { + return nil, err + } + + e.t.Log("waiting for message to execute") + wait, err := e.StateWaitMsg(ctx, smsg.Cid(), 3, 0, false) + if err != nil { + return nil, err + } + if !wait.Receipt.ExitCode.IsSuccess() { + result, err := e.StateReplay(ctx, types.EmptyTSK, wait.Message) + require.NoError(e.t, err) + e.t.Log(result.Error) + } + return wait, nil +} + +// LoadEvents loads all events in an event AMT. +func (e *EVM) LoadEvents(ctx context.Context, eventsRoot cid.Cid) []types.Event { + require := require.New(e.t) + + s := &apiIpldStore{ctx, e} + amt, err := amt4.LoadAMT(ctx, s, eventsRoot, amt4.UseTreeBitWidth(types.EventAMTBitwidth)) + require.NoError(err) + + ret := make([]types.Event, 0, amt.Len()) + err = amt.ForEach(ctx, func(u uint64, deferred *cbg.Deferred) error { + var evt types.Event + if err := evt.UnmarshalCBOR(bytes.NewReader(deferred.Raw)); err != nil { + return err + } + ret = append(ret, evt) + return nil + }) + require.NoError(err) + return ret +} + +func (e *EVM) NewAccount() (*key.Key, ethtypes.EthAddress, address.Address) { + // Generate a secp256k1 key; this will back the Ethereum identity. + key, err := key.GenerateKey(types.KTSecp256k1) + require.NoError(e.t, err) + + ethAddr, err := ethtypes.EthAddressFromPubKey(key.PublicKey) + require.NoError(e.t, err) + + ea, err := ethtypes.CastEthAddress(ethAddr) + require.NoError(e.t, err) + + addr, err := ea.ToFilecoinAddress() + require.NoError(e.t, err) + + return key, *(*ethtypes.EthAddress)(ethAddr), addr +} + +// AssertAddressBalanceConsistent checks that the balance reported via the +// Filecoin and Ethereum operations for an f410 address is identical, returning +// the balance. +func (e *EVM) AssertAddressBalanceConsistent(ctx context.Context, addr address.Address) big.Int { + // Validate the arg is an f410 address. + require.Equal(e.t, address.Delegated, addr.Protocol()) + payload := addr.Payload() + namespace, _, err := varint.FromUvarint(payload) + require.NoError(e.t, err) + require.Equal(e.t, builtintypes.EthereumAddressManagerActorID, namespace) + + fbal, err := e.WalletBalance(ctx, addr) + require.NoError(e.t, err) + + ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(addr) + require.NoError(e.t, err) + + ebal, err := e.EthGetBalance(ctx, ethAddr, "latest") + require.NoError(e.t, err) + + require.Equal(e.t, fbal, types.BigInt(ebal)) + return fbal +} + +// SignTransaction signs an Ethereum transaction in place with the supplied private key. +func (e *EVM) SignTransaction(tx *ethtypes.EthTxArgs, privKey []byte) { + preimage, err := tx.ToRlpUnsignedMsg() + require.NoError(e.t, err) + + // sign the RLP payload + signature, err := sigs.Sign(crypto.SigTypeDelegated, privKey, preimage) + require.NoError(e.t, err) + + r, s, v, err := ethtypes.RecoverSignature(*signature) + require.NoError(e.t, err) + + tx.V = big.Int(v) + tx.R = big.Int(r) + tx.S = big.Int(s) +} + +// SubmitTransaction submits the transaction via the Eth endpoint. +func (e *EVM) SubmitTransaction(ctx context.Context, tx *ethtypes.EthTxArgs) ethtypes.EthHash { + signed, err := tx.ToRlpSignedMsg() + require.NoError(e.t, err) + + hash, err := e.EthSendRawTransaction(ctx, signed) + require.NoError(e.t, err) + + return hash +} + +// ComputeContractAddress computes the address of a contract deployed by the +// specified address with the specified nonce. +func (e *EVM) ComputeContractAddress(deployer ethtypes.EthAddress, nonce uint64) ethtypes.EthAddress { + nonceRlp, err := formatInt(int(nonce)) + require.NoError(e.t, err) + + encoded, err := ethtypes.EncodeRLP([]interface{}{ + deployer[:], + nonceRlp, + }) + require.NoError(e.t, err) + + hasher := sha3.NewLegacyKeccak256() + hasher.Write(encoded) + return *(*ethtypes.EthAddress)(hasher.Sum(nil)[12:]) +} + +// return eth block from a wait return +// this necessarily goes back one parent in the chain because wait is one block ahead of execution +func (e *EVM) GetEthBlockFromWait(ctx context.Context, wait *api.MsgLookup) ethtypes.EthBlock { + c, err := wait.TipSet.Cid() + require.NoError(e.t, err) + hash, err := ethtypes.EthHashFromCid(c) + require.NoError(e.t, err) + + ethBlockParent, err := e.EthGetBlockByHash(ctx, hash, true) + require.NoError(e.t, err) + ethBlock, err := e.EthGetBlockByHash(ctx, ethBlockParent.ParentHash, true) + require.NoError(e.t, err) + + return ethBlock +} + +func (e *EVM) InvokeContractByFuncName(ctx context.Context, fromAddr address.Address, idAddr address.Address, funcSignature string, inputData []byte) ([]byte, *api.MsgLookup, error) { + entryPoint := CalcFuncSignature(funcSignature) + wait, err := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData) + if err != nil { + return nil, wait, err + } + if !wait.Receipt.ExitCode.IsSuccess() { + result, err := e.StateReplay(ctx, types.EmptyTSK, wait.Message) + require.NoError(e.t, err) + return nil, wait, errors.New(result.Error) + } + result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return))) + if err != nil { + return nil, wait, err + } + return result, wait, nil +} + +func (e *EVM) InvokeContractByFuncNameExpectExit(ctx context.Context, fromAddr address.Address, idAddr address.Address, funcSignature string, inputData []byte, exit exitcode.ExitCode) { + entryPoint := CalcFuncSignature(funcSignature) + wait, _ := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData) + require.Equal(e.t, exit, wait.Receipt.ExitCode) +} + +// function signatures are the first 4 bytes of the hash of the function name and types +func CalcFuncSignature(funcName string) []byte { + hasher := sha3.NewLegacyKeccak256() + hasher.Write([]byte(funcName)) + hash := hasher.Sum(nil) + return hash[:4] +} + +// TODO: cleanup and put somewhere reusable. +type apiIpldStore struct { + ctx context.Context + api api.FullNode +} + +func (ht *apiIpldStore) Context() context.Context { + return ht.ctx +} + +func (ht *apiIpldStore) Get(ctx context.Context, c cid.Cid, out interface{}) error { + raw, err := ht.api.ChainReadObj(ctx, c) + if err != nil { + return err + } + + cu, ok := out.(cbg.CBORUnmarshaler) + if ok { + if err := cu.UnmarshalCBOR(bytes.NewReader(raw)); err != nil { + return err + } + return nil + } + + return fmt.Errorf("object does not implement CBORUnmarshaler") +} + +func (ht *apiIpldStore) Put(ctx context.Context, v interface{}) (cid.Cid, error) { + panic("No mutations allowed") +} + +func formatInt(val int) ([]byte, error) { + buf := new(bytes.Buffer) + err := binary.Write(buf, binary.BigEndian, int64(val)) + if err != nil { + return nil, err + } + return removeLeadingZeros(buf.Bytes()), nil +} + +func removeLeadingZeros(data []byte) []byte { + firstNonZeroIndex := len(data) + for i, b := range data { + if b > 0 { + firstNonZeroIndex = i + break + } + } + return data[firstNonZeroIndex:] +} + +func SetupFEVMTest(t *testing.T) (context.Context, context.CancelFunc, *TestFullNode) { + // make all logs extra quiet for fevm tests + lvl, err := logging.LevelFromString("error") + if err != nil { + panic(err) + } + logging.SetAllLoggers(lvl) + + blockTime := 100 * time.Millisecond + client, _, ens := EnsembleMinimal(t, MockProofs(), ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + + // require that the initial balance is 100 million FIL in setup + // this way other tests can count on this initial wallet balance + fromAddr := client.DefaultKey.Address + bal, err := client.WalletBalance(ctx, fromAddr) + require.NoError(t, err) + originalBalance := types.FromFil(uint64(100_000_000)) // 100 million FIL + require.Equal(t, originalBalance, bal) + + return ctx, cancel, client +} + +func (e *EVM) TransferValueOrFail(ctx context.Context, fromAddr address.Address, toAddr address.Address, sendAmount big.Int) *api.MsgLookup { + sendMsg := &types.Message{ + From: fromAddr, + To: toAddr, + Value: sendAmount, + } + signedMsg, err := e.MpoolPushMessage(ctx, sendMsg, nil) + require.NoError(e.t, err) + mLookup, err := e.StateWaitMsg(ctx, signedMsg.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(e.t, err) + require.Equal(e.t, exitcode.Ok, mLookup.Receipt.ExitCode) + return mLookup +} + +func NewEthFilterBuilder() *EthFilterBuilder { + return &EthFilterBuilder{} +} + +type EthFilterBuilder struct { + filter ethtypes.EthFilterSpec +} + +func (e *EthFilterBuilder) Filter() *ethtypes.EthFilterSpec { return &e.filter } + +func (e *EthFilterBuilder) FromBlock(v string) *EthFilterBuilder { + e.filter.FromBlock = &v + return e +} + +func (e *EthFilterBuilder) FromBlockEpoch(v abi.ChainEpoch) *EthFilterBuilder { + s := ethtypes.EthUint64(v).Hex() + e.filter.FromBlock = &s + return e +} + +func (e *EthFilterBuilder) ToBlock(v string) *EthFilterBuilder { + e.filter.ToBlock = &v + return e +} + +func (e *EthFilterBuilder) ToBlockEpoch(v abi.ChainEpoch) *EthFilterBuilder { + s := ethtypes.EthUint64(v).Hex() + e.filter.ToBlock = &s + return e +} + +func (e *EthFilterBuilder) BlockHash(h ethtypes.EthHash) *EthFilterBuilder { + e.filter.BlockHash = &h + return e +} + +func (e *EthFilterBuilder) AddressOneOf(as ...ethtypes.EthAddress) *EthFilterBuilder { + e.filter.Address = as + return e +} + +func (e *EthFilterBuilder) Topic1OneOf(hs ...ethtypes.EthHash) *EthFilterBuilder { + if len(e.filter.Topics) == 0 { + e.filter.Topics = make(ethtypes.EthTopicSpec, 1) + } + e.filter.Topics[0] = hs + return e +} + +func (e *EthFilterBuilder) Topic2OneOf(hs ...ethtypes.EthHash) *EthFilterBuilder { + for len(e.filter.Topics) < 2 { + e.filter.Topics = append(e.filter.Topics, nil) + } + e.filter.Topics[1] = hs + return e +} + +func (e *EthFilterBuilder) Topic3OneOf(hs ...ethtypes.EthHash) *EthFilterBuilder { + for len(e.filter.Topics) < 3 { + e.filter.Topics = append(e.filter.Topics, nil) + } + e.filter.Topics[2] = hs + return e +} + +func (e *EthFilterBuilder) Topic4OneOf(hs ...ethtypes.EthHash) *EthFilterBuilder { + for len(e.filter.Topics) < 4 { + e.filter.Topics = append(e.filter.Topics, nil) + } + e.filter.Topics[3] = hs + return e +} diff --git a/itests/kit/log.go b/itests/kit/log.go index 2932255d2..0da9adfeb 100644 --- a/itests/kit/log.go +++ b/itests/kit/log.go @@ -1,6 +1,9 @@ package kit import ( + "io" + "log" + logging "github.com/ipfs/go-log/v2" "github.com/filecoin-project/lotus/lib/lotuslog" @@ -13,9 +16,20 @@ func QuietMiningLogs() { _ = logging.SetLogLevel("chainstore", "ERROR") _ = logging.SetLogLevel("chain", "ERROR") _ = logging.SetLogLevel("sub", "ERROR") + _ = logging.SetLogLevel("wdpost", "ERROR") _ = logging.SetLogLevel("storageminer", "ERROR") _ = logging.SetLogLevel("pubsub", "ERROR") _ = logging.SetLogLevel("gen", "ERROR") _ = logging.SetLogLevel("rpc", "ERROR") _ = logging.SetLogLevel("dht/RtRefreshManager", "ERROR") } + +func QuietAllLogsExcept(names ...string) { + log.SetOutput(io.Discard) // suppress LogDatastore messages + + lotuslog.SetupLogLevels() + logging.SetAllLoggers(logging.LevelError) + for _, name := range names { + _ = logging.SetLogLevel(name, "INFO") + } +} diff --git a/itests/kit/node_full.go b/itests/kit/node_full.go index 12db91c68..3e80ed688 100644 --- a/itests/kit/node_full.go +++ b/itests/kit/node_full.go @@ -1,6 +1,7 @@ package kit import ( + "bytes" "context" "fmt" "testing" @@ -10,15 +11,18 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" + cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/v1api" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet/key" cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/gateway" "github.com/filecoin-project/lotus/node" ) @@ -43,6 +47,10 @@ type TestFullNode struct { Stop node.StopFunc + // gateway handler makes it convenient to register callbalks per topic, so we + // also use it for tests + EthSubRouter *gateway.EthSubHandler + options nodeOpts } @@ -124,6 +132,50 @@ func (f *TestFullNode) AssignPrivKey(pkey *Libp2p) { f.Pkey = pkey } +type SendCall struct { + Method abi.MethodNum + Params []byte +} + +func (f *TestFullNode) MakeSendCall(m abi.MethodNum, params cbg.CBORMarshaler) SendCall { + var b bytes.Buffer + err := params.MarshalCBOR(&b) + require.NoError(f.t, err) + return SendCall{ + Method: m, + Params: b.Bytes(), + } +} + +func (f *TestFullNode) ExpectSend(ctx context.Context, from, to address.Address, value types.BigInt, errContains string, sc ...SendCall) *types.SignedMessage { + msg := &types.Message{From: from, To: to, Value: value} + + if len(sc) == 1 { + msg.Method = sc[0].Method + msg.Params = sc[0].Params + } + + _, err := f.GasEstimateMessageGas(ctx, msg, nil, types.EmptyTSK) + if errContains != "" { + require.ErrorContains(f.t, err, errContains) + return nil + } + require.NoError(f.t, err) + + if errContains == "" { + m, err := f.MpoolPushMessage(ctx, msg, nil) + require.NoError(f.t, err) + + r, err := f.StateWaitMsg(ctx, m.Cid(), 1, api.LookbackNoLimit, true) + require.NoError(f.t, err) + + require.Equal(f.t, exitcode.Ok, r.Receipt.ExitCode) + return m + } + + return nil +} + // ChainPredicate encapsulates a chain condition. type ChainPredicate func(set *types.TipSet) bool @@ -135,13 +187,21 @@ func HeightAtLeast(target abi.ChainEpoch) ChainPredicate { } } -// BlockMinedBy returns a ChainPredicate that is satisfied when we observe the -// first block mined by the specified miner. -func BlockMinedBy(miner address.Address) ChainPredicate { +// BlocksMinedByAll returns a ChainPredicate that is satisfied when we observe a +// tipset including blocks from all the specified miners, in no particular order. +func BlocksMinedByAll(miner ...address.Address) ChainPredicate { return func(ts *types.TipSet) bool { + seen := make([]bool, len(miner)) + var done int for _, b := range ts.Blocks() { - if b.Miner == miner { - return true + for i, m := range miner { + if b.Miner != m || seen[i] { + continue + } + seen[i] = true + if done++; done == len(miner) { + return true + } } } return false diff --git a/itests/kit/node_miner.go b/itests/kit/node_miner.go index 032cef87c..dd6f3088c 100644 --- a/itests/kit/node_miner.go +++ b/itests/kit/node_miner.go @@ -224,3 +224,38 @@ func (tm *TestMiner) SectorsListNonGenesis(ctx context.Context) ([]abi.SectorNum return l[tm.PresealSectors:], nil } + +// comes from https://github.com/filecoin-project/lotus/blob/8ba4355cabd25e5f65261aaa561ff676321ffbd8/storage/sealer/manager.go#L1226 +// todo: have this defined in one place +type SchedInfo struct { + CallToWork struct{} + EarlyRet interface{} + ReturnedWork interface{} + SchedInfo struct { + OpenWindows []string + Requests []struct { + Priority int + SchedId uuid.UUID + Sector struct { + Miner int + Number int + } + TaskType string + } + } + Waiting interface{} +} + +func (tm *TestMiner) SchedInfo(ctx context.Context) SchedInfo { + schedb, err := tm.SealingSchedDiag(ctx, false) + require.NoError(tm.t, err) + + j, err := json.MarshalIndent(&schedb, "", " ") + require.NoError(tm.t, err) + + var b SchedInfo + err = json.Unmarshal(j, &b) + require.NoError(tm.t, err) + + return b +} diff --git a/itests/kit/node_opts.go b/itests/kit/node_opts.go index 9c482700c..5d418c5be 100644 --- a/itests/kit/node_opts.go +++ b/itests/kit/node_opts.go @@ -58,7 +58,16 @@ var DefaultNodeOpts = nodeOpts{ sectors: DefaultPresealsPerBootstrapMiner, sectorSize: abi.SectorSize(2 << 10), // 2KiB. - workerTasks: []sealtasks.TaskType{sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize}, + cfgOpts: []CfgOption{ + func(cfg *config.FullNode) error { + // test defaults + + cfg.Fevm.EnableEthRPC = true + return nil + }, + }, + + workerTasks: []sealtasks.TaskType{sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed}, workerStorageOpt: func(store paths.Store) paths.Store { return store }, } @@ -229,7 +238,7 @@ func WithWorkerName(n string) NodeOpt { } } -var WithSealWorkerTasks = WithTaskTypes([]sealtasks.TaskType{sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTPreCommit2, sealtasks.TTCommit2, sealtasks.TTUnseal}) +var WithSealWorkerTasks = WithTaskTypes(append([]sealtasks.TaskType{sealtasks.TTAddPiece, sealtasks.TTDataCid, sealtasks.TTPreCommit1, sealtasks.TTPreCommit2, sealtasks.TTCommit2, sealtasks.TTUnseal}, DefaultNodeOpts.workerTasks...)) func WithWorkerStorage(transform func(paths.Store) paths.Store) NodeOpt { return func(opts *nodeOpts) error { @@ -280,3 +289,17 @@ func SplitstoreMessges() NodeOpt { return nil }) } + +func WithEthRPC() NodeOpt { + return WithCfgOpt(func(cfg *config.FullNode) error { + cfg.Fevm.EnableEthRPC = true + return nil + }) +} + +func DisableEthRPC() NodeOpt { + return WithCfgOpt(func(cfg *config.FullNode) error { + cfg.Fevm.EnableEthRPC = false + return nil + }) +} diff --git a/itests/kit/rpc.go b/itests/kit/rpc.go index 684742ad3..5d40ac3e9 100644 --- a/itests/kit/rpc.go +++ b/itests/kit/rpc.go @@ -7,11 +7,14 @@ import ( "net/http" "net/http/httptest" "testing" + "time" "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" "github.com/stretchr/testify/require" + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/lotus/api/client" "github.com/filecoin-project/lotus/cmd/lotus-worker/sealworker" "github.com/filecoin-project/lotus/node" @@ -22,7 +25,10 @@ type Closer func() func CreateRPCServer(t *testing.T, handler http.Handler, listener net.Listener) (*httptest.Server, multiaddr.Multiaddr, Closer) { testServ := &httptest.Server{ Listener: listener, - Config: &http.Server{Handler: handler}, + Config: &http.Server{ + Handler: handler, + ReadHeaderTimeout: 30 * time.Second, + }, } testServ.Start() @@ -48,7 +54,12 @@ func fullRpc(t *testing.T, f *TestFullNode) (*TestFullNode, Closer) { fmt.Printf("FULLNODE RPC ENV FOR CLI DEBUGGING `export FULLNODE_API_INFO=%s`\n", "ws://"+srv.Listener.Addr().String()) sendItestdNotif("FULLNODE_API_INFO", t.Name(), "ws://"+srv.Listener.Addr().String()) - cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil) + rpcOpts := []jsonrpc.Option{ + jsonrpc.WithClientHandler("Filecoin", f.EthSubRouter), + jsonrpc.WithClientHandlerAlias("eth_subscription", "Filecoin.EthSubscription"), + } + + cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil, rpcOpts...) require.NoError(t, err) f.ListenAddr, f.ListenURL, f.FullNode = maddr, srv.URL, cl diff --git a/itests/kit/solidity.go b/itests/kit/solidity.go new file mode 100644 index 000000000..6999bd91b --- /dev/null +++ b/itests/kit/solidity.go @@ -0,0 +1,68 @@ +package kit + +import ( + "golang.org/x/crypto/sha3" + + "github.com/filecoin-project/lotus/chain/types/ethtypes" +) + +func EthTopicHash(sig string) ethtypes.EthHash { + hasher := sha3.NewLegacyKeccak256() + hasher.Write([]byte(sig)) + var hash ethtypes.EthHash + copy(hash[:], hasher.Sum(nil)) + return hash +} + +func EthFunctionHash(sig string) []byte { + hasher := sha3.NewLegacyKeccak256() + hasher.Write([]byte(sig)) + return hasher.Sum(nil)[:4] +} + +// SolidityContractDef holds information about one of the test contracts +type SolidityContractDef struct { + Filename string // filename of the hex of the contract, e.g. contracts/EventMatrix.hex + Fn map[string][]byte // mapping of function names to 32-bit selector + Ev map[string]ethtypes.EthHash // mapping of event names to 256-bit signature hashes +} + +var EventMatrixContract = SolidityContractDef{ + Filename: "contracts/EventMatrix.hex", + Fn: map[string][]byte{ + "logEventZeroData": EthFunctionHash("logEventZeroData()"), + "logEventOneData": EthFunctionHash("logEventOneData(uint256)"), + "logEventTwoData": EthFunctionHash("logEventTwoData(uint256,uint256)"), + "logEventThreeData": EthFunctionHash("logEventThreeData(uint256,uint256,uint256)"), + "logEventFourData": EthFunctionHash("logEventFourData(uint256,uint256,uint256,uint256)"), + "logEventOneIndexed": EthFunctionHash("logEventOneIndexed(uint256)"), + "logEventTwoIndexed": EthFunctionHash("logEventTwoIndexed(uint256,uint256)"), + "logEventThreeIndexed": EthFunctionHash("logEventThreeIndexed(uint256,uint256,uint256)"), + "logEventOneIndexedWithData": EthFunctionHash("logEventOneIndexedWithData(uint256,uint256)"), + "logEventTwoIndexedWithData": EthFunctionHash("logEventTwoIndexedWithData(uint256,uint256,uint256)"), + "logEventThreeIndexedWithData": EthFunctionHash("logEventThreeIndexedWithData(uint256,uint256,uint256,uint256)"), + }, + Ev: map[string]ethtypes.EthHash{ + "EventZeroData": EthTopicHash("EventZeroData()"), + "EventOneData": EthTopicHash("EventOneData(uint256)"), + "EventTwoData": EthTopicHash("EventTwoData(uint256,uint256)"), + "EventThreeData": EthTopicHash("EventThreeData(uint256,uint256,uint256)"), + "EventFourData": EthTopicHash("EventFourData(uint256,uint256,uint256,uint256)"), + "EventOneIndexed": EthTopicHash("EventOneIndexed(uint256)"), + "EventTwoIndexed": EthTopicHash("EventTwoIndexed(uint256,uint256)"), + "EventThreeIndexed": EthTopicHash("EventThreeIndexed(uint256,uint256,uint256)"), + "EventOneIndexedWithData": EthTopicHash("EventOneIndexedWithData(uint256,uint256)"), + "EventTwoIndexedWithData": EthTopicHash("EventTwoIndexedWithData(uint256,uint256,uint256)"), + "EventThreeIndexedWithData": EthTopicHash("EventThreeIndexedWithData(uint256,uint256,uint256,uint256)"), + }, +} + +var EventsContract = SolidityContractDef{ + Filename: "contracts/events.bin", + Fn: map[string][]byte{ + "log_zero_data": {0x00, 0x00, 0x00, 0x00}, + "log_zero_nodata": {0x00, 0x00, 0x00, 0x01}, + "log_four_data": {0x00, 0x00, 0x00, 0x02}, + }, + Ev: map[string]ethtypes.EthHash{}, +} diff --git a/itests/kit/state.go b/itests/kit/state.go new file mode 100644 index 000000000..e66576be3 --- /dev/null +++ b/itests/kit/state.go @@ -0,0 +1,33 @@ +package kit + +import ( + "context" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" + actorstypes "github.com/filecoin-project/go-state-types/actors" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" +) + +// AssertActorType verifies that the supplied address is an actor of the +// specified type (as per its manifest key). +func (f *TestFullNode) AssertActorType(ctx context.Context, addr address.Address, actorType string) { + // validate that an placeholder was created + act, err := f.StateGetActor(ctx, addr, types.EmptyTSK) + require.NoError(f.t, err) + + nv, err := f.StateNetworkVersion(ctx, types.EmptyTSK) + require.NoError(f.t, err) + + av, err := actorstypes.VersionForNetwork(nv) + require.NoError(f.t, err) + + codecid, exists := actors.GetActorCodeID(av, actorType) + require.True(f.t, exists) + + // check the code CID + require.Equal(f.t, codecid, act.Code) +} diff --git a/itests/lite_migration_test.go b/itests/lite_migration_test.go index 541a56b21..0f846e6fa 100644 --- a/itests/lite_migration_test.go +++ b/itests/lite_migration_test.go @@ -19,7 +19,6 @@ import ( "github.com/filecoin-project/specs-actors/v8/actors/util/adt" "github.com/filecoin-project/lotus/blockstore" - "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/builtin/system" "github.com/filecoin-project/lotus/chain/consensus/filcns" "github.com/filecoin-project/lotus/chain/state" @@ -95,7 +94,7 @@ func makeTestManifest(t *testing.T, ctxStore adt.Store, av actorstypes.Version) builder := cid.V1Builder{Codec: cid.Raw, MhType: mh.IDENTITY} manifestData := manifest.ManifestData{} - for _, name := range actors.GetBuiltinActorsKeys(av) { + for _, name := range manifest.GetBuiltinActorsKeys(av) { codeCid, err := builder.Sum([]byte(fmt.Sprintf("fil/8/%s", name))) if err != nil { t.Fatal(err) diff --git a/itests/migration_nv17_test.go b/itests/migration_nv17_test.go index 445bd34cd..1b0d13ae1 100644 --- a/itests/migration_nv17_test.go +++ b/itests/migration_nv17_test.go @@ -38,8 +38,6 @@ import ( ) func TestMigrationNV17(t *testing.T) { - ctx := context.Background() - kit.QuietMiningLogs() rootKey, err := key.GenerateKey(types.KTSecp256k1) @@ -201,6 +199,7 @@ func TestMigrationNV17(t *testing.T) { require.NoError(t, err) sig, err := clientApi.WalletSign(ctx, verifiedClientAddr, serializedProposal.Bytes()) + require.NoError(t, err) publishDealParams := markettypes.PublishStorageDealsParams{ Deals: []markettypes.ClientDealProposal{{ @@ -407,6 +406,7 @@ func TestMigrationNV17(t *testing.T) { require.NoError(t, err) sig, err = clientApi.WalletSign(ctx, verifiedClientAddr, serializedProposal.Bytes()) + require.NoError(t, err) publishDealParams = markettypes.PublishStorageDealsParams{ Deals: []markettypes.ClientDealProposal{{ diff --git a/itests/migration_nv18_test.go b/itests/migration_nv18_test.go new file mode 100644 index 000000000..44bf3806c --- /dev/null +++ b/itests/migration_nv18_test.go @@ -0,0 +1,98 @@ +package itests + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/go-state-types/network" + gstStore "github.com/filecoin-project/go-state-types/store" + + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/chain/actors" + builtin2 "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/consensus/filcns" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/chain/vm" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/node/impl" +) + +func TestMigrationNV18(t *testing.T) { + kit.QuietMiningLogs() + + nv18epoch := abi.ChainEpoch(100) + testClient, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), + kit.UpgradeSchedule(stmgr.Upgrade{ + Network: network.Version17, + Height: -1, + }, stmgr.Upgrade{ + Network: network.Version18, + Height: nv18epoch, + Migration: filcns.UpgradeActorsV10, + }, + )) + + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + clientApi := testClient.FullNode.(*impl.FullNodeAPI) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + testClient.WaitTillChain(ctx, kit.HeightAtLeast(nv18epoch+5)) + + // Now that we have upgraded, we need to: + // - the EAM exists, has "empty" state + // - the EthZeroAddress exists + // - all actors have nil Address fields + + bs := blockstore.NewAPIBlockstore(testClient) + ctxStore := gstStore.WrapBlockStore(ctx, bs) + + currTs, err := clientApi.ChainHead(ctx) + require.NoError(t, err) + + newStateTree, err := state.LoadStateTree(ctxStore, currTs.Blocks()[0].ParentStateRoot) + require.NoError(t, err) + + require.Equal(t, types.StateTreeVersion5, newStateTree.Version()) + + codeIDsv10, ok := actors.GetActorCodeIDsFromManifest(actorstypes.Version10) + require.True(t, ok) + + // check the EAM actor + EAMActor, err := newStateTree.GetActor(builtin.EthereumAddressManagerActorAddr) + require.NoError(t, err) + require.Equal(t, vm.EmptyObjectCid, EAMActor.Head) + EAMCodeID, ok := codeIDsv10[manifest.EamKey] + require.True(t, ok) + require.Equal(t, EAMCodeID, EAMActor.Code) + + // check the EthZeroAddress + ethZeroAddr, err := (ethtypes.EthAddress{}).ToFilecoinAddress() + require.NoError(t, err) + ethZeroAddrID, err := newStateTree.LookupID(ethZeroAddr) + require.NoError(t, err) + ethZeroActor, err := newStateTree.GetActor(ethZeroAddrID) + require.NoError(t, err) + require.True(t, builtin2.IsEthAccountActor(ethZeroActor.Code)) + require.Equal(t, vm.EmptyObjectCid, ethZeroActor.Head) + + // check all actor's Address fields + require.NoError(t, newStateTree.ForEach(func(address address.Address, actor *types.Actor) error { + if address != ethZeroAddrID { + require.Nil(t, actor.Address) + } + return nil + })) +} diff --git a/itests/multisig_test.go b/itests/multisig_test.go index 63cc2f511..92d9afca7 100644 --- a/itests/multisig_test.go +++ b/itests/multisig_test.go @@ -133,7 +133,7 @@ func TestMultisigReentrant(t *testing.T) { sl, err := client.StateReplay(ctx, types.EmptyTSK, pm.Cid()) require.NoError(t, err, "failed to replay reentrant propose message (StateWaitMsg)") - require.Equal(t, 1025, countDepth(sl.ExecutionTrace)) + require.Equal(t, 1024, countDepth(sl.ExecutionTrace), "failed: %s", sl.Error) } func countDepth(trace types.ExecutionTrace) int { diff --git a/itests/pending_deal_allocation_test.go b/itests/pending_deal_allocation_test.go index 9ca1772e4..c1e0531cf 100644 --- a/itests/pending_deal_allocation_test.go +++ b/itests/pending_deal_allocation_test.go @@ -31,8 +31,6 @@ import ( ) func TestGetAllocationForPendingDeal(t *testing.T) { - ctx := context.Background() - rootKey, err := key.GenerateKey(types.KTSecp256k1) require.NoError(t, err) @@ -146,6 +144,7 @@ func TestGetAllocationForPendingDeal(t *testing.T) { require.NoError(t, err) sig, err := api.WalletSign(ctx, verifiedClientAddr, serializedProposal.Bytes()) + require.NoError(t, err) publishDealParams := markettypes.PublishStorageDealsParams{ Deals: []markettypes.ClientDealProposal{{ @@ -196,5 +195,6 @@ func TestGetAllocationForPendingDeal(t *testing.T) { } marketDeal, err := api.StateMarketStorageDeal(ctx, dealIds[0], types.EmptyTSK) + require.NoError(t, err) require.Equal(t, marketDeal.State.SectorStartEpoch, abi.ChainEpoch(-1)) } diff --git a/itests/raft_messagesigner_test.go b/itests/raft_messagesigner_test.go index f94095b90..220da9699 100644 --- a/itests/raft_messagesigner_test.go +++ b/itests/raft_messagesigner_test.go @@ -79,7 +79,6 @@ func setup(ctx context.Context, t *testing.T, node0 *kit.TestFullNode, node1 *ki node.Override(node.GoRPCServer, modules.NewRPCServer), ) //raftOps := kit.ConstructorOpts() - kit.ThroughRPC() ens := kit.NewEnsemble(t).FullNode(node0, raftOps, kit.ThroughRPC()).FullNode(node1, raftOps, kit.ThroughRPC()).FullNode(node2, raftOps, kit.ThroughRPC()) node0.AssignPrivKey(pkey0) @@ -489,6 +488,8 @@ func TestChainStoreSync(t *testing.T) { } func TestGoRPCAuth(t *testing.T) { + // TODO Fix Raft, then enable this test. https://github.com/filecoin-project/lotus/issues/9888 + t.SkipNow() blockTime := 1 * time.Second @@ -527,7 +528,6 @@ func TestGoRPCAuth(t *testing.T) { node.Override(node.GoRPCServer, modules.NewRPCServer), ) //raftOps := kit.ConstructorOpts() - kit.ThroughRPC() ens := kit.NewEnsemble(t).FullNode(&node0, raftOps, kit.ThroughRPC()).FullNode(&node1, raftOps, kit.ThroughRPC()).FullNode(&node2, raftOps, kit.ThroughRPC()).FullNode(&node3, raftOps) node0.AssignPrivKey(pkey0) diff --git a/itests/remove_verifreg_datacap_test.go b/itests/remove_verifreg_datacap_test.go index a0ef1b1c6..3fd241748 100644 --- a/itests/remove_verifreg_datacap_test.go +++ b/itests/remove_verifreg_datacap_test.go @@ -29,8 +29,6 @@ import ( ) func TestNoRemoveDatacapFromVerifreg(t *testing.T) { - ctx := context.Background() - kit.QuietMiningLogs() rootKey, err := key.GenerateKey(types.KTSecp256k1) @@ -185,6 +183,7 @@ func TestNoRemoveDatacapFromVerifreg(t *testing.T) { require.NoError(t, err) sig, err := clientApi.WalletSign(ctx, verifiedClientAddr, serializedProposal.Bytes()) + require.NoError(t, err) publishDealParams := markettypes.PublishStorageDealsParams{ Deals: []markettypes.ClientDealProposal{{ @@ -276,6 +275,7 @@ func TestNoRemoveDatacapFromVerifreg(t *testing.T) { Params: params, Value: big.Zero(), }, types.EmptyTSK) + require.Error(t, err) require.False(t, callResult.MsgRct.ExitCode.IsSuccess()) verifregDatacapAfter, err := clientApi.StateVerifiedClientStatus(ctx, builtin.VerifiedRegistryActorAddr, types.EmptyTSK) diff --git a/itests/sector_make_cc_avail_test.go b/itests/sector_make_cc_avail_test.go index c6ed4b36d..524b3c70f 100644 --- a/itests/sector_make_cc_avail_test.go +++ b/itests/sector_make_cc_avail_test.go @@ -44,6 +44,7 @@ func TestMakeAvailable(t *testing.T) { { si, err := client.StateSectorGetInfo(ctx, maddr, CCUpgrade, types.EmptyTSK) require.NoError(t, err) + require.NotNil(t, si) require.Less(t, 50000, int(si.Expiration)) } client.WaitForSectorActive(ctx, t, CCUpgrade, maddr) diff --git a/itests/sector_prefer_no_upgrade_test.go b/itests/sector_prefer_no_upgrade_test.go index 0294899d9..96f07f9e4 100644 --- a/itests/sector_prefer_no_upgrade_test.go +++ b/itests/sector_prefer_no_upgrade_test.go @@ -46,6 +46,7 @@ func TestPreferNoUpgrade(t *testing.T) { { si, err := client.StateSectorGetInfo(ctx, maddr, CCUpgrade, types.EmptyTSK) require.NoError(t, err) + require.NotNil(t, si) require.Less(t, 50000, int(si.Expiration)) } client.WaitForSectorActive(ctx, t, CCUpgrade, maddr) diff --git a/itests/sector_revert_available_test.go b/itests/sector_revert_available_test.go index 99d410e95..41a46024f 100644 --- a/itests/sector_revert_available_test.go +++ b/itests/sector_revert_available_test.go @@ -42,6 +42,7 @@ func TestAbortUpgradeAvailable(t *testing.T) { { si, err := client.StateSectorGetInfo(ctx, maddr, CCUpgrade, types.EmptyTSK) require.NoError(t, err) + require.NotNil(t, si) require.Less(t, 50000, int(si.Expiration)) } client.WaitForSectorActive(ctx, t, CCUpgrade, maddr) diff --git a/itests/sector_unseal_test.go b/itests/sector_unseal_test.go new file mode 100644 index 000000000..5d05cb0e3 --- /dev/null +++ b/itests/sector_unseal_test.go @@ -0,0 +1,142 @@ +package itests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/storage/sealer/sealtasks" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +func TestUnsealPiece(t *testing.T) { + ctx := context.Background() + blockTime := 1 * time.Millisecond + kit.QuietMiningLogs() + + _, miner, ens := kit.EnsembleMinimal(t, kit.WithAllSubsystems(), kit.ThroughRPC(), kit.WithNoLocalSealing(true), + kit.NoStorage(), // no storage to have better control over path settings + kit.MutateSealingConfig(func(sc *config.SealingConfig) { + sc.FinalizeEarly = true + sc.AlwaysKeepUnsealedCopy = false + })) // no mock proofs + + var worker kit.TestWorker + ens.Worker(miner, &worker, kit.ThroughRPC(), kit.NoStorage(), // no storage to have better control over path settings + kit.WithTaskTypes([]sealtasks.TaskType{ + sealtasks.TTFetch, sealtasks.TTAddPiece, + sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed, sealtasks.TTPreCommit1, sealtasks.TTPreCommit2, sealtasks.TTCommit2, + sealtasks.TTReplicaUpdate, sealtasks.TTUnseal, // only first update step, later steps will not run and we'll abort + }), + ) + + ens.Start().InterconnectAll().BeginMiningMustPost(blockTime) + + maddr, err := miner.ActorAddress(ctx) + if err != nil { + t.Fatal(err) + } + + // get storage paths + + // store-only path on the miner + miner.AddStorage(ctx, t, func(cfg *storiface.LocalStorageMeta) { + cfg.CanSeal = false + cfg.CanStore = true + }) + + mlocal, err := miner.StorageLocal(ctx) + require.NoError(t, err) + require.Len(t, mlocal, 2) // genesis and one local + + // we want a seal-only path on the worker disconnected from miner path + worker.AddStorage(ctx, t, func(cfg *storiface.LocalStorageMeta) { + cfg.CanSeal = true + cfg.CanStore = false + }) + + wpaths, err := worker.Paths(ctx) + require.NoError(t, err) + require.Len(t, wpaths, 1) + + // check which sectors files are present on the miner/worker storage paths + checkSectors := func(miners, workers storiface.SectorFileType) { + paths, err := miner.StorageList(ctx) + require.NoError(t, err) + require.Len(t, paths, 3) // genesis, miner, worker + + // first loop for debugging + for id, decls := range paths { + pinfo, err := miner.StorageInfo(ctx, id) + require.NoError(t, err) + + switch { + case id == wpaths[0].ID: // worker path + fmt.Println("Worker Decls ", len(decls), decls) + case !pinfo.CanStore && !pinfo.CanSeal: // genesis path + fmt.Println("Genesis Decls ", len(decls), decls) + default: // miner path + fmt.Println("Miner Decls ", len(decls), decls) + } + } + + for id, decls := range paths { + pinfo, err := miner.StorageInfo(ctx, id) + require.NoError(t, err) + + switch { + case id == wpaths[0].ID: // worker path + if workers != storiface.FTNone { + require.Len(t, decls, 1) + require.EqualValues(t, workers.Strings(), decls[0].SectorFileType.Strings()) + } else { + require.Len(t, decls, 0) + } + case !pinfo.CanStore && !pinfo.CanSeal: // genesis path + require.Len(t, decls, kit.DefaultPresealsPerBootstrapMiner) + default: // miner path + if miners != storiface.FTNone { + require.Len(t, decls, 1) + require.EqualValues(t, miners.Strings(), decls[0].SectorFileType.Strings()) + } else { + require.Len(t, decls, 0) + } + } + } + } + checkSectors(storiface.FTNone, storiface.FTNone) + + // get a sector for upgrading + miner.PledgeSectors(ctx, 1, 0, nil) + sl, err := miner.SectorsListNonGenesis(ctx) + require.NoError(t, err) + require.Len(t, sl, 1, "expected 1 sector") + + sector := sl[0] + + checkSectors(storiface.FTCache|storiface.FTSealed, storiface.FTNone) + + sinfo, err := miner.SectorsStatus(ctx, sector, false) + require.NoError(t, err) + + minerId, err := address.IDFromAddress(maddr) + require.NoError(t, err) + + sectorRef := storiface.SectorRef{ + ID: abi.SectorID{Miner: abi.ActorID(minerId), Number: sector}, + ProofType: sinfo.SealProof, + } + + err = miner.SectorsUnsealPiece(ctx, sectorRef, 0, 0, sinfo.Ticket.Value, sinfo.CommD) + require.NoError(t, err) + + checkSectors(storiface.FTCache|storiface.FTSealed|storiface.FTUnsealed, storiface.FTNone) +} diff --git a/itests/specs/eth_openrpc.json b/itests/specs/eth_openrpc.json new file mode 100644 index 000000000..0f354b5c7 --- /dev/null +++ b/itests/specs/eth_openrpc.json @@ -0,0 +1,4392 @@ +{ + "openrpc": "1.2.4", + "info": { + "title": "Ethereum JSON-RPC Specification", + "description": "A specification of the standard interface for Ethereum clients.", + "license": { + "name": "CC0-1.0", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "version": "0.0.0" + }, + "methods": [ + { + "name": "eth_getBlockByHash", + "summary": "Returns information about a block by hash.", + "params": [ + { + "name": "Block hash", + "required": true, + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "name": "Hydrated transactions", + "required": true, + "schema": { + "title": "hydrated", + "type": "boolean" + } + } + ], + "result": { + "name": "Block information", + "schema": { + "title": "Block object", + "type": "object", + "required": [ + "parentHash", + "sha3Uncles", + "miner", + "stateRoot", + "transactionsRoot", + "receiptsRoot", + "logsBloom", + "number", + "gasLimit", + "gasUsed", + "timestamp", + "extraData", + "mixHash", + "nonce", + "size", + "transactions", + "uncles" + ], + "properties": { + "parentHash": { + "title": "Parent block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "sha3Uncles": { + "title": "Ommers hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "miner": { + "title": "Coinbase", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "stateRoot": { + "title": "State root", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "transactionsRoot": { + "title": "Transactions root", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "receiptsRoot": { + "title": "Receipts root", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "logsBloom": { + "title": "Bloom filter", + "type": "string", + "pattern": "^0x[0-9a-f]{512}$" + }, + "difficulty": { + "title": "Difficulty", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "number": { + "title": "Number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "gasLimit": { + "title": "Gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "gasUsed": { + "title": "Gas used", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "timestamp": { + "title": "Timestamp", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "extraData": { + "title": "Extra data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "mixHash": { + "title": "Mix hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "nonce": { + "title": "Nonce", + "type": "string", + "pattern": "^0x[0-9a-f]{16}$" + }, + "totalDifficulty": { + "title": "Total difficult", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "baseFeePerGas": { + "title": "Base fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "size": { + "title": "Block size", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "transactions": { + "anyOf": [ + { + "title": "Transaction hashes", + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "title": "Full transactions", + "type": "array", + "items": { + "oneOf": [ + { + "title": "Signed 1559 Transaction", + "type": "object", + "required": [ + "accessList", + "chainId", + "gas", + "input", + "maxFeePerGas", + "maxPriorityFeePerGas", + "nonce", + "r", + "s", + "type", + "value", + "v" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "maxPriorityFeePerGas": { + "title": "max priority fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Maximum fee per gas the sender is willing to pay to miners in wei" + }, + "maxFeePerGas": { + "title": "max fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The maximum total fee per gas the sender is willing to pay (includes the network / base fee and miner / priority fee) in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "title": "Signed 2930 Transaction", + "type": "object", + "required": [ + "accessList", + "chainId", + "gas", + "gasPrice", + "input", + "nonce", + "r", + "s", + "type", + "value", + "v" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "title": "Signed Legacy Transaction", + "type": "object", + "required": [ + "gas", + "gasPrice", + "input", + "nonce", + "r", + "s", + "type", + "v", + "value" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + } + ] + } + } + ] + }, + "uncles": { + "title": "Uncles", + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + } + }, + { + "name": "eth_getBlockByNumber", + "summary": "Returns information about a block by number.", + "params": [ + { + "name": "Block", + "required": true, + "schema": { + "title": "Block number or tag", + "oneOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + } + ] + } + }, + { + "name": "Hydrated transactions", + "required": true, + "schema": { + "title": "hydrated", + "type": "boolean" + } + } + ], + "result": { + "name": "Block information", + "schema": { + "title": "Block object", + "type": "object", + "required": [ + "parentHash", + "sha3Uncles", + "miner", + "stateRoot", + "transactionsRoot", + "receiptsRoot", + "logsBloom", + "number", + "gasLimit", + "gasUsed", + "timestamp", + "extraData", + "mixHash", + "nonce", + "size", + "transactions", + "uncles" + ], + "properties": { + "parentHash": { + "title": "Parent block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "sha3Uncles": { + "title": "Ommers hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "miner": { + "title": "Coinbase", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "stateRoot": { + "title": "State root", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "transactionsRoot": { + "title": "Transactions root", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "receiptsRoot": { + "title": "Receipts root", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "logsBloom": { + "title": "Bloom filter", + "type": "string", + "pattern": "^0x[0-9a-f]{512}$" + }, + "difficulty": { + "title": "Difficulty", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "number": { + "title": "Number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "gasLimit": { + "title": "Gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "gasUsed": { + "title": "Gas used", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "timestamp": { + "title": "Timestamp", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "extraData": { + "title": "Extra data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "mixHash": { + "title": "Mix hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "nonce": { + "title": "Nonce", + "type": "string", + "pattern": "^0x[0-9a-f]{16}$" + }, + "totalDifficulty": { + "title": "Total difficult", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "baseFeePerGas": { + "title": "Base fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "size": { + "title": "Block size", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "transactions": { + "anyOf": [ + { + "title": "Transaction hashes", + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "title": "Full transactions", + "type": "array", + "items": { + "oneOf": [ + { + "title": "Signed 1559 Transaction", + "type": "object", + "required": [ + "accessList", + "chainId", + "gas", + "input", + "maxFeePerGas", + "maxPriorityFeePerGas", + "nonce", + "r", + "s", + "type", + "value", + "v" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "maxPriorityFeePerGas": { + "title": "max priority fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Maximum fee per gas the sender is willing to pay to miners in wei" + }, + "maxFeePerGas": { + "title": "max fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The maximum total fee per gas the sender is willing to pay (includes the network / base fee and miner / priority fee) in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "title": "Signed 2930 Transaction", + "type": "object", + "required": [ + "accessList", + "chainId", + "gas", + "gasPrice", + "input", + "nonce", + "r", + "s", + "type", + "value", + "v" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "title": "Signed Legacy Transaction", + "type": "object", + "required": [ + "gas", + "gasPrice", + "input", + "nonce", + "r", + "s", + "type", + "v", + "value" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + } + ] + } + } + ] + }, + "uncles": { + "title": "Uncles", + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + } + }, + { + "name": "eth_getBlockTransactionCountByHash", + "summary": "Returns the number of transactions in a block from a block matching the given block hash.", + "params": [ + { + "name": "Block hash", + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ], + "result": { + "name": "Transaction count", + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_getBlockTransactionCountByNumber", + "summary": "Returns the number of transactions in a block matching the given block number.", + "params": [ + { + "name": "Block", + "schema": { + "title": "Block number or tag", + "oneOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + } + ] + } + } + ], + "result": { + "name": "Transaction count", + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_getUncleCountByBlockHash", + "summary": "Returns the number of uncles in a block from a block matching the given block hash.", + "params": [ + { + "name": "Block hash", + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ], + "result": { + "name": "Uncle count", + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_getUncleCountByBlockNumber", + "summary": "Returns the number of transactions in a block matching the given block number.", + "params": [ + { + "name": "Block", + "schema": { + "title": "Block number or tag", + "oneOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + } + ] + } + } + ], + "result": { + "name": "Uncle count", + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_chainId", + "summary": "Returns the chain ID of the current network.", + "params": [], + "result": { + "name": "Chain ID", + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_syncing", + "summary": "Returns an object with data about the sync status or false.", + "params": [], + "result": { + "name": "Syncing status", + "schema": { + "title": "Syncing status", + "oneOf": [ + { + "title": "Syncing progress", + "type": "object", + "properties": { + "startingBlock": { + "title": "Starting block", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "currentBlock": { + "title": "Current block", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "highestBlock": { + "title": "Highest block", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "title": "Not syncing", + "description": "Should always return false if not syncing.", + "type": "boolean" + } + ] + } + } + }, + { + "name": "eth_coinbase", + "summary": "Returns the client coinbase address.", + "params": [], + "result": { + "name": "Coinbase address", + "schema": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + } + } + }, + { + "name": "eth_accounts", + "summary": "Returns a list of addresses owned by client.", + "params": [], + "result": { + "name": "Accounts", + "schema": { + "title": "Accounts", + "type": "array", + "items": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + } + } + } + }, + { + "name": "eth_blockNumber", + "summary": "Returns the number of most recent block.", + "params": [], + "result": { + "name": "Block number", + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_call", + "summary": "Executes a new message call immediately without creating a transaction on the block chain.", + "params": [ + { + "name": "Transaction", + "required": true, + "schema": { + "type": "object", + "title": "Transaction object generic to all types", + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "from": { + "title": "from address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "maxPriorityFeePerGas": { + "title": "max priority fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Maximum fee per gas the sender is willing to pay to miners in wei" + }, + "maxFeePerGas": { + "title": "max fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The maximum total fee per gas the sender is willing to pay (includes the network / base fee and miner / priority fee) in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + } + } + } + }, + { + "name": "Block", + "required": false, + "schema": { + "title": "Block number, tag, or block hash", + "anyOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + }, + { + "title": "Block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + ] + } + } + ], + "result": { + "name": "Return data", + "schema": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + }, + { + "name": "eth_estimateGas", + "summary": "Generates and returns an estimate of how much gas is necessary to allow the transaction to complete.", + "params": [ + { + "name": "Transaction", + "required": true, + "schema": { + "type": "object", + "title": "Transaction object generic to all types", + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "from": { + "title": "from address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "maxPriorityFeePerGas": { + "title": "max priority fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Maximum fee per gas the sender is willing to pay to miners in wei" + }, + "maxFeePerGas": { + "title": "max fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The maximum total fee per gas the sender is willing to pay (includes the network / base fee and miner / priority fee) in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + } + } + } + }, + { + "name": "Block", + "required": false, + "schema": { + "title": "Block number or tag", + "oneOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + } + ] + } + } + ], + "result": { + "name": "Gas used", + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_createAccessList", + "summary": "Generates an access list for a transaction.", + "params": [ + { + "name": "Transaction", + "required": true, + "schema": { + "type": "object", + "title": "Transaction object generic to all types", + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "from": { + "title": "from address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "maxPriorityFeePerGas": { + "title": "max priority fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Maximum fee per gas the sender is willing to pay to miners in wei" + }, + "maxFeePerGas": { + "title": "max fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The maximum total fee per gas the sender is willing to pay (includes the network / base fee and miner / priority fee) in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + } + } + } + }, + { + "name": "Block", + "required": false, + "schema": { + "title": "Block number or tag", + "oneOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + } + ] + } + } + ], + "result": { + "name": "Gas used", + "schema": { + "title": "Access list result", + "type": "object", + "properties": { + "accessList": { + "title": "accessList", + "type": "array", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "error": { + "title": "error", + "type": "string" + }, + "gasUsed": { + "title": "Gas used", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + } + } + }, + { + "name": "eth_gasPrice", + "summary": "Returns the current price per gas in wei.", + "params": [], + "result": { + "name": "Gas price", + "schema": { + "title": "Gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_maxPriorityFeePerGas", + "summary": "Returns the current maxPriorityFeePerGas per gas in wei.", + "params": [], + "result": { + "name": "Max priority fee per gas", + "schema": { + "title": "Max priority fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_feeHistory", + "summary": "Transaction fee history", + "description": "Returns transaction base fee per gas and effective priority fee per gas for the requested/supported block range.", + "params": [ + { + "name": "blockCount", + "description": "Requested range of blocks. Clients will return less than the requested range if not all blocks are available.", + "required": true, + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + }, + { + "name": "newestBlock", + "description": "Highest block of the requested range.", + "required": true, + "schema": { + "title": "Block number or tag", + "oneOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + } + ] + } + }, + { + "name": "rewardPercentiles", + "description": "A monotonically increasing list of percentile values. For each block in the requested range, the transactions will be sorted in ascending order by effective tip per gas and the coresponding effective tip for the percentile will be determined, accounting for gas consumed.", + "required": true, + "schema": { + "title": "rewardPercentiles", + "type": "array", + "items": { + "title": "rewardPercentile", + "description": "Floating point value between 0 and 100.", + "type": "number" + } + } + } + ], + "result": { + "name": "feeHistoryResult", + "description": "Fee history for the returned block range. This can be a subsection of the requested range if not all blocks are available.", + "schema": { + "title": "feeHistoryResults", + "description": "Fee history results.", + "type": "object", + "required": [ + "oldestBlock", + "baseFeePerGas", + "gasUsedRatio" + ], + "properties": { + "oldestBlock": { + "title": "oldestBlock", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Lowest number block of returned range." + }, + "baseFeePerGas": { + "title": "baseFeePerGasArray", + "description": "An array of block base fees per gas. This includes the next block after the newest of the returned range, because this value can be derived from the newest block. Zeroes are returned for pre-EIP-1559 blocks.", + "type": "array", + "items": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + }, + "reward": { + "title": "rewardArray", + "description": "A two-dimensional array of effective priority fees per gas at the requested block percentiles.", + "type": "array", + "items": { + "title": "rewardPercentile", + "description": "An array of effective priority fee per gas data points from a single block. All zeroes are returned if the block is empty.", + "type": "array", + "items": { + "title": "rewardPercentile", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "A given percentile sample of effective priority fees per gas from a single block in ascending order, weighted by gas used. Zeroes are returned if the block is empty." + } + } + } + } + } + } + }, + { + "name": "eth_newFilter", + "summary": "Creates a filter object, based on filter options, to notify when the state changes (logs).", + "params": [ + { + "name": "Filter", + "schema": { + "title": "filter", + "type": "object", + "properties": { + "fromBlock": { + "title": "from block", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "toBlock": { + "title": "to block", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "address": { + "title": "Address(es)", + "oneOf": [ + { + "title": "Address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + { + "title": "Addresses", + "type": "array", + "items": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + } + } + ] + }, + "topics": { + "title": "Topics", + "type": "array", + "items": { + "title": "Filter Topic List Entry", + "oneOf": [ + { + "title": "Any Topic Match", + "type": "null" + }, + { + "title": "Single Topic Match", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + { + "title": "Multiple Topic Match", + "type": "array", + "items": { + "title": "32 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ] + } + } + } + } + } + ], + "result": { + "name": "Filter Identifier", + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + }, + { + "name": "eth_newBlockFilter", + "summary": "Creates a filter in the node, to notify when a new block arrives.", + "params": [], + "result": { + "name": "Filter Identifier", + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + }, + { + "name": "eth_newPendingTransactionFilter", + "summary": "Creates a filter in the node, to notify when new pending transactions arrive.", + "params": [], + "result": { + "name": "Filter Identifier", + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + }, + { + "name": "eth_uninstallFilter", + "summary": "Uninstalls a filter with given id.", + "params": [ + { + "name": "Filter Identifier", + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ], + "result": { + "name": "Success", + "schema": { + "type": "boolean" + } + } + }, + { + "name": "eth_getFilterChanges", + "summary": "Polling method for a filter, which returns an array of logs which occurred since last poll.", + "params": [ + { + "name": "Filter Identifier", + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ], + "result": { + "name": "Log objects", + "schema": { + "title": "Filter results", + "oneOf": [ + { + "title": "new block hashes", + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "title": "new transaction hashes", + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "title": "new logs", + "type": "array", + "items": { + "title": "log", + "type": "object", + "required": [ + "transactionHash" + ], + "properties": { + "removed": { + "title": "removed", + "type": "boolean" + }, + "logIndex": { + "title": "log index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "transactionIndex": { + "title": "transaction index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "transactionHash": { + "title": "transaction hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockHash": { + "title": "block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockNumber": { + "title": "block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "address": { + "title": "address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "data": { + "title": "data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "topics": { + "title": "topics", + "type": "array", + "items": { + "title": "32 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + } + ] + } + } + }, + { + "name": "eth_getFilterLogs", + "summary": "Returns an array of all logs matching filter with given id.", + "params": [ + { + "name": "Filter Identifier", + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ], + "result": { + "name": "Log objects", + "schema": { + "title": "Filter results", + "oneOf": [ + { + "title": "new block hashes", + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "title": "new transaction hashes", + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "title": "new logs", + "type": "array", + "items": { + "title": "log", + "type": "object", + "required": [ + "transactionHash" + ], + "properties": { + "removed": { + "title": "removed", + "type": "boolean" + }, + "logIndex": { + "title": "log index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "transactionIndex": { + "title": "transaction index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "transactionHash": { + "title": "transaction hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockHash": { + "title": "block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockNumber": { + "title": "block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "address": { + "title": "address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "data": { + "title": "data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "topics": { + "title": "topics", + "type": "array", + "items": { + "title": "32 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + } + ] + } + } + }, + { + "name": "eth_getLogs", + "summary": "Returns an array of all logs matching filter with given id.", + "params": [ + { + "name": "Filter", + "schema": { + "title": "filter", + "type": "object", + "properties": { + "fromBlock": { + "title": "from block", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "toBlock": { + "title": "to block", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "address": { + "title": "Address(es)", + "oneOf": [ + { + "title": "Address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + { + "title": "Addresses", + "type": "array", + "items": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + } + } + ] + }, + "topics": { + "title": "Topics", + "type": "array", + "items": { + "title": "Filter Topic List Entry", + "oneOf": [ + { + "title": "Any Topic Match", + "type": "null" + }, + { + "title": "Single Topic Match", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + { + "title": "Multiple Topic Match", + "type": "array", + "items": { + "title": "32 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ] + } + } + } + } + } + ], + "result": { + "name": "Log objects", + "schema": { + "title": "Filter results", + "oneOf": [ + { + "title": "new block hashes", + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "title": "new transaction hashes", + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "title": "new logs", + "type": "array", + "items": { + "title": "log", + "type": "object", + "required": [ + "transactionHash" + ], + "properties": { + "removed": { + "title": "removed", + "type": "boolean" + }, + "logIndex": { + "title": "log index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "transactionIndex": { + "title": "transaction index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "transactionHash": { + "title": "transaction hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockHash": { + "title": "block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockNumber": { + "title": "block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "address": { + "title": "address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "data": { + "title": "data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "topics": { + "title": "topics", + "type": "array", + "items": { + "title": "32 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + } + ] + } + } + }, + { + "name": "eth_mining", + "summary": "Returns whether the client is actively mining new blocks.", + "params": [], + "result": { + "name": "Mining status", + "schema": { + "title": "miningStatus", + "type": "boolean" + } + } + }, + { + "name": "eth_hashrate", + "summary": "Returns the number of hashes per second that the node is mining with.", + "params": [], + "result": { + "name": "Mining status", + "schema": { + "title": "Hashrate", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_getWork", + "summary": "Returns the hash of the current block, the seedHash, and the boundary condition to be met (“target”).", + "params": [], + "result": { + "name": "Current work", + "schema": { + "type": "array", + "items": [ + { + "title": "Proof-of-work hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + { + "title": "seed hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + { + "title": "difficulty", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + ] + } + } + }, + { + "name": "eth_submitWork", + "summary": "Used for submitting a proof-of-work solution.", + "params": [ + { + "name": "nonce", + "required": true, + "schema": { + "title": "8 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{16}$" + } + }, + { + "name": "hash", + "required": true, + "schema": { + "title": "32 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "name": "digest", + "required": true, + "schema": { + "title": "32 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ], + "result": { + "name": "Success", + "schema": { + "type": "boolean" + } + } + }, + { + "name": "eth_submitHashrate", + "summary": "Used for submitting mining hashrate.", + "params": [ + { + "name": "Hashrate", + "required": true, + "schema": { + "title": "32 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "name": "ID", + "required": true, + "schema": { + "title": "32 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ], + "result": { + "name": "Success", + "schema": { + "type": "boolean" + } + } + }, + { + "name": "eth_sign", + "summary": "Returns an EIP-191 signature over the provided data.", + "params": [ + { + "name": "Address", + "required": true, + "schema": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + } + }, + { + "name": "Message", + "required": true, + "schema": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + ], + "result": { + "name": "Signature", + "schema": { + "title": "65 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{65}$" + } + } + }, + { + "name": "eth_signTransaction", + "summary": "Returns an RLP encoded transaction signed by the specified account.", + "params": [ + { + "name": "Transaction", + "required": true, + "schema": { + "type": "object", + "title": "Transaction object generic to all types", + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "from": { + "title": "from address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "maxPriorityFeePerGas": { + "title": "max priority fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Maximum fee per gas the sender is willing to pay to miners in wei" + }, + "maxFeePerGas": { + "title": "max fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The maximum total fee per gas the sender is willing to pay (includes the network / base fee and miner / priority fee) in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + } + } + } + } + ], + "result": { + "name": "Encoded transaction", + "schema": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + }, + { + "name": "eth_getBalance", + "summary": "Returns the balance of the account of given address.", + "params": [ + { + "name": "Address", + "required": true, + "schema": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + } + }, + { + "name": "Block", + "required": false, + "schema": { + "title": "Block number, tag, or block hash", + "anyOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + }, + { + "title": "Block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + ] + } + } + ], + "result": { + "name": "Balance", + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_getStorageAt", + "summary": "Returns the value from a storage position at a given address.", + "params": [ + { + "name": "Address", + "required": true, + "schema": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + } + }, + { + "name": "Storage slot", + "required": true, + "schema": { + "title": "hex encoded 256 bit unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]{0,31})|0$" + } + }, + { + "name": "Block", + "required": false, + "schema": { + "title": "Block number, tag, or block hash", + "anyOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + }, + { + "title": "Block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + ] + } + } + ], + "result": { + "name": "Value", + "schema": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + }, + { + "name": "eth_getTransactionCount", + "summary": "Returns the number of transactions sent from an address.", + "params": [ + { + "name": "Address", + "required": true, + "schema": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + } + }, + { + "name": "Block", + "required": false, + "schema": { + "title": "Block number, tag, or block hash", + "anyOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + }, + { + "title": "Block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + ] + } + } + ], + "result": { + "name": "Transaction count", + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "name": "eth_getCode", + "summary": "Returns code at a given address.", + "params": [ + { + "name": "Address", + "required": true, + "schema": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + } + }, + { + "name": "Block", + "required": false, + "schema": { + "title": "Block number, tag, or block hash", + "anyOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + }, + { + "title": "Block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + ] + } + } + ], + "result": { + "name": "Bytecode", + "schema": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + }, + { + "name": "eth_getProof", + "summary": "Returns the merkle proof for a given account and optionally some storage keys.", + "params": [ + { + "name": "Address", + "required": true, + "schema": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + } + }, + { + "name": "StorageKeys", + "required": true, + "schema": { + "title": "Storage keys", + "type": "array", + "items": { + "title": "32 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{0,64}$" + } + } + }, + { + "name": "Block", + "required": true, + "schema": { + "title": "Block number, tag, or block hash", + "anyOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + }, + { + "title": "Block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + ] + } + } + ], + "result": { + "name": "Account", + "schema": { + "title": "Account proof", + "type": "object", + "required": [ + "address", + "accountProof", + "balance", + "codeHash", + "nonce", + "storageHash", + "storageProof" + ], + "properties": { + "address": { + "title": "address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "accountProof": { + "title": "accountProof", + "type": "array", + "items": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + }, + "balance": { + "title": "balance", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]{0,31})|0$" + }, + "codeHash": { + "title": "codeHash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]{0,15})|0$" + }, + "storageHash": { + "title": "storageHash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "storageProof": { + "title": "Storage proofs", + "type": "array", + "items": { + "title": "Storage proof", + "type": "object", + "required": [ + "key", + "value", + "proof" + ], + "properties": { + "key": { + "title": "key", + "type": "string", + "pattern": "^0x[0-9a-f]{0,64}$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]{0,31})|0$" + }, + "proof": { + "title": "proof", + "type": "array", + "items": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + } + } + } + } + } + } + }, + { + "name": "eth_sendTransaction", + "summary": "Signs and submits a transaction.", + "params": [ + { + "name": "Transaction", + "required": true, + "schema": { + "type": "object", + "title": "Transaction object generic to all types", + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "from": { + "title": "from address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "maxPriorityFeePerGas": { + "title": "max priority fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Maximum fee per gas the sender is willing to pay to miners in wei" + }, + "maxFeePerGas": { + "title": "max fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The maximum total fee per gas the sender is willing to pay (includes the network / base fee and miner / priority fee) in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + } + } + } + } + ], + "result": { + "name": "Transaction hash", + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + }, + { + "name": "eth_sendRawTransaction", + "summary": "Submits a raw transaction.", + "params": [ + { + "name": "Transaction", + "required": true, + "schema": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + ], + "result": { + "name": "Transaction hash", + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + }, + { + "name": "eth_getTransactionByHash", + "summary": "Returns the information about a transaction requested by transaction hash.", + "params": [ + { + "name": "Transaction hash", + "required": true, + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ], + "result": { + "name": "Transaction information", + "schema": { + "type": "object", + "title": "Transaction information", + "required": [ + "blockHash", + "blockNumber", + "from", + "hash", + "transactionIndex" + ], + "oneOf": [ + { + "title": "Signed 1559 Transaction", + "type": "object", + "required": [ + "accessList", + "chainId", + "gas", + "input", + "maxFeePerGas", + "maxPriorityFeePerGas", + "nonce", + "r", + "s", + "type", + "value", + "v" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "maxPriorityFeePerGas": { + "title": "max priority fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Maximum fee per gas the sender is willing to pay to miners in wei" + }, + "maxFeePerGas": { + "title": "max fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The maximum total fee per gas the sender is willing to pay (includes the network / base fee and miner / priority fee) in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "title": "Signed 2930 Transaction", + "type": "object", + "required": [ + "accessList", + "chainId", + "gas", + "gasPrice", + "input", + "nonce", + "r", + "s", + "type", + "value", + "v" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "title": "Signed Legacy Transaction", + "type": "object", + "required": [ + "gas", + "gasPrice", + "input", + "nonce", + "r", + "s", + "type", + "v", + "value" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + } + ], + "properties": { + "blockHash": { + "title": "block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockNumber": { + "title": "block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "from": { + "title": "from address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "hash": { + "title": "transaction hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "transactionIndex": { + "title": "transaction index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + } + } + }, + { + "name": "eth_getTransactionByBlockHashAndIndex", + "summary": "Returns information about a transaction by block hash and transaction index position.", + "params": [ + { + "name": "Block hash", + "required": true, + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + }, + { + "name": "Transaction index", + "required": true, + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + ], + "result": { + "name": "Transaction information", + "schema": { + "type": "object", + "title": "Transaction information", + "required": [ + "blockHash", + "blockNumber", + "from", + "hash", + "transactionIndex" + ], + "oneOf": [ + { + "title": "Signed 1559 Transaction", + "type": "object", + "required": [ + "accessList", + "chainId", + "gas", + "input", + "maxFeePerGas", + "maxPriorityFeePerGas", + "nonce", + "r", + "s", + "type", + "value", + "v" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "maxPriorityFeePerGas": { + "title": "max priority fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Maximum fee per gas the sender is willing to pay to miners in wei" + }, + "maxFeePerGas": { + "title": "max fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The maximum total fee per gas the sender is willing to pay (includes the network / base fee and miner / priority fee) in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "title": "Signed 2930 Transaction", + "type": "object", + "required": [ + "accessList", + "chainId", + "gas", + "gasPrice", + "input", + "nonce", + "r", + "s", + "type", + "value", + "v" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "title": "Signed Legacy Transaction", + "type": "object", + "required": [ + "gas", + "gasPrice", + "input", + "nonce", + "r", + "s", + "type", + "v", + "value" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + } + ], + "properties": { + "blockHash": { + "title": "block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockNumber": { + "title": "block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "from": { + "title": "from address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "hash": { + "title": "transaction hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "transactionIndex": { + "title": "transaction index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + } + } + }, + { + "name": "eth_getTransactionByBlockNumberAndIndex", + "summary": "Returns information about a transaction by block number and transaction index position.", + "params": [ + { + "name": "Block", + "required": true, + "schema": { + "title": "Block number or tag", + "oneOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + } + ] + } + }, + { + "name": "Transaction index", + "required": true, + "schema": { + "title": "hex encoded unsigned integer", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + ], + "result": { + "name": "Transaction information", + "schema": { + "type": "object", + "title": "Transaction information", + "required": [ + "blockHash", + "blockNumber", + "from", + "hash", + "transactionIndex" + ], + "oneOf": [ + { + "title": "Signed 1559 Transaction", + "type": "object", + "required": [ + "accessList", + "chainId", + "gas", + "input", + "maxFeePerGas", + "maxPriorityFeePerGas", + "nonce", + "r", + "s", + "type", + "value", + "v" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "maxPriorityFeePerGas": { + "title": "max priority fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Maximum fee per gas the sender is willing to pay to miners in wei" + }, + "maxFeePerGas": { + "title": "max fee per gas", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The maximum total fee per gas the sender is willing to pay (includes the network / base fee and miner / priority fee) in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "title": "Signed 2930 Transaction", + "type": "object", + "required": [ + "accessList", + "chainId", + "gas", + "gasPrice", + "input", + "nonce", + "r", + "s", + "type", + "value", + "v" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "accessList": { + "title": "accessList", + "type": "array", + "description": "EIP-2930 access list", + "items": { + "title": "Access list entry", + "type": "object", + "properties": { + "address": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "storageKeys": { + "type": "array", + "items": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature." + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + }, + { + "title": "Signed Legacy Transaction", + "type": "object", + "required": [ + "gas", + "gasPrice", + "input", + "nonce", + "r", + "s", + "type", + "v", + "value" + ], + "properties": { + "type": { + "title": "type", + "type": "string", + "pattern": "^0x([0-9,a-f,A-F]?){1,2}$" + }, + "nonce": { + "title": "nonce", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "to": { + "title": "to address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "gas": { + "title": "gas limit", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "value": { + "title": "value", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "input": { + "title": "input data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "gasPrice": { + "title": "gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The gas price willing to be paid by the sender in wei" + }, + "chainId": { + "title": "chainId", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Chain ID that this transaction is valid on." + }, + "v": { + "title": "v", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "r": { + "title": "r", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "s": { + "title": "s", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + } + ], + "properties": { + "blockHash": { + "title": "block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockNumber": { + "title": "block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "from": { + "title": "from address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "hash": { + "title": "transaction hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "transactionIndex": { + "title": "transaction index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + } + } + } + } + }, + { + "name": "eth_getTransactionReceipt", + "summary": "Returns the receipt of a transaction by transaction hash.", + "params": [ + { + "name": "Transaction hash", + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ], + "result": { + "name": "Receipt Information", + "schema": { + "type": "object", + "title": "Receipt info", + "required": [ + "blockHash", + "blockNumber", + "from", + "cumulativeGasUsed", + "gasUsed", + "logs", + "logsBloom", + "transactionHash", + "transactionIndex", + "effectiveGasPrice" + ], + "properties": { + "transactionHash": { + "title": "transaction hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "transactionIndex": { + "title": "transaction index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "blockHash": { + "title": "block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockNumber": { + "title": "block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "from": { + "title": "from", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "to": { + "title": "to", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$", + "description": "Address of the receiver or null in a contract creation transaction." + }, + "cumulativeGasUsed": { + "title": "cumulative gas used", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The sum of gas used by this transaction and all preceding transactions in the same block." + }, + "gasUsed": { + "title": "gas used", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The amount of gas used for this specific transaction alone." + }, + "contractAddress": { + "title": "contract address", + "description": "The contract address created, if the transaction was a contract creation, otherwise null.", + "oneOf": [ + { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + { + "name": null, + "type": "null" + } + ] + }, + "logs": { + "title": "logs", + "type": "array", + "items": { + "title": "log", + "type": "object", + "required": [ + "transactionHash" + ], + "properties": { + "removed": { + "title": "removed", + "type": "boolean" + }, + "logIndex": { + "title": "log index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "transactionIndex": { + "title": "transaction index", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "transactionHash": { + "title": "transaction hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockHash": { + "title": "block hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "blockNumber": { + "title": "block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + "address": { + "title": "address", + "type": "string", + "pattern": "^0x[0-9,a-f,A-F]{40}$" + }, + "data": { + "title": "data", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "topics": { + "title": "topics", + "type": "array", + "items": { + "title": "32 hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + } + } + }, + "logsBloom": { + "title": "logs bloom", + "type": "string", + "pattern": "^0x[0-9a-f]{512}$" + }, + "root": { + "title": "state root", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$", + "description": "The post-transaction state root. Only specified for transactions included before the Byzantium upgrade." + }, + "status": { + "title": "status", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "Either 1 (success) or 0 (failure). Only specified for transactions included after the Byzantium upgrade." + }, + "effectiveGasPrice": { + "title": "effective gas price", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$", + "description": "The actual value per gas deducted from the senders account. Before EIP-1559, this is equal to the transaction's gas price. After, it is equal to baseFeePerGas + min(maxFeePerGas - baseFeePerGas, maxPriorityFeePerGas)." + } + } + } + } + }, + { + "name": "debug_getRawHeader", + "summary": "Returns an RLP-encoded header.", + "params": [ + { + "name": "Block", + "required": true, + "schema": { + "title": "Block number or tag", + "oneOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + } + ] + } + } + ], + "result": { + "name": "Header RLP", + "schema": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + }, + { + "name": "debug_getRawBlock", + "summary": "Returns an RLP-encoded block.", + "params": [ + { + "name": "Block", + "required": true, + "schema": { + "title": "Block number or tag", + "oneOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + } + ] + } + } + ], + "result": { + "name": "Block RLP", + "schema": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + }, + { + "name": "debug_getRawTransaction", + "summary": "Returns an array of EIP-2718 binary-encoded transactions.", + "params": [ + { + "name": "Transaction hash", + "required": true, + "schema": { + "title": "32 byte hex value", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + } + } + ], + "result": { + "name": "EIP-2718 binary-encoded transaction", + "schema": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + }, + { + "name": "debug_getRawReceipts", + "summary": "Returns an array of EIP-2718 binary-encoded receipts.", + "params": [ + { + "name": "Block", + "required": true, + "schema": { + "title": "Block number or tag", + "oneOf": [ + { + "title": "Block number", + "type": "string", + "pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$" + }, + { + "title": "Block tag", + "type": "string", + "enum": [ + "earliest", + "finalized", + "safe", + "latest", + "pending" + ], + "description": "`earliest`: The lowest numbered block the client has available; `finalized`: The most recent crypto-economically secure block, cannot be re-orged outside of manual intervention driven by community coordination; `safe`: The most recent block that is safe from re-orgs under honest majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical chain observed by the client, this block may be re-orged out of the canonical chain even under healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` and containing the set of transactions usually taken from local mempool. Before the merge transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to with `-39001: Unknown block` error" + } + ] + } + } + ], + "result": { + "name": "Receipts", + "schema": { + "title": "Receipt array", + "type": "array", + "items": { + "title": "hex encoded bytes", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + } + }, + { + "name": "debug_getBadBlocks", + "summary": "Returns an array of recent bad blocks that the client has seen on the network.", + "params": [], + "result": { + "name": "Blocks", + "schema": { + "title": "Bad block array", + "type": "array", + "items": { + "title": "Bad block", + "type": "object", + "required": [ + "block", + "hash", + "rlp" + ], + "properties": { + "block": { + "title": "Block", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + }, + "hash": { + "title": "Hash", + "type": "string", + "pattern": "^0x[0-9a-f]{64}$" + }, + "rlp": { + "title": "RLP", + "type": "string", + "pattern": "^0x[0-9a-f]*$" + } + } + } + } + } + } + ], + "components": {} +} diff --git a/itests/splitstore_test.go b/itests/splitstore_test.go index 957efe32f..4bbe56536 100644 --- a/itests/splitstore_test.go +++ b/itests/splitstore_test.go @@ -249,6 +249,49 @@ func TestMessagesMode(t *testing.T) { assert.True(g.t, g.Exists(ctx, garbageM), "Garbage message not found in splitstore") } +func TestCompactRetainsTipSetRef(t *testing.T) { + ctx := context.Background() + // disable sync checking because efficient itests require that the node is out of sync : / + splitstore.CheckSyncGap = false + opts := []interface{}{kit.MockProofs(), kit.SplitstoreDiscard()} + full, genesisMiner, ens := kit.EnsembleMinimal(t, opts...) + bm := ens.InterconnectAll().BeginMining(4 * time.Millisecond)[0] + _ = genesisMiner + _ = bm + + check, err := full.ChainHead(ctx) + require.NoError(t, err) + e := check.Height() + checkRef, err := check.Key().Cid() + require.NoError(t, err) + assert.True(t, ipldExists(ctx, t, checkRef, full)) // reference to tipset key should be persisted before compaction + + // Determine index of compaction that covers tipset "check" and wait for compaction + for { + bm.Pause() + if splitStoreCompacting(ctx, t, full) { + bm.Restart() + time.Sleep(1 * time.Second) + } else { + break + } + } + lastCompactionEpoch := splitStoreBaseEpoch(ctx, t, full) + garbageCompactionIndex := splitStoreCompactionIndex(ctx, t, full) + 1 + boundary := lastCompactionEpoch + splitstore.CompactionThreshold - splitstore.CompactionBoundary + + for e > boundary { + boundary += splitstore.CompactionThreshold - splitstore.CompactionBoundary + garbageCompactionIndex++ + } + bm.Restart() + + // wait for compaction to occur + waitForCompaction(ctx, t, garbageCompactionIndex, full) + assert.True(t, ipldExists(ctx, t, checkRef, full)) // reference to tipset key should be persisted after compaction + bm.Stop() +} + func waitForCompaction(ctx context.Context, t *testing.T, cIdx int64, n *kit.TestFullNode) { for { if splitStoreCompactionIndex(ctx, t, n) >= cIdx { @@ -307,6 +350,14 @@ func splitStorePruneIndex(ctx context.Context, t *testing.T, n *kit.TestFullNode return pruneIndex } +func ipldExists(ctx context.Context, t *testing.T, c cid.Cid, n *kit.TestFullNode) bool { + found, err := n.ChainHasObj(ctx, c) + if err != nil { + t.Fatalf("ChainHasObj failure: %s", err) + } + return found +} + // Create on chain unreachable garbage for a network to exercise splitstore // one garbage cid created at a time // @@ -361,12 +412,10 @@ func (g *Garbager) Exists(ctx context.Context, c cid.Cid) bool { return false } else if err != nil { g.t.Fatalf("ChainReadObj failure on existence check: %s", err) + return false // unreachable } else { return true } - - g.t.Fatal("unreachable") - return false } func (g *Garbager) newPeerID(ctx context.Context) abi.ChainEpoch { diff --git a/itests/wdpost_dispute_test.go b/itests/wdpost_dispute_test.go index eedb3e8f6..c4512874a 100644 --- a/itests/wdpost_dispute_test.go +++ b/itests/wdpost_dispute_test.go @@ -113,7 +113,7 @@ func TestWindowPostDispute(t *testing.T) { //stm: @CHAIN_STATE_MINER_CALCULATE_DEADLINE_001 di, err = client.StateMinerProvingDeadline(ctx, evilMinerAddr, types.EmptyTSK) require.NoError(t, err) - if di.Index == evilSectorLoc.Deadline && di.CurrentEpoch-di.PeriodStart > 1 { + if di.Index == evilSectorLoc.Deadline && di.CurrentEpoch-di.Open > 1 { break } build.Clock.Sleep(blocktime) @@ -217,7 +217,8 @@ func TestWindowPostDispute(t *testing.T) { //stm: @CHAIN_STATE_MINER_CALCULATE_DEADLINE_001 di, err = client.StateMinerProvingDeadline(ctx, evilMinerAddr, types.EmptyTSK) require.NoError(t, err) - if di.Index == evilSectorLoc.Deadline { + + if di.Index == evilSectorLoc.Deadline && di.CurrentEpoch-di.Open > 1 { break } build.Clock.Sleep(blocktime) diff --git a/itests/wdpost_no_miner_storage_test.go b/itests/wdpost_no_miner_storage_test.go index ac0eb8505..8c0e112f5 100644 --- a/itests/wdpost_no_miner_storage_test.go +++ b/itests/wdpost_no_miner_storage_test.go @@ -37,7 +37,7 @@ func TestWindowPostNoMinerStorage(t *testing.T) { Worker(&miner, &sealw, kit.ThroughRPC(), kit.WithSealWorkerTasks). Start() - ens.InterconnectAll().BeginMiningMustPost(2 * time.Millisecond) + ens.InterconnectAll().BeginMiningMustPost(10 * time.Millisecond) miner.PledgeSectors(ctx, sealSectors, 0, nil) diff --git a/itests/wdpost_test.go b/itests/wdpost_test.go index a3d157ef0..f77b5cd1b 100644 --- a/itests/wdpost_test.go +++ b/itests/wdpost_test.go @@ -52,6 +52,10 @@ func TestWindowedPost(t *testing.T) { } func testWindowPostUpgrade(t *testing.T, blocktime time.Duration, nSectors int, upgradeHeight abi.ChainEpoch) { + + /// XXX TEMPORARILY DISABLED UNTIL NV18 MIGRATION IS IMPLEMENTED + t.Skip("temporarily disabled as nv18 migration is not yet implemented") + ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/itests/worker_test.go b/itests/worker_test.go index 2e3722884..b002660f1 100644 --- a/itests/worker_test.go +++ b/itests/worker_test.go @@ -2,13 +2,11 @@ package itests import ( "context" - "encoding/json" "strings" "sync/atomic" "testing" "time" - "github.com/google/uuid" logging "github.com/ipfs/go-log/v2" "github.com/stretchr/testify/require" "golang.org/x/xerrors" @@ -79,7 +77,7 @@ func TestWorkerPledgeLocalFin(t *testing.T) { func TestWorkerDataCid(t *testing.T) { ctx := context.Background() _, miner, worker, _ := kit.EnsembleWorker(t, kit.WithAllSubsystems(), kit.ThroughRPC(), kit.WithNoLocalSealing(true), - kit.WithTaskTypes([]sealtasks.TaskType{sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTDataCid, sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTPreCommit2, sealtasks.TTCommit2, sealtasks.TTUnseal})) // no mock proofs + kit.WithSealWorkerTasks) // no mock proofs e, err := worker.Enabled(ctx) require.NoError(t, err) @@ -409,7 +407,7 @@ func TestWindowPostWorkerManualPoSt(t *testing.T) { func TestSchedulerRemoveRequest(t *testing.T) { ctx := context.Background() _, miner, worker, _ := kit.EnsembleWorker(t, kit.WithAllSubsystems(), kit.ThroughRPC(), kit.WithNoLocalSealing(true), - kit.WithTaskTypes([]sealtasks.TaskType{sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTDataCid, sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTCommit2, sealtasks.TTUnseal})) // no mock proofs + kit.WithTaskTypes([]sealtasks.TaskType{sealtasks.TTAddPiece, sealtasks.TTPreCommit1})) // no mock proofs //ens.InterconnectAll().BeginMining(50 * time.Millisecond) @@ -417,26 +415,6 @@ func TestSchedulerRemoveRequest(t *testing.T) { require.NoError(t, err) require.True(t, e) - type info struct { - CallToWork struct { - } `json:"CallToWork"` - EarlyRet interface{} `json:"EarlyRet"` - ReturnedWork interface{} `json:"ReturnedWork"` - SchedInfo struct { - OpenWindows []string `json:"OpenWindows"` - Requests []struct { - Priority int `json:"Priority"` - SchedID string `json:"SchedId"` - Sector struct { - Miner int `json:"Miner"` - Number int `json:"Number"` - } `json:"Sector"` - TaskType string `json:"TaskType"` - } `json:"Requests"` - } `json:"SchedInfo"` - Waiting interface{} `json:"Waiting"` - } - tocheck := miner.StartPledge(ctx, 1, 0, nil) var sn abi.SectorNumber for n := range tocheck { @@ -453,39 +431,18 @@ func TestSchedulerRemoveRequest(t *testing.T) { } // Dump current scheduler info - schedb, err := miner.SealingSchedDiag(ctx, false) - require.NoError(t, err) - - j, err := json.MarshalIndent(&schedb, "", " ") - require.NoError(t, err) - - var b info - err = json.Unmarshal(j, &b) - require.NoError(t, err) - - var schedidb uuid.UUID + b := miner.SchedInfo(ctx) // cast scheduler info and get the request UUID. Call the SealingRemoveRequest() require.Len(t, b.SchedInfo.Requests, 1) require.Equal(t, "seal/v0/precommit/2", b.SchedInfo.Requests[0].TaskType) - schedidb, err = uuid.Parse(b.SchedInfo.Requests[0].SchedID) - require.NoError(t, err) - - err = miner.SealingRemoveRequest(ctx, schedidb) + err = miner.SealingRemoveRequest(ctx, b.SchedInfo.Requests[0].SchedId) require.NoError(t, err) // Dump the schduler again and compare the UUID if a request is present // If no request present then pass the test - scheda, err := miner.SealingSchedDiag(ctx, false) - require.NoError(t, err) - - k, err := json.MarshalIndent(&scheda, "", " ") - require.NoError(t, err) - - var a info - err = json.Unmarshal(k, &a) - require.NoError(t, err) + a := miner.SchedInfo(ctx) require.Len(t, a.SchedInfo.Requests, 0) } diff --git a/itests/worker_upgrade_test.go b/itests/worker_upgrade_test.go new file mode 100644 index 000000000..b253a26a5 --- /dev/null +++ b/itests/worker_upgrade_test.go @@ -0,0 +1,170 @@ +package itests + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/node/config" + sealing "github.com/filecoin-project/lotus/storage/pipeline" + "github.com/filecoin-project/lotus/storage/sealer/sealtasks" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +func TestWorkerUpgradeAbortCleanup(t *testing.T) { + ctx := context.Background() + blockTime := 1 * time.Millisecond + kit.QuietMiningLogs() + + client, miner, ens := kit.EnsembleMinimal(t, kit.WithAllSubsystems(), kit.ThroughRPC(), kit.WithNoLocalSealing(true), + kit.NoStorage(), // no storage to have better control over path settings + kit.MutateSealingConfig(func(sc *config.SealingConfig) { sc.FinalizeEarly = true })) // no mock proofs + + var worker kit.TestWorker + ens.Worker(miner, &worker, kit.ThroughRPC(), kit.NoStorage(), // no storage to have better control over path settings + kit.WithTaskTypes([]sealtasks.TaskType{ + sealtasks.TTFetch, sealtasks.TTAddPiece, + sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed, sealtasks.TTPreCommit1, sealtasks.TTPreCommit2, sealtasks.TTCommit2, + sealtasks.TTReplicaUpdate, // only first update step, later steps will not run and we'll abort + }), + ) + + ens.Start().InterconnectAll().BeginMiningMustPost(blockTime) + + maddr, err := miner.ActorAddress(ctx) + if err != nil { + t.Fatal(err) + } + + // get storage paths + + // store-only path on the miner + miner.AddStorage(ctx, t, func(cfg *storiface.LocalStorageMeta) { + cfg.CanSeal = false + cfg.CanStore = true + }) + + mlocal, err := miner.StorageLocal(ctx) + require.NoError(t, err) + require.Len(t, mlocal, 2) // genesis and one local + + // we want a seal-only path on the worker disconnected from miner path + worker.AddStorage(ctx, t, func(cfg *storiface.LocalStorageMeta) { + cfg.CanSeal = true + cfg.CanStore = false + }) + + wpaths, err := worker.Paths(ctx) + require.NoError(t, err) + require.Len(t, wpaths, 1) + + // check sectors in paths + checkSectors := func(miners, workers storiface.SectorFileType) { + paths, err := miner.StorageList(ctx) + require.NoError(t, err) + require.Len(t, paths, 3) // genesis, miner, worker + + // first loop for debugging + for id, decls := range paths { + pinfo, err := miner.StorageInfo(ctx, id) + require.NoError(t, err) + + switch { + case id == wpaths[0].ID: // worker path + fmt.Println("Worker Decls ", len(decls), decls) + case !pinfo.CanStore && !pinfo.CanSeal: // genesis path + fmt.Println("Genesis Decls ", len(decls), decls) + default: // miner path + fmt.Println("Miner Decls ", len(decls), decls) + } + } + + for id, decls := range paths { + pinfo, err := miner.StorageInfo(ctx, id) + require.NoError(t, err) + + switch { + case id == wpaths[0].ID: // worker path + if workers != storiface.FTNone { + require.Len(t, decls, 1) + require.EqualValues(t, workers.Strings(), decls[0].SectorFileType.Strings()) + } else { + require.Len(t, decls, 0) + } + case !pinfo.CanStore && !pinfo.CanSeal: // genesis path + require.Len(t, decls, kit.DefaultPresealsPerBootstrapMiner) + default: // miner path + if miners != storiface.FTNone { + require.Len(t, decls, 1) + require.EqualValues(t, miners.Strings(), decls[0].SectorFileType.Strings()) + } else { + require.Len(t, decls, 0) + } + } + } + } + checkSectors(storiface.FTNone, storiface.FTNone) + + // get a sector for upgrading + miner.PledgeSectors(ctx, 1, 0, nil) + sl, err := miner.SectorsListNonGenesis(ctx) + require.NoError(t, err) + require.Len(t, sl, 1, "expected 1 sector") + + snum := sl[0] + + checkSectors(storiface.FTCache|storiface.FTSealed, storiface.FTNone) + + client.WaitForSectorActive(ctx, t, snum, maddr) + + // make available + err = miner.SectorMarkForUpgrade(ctx, snum, true) + require.NoError(t, err) + + // Start a deal + + dh := kit.NewDealHarness(t, client, miner, miner) + res, _ := client.CreateImportFile(ctx, 123, 0) + dp := dh.DefaultStartDealParams() + dp.Data.Root = res.Root + deal := dh.StartDeal(ctx, dp) + + // wait for the deal to be in a sector + dh.WaitDealSealed(ctx, deal, true, false, nil) + + // wait for replica update to happen + require.Eventually(t, func() bool { + sstate, err := miner.SectorsStatus(ctx, snum, false) + require.NoError(t, err) + return sstate.State == api.SectorState(sealing.ProveReplicaUpdate) + }, 10*time.Second, 50*time.Millisecond) + + // check that the sector was copied to the worker + checkSectors(storiface.FTCache|storiface.FTSealed, storiface.FTCache|storiface.FTSealed|storiface.FTUnsealed|storiface.FTUpdate|storiface.FTUpdateCache) + + // abort upgrade + err = miner.SectorAbortUpgrade(ctx, snum) + require.NoError(t, err) + + // the task is stuck in scheduler, so manually abort the task to get the sector fsm moving + si := miner.SchedInfo(ctx) + err = miner.SealingRemoveRequest(ctx, si.SchedInfo.Requests[0].SchedId) + require.NoError(t, err) + + var lastState api.SectorState + require.Eventually(t, func() bool { + sstate, err := miner.SectorsStatus(ctx, snum, false) + require.NoError(t, err) + lastState = sstate.State + + return sstate.State == api.SectorState(sealing.Proving) + }, 10*time.Second, 50*time.Millisecond, "last state was %s", &lastState) + + // check that nothing was left on the worker + checkSectors(storiface.FTCache|storiface.FTSealed, storiface.FTNone) +} diff --git a/lib/consensus/raft/config.go b/lib/consensus/raft/config.go index 983e4cc4d..81bdb7fdc 100644 --- a/lib/consensus/raft/config.go +++ b/lib/consensus/raft/config.go @@ -97,8 +97,8 @@ func NewClusterRaftConfig(userRaftConfig *config.UserRaftConfig) *ClusterRaftCon } -// // Validate checks that this configuration has working values, -// // at least in appearance. +// Validate checks that this configuration has working values, +// at least in appearance. func ValidateConfig(cfg *ClusterRaftConfig) error { if cfg.RaftConfig == nil { return xerrors.Errorf("no hashicorp/raft.Config") diff --git a/lib/consensus/raft/consensus.go b/lib/consensus/raft/consensus.go index 085f94c72..60d9dc305 100644 --- a/lib/consensus/raft/consensus.go +++ b/lib/consensus/raft/consensus.go @@ -152,6 +152,12 @@ func NewConsensus(host host.Host, cfg *ClusterRaftConfig, mpool *messagepool.Mes peers := []peer.ID{} addrInfos, err := addrutil.ParseAddresses(ctx, cfg.InitPeerset) + if err != nil { + logger.Error("error parsing addresses: ", err) + cancel() + return nil, err + } + for _, addrInfo := range addrInfos { peers = append(peers, addrInfo.ID) @@ -422,7 +428,7 @@ func (cc *Consensus) RmPeer(ctx context.Context, pid peer.ID) error { return err } // Being here means we are the leader and can commit - finalErr = cc.raft.RemovePeer(ctx, peer.Encode(pid)) + finalErr = cc.raft.RemovePeer(ctx, pid.String()) if finalErr != nil { time.Sleep(cc.config.CommitRetryDelay) continue diff --git a/lib/consensus/raft/raft.go b/lib/consensus/raft/raft.go index 76c23a6d1..9cfd41a4a 100644 --- a/lib/consensus/raft/raft.go +++ b/lib/consensus/raft/raft.go @@ -80,7 +80,7 @@ func newRaftWrapper( raftW.staging = staging raftW.repo = repo // Set correct LocalID - cfg.RaftConfig.LocalID = hraft.ServerID(peer.Encode(host.ID())) + cfg.RaftConfig.LocalID = hraft.ServerID(host.ID().String()) df := cfg.GetDataFolder(repo) err := makeDataFolder(df) @@ -248,7 +248,7 @@ func makeServerConf(peers []peer.ID) hraft.Configuration { // Servers are peers + self. We avoid duplicate entries below for _, pid := range peers { - p := peer.Encode(pid) + p := pid.String() _, ok := sm[p] if !ok { // avoid dups sm[p] = struct{}{} @@ -284,7 +284,7 @@ func (rw *raftWrapper) WaitForLeader(ctx context.Context) (string, error) { func (rw *raftWrapper) WaitForVoter(ctx context.Context) error { logger.Debug("waiting until we are promoted to a voter") - pid := hraft.ServerID(peer.Encode(rw.host.ID())) + pid := hraft.ServerID(rw.host.ID().String()) for { select { case <-ctx.Done(): diff --git a/lib/lazy/getonce.go b/lib/lazy/getonce.go new file mode 100644 index 000000000..7f9d4d664 --- /dev/null +++ b/lib/lazy/getonce.go @@ -0,0 +1,50 @@ +package lazy + +import ( + "context" + "sync" +) + +type Lazy[T any] struct { + Get func() (T, error) + + once sync.Once + + val T + err error +} + +func MakeLazy[T any](get func() (T, error)) *Lazy[T] { + return &Lazy[T]{ + Get: get, + } +} + +func (l *Lazy[T]) Val() (T, error) { + l.once.Do(func() { + l.val, l.err = l.Get() + }) + return l.val, l.err +} + +type LazyCtx[T any] struct { + Get func(context.Context) (T, error) + + once sync.Once + + val T + err error +} + +func MakeLazyCtx[T any](get func(ctx context.Context) (T, error)) *LazyCtx[T] { + return &LazyCtx[T]{ + Get: get, + } +} + +func (l *LazyCtx[T]) Val(ctx context.Context) (T, error) { + l.once.Do(func() { + l.val, l.err = l.Get(ctx) + }) + return l.val, l.err +} diff --git a/lib/must/must.go b/lib/must/must.go new file mode 100644 index 000000000..e072b4e04 --- /dev/null +++ b/lib/must/must.go @@ -0,0 +1,9 @@ +package must + +func One[R any](r R, err error) R { + if err != nil { + panic(err) + } + + return r +} diff --git a/lib/result/result.go b/lib/result/result.go index bec839d7a..56a9ffab7 100644 --- a/lib/result/result.go +++ b/lib/result/result.go @@ -30,6 +30,12 @@ func Wrap[T any](value T, err error) Result[T] { } } -func (r *Result[T]) Unwrap() (T, error) { +func (r Result[T]) Unwrap() (T, error) { return r.Value, r.Error } + +func (r Result[T]) Assert(noErrFn func(err error, msgAndArgs ...interface{})) T { + noErrFn(r.Error) + + return r.Value +} diff --git a/lib/sigs/delegated/init.go b/lib/sigs/delegated/init.go new file mode 100644 index 000000000..81886ceaa --- /dev/null +++ b/lib/sigs/delegated/init.go @@ -0,0 +1,79 @@ +package delegated + +import ( + "fmt" + + "golang.org/x/crypto/sha3" + + "github.com/filecoin-project/go-address" + gocrypto "github.com/filecoin-project/go-crypto" + "github.com/filecoin-project/go-state-types/builtin" + crypto1 "github.com/filecoin-project/go-state-types/crypto" + + "github.com/filecoin-project/lotus/lib/sigs" +) + +type delegatedSigner struct{} + +func (delegatedSigner) GenPrivate() ([]byte, error) { + priv, err := gocrypto.GenerateKey() + if err != nil { + return nil, err + } + return priv, nil +} + +func (delegatedSigner) ToPublic(pk []byte) ([]byte, error) { + return gocrypto.PublicKey(pk), nil +} + +func (s delegatedSigner) Sign(pk []byte, msg []byte) ([]byte, error) { + hasher := sha3.NewLegacyKeccak256() + hasher.Write(msg) + hashSum := hasher.Sum(nil) + sig, err := gocrypto.Sign(pk, hashSum) + if err != nil { + return nil, err + } + + return sig, nil +} + +func (delegatedSigner) Verify(sig []byte, a address.Address, msg []byte) error { + hasher := sha3.NewLegacyKeccak256() + hasher.Write(msg) + hash := hasher.Sum(nil) + + pubk, err := gocrypto.EcRecover(hash, sig) + if err != nil { + return err + } + + // if we get an uncompressed public key (that's what we get from the library, + // but putting this check here for defensiveness), strip the prefix + if pubk[0] == 0x04 { + pubk = pubk[1:] + } + + hasher.Reset() + hasher.Write(pubk) + addrHash := hasher.Sum(nil) + + // The address hash will not start with [12]byte{0xff}, so we don't have to use + // EthAddr.ToFilecoinAddress() to handle the case with an id address + // Also, importing ethtypes here will cause circulating import + maybeaddr, err := address.NewDelegatedAddress(builtin.EthereumAddressManagerActorID, addrHash[12:]) + if err != nil { + return err + } + + if maybeaddr != a { + return fmt.Errorf("signature did not match maybeaddr: %s, signer: %s", maybeaddr, a) + } + + return nil +} + +func init() { + sigs.RegisterSignature(crypto1.SigTypeDelegated, delegatedSigner{}) +} diff --git a/markets/dagstore/blockstore.go b/markets/dagstore/blockstore.go index 317cb08b9..593204ec8 100644 --- a/markets/dagstore/blockstore.go +++ b/markets/dagstore/blockstore.go @@ -4,9 +4,9 @@ import ( "context" "io" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" bstore "github.com/ipfs/go-ipfs-blockstore" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" "github.com/filecoin-project/dagstore" diff --git a/markets/idxprov/mesh.go b/markets/idxprov/mesh.go index 706115a25..e69e213ad 100644 --- a/markets/idxprov/mesh.go +++ b/markets/idxprov/mesh.go @@ -38,10 +38,13 @@ func (mc Libp2pMeshCreator) Connect(ctx context.Context) error { return fmt.Errorf("failed to fetch full node listen addrs, err: %w", err) } - // Connect to the full node, ask it to protect the connection and protect the connection on - // markets end too. - if err := mc.marketsHost.Connect(ctx, faddrs); err != nil { - return fmt.Errorf("failed to connect index provider host with the full node: %w", err) + // Connect from the full node, ask it to protect the connection and protect the connection on + // markets end too. Connection is initiated form full node to avoid the need to expose libp2p port on full node + if err := mc.fullnodeApi.NetConnect(ctx, peer.AddrInfo{ + ID: mc.marketsHost.ID(), + Addrs: mc.marketsHost.Addrs(), + }); err != nil { + return fmt.Errorf("failed to connect to index provider host from full node: %w", err) } mc.marketsHost.ConnManager().Protect(faddrs.ID, protectTag) diff --git a/markets/storageadapter/api.go b/markets/storageadapter/api.go index b93ffdfbb..3105f2261 100644 --- a/markets/storageadapter/api.go +++ b/markets/storageadapter/api.go @@ -3,9 +3,9 @@ package storageadapter import ( "context" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" + blocks "github.com/ipfs/go-libipfs/blocks" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" diff --git a/markets/storageadapter/ondealsectorcommitted_test.go b/markets/storageadapter/ondealsectorcommitted_test.go index 1d7519ff9..592c22db7 100644 --- a/markets/storageadapter/ondealsectorcommitted_test.go +++ b/markets/storageadapter/ondealsectorcommitted_test.go @@ -10,8 +10,8 @@ import ( "testing" "time" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + blocks "github.com/ipfs/go-libipfs/blocks" "github.com/stretchr/testify/require" "golang.org/x/xerrors" diff --git a/metrics/metrics.go b/metrics/metrics.go index 8a4c3aa31..149195faf 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -14,7 +14,7 @@ import ( ) // Distribution -var defaultMillisecondsDistribution = view.Distribution(0.01, 0.05, 0.1, 0.3, 0.6, 0.8, 1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100, 130, 160, 200, 250, 300, 400, 500, 650, 800, 1000, 2000, 3000, 4000, 5000, 7500, 10000, 20000, 50000, 100000) +var defaultMillisecondsDistribution = view.Distribution(0.01, 0.05, 0.1, 0.3, 0.6, 0.8, 1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100, 130, 160, 200, 250, 300, 400, 500, 650, 800, 1000, 2000, 3000, 4000, 5000, 7500, 10000, 20000, 50000, 100_000, 250_000, 500_000, 1000_000) var workMillisecondsDistribution = view.Distribution( 250, 500, 1000, 2000, 5000, 10_000, 30_000, 60_000, 2*60_000, 5*60_000, 10*60_000, 15*60_000, 30*60_000, // short sealing tasks 40*60_000, 45*60_000, 50*60_000, 55*60_000, 60*60_000, 65*60_000, 70*60_000, 75*60_000, 80*60_000, 85*60_000, 100*60_000, 120*60_000, // PC2 / C2 range @@ -22,6 +22,8 @@ var workMillisecondsDistribution = view.Distribution( 350*60_000, 400*60_000, 600*60_000, 800*60_000, 1000*60_000, 1300*60_000, 1800*60_000, 4000*60_000, 10000*60_000, // intel PC1 range ) +var queueSizeDistribution = view.Distribution(0, 1, 2, 3, 5, 7, 10, 15, 25, 35, 50, 70, 90, 130, 200, 300, 500, 1000, 2000, 5000, 10000) + // Global Tags var ( // common @@ -48,6 +50,9 @@ var ( StorageID, _ = tag.NewKey("storage_id") SectorState, _ = tag.NewKey("sector_state") + PathSeal, _ = tag.NewKey("path_seal") + PathStorage, _ = tag.NewKey("path_storage") + // rcmgr ServiceID, _ = tag.NewKey("svc") ProtocolID, _ = tag.NewKey("proto") @@ -136,6 +141,13 @@ var ( StorageLimitUsedBytes = stats.Int64("storage/path_limit_used_bytes", "used optional storage limit bytes", stats.UnitBytes) StorageLimitMaxBytes = stats.Int64("storage/path_limit_max_bytes", "optional storage limit", stats.UnitBytes) + SchedAssignerCycleDuration = stats.Float64("sched/assigner_cycle_ms", "Duration of scheduler assigner cycle", stats.UnitMilliseconds) + SchedAssignerCandidatesDuration = stats.Float64("sched/assigner_cycle_candidates_ms", "Duration of scheduler assigner candidate matching step", stats.UnitMilliseconds) + SchedAssignerWindowSelectionDuration = stats.Float64("sched/assigner_cycle_window_select_ms", "Duration of scheduler window selection step", stats.UnitMilliseconds) + SchedAssignerSubmitDuration = stats.Float64("sched/assigner_cycle_submit_ms", "Duration of scheduler window submit step", stats.UnitMilliseconds) + SchedCycleOpenWindows = stats.Int64("sched/assigner_cycle_open_window", "Number of open windows in scheduling cycles", stats.UnitDimensionless) + SchedCycleQueueSize = stats.Int64("sched/assigner_cycle_task_queue_entry", "Number of task queue entries in scheduling cycles", stats.UnitDimensionless) + DagStorePRInitCount = stats.Int64("dagstore/pr_init_count", "PieceReader init count", stats.UnitDimensionless) DagStorePRBytesRequested = stats.Int64("dagstore/pr_requested_bytes", "PieceReader requested bytes", stats.UnitBytes) DagStorePRBytesDiscarded = stats.Int64("dagstore/pr_discarded_bytes", "PieceReader discarded bytes", stats.UnitBytes) @@ -380,52 +392,77 @@ var ( StorageFSAvailableView = &view.View{ Measure: StorageFSAvailable, Aggregation: view.LastValue(), - TagKeys: []tag.Key{StorageID}, + TagKeys: []tag.Key{StorageID, PathStorage, PathSeal}, } StorageAvailableView = &view.View{ Measure: StorageAvailable, Aggregation: view.LastValue(), - TagKeys: []tag.Key{StorageID}, + TagKeys: []tag.Key{StorageID, PathStorage, PathSeal}, } StorageReservedView = &view.View{ Measure: StorageReserved, Aggregation: view.LastValue(), - TagKeys: []tag.Key{StorageID}, + TagKeys: []tag.Key{StorageID, PathStorage, PathSeal}, } StorageLimitUsedView = &view.View{ Measure: StorageLimitUsed, Aggregation: view.LastValue(), - TagKeys: []tag.Key{StorageID}, + TagKeys: []tag.Key{StorageID, PathStorage, PathSeal}, } StorageCapacityBytesView = &view.View{ Measure: StorageCapacityBytes, Aggregation: view.LastValue(), - TagKeys: []tag.Key{StorageID}, + TagKeys: []tag.Key{StorageID, PathStorage, PathSeal}, } StorageFSAvailableBytesView = &view.View{ Measure: StorageFSAvailableBytes, Aggregation: view.LastValue(), - TagKeys: []tag.Key{StorageID}, + TagKeys: []tag.Key{StorageID, PathStorage, PathSeal}, } StorageAvailableBytesView = &view.View{ Measure: StorageAvailableBytes, Aggregation: view.LastValue(), - TagKeys: []tag.Key{StorageID}, + TagKeys: []tag.Key{StorageID, PathStorage, PathSeal}, } StorageReservedBytesView = &view.View{ Measure: StorageReservedBytes, Aggregation: view.LastValue(), - TagKeys: []tag.Key{StorageID}, + TagKeys: []tag.Key{StorageID, PathStorage, PathSeal}, } StorageLimitUsedBytesView = &view.View{ Measure: StorageLimitUsedBytes, Aggregation: view.LastValue(), - TagKeys: []tag.Key{StorageID}, + TagKeys: []tag.Key{StorageID, PathStorage, PathSeal}, } StorageLimitMaxBytesView = &view.View{ Measure: StorageLimitMaxBytes, Aggregation: view.LastValue(), - TagKeys: []tag.Key{StorageID}, + TagKeys: []tag.Key{StorageID, PathStorage, PathSeal}, + } + + SchedAssignerCycleDurationView = &view.View{ + Measure: SchedAssignerCycleDuration, + Aggregation: defaultMillisecondsDistribution, + } + SchedAssignerCandidatesDurationView = &view.View{ + Measure: SchedAssignerCandidatesDuration, + Aggregation: defaultMillisecondsDistribution, + } + SchedAssignerWindowSelectionDurationView = &view.View{ + Measure: SchedAssignerWindowSelectionDuration, + Aggregation: defaultMillisecondsDistribution, + } + SchedAssignerSubmitDurationView = &view.View{ + Measure: SchedAssignerSubmitDuration, + Aggregation: defaultMillisecondsDistribution, + } + SchedCycleOpenWindowsView = &view.View{ + Measure: SchedCycleOpenWindows, + Aggregation: queueSizeDistribution, + } + SchedCycleQueueSizeView = &view.View{ + Measure: SchedCycleQueueSize, + Aggregation: queueSizeDistribution, } DagStorePRInitCountView = &view.View{ @@ -697,6 +734,7 @@ var MinerNodeViews = append([]*view.View{ WorkerCallsReturnedCountView, WorkerUntrackedCallsReturnedView, WorkerCallsReturnedDurationView, + SectorStatesView, StorageFSAvailableView, StorageAvailableView, @@ -708,6 +746,14 @@ var MinerNodeViews = append([]*view.View{ StorageReservedBytesView, StorageLimitUsedBytesView, StorageLimitMaxBytesView, + + SchedAssignerCycleDurationView, + SchedAssignerCandidatesDurationView, + SchedAssignerWindowSelectionDurationView, + SchedAssignerSubmitDurationView, + SchedCycleOpenWindowsView, + SchedCycleQueueSizeView, + DagStorePRInitCountView, DagStorePRBytesRequestedView, DagStorePRBytesDiscardedView, diff --git a/miner/warmup.go b/miner/warmup.go index 3b73afbc9..46236784a 100644 --- a/miner/warmup.go +++ b/miner/warmup.go @@ -59,6 +59,9 @@ out: if err != nil { return xerrors.Errorf("getting sector info: %w", err) } + if si == nil { + return xerrors.Errorf("sector not found %d", sector) + } ts, err := m.api.ChainHead(ctx) if err != nil { diff --git a/node/builder.go b/node/builder.go index eaf932e2e..88b67a96d 100644 --- a/node/builder.go +++ b/node/builder.go @@ -30,6 +30,7 @@ import ( "github.com/filecoin-project/lotus/lib/lotuslog" "github.com/filecoin-project/lotus/lib/peermgr" _ "github.com/filecoin-project/lotus/lib/sigs/bls" + _ "github.com/filecoin-project/lotus/lib/sigs/delegated" _ "github.com/filecoin-project/lotus/lib/sigs/secp" "github.com/filecoin-project/lotus/markets/storageadapter" "github.com/filecoin-project/lotus/node/config" @@ -125,6 +126,8 @@ const ( SetApiEndpointKey + StoreEventsKey + _nInvokes // keep this last ) diff --git a/node/builder_chain.go b/node/builder_chain.go index 2201be2e6..4e5bad61d 100644 --- a/node/builder_chain.go +++ b/node/builder_chain.go @@ -17,6 +17,7 @@ import ( "github.com/filecoin-project/lotus/chain/beacon" "github.com/filecoin-project/lotus/chain/consensus" "github.com/filecoin-project/lotus/chain/consensus/filcns" + "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/gen/slashfilter" "github.com/filecoin-project/lotus/chain/market" @@ -151,6 +152,8 @@ var ChainNode = Options( Override(new(full.MpoolModuleAPI), From(new(api.Gateway))), Override(new(full.StateModuleAPI), From(new(api.Gateway))), Override(new(stmgr.StateManagerAPI), rpcstmgr.NewRPCStateManager), + Override(new(full.EthModuleAPI), From(new(api.Gateway))), + Override(new(full.EthEventAPI), From(new(api.Gateway))), ), // Full node API / service startup @@ -216,6 +219,11 @@ func ConfigFullNode(c interface{}) Option { Override(SetupFallbackBlockstoresKey, modules.InitFallbackBlockstores), ), + // If the Eth JSON-RPC is enabled, enable storing events at the ChainStore. + // This is the case even if real-time and historic filtering are disabled, + // as it enables us to serve logs in eth_getTransactionReceipt. + If(cfg.Fevm.EnableEthRPC, Override(StoreEventsKey, modules.EnableStoringEvents)), + Override(new(dtypes.ClientImportMgr), modules.ClientImportMgr), Override(new(dtypes.ClientBlockstore), modules.ClientBlockstore), @@ -241,6 +249,7 @@ func ConfigFullNode(c interface{}) Option { Unset(new(*wallet.LocalWallet)), Override(new(wallet.Default), wallet.NilDefault), ), + // Chain node cluster enabled If(cfg.Cluster.ClusterModeEnabled, Override(new(*gorpc.Client), modules.NewRPCClient), @@ -251,6 +260,21 @@ func ConfigFullNode(c interface{}) Option { Override(new(*modules.RPCHandler), modules.NewRPCHandler), Override(GoRPCServer, modules.NewRPCServer), ), + + // Actor event filtering support + Override(new(events.EventAPI), From(new(modules.EventAPI))), + + // in lite-mode Eth api is provided by gateway + ApplyIf(isFullNode, + If(cfg.Fevm.EnableEthRPC, + Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm)), + Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.Fevm)), + ), + If(!cfg.Fevm.EnableEthRPC, + Override(new(full.EthModuleAPI), &full.EthModuleDummy{}), + Override(new(full.EthEventAPI), &full.EthModuleDummy{}), + ), + ), ) } diff --git a/node/config/def.go b/node/config/def.go index dc26f1661..9a24449ba 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -70,11 +70,12 @@ func defCommon() Common { DirectPeers: nil, }, } - } -var DefaultDefaultMaxFee = types.MustParseFIL("0.07") -var DefaultSimultaneousTransfers = uint64(20) +var ( + DefaultDefaultMaxFee = types.MustParseFIL("0.07") + DefaultSimultaneousTransfers = uint64(20) +) // DefaultFullNode returns the default config func DefaultFullNode() *FullNode { @@ -98,6 +99,18 @@ func DefaultFullNode() *FullNode { }, }, Cluster: *DefaultUserRaftConfig(), + Fevm: FevmConfig{ + EnableEthRPC: false, + EthTxHashMappingLifetimeDays: 0, + Events: Events{ + DisableRealTimeFilterAPI: false, + DisableHistoricFilterAPI: false, + FilterTTL: Duration(time.Hour * 24), + MaxFilters: 100, + MaxFilterResults: 10000, + MaxFilterHeightRange: 2880, // conservative limit of one day + }, + }, } } @@ -255,8 +268,10 @@ func DefaultStorageMiner() *StorageMiner { return cfg } -var _ encoding.TextMarshaler = (*Duration)(nil) -var _ encoding.TextUnmarshaler = (*Duration)(nil) +var ( + _ encoding.TextMarshaler = (*Duration)(nil) + _ encoding.TextUnmarshaler = (*Duration)(nil) +) // Duration is a wrapper type for time.Duration // for decoding and encoding from/to TOML diff --git a/node/config/doc_gen.go b/node/config/doc_gen.go index ecf533137..8b79bed4f 100644 --- a/node/config/doc_gen.go +++ b/node/config/doc_gen.go @@ -341,6 +341,59 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/# Comment: ``, }, }, + "Events": []DocField{ + { + Name: "DisableRealTimeFilterAPI", + Type: "bool", + + Comment: `EnableEthRPC enables APIs that +DisableRealTimeFilterAPI will disable the RealTimeFilterAPI that can create and query filters for actor events as they are emitted. +The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.`, + }, + { + Name: "DisableHistoricFilterAPI", + Type: "bool", + + Comment: `DisableHistoricFilterAPI will disable the HistoricFilterAPI that can create and query filters for actor events +that occurred in the past. HistoricFilterAPI maintains a queryable index of events. +The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.`, + }, + { + Name: "FilterTTL", + Type: "Duration", + + Comment: `FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than +this time become eligible for automatic deletion.`, + }, + { + Name: "MaxFilters", + Type: "int", + + Comment: `MaxFilters specifies the maximum number of filters that may exist at any one time.`, + }, + { + Name: "MaxFilterResults", + Type: "int", + + Comment: `MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter.`, + }, + { + Name: "MaxFilterHeightRange", + Type: "uint64", + + Comment: `MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying +the entire chain)`, + }, + { + Name: "DatabasePath", + Type: "string", + + Comment: `DatabasePath is the full path to a sqlite database that will be used to index actor events to +support the historic filter APIs. If the database does not exist it will be created. The directory containing +the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as +relative to the CWD (current working directory).`, + }, + }, "FeeConfig": []DocField{ { Name: "DefaultMaxFee", @@ -349,6 +402,28 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/# Comment: ``, }, }, + "FevmConfig": []DocField{ + { + Name: "EnableEthRPC", + Type: "bool", + + Comment: `EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids. +This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.`, + }, + { + Name: "EthTxHashMappingLifetimeDays", + Type: "int", + + Comment: `EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days +Set to 0 to keep all mappings`, + }, + { + Name: "Events", + Type: "Events", + + Comment: ``, + }, + }, "FullNode": []DocField{ { Name: "Client", @@ -378,6 +453,12 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/# Name: "Cluster", Type: "UserRaftConfig", + Comment: ``, + }, + { + Name: "Fevm", + Type: "FevmConfig", + Comment: ``, }, }, @@ -788,6 +869,35 @@ Type: Array of multiaddress peerinfo strings, must include peerid (/p2p/12D3K... Comment: ``, }, + { + Name: "JsonTracer", + Type: "string", + + Comment: `Path to file that will be used to output tracer content in JSON format. +If present tracer will save data to defined file. +Format: file path`, + }, + { + Name: "ElasticSearchTracer", + Type: "string", + + Comment: `Connection string for elasticsearch instance. +If present tracer will save data to elasticsearch. +Format: https://:@:/`, + }, + { + Name: "ElasticSearchIndex", + Type: "string", + + Comment: `Name of elasticsearch index that will be used to save tracer data. +This property is used only if ElasticSearchTracer propery is set.`, + }, + { + Name: "TracerSourceAuth", + Type: "string", + + Comment: `Auth token that will be passed with logs to elasticsearch - used for weighted peers score.`, + }, }, "RetrievalPricing": []DocField{ { diff --git a/node/config/types.go b/node/config/types.go index 90d878b7e..690e8caee 100644 --- a/node/config/types.go +++ b/node/config/types.go @@ -27,6 +27,7 @@ type FullNode struct { Fees FeeConfig Chainstore Chainstore Cluster UserRaftConfig + Fevm FevmConfig } // // Common @@ -168,7 +169,6 @@ type DealmakingConfig struct { } type IndexProviderConfig struct { - // Enable set whether to enable indexing announcement to the network and expose endpoints that // allow indexer nodes to process announcements. Enabled by default. Enable bool @@ -563,6 +563,19 @@ type Pubsub struct { DirectPeers []string IPColocationWhitelist []string RemoteTracer string + // Path to file that will be used to output tracer content in JSON format. + // If present tracer will save data to defined file. + // Format: file path + JsonTracer string + // Connection string for elasticsearch instance. + // If present tracer will save data to elasticsearch. + // Format: https://:@:/ + ElasticSearchTracer string + // Name of elasticsearch index that will be used to save tracer data. + // This property is used only if ElasticSearchTracer propery is set. + ElasticSearchIndex string + // Auth token that will be passed with logs to elasticsearch - used for weighted peers score. + TracerSourceAuth string } type Chainstore struct { @@ -645,3 +658,52 @@ type UserRaftConfig struct { // Tracing enables propagation of contexts across binary boundaries. Tracing bool } + +type FevmConfig struct { + // EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids. + // This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above. + EnableEthRPC bool + + // EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days + // Set to 0 to keep all mappings + EthTxHashMappingLifetimeDays int + + Events Events +} + +type Events struct { + // EnableEthRPC enables APIs that + // DisableRealTimeFilterAPI will disable the RealTimeFilterAPI that can create and query filters for actor events as they are emitted. + // The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag. + DisableRealTimeFilterAPI bool + + // DisableHistoricFilterAPI will disable the HistoricFilterAPI that can create and query filters for actor events + // that occurred in the past. HistoricFilterAPI maintains a queryable index of events. + // The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag. + DisableHistoricFilterAPI bool + + // FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than + // this time become eligible for automatic deletion. + FilterTTL Duration + + // MaxFilters specifies the maximum number of filters that may exist at any one time. + MaxFilters int + + // MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter. + MaxFilterResults int + + // MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying + // the entire chain) + MaxFilterHeightRange uint64 + + // DatabasePath is the full path to a sqlite database that will be used to index actor events to + // support the historic filter APIs. If the database does not exist it will be created. The directory containing + // the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as + // relative to the CWD (current working directory). + DatabasePath string + + // Others, not implemented yet: + // Set a limit on the number of active websocket subscriptions (may be zero) + // Set a timeout for subscription clients + // Set upper bound on index size +} diff --git a/node/hello/hello.go b/node/hello/hello.go index 651716da9..e05b8a482 100644 --- a/node/hello/hello.go +++ b/node/hello/hello.go @@ -158,6 +158,9 @@ func (hs *Service) SayHello(ctx context.Context, pid peer.ID) error { if err := cborutil.WriteCborRPC(s, hmsg); err != nil { return xerrors.Errorf("writing rpc to peer: %w", err) } + if err := s.CloseWrite(); err != nil { + log.Warnw("CloseWrite err", "error", err) + } go func() { defer s.Close() //nolint:errcheck diff --git a/node/impl/full.go b/node/impl/full.go index 03a28eb75..affcc960e 100644 --- a/node/impl/full.go +++ b/node/impl/full.go @@ -35,6 +35,7 @@ type FullNodeAPI struct { full.WalletAPI full.SyncAPI full.RaftAPI + full.EthAPI DS dtypes.MetadataDS NetworkName dtypes.NetworkName diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index ca245dcda..17444ca58 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -6,16 +6,17 @@ import ( "context" "encoding/json" "io" + "math" "strconv" "strings" "sync" - blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" offline "github.com/ipfs/go-ipfs-exchange-offline" cbor "github.com/ipfs/go-ipld-cbor" ipld "github.com/ipfs/go-ipld-format" + blocks "github.com/ipfs/go-libipfs/blocks" logging "github.com/ipfs/go-log/v2" "github.com/ipfs/go-merkledag" mh "github.com/multiformats/go-multihash" @@ -24,6 +25,7 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + amt4 "github.com/filecoin-project/go-amt-ipld/v4" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/util/adt" @@ -654,6 +656,33 @@ func (a *ChainAPI) ChainBlockstoreInfo(ctx context.Context) (map[string]interfac return info.Info(), nil } +// ChainGetEvents returns the events under an event AMT root CID. +// +// TODO (raulk) make copies of this logic elsewhere use this (e.g. itests, CLI, events filter). +func (a *ChainAPI) ChainGetEvents(ctx context.Context, root cid.Cid) ([]types.Event, error) { + store := cbor.NewCborStore(a.ExposedBlockstore) + evtArr, err := amt4.LoadAMT(ctx, store, root, amt4.UseTreeBitWidth(types.EventAMTBitwidth)) + if err != nil { + return nil, xerrors.Errorf("load events amt: %w", err) + } + + ret := make([]types.Event, 0, evtArr.Len()) + var evt types.Event + err = evtArr.ForEach(ctx, func(u uint64, deferred *cbg.Deferred) error { + if u > math.MaxInt { + return xerrors.Errorf("too many events") + } + if err := evt.UnmarshalCBOR(bytes.NewReader(deferred.Raw)); err != nil { + return err + } + + ret = append(ret, evt) + return nil + }) + + return ret, err +} + func (a *ChainAPI) ChainPrune(ctx context.Context, opts api.PruneOpts) error { pruner, ok := a.BaseBlockstore.(interface { PruneChain(opts api.PruneOpts) error diff --git a/node/impl/full/dummy.go b/node/impl/full/dummy.go new file mode 100644 index 000000000..d86b02d4b --- /dev/null +++ b/node/impl/full/dummy.go @@ -0,0 +1,169 @@ +package full + +import ( + "context" + "errors" + + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types/ethtypes" +) + +var ErrModuleDisabled = errors.New("module disabled, enable with Fevm.EnableEthRPC / LOTUS_FEVM_ENABLEETHRPC") + +type EthModuleDummy struct{} + +func (e *EthModuleDummy) EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) { + return address.Undef, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) { + return nil, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) { + return nil, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) { + return 0, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) { + return nil, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) { + return 0, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) { + return 0, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) { + return ethtypes.EthBlock{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) { + return ethtypes.EthBlock{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) { + return nil, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) { + return 0, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) { + return nil, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) { + return ethtypes.EthTx{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) { + return ethtypes.EthTx{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) { + return nil, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) { + return nil, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) { + return ethtypes.EthBigIntZero, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { + return ethtypes.EthFeeHistory{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) { + return 0, ErrModuleDisabled +} + +func (e *EthModuleDummy) NetVersion(ctx context.Context) (string, error) { + return "", ErrModuleDisabled +} + +func (e *EthModuleDummy) NetListening(ctx context.Context) (bool, error) { + return false, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) { + return 0, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) { + return ethtypes.EthBigIntZero, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) { + return 0, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) { + return nil, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) { + return ethtypes.EthBigIntZero, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) { + return ethtypes.EthHash{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) Web3ClientVersion(ctx context.Context) (string, error) { + return "", ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) { + return ðtypes.EthFilterResult{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + return ðtypes.EthFilterResult{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + return ðtypes.EthFilterResult{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthNewFilter(ctx context.Context, filter *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) { + return ethtypes.EthFilterID{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) { + return ethtypes.EthFilterID{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) { + return ethtypes.EthFilterID{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) { + return false, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) { + return ethtypes.EthSubscriptionID{}, ErrModuleDisabled +} + +func (e *EthModuleDummy) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) { + return false, ErrModuleDisabled +} + +var _ EthModuleAPI = &EthModuleDummy{} +var _ EthEventAPI = &EthModuleDummy{} diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go new file mode 100644 index 000000000..b1d03db4b --- /dev/null +++ b/node/impl/full/eth.go @@ -0,0 +1,2381 @@ +package full + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "sort" + "strconv" + "sync" + "time" + + "github.com/google/uuid" + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + builtintypes "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/builtin/v10/eam" + "github.com/filecoin-project/go-state-types/builtin/v10/evm" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/exitcode" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin" + builtinevm "github.com/filecoin-project/lotus/chain/actors/builtin/evm" + "github.com/filecoin-project/lotus/chain/ethhashlookup" + "github.com/filecoin-project/lotus/chain/events/filter" + "github.com/filecoin-project/lotus/chain/messagepool" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/node/modules/dtypes" +) + +type EthModuleAPI interface { + EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) + EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) + EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) + EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) + EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) + EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) + EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) + EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) + EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) + EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) + EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) + EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) + EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) + EthChainId(ctx context.Context) (ethtypes.EthUint64, error) + NetVersion(ctx context.Context) (string, error) + NetListening(ctx context.Context) (bool, error) + EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) + EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) + EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) + EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) + EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) + EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) + Web3ClientVersion(ctx context.Context) (string, error) +} + +type EthEventAPI interface { + EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) + EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) + EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) + EthNewFilter(ctx context.Context, filter *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) + EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) + EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) + EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) + EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) + EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) +} + +var ( + _ EthModuleAPI = *new(api.FullNode) + _ EthEventAPI = *new(api.FullNode) + + _ EthModuleAPI = *new(api.Gateway) +) + +// EthModule provides the default implementation of the standard Ethereum JSON-RPC API. +// +// # Execution model reconciliation +// +// Ethereum relies on an immediate block-based execution model. The block that includes +// a transaction is also the block that executes it. Each block specifies the state root +// resulting from executing all transactions within it (output state). +// +// In Filecoin, at every epoch there is an unknown number of round winners all of whom are +// entitled to publish a block. Blocks are collected into a tipset. A tipset is committed +// only when the subsequent tipset is built on it (i.e. it becomes a parent). Block producers +// execute the parent tipset and specify the resulting state root in the block being produced. +// In other words, contrary to Ethereum, each block specifies the input state root. +// +// Ethereum clients expect transactions returned via eth_getBlock* to have a receipt +// (due to immediate execution). For this reason: +// +// - eth_blockNumber returns the latest executed epoch (head - 1) +// - The 'latest' block refers to the latest executed epoch (head - 1) +// - The 'pending' block refers to the current speculative tipset (head) +// - eth_getTransactionByHash returns the inclusion tipset of a message, but +// only after it has executed. +// - eth_getTransactionReceipt ditto. +// +// "Latest executed epoch" refers to the tipset that this node currently +// accepts as the best parent tipset, based on the blocks it is accumulating +// within the HEAD tipset. +type EthModule struct { + Chain *store.ChainStore + Mpool *messagepool.MessagePool + StateManager *stmgr.StateManager + EthTxHashManager *EthTxHashManager + + ChainAPI + MpoolAPI + StateAPI +} + +var _ EthModuleAPI = (*EthModule)(nil) + +type EthEvent struct { + Chain *store.ChainStore + EventFilterManager *filter.EventFilterManager + TipSetFilterManager *filter.TipSetFilterManager + MemPoolFilterManager *filter.MemPoolFilterManager + FilterStore filter.FilterStore + SubManager *EthSubscriptionManager + MaxFilterHeightRange abi.ChainEpoch + SubscribtionCtx context.Context +} + +var _ EthEventAPI = (*EthEvent)(nil) + +type EthAPI struct { + fx.In + + Chain *store.ChainStore + + EthModuleAPI + EthEventAPI +} + +func (a *EthModule) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) { + return stmgr.GetNetworkName(ctx, a.StateManager, a.Chain.GetHeaviestTipSet().ParentState()) +} + +func (a *EthModule) EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) { + // eth_blockNumber needs to return the height of the latest committed tipset. + // Ethereum clients expect all transactions included in this block to have execution outputs. + // This is the parent of the head tipset. The head tipset is speculative, has not been + // recognized by the network, and its messages are only included, not executed. + // See https://github.com/filecoin-project/ref-fvm/issues/1135. + heaviest := a.Chain.GetHeaviestTipSet() + if height := heaviest.Height(); height == 0 { + // we're at genesis. + return ethtypes.EthUint64(height), nil + } + // First non-null parent. + effectiveParent := heaviest.Parents() + parent, err := a.Chain.GetTipSetFromKey(ctx, effectiveParent) + if err != nil { + return 0, err + } + return ethtypes.EthUint64(parent.Height()), nil +} + +func (a *EthModule) EthAccounts(context.Context) ([]ethtypes.EthAddress, error) { + // The lotus node is not expected to hold manage accounts, so we'll always return an empty array + return []ethtypes.EthAddress{}, nil +} + +func (a *EthAPI) EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) { + return ethAddress.ToFilecoinAddress() +} + +func (a *EthAPI) FilecoinAddressToEthAddress(ctx context.Context, filecoinAddress address.Address) (ethtypes.EthAddress, error) { + return ethtypes.EthAddressFromFilecoinAddress(filecoinAddress) +} + +func (a *EthModule) countTipsetMsgs(ctx context.Context, ts *types.TipSet) (int, error) { + blkMsgs, err := a.Chain.BlockMsgsForTipset(ctx, ts) + if err != nil { + return 0, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err) + } + + count := 0 + for _, blkMsg := range blkMsgs { + // TODO: may need to run canonical ordering and deduplication here + count += len(blkMsg.BlsMessages) + len(blkMsg.SecpkMessages) + } + return count, nil +} + +func (a *EthModule) EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) { + ts, err := a.Chain.GetTipsetByHeight(ctx, abi.ChainEpoch(blkNum), nil, false) + if err != nil { + return ethtypes.EthUint64(0), xerrors.Errorf("error loading tipset %s: %w", ts, err) + } + + count, err := a.countTipsetMsgs(ctx, ts) + return ethtypes.EthUint64(count), err +} + +func (a *EthModule) EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) { + ts, err := a.Chain.GetTipSetByCid(ctx, blkHash.ToCid()) + if err != nil { + return ethtypes.EthUint64(0), xerrors.Errorf("error loading tipset %s: %w", ts, err) + } + count, err := a.countTipsetMsgs(ctx, ts) + return ethtypes.EthUint64(count), err +} + +func (a *EthModule) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) { + ts, err := a.Chain.GetTipSetByCid(ctx, blkHash.ToCid()) + if err != nil { + return ethtypes.EthBlock{}, xerrors.Errorf("error loading tipset %s: %w", ts, err) + } + return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.StateAPI) +} + +func (a *EthModule) parseBlkParam(ctx context.Context, blkParam string) (tipset *types.TipSet, err error) { + if blkParam == "earliest" { + return nil, fmt.Errorf("block param \"earliest\" is not supported") + } + + head := a.Chain.GetHeaviestTipSet() + switch blkParam { + case "pending": + return head, nil + case "latest": + parent, err := a.Chain.GetTipSetFromKey(ctx, head.Parents()) + if err != nil { + return nil, fmt.Errorf("cannot get parent tipset") + } + return parent, nil + default: + var num ethtypes.EthUint64 + err := num.UnmarshalJSON([]byte(`"` + blkParam + `"`)) + if err != nil { + return nil, fmt.Errorf("cannot parse block number: %v", err) + } + ts, err := a.Chain.GetTipsetByHeight(ctx, abi.ChainEpoch(num), nil, false) + if err != nil { + return nil, fmt.Errorf("cannot get tipset at height: %v", num) + } + return ts, nil + } +} + +func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkParam string, fullTxInfo bool) (ethtypes.EthBlock, error) { + ts, err := a.parseBlkParam(ctx, blkParam) + if err != nil { + return ethtypes.EthBlock{}, err + } + return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.StateAPI) +} + +func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) { + // Ethereum's behavior is to return null when the txHash is invalid, so we use nil to check if txHash is valid + if txHash == nil { + return nil, nil + } + + c, err := a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash) + if err != nil { + log.Debug("could not find transaction hash %s in lookup table", txHash.String()) + } + + // This isn't an eth transaction we have the mapping for, so let's look it up as a filecoin message + if c == cid.Undef { + c = txHash.ToCid() + } + + // first, try to get the cid from mined transactions + msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, c, api.LookbackNoLimit, true) + if err == nil && msgLookup != nil { + tx, err := newEthTxFromMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI) + if err == nil { + return &tx, nil + } + } + + // if not found, try to get it from the mempool + pending, err := a.MpoolAPI.MpoolPending(ctx, types.EmptyTSK) + if err != nil { + // inability to fetch mpool pending transactions is an internal node error + // that needs to be reported as-is + return nil, fmt.Errorf("cannot get pending txs from mpool: %s", err) + } + + for _, p := range pending { + if p.Cid() == c { + tx, err := newEthTxFromSignedMessage(ctx, p, a.StateAPI) + if err != nil { + return nil, fmt.Errorf("could not convert Filecoin message into tx: %s", err) + } + return &tx, nil + } + } + // Ethereum clients expect an empty response when the message was not found + return nil, nil +} + +func (a *EthModule) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) { + // Ethereum's behavior is to return null when the txHash is invalid, so we use nil to check if txHash is valid + if txHash == nil { + return nil, nil + } + + c, err := a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash) + // We fall out of the first condition and continue + if errors.Is(err, ethhashlookup.ErrNotFound) { + log.Debug("could not find transaction hash %s in lookup table", txHash.String()) + } else if err != nil { + return nil, xerrors.Errorf("database error: %w", err) + } else { + return &c, nil + } + + // This isn't an eth transaction we have the mapping for, so let's try looking it up as a filecoin message + if c == cid.Undef { + c = txHash.ToCid() + } + + _, err = a.StateAPI.Chain.GetSignedMessage(ctx, c) + if err == nil { + // This is an Eth Tx, Secp message, Or BLS message in the mpool + return &c, nil + } + + _, err = a.StateAPI.Chain.GetMessage(ctx, c) + if err == nil { + // This is a BLS message + return &c, nil + } + + // Ethereum clients expect an empty response when the message was not found + return nil, nil +} + +func (a *EthModule) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) { + hash, err := EthTxHashFromMessageCid(ctx, cid, a.StateAPI) + if hash == ethtypes.EmptyEthHash { + // not found + return nil, nil + } + + return &hash, err +} + +func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam string) (ethtypes.EthUint64, error) { + addr, err := sender.ToFilecoinAddress() + if err != nil { + return ethtypes.EthUint64(0), nil + } + + ts, err := a.parseBlkParam(ctx, blkParam) + if err != nil { + return ethtypes.EthUint64(0), xerrors.Errorf("cannot parse block param: %s", blkParam) + } + + // First, handle the case where the "sender" is an EVM actor. + if actor, err := a.StateManager.LoadActor(ctx, addr, ts); err != nil { + if xerrors.Is(err, types.ErrActorNotFound) { + return 0, nil + } + return 0, xerrors.Errorf("failed to lookup contract %s: %w", sender, err) + } else if builtinactors.IsEvmActor(actor.Code) { + evmState, err := builtinevm.Load(a.Chain.ActorStore(ctx), actor) + if err != nil { + return 0, xerrors.Errorf("failed to load evm state: %w", err) + } + if alive, err := evmState.IsAlive(); err != nil { + return 0, err + } else if !alive { + return 0, nil + } + nonce, err := evmState.Nonce() + return ethtypes.EthUint64(nonce), err + } + + nonce, err := a.Mpool.GetNonce(ctx, addr, ts.Key()) + if err != nil { + return ethtypes.EthUint64(0), nil + } + return ethtypes.EthUint64(nonce), nil +} + +func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) { + c, err := a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(txHash) + if err != nil { + log.Debug("could not find transaction hash %s in lookup table", txHash.String()) + } + + // This isn't an eth transaction we have the mapping for, so let's look it up as a filecoin message + if c == cid.Undef { + c = txHash.ToCid() + } + + msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, c, api.LookbackNoLimit, true) + if err != nil || msgLookup == nil { + return nil, nil + } + + tx, err := newEthTxFromMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI) + if err != nil { + return nil, nil + } + + replay, err := a.StateAPI.StateReplay(ctx, types.EmptyTSK, c) + if err != nil { + return nil, nil + } + + var events []types.Event + if rct := replay.MsgRct; rct != nil && rct.EventsRoot != nil { + events, err = a.ChainAPI.ChainGetEvents(ctx, *rct.EventsRoot) + if err != nil { + return nil, nil + } + } + + receipt, err := newEthTxReceipt(ctx, tx, msgLookup, replay, events, a.StateAPI) + if err != nil { + return nil, nil + } + + return &receipt, nil +} + +func (a *EthModule) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) { + return ethtypes.EthTx{}, nil +} + +func (a *EthModule) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) { + return ethtypes.EthTx{}, nil +} + +// EthGetCode returns string value of the compiled bytecode +func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, blkParam string) (ethtypes.EthBytes, error) { + to, err := ethAddr.ToFilecoinAddress() + if err != nil { + return nil, xerrors.Errorf("cannot get Filecoin address: %w", err) + } + + ts, err := a.parseBlkParam(ctx, blkParam) + if err != nil { + return nil, xerrors.Errorf("cannot parse block param: %s", blkParam) + } + + // StateManager.Call will panic if there is no parent + if ts.Height() == 0 { + return nil, xerrors.Errorf("block param must not specify genesis block") + } + + actor, err := a.StateManager.LoadActor(ctx, to, ts) + if err != nil { + if xerrors.Is(err, types.ErrActorNotFound) { + return nil, nil + } + return nil, xerrors.Errorf("failed to lookup contract %s: %w", ethAddr, err) + } + + // Not a contract. We could try to distinguish between accounts and "native" contracts here, + // but it's not worth it. + if !builtinactors.IsEvmActor(actor.Code) { + return nil, nil + } + + msg := &types.Message{ + From: builtinactors.SystemActorAddr, + To: to, + Value: big.Zero(), + Method: builtintypes.MethodsEVM.GetBytecode, + Params: nil, + GasLimit: build.BlockGasLimit, + GasFeeCap: big.Zero(), + GasPremium: big.Zero(), + } + + // Try calling until we find a height with no migration. + var res *api.InvocResult + for { + res, err = a.StateManager.Call(ctx, msg, ts) + if err != stmgr.ErrExpensiveFork { + break + } + ts, err = a.Chain.GetTipSetFromKey(ctx, ts.Parents()) + if err != nil { + return nil, xerrors.Errorf("getting parent tipset: %w", err) + } + } + + if err != nil { + return nil, xerrors.Errorf("failed to call GetBytecode: %w", err) + } + + if res.MsgRct == nil { + return nil, fmt.Errorf("no message receipt") + } + + if res.MsgRct.ExitCode.IsError() { + return nil, xerrors.Errorf("GetBytecode failed: %s", res.Error) + } + + var getBytecodeReturn evm.GetBytecodeReturn + if err := getBytecodeReturn.UnmarshalCBOR(bytes.NewReader(res.MsgRct.Return)); err != nil { + return nil, fmt.Errorf("failed to decode EVM bytecode CID: %w", err) + } + + // The contract has selfdestructed, so the code is "empty". + if getBytecodeReturn.Cid == nil { + return nil, nil + } + + blk, err := a.Chain.StateBlockstore().Get(ctx, *getBytecodeReturn.Cid) + if err != nil { + return nil, fmt.Errorf("failed to get EVM bytecode: %w", err) + } + + return blk.RawData(), nil +} + +func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) { + ts, err := a.parseBlkParam(ctx, blkParam) + if err != nil { + return nil, xerrors.Errorf("cannot parse block param: %s", blkParam) + } + + l := len(position) + if l > 32 { + return nil, fmt.Errorf("supplied storage key is too long") + } + + // pad with zero bytes if smaller than 32 bytes + position = append(make([]byte, 32-l, 32), position...) + + to, err := ethAddr.ToFilecoinAddress() + if err != nil { + return nil, xerrors.Errorf("cannot get Filecoin address: %w", err) + } + + // use the system actor as the caller + from, err := address.NewIDAddress(0) + if err != nil { + return nil, fmt.Errorf("failed to construct system sender address: %w", err) + } + + actor, err := a.StateManager.LoadActor(ctx, to, ts) + if err != nil { + if xerrors.Is(err, types.ErrActorNotFound) { + return ethtypes.EthBytes(make([]byte, 32)), nil + } + return nil, xerrors.Errorf("failed to lookup contract %s: %w", ethAddr, err) + } + + if !builtinactors.IsEvmActor(actor.Code) { + return ethtypes.EthBytes(make([]byte, 32)), nil + } + + params, err := actors.SerializeParams(&evm.GetStorageAtParams{ + StorageKey: *(*[32]byte)(position), + }) + if err != nil { + return nil, fmt.Errorf("failed to serialize parameters: %w", err) + } + + msg := &types.Message{ + From: from, + To: to, + Value: big.Zero(), + Method: builtintypes.MethodsEVM.GetStorageAt, + Params: params, + GasLimit: build.BlockGasLimit, + GasFeeCap: big.Zero(), + GasPremium: big.Zero(), + } + + // Try calling until we find a height with no migration. + var res *api.InvocResult + for { + res, err = a.StateManager.Call(ctx, msg, ts) + if err != stmgr.ErrExpensiveFork { + break + } + ts, err = a.Chain.GetTipSetFromKey(ctx, ts.Parents()) + if err != nil { + return nil, xerrors.Errorf("getting parent tipset: %w", err) + } + } + + if err != nil { + return nil, xerrors.Errorf("Call failed: %w", err) + } + + if res.MsgRct == nil { + return nil, xerrors.Errorf("no message receipt") + } + + if res.MsgRct.ExitCode.IsError() { + return nil, xerrors.Errorf("failed to lookup storage slot: %s", res.Error) + } + + var ret abi.CborBytes + if err := ret.UnmarshalCBOR(bytes.NewReader(res.MsgRct.Return)); err != nil { + return nil, xerrors.Errorf("failed to unmarshal storage slot: %w", err) + } + + // pad with zero bytes if smaller than 32 bytes + ret = append(make([]byte, 32-len(ret), 32), ret...) + + return ethtypes.EthBytes(ret), nil +} + +func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) { + filAddr, err := address.ToFilecoinAddress() + if err != nil { + return ethtypes.EthBigInt{}, err + } + + ts, err := a.parseBlkParam(ctx, blkParam) + if err != nil { + return ethtypes.EthBigInt{}, xerrors.Errorf("cannot parse block param: %s", blkParam) + } + + st, _, err := a.StateManager.TipSetState(ctx, ts) + if err != nil { + return ethtypes.EthBigInt{}, xerrors.Errorf("failed to compute tipset state: %w", err) + } + + actor, err := a.StateManager.LoadActorRaw(ctx, filAddr, st) + if xerrors.Is(err, types.ErrActorNotFound) { + return ethtypes.EthBigIntZero, nil + } else if err != nil { + return ethtypes.EthBigInt{}, err + } + + return ethtypes.EthBigInt{Int: actor.Balance.Int}, nil +} + +func (a *EthModule) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) { + return ethtypes.EthUint64(build.Eip155ChainId), nil +} + +func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { + params, err := jsonrpc.DecodeParams[ethtypes.EthFeeHistoryParams](p) + if err != nil { + return ethtypes.EthFeeHistory{}, xerrors.Errorf("decoding params: %w", err) + } + if params.BlkCount > 1024 { + return ethtypes.EthFeeHistory{}, fmt.Errorf("block count should be smaller than 1024") + } + rewardPercentiles := make([]float64, 0) + if params.RewardPercentiles != nil { + rewardPercentiles = append(rewardPercentiles, *params.RewardPercentiles...) + } + for i, rp := range rewardPercentiles { + if rp < 0 || rp > 100 { + return ethtypes.EthFeeHistory{}, fmt.Errorf("invalid reward percentile: %f should be between 0 and 100", rp) + } + if i > 0 && rp < rewardPercentiles[i-1] { + return ethtypes.EthFeeHistory{}, fmt.Errorf("invalid reward percentile: %f should be larger than %f", rp, rewardPercentiles[i-1]) + } + } + + ts, err := a.parseBlkParam(ctx, params.NewestBlkNum) + if err != nil { + return ethtypes.EthFeeHistory{}, fmt.Errorf("bad block parameter %s: %s", params.NewestBlkNum, err) + } + + // Deal with the case that the chain is shorter than the number of requested blocks. + oldestBlkHeight := uint64(1) + if abi.ChainEpoch(params.BlkCount) <= ts.Height() { + oldestBlkHeight = uint64(ts.Height()) - uint64(params.BlkCount) + 1 + } + + // NOTE: baseFeePerGas should include the next block after the newest of the returned range, + // because the next base fee can be inferred from the messages in the newest block. + // However, this is NOT the case in Filecoin due to deferred execution, so the best + // we can do is duplicate the last value. + baseFeeArray := []ethtypes.EthBigInt{ethtypes.EthBigInt(ts.Blocks()[0].ParentBaseFee)} + gasUsedRatioArray := []float64{} + rewardsArray := make([][]ethtypes.EthBigInt, 0) + + for ts.Height() >= abi.ChainEpoch(oldestBlkHeight) { + // Unfortunately we need to rebuild the full message view so we can + // totalize gas used in the tipset. + msgs, err := a.Chain.MessagesForTipset(ctx, ts) + if err != nil { + return ethtypes.EthFeeHistory{}, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err) + } + + txGasRewards := gasRewardSorter{} + for txIdx, msg := range msgs { + msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, msg.Cid(), api.LookbackNoLimit, false) + if err != nil || msgLookup == nil { + return ethtypes.EthFeeHistory{}, nil + } + + tx, err := newEthTxFromMessageLookup(ctx, msgLookup, txIdx, a.Chain, a.StateAPI) + if err != nil { + return ethtypes.EthFeeHistory{}, nil + } + + txGasRewards = append(txGasRewards, gasRewardTuple{ + reward: tx.Reward(ts.Blocks()[0].ParentBaseFee), + gas: uint64(msgLookup.Receipt.GasUsed), + }) + } + + rewards, totalGasUsed := calculateRewardsAndGasUsed(rewardPercentiles, txGasRewards) + + // arrays should be reversed at the end + baseFeeArray = append(baseFeeArray, ethtypes.EthBigInt(ts.Blocks()[0].ParentBaseFee)) + gasUsedRatioArray = append(gasUsedRatioArray, float64(totalGasUsed)/float64(build.BlockGasLimit)) + rewardsArray = append(rewardsArray, rewards) + + parentTsKey := ts.Parents() + ts, err = a.Chain.LoadTipSet(ctx, parentTsKey) + if err != nil { + return ethtypes.EthFeeHistory{}, fmt.Errorf("cannot load tipset key: %v", parentTsKey) + } + } + + // Reverse the arrays; we collected them newest to oldest; the client expects oldest to newest. + for i, j := 0, len(baseFeeArray)-1; i < j; i, j = i+1, j-1 { + baseFeeArray[i], baseFeeArray[j] = baseFeeArray[j], baseFeeArray[i] + } + for i, j := 0, len(gasUsedRatioArray)-1; i < j; i, j = i+1, j-1 { + gasUsedRatioArray[i], gasUsedRatioArray[j] = gasUsedRatioArray[j], gasUsedRatioArray[i] + } + for i, j := 0, len(rewardsArray)-1; i < j; i, j = i+1, j-1 { + rewardsArray[i], rewardsArray[j] = rewardsArray[j], rewardsArray[i] + } + + ret := ethtypes.EthFeeHistory{ + OldestBlock: ethtypes.EthUint64(oldestBlkHeight), + BaseFeePerGas: baseFeeArray, + GasUsedRatio: gasUsedRatioArray, + } + if params.RewardPercentiles != nil { + ret.Reward = &rewardsArray + } + return ret, nil +} + +func (a *EthModule) NetVersion(ctx context.Context) (string, error) { + // Note that networkId is not encoded in hex + nv, err := a.StateNetworkVersion(ctx, types.EmptyTSK) + if err != nil { + return "", err + } + return strconv.FormatUint(uint64(nv), 10), nil +} + +func (a *EthModule) NetListening(ctx context.Context) (bool, error) { + return true, nil +} + +func (a *EthModule) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) { + height := a.Chain.GetHeaviestTipSet().Height() + return ethtypes.EthUint64(a.StateManager.GetNetworkVersion(ctx, height)), nil +} + +func (a *EthModule) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) { + gasPremium, err := a.GasAPI.GasEstimateGasPremium(ctx, 0, builtinactors.SystemActorAddr, 10000, types.EmptyTSK) + if err != nil { + return ethtypes.EthBigInt(big.Zero()), err + } + return ethtypes.EthBigInt(gasPremium), nil +} + +func (a *EthModule) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) { + // According to Geth's implementation, eth_gasPrice should return base + tip + // Ref: https://github.com/ethereum/pm/issues/328#issuecomment-853234014 + + ts := a.Chain.GetHeaviestTipSet() + baseFee := ts.Blocks()[0].ParentBaseFee + + premium, err := a.EthMaxPriorityFeePerGas(ctx) + if err != nil { + return ethtypes.EthBigInt(big.Zero()), nil + } + + gasPrice := big.Add(baseFee, big.Int(premium)) + return ethtypes.EthBigInt(gasPrice), nil +} + +func (a *EthModule) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) { + txArgs, err := ethtypes.ParseEthTxArgs(rawTx) + if err != nil { + return ethtypes.EmptyEthHash, err + } + + smsg, err := txArgs.ToSignedMessage() + if err != nil { + return ethtypes.EmptyEthHash, err + } + + _, err = a.MpoolAPI.MpoolPush(ctx, smsg) + if err != nil { + return ethtypes.EmptyEthHash, err + } + + return ethtypes.EthHashFromTxBytes(rawTx), nil +} + +func (a *EthModule) Web3ClientVersion(ctx context.Context) (string, error) { + return build.UserVersion(), nil +} + +func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.EthCall) (*types.Message, error) { + var from address.Address + if tx.From == nil || *tx.From == (ethtypes.EthAddress{}) { + // Send from the filecoin "system" address. + var err error + from, err = (ethtypes.EthAddress{}).ToFilecoinAddress() + if err != nil { + return nil, fmt.Errorf("failed to construct the ethereum system address: %w", err) + } + } else { + // The from address must be translatable to an f4 address. + var err error + from, err = tx.From.ToFilecoinAddress() + if err != nil { + return nil, fmt.Errorf("failed to translate sender address (%s): %w", tx.From.String(), err) + } + if p := from.Protocol(); p != address.Delegated { + return nil, fmt.Errorf("expected a class 4 address, got: %d: %w", p, err) + } + } + + var params []byte + if len(tx.Data) > 0 { + initcode := abi.CborBytes(tx.Data) + params2, err := actors.SerializeParams(&initcode) + if err != nil { + return nil, fmt.Errorf("failed to serialize params: %w", err) + } + params = params2 + } + + var to address.Address + var method abi.MethodNum + if tx.To == nil { + // this is a contract creation + to = builtintypes.EthereumAddressManagerActorAddr + method = builtintypes.MethodsEAM.CreateExternal + } else { + addr, err := tx.To.ToFilecoinAddress() + if err != nil { + return nil, xerrors.Errorf("cannot get Filecoin address: %w", err) + } + to = addr + method = builtintypes.MethodsEVM.InvokeContract + } + + return &types.Message{ + From: from, + To: to, + Value: big.Int(tx.Value), + Method: method, + Params: params, + GasLimit: build.BlockGasLimit, + GasFeeCap: big.Zero(), + GasPremium: big.Zero(), + }, nil +} + +func (a *EthModule) applyMessage(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (res *api.InvocResult, err error) { + ts, err := a.Chain.GetTipSetFromKey(ctx, tsk) + if err != nil { + return nil, xerrors.Errorf("cannot get tipset: %w", err) + } + + // Try calling until we find a height with no migration. + for { + res, err = a.StateManager.CallWithGas(ctx, msg, []types.ChainMsg{}, ts) + if err != stmgr.ErrExpensiveFork { + break + } + ts, err = a.Chain.GetTipSetFromKey(ctx, ts.Parents()) + if err != nil { + return nil, xerrors.Errorf("getting parent tipset: %w", err) + } + } + if err != nil { + return nil, xerrors.Errorf("CallWithGas failed: %w", err) + } + if res.MsgRct.ExitCode.IsError() { + reason := parseEthRevert(res.MsgRct.Return) + return nil, xerrors.Errorf("message execution failed: exit %s, revert reason: %s, vm error: %s", res.MsgRct.ExitCode, reason, res.Error) + } + return res, nil +} + +func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) { + msg, err := a.ethCallToFilecoinMessage(ctx, tx) + if err != nil { + return ethtypes.EthUint64(0), err + } + + // Set the gas limit to the zero sentinel value, which makes + // gas estimation actually run. + msg.GasLimit = 0 + + ts := a.Chain.GetHeaviestTipSet() + gassedMsg, err := a.GasAPI.GasEstimateMessageGas(ctx, msg, nil, ts.Key()) + if err != nil { + // On failure, GasEstimateMessageGas doesn't actually return the invocation result, + // it just returns an error. That means we can't get the revert reason. + // + // So we re-execute the message with EthCall (well, applyMessage which contains the + // guts of EthCall). This will give us an ethereum specific error with revert + // information. + msg.GasLimit = build.BlockGasLimit + if _, err2 := a.applyMessage(ctx, msg, ts.Key()); err2 != nil { + err = err2 + } + return ethtypes.EthUint64(0), xerrors.Errorf("failed to estimate gas: %w", err) + } + + expectedGas, err := ethGasSearch(ctx, a.Chain, a.Stmgr, a.Mpool, gassedMsg, ts) + if err != nil { + return 0, xerrors.Errorf("gas search failed: %w", err) + } + + return ethtypes.EthUint64(expectedGas), nil +} + +// gasSearch does an exponential search to find a gas value to execute the +// message with. It first finds a high gas limit that allows the message to execute +// by doubling the previous gas limit until it succeeds then does a binary +// search till it gets within a range of 1% +func gasSearch( + ctx context.Context, + smgr *stmgr.StateManager, + msgIn *types.Message, + priorMsgs []types.ChainMsg, + ts *types.TipSet, +) (int64, error) { + msg := *msgIn + + high := msg.GasLimit + low := msg.GasLimit + + canSucceed := func(limit int64) (bool, error) { + msg.GasLimit = limit + + res, err := smgr.CallWithGas(ctx, &msg, priorMsgs, ts) + if err != nil { + return false, xerrors.Errorf("CallWithGas failed: %w", err) + } + + if res.MsgRct.ExitCode.IsSuccess() { + return true, nil + } + + return false, nil + } + + for { + ok, err := canSucceed(high) + if err != nil { + return -1, xerrors.Errorf("searching for high gas limit failed: %w", err) + } + if ok { + break + } + + low = high + high = high * 2 + + if high > build.BlockGasLimit { + high = build.BlockGasLimit + break + } + } + + checkThreshold := high / 100 + for (high - low) > checkThreshold { + median := (low + high) / 2 + ok, err := canSucceed(median) + if err != nil { + return -1, xerrors.Errorf("searching for optimal gas limit failed: %w", err) + } + + if ok { + high = median + } else { + low = median + } + + checkThreshold = median / 100 + } + + return high, nil +} + +func traceContainsExitCode(et types.ExecutionTrace, ex exitcode.ExitCode) bool { + if et.MsgRct.ExitCode == ex { + return true + } + + for _, et := range et.Subcalls { + if traceContainsExitCode(et, ex) { + return true + } + } + + return false +} + +// ethGasSearch executes a message for gas estimation using the previously estimated gas. +// If the message fails due to an out of gas error then a gas search is performed. +// See gasSearch. +func ethGasSearch( + ctx context.Context, + cstore *store.ChainStore, + smgr *stmgr.StateManager, + mpool *messagepool.MessagePool, + msgIn *types.Message, + ts *types.TipSet, +) (int64, error) { + msg := *msgIn + currTs := ts + + res, priorMsgs, ts, err := gasEstimateCallWithGas(ctx, cstore, smgr, mpool, &msg, currTs) + if err != nil { + return -1, xerrors.Errorf("gas estimation failed: %w", err) + } + + if res.MsgRct.ExitCode.IsSuccess() { + return msg.GasLimit, nil + } + + if traceContainsExitCode(res.ExecutionTrace, exitcode.SysErrOutOfGas) { + ret, err := gasSearch(ctx, smgr, &msg, priorMsgs, ts) + if err != nil { + return -1, xerrors.Errorf("gas estimation search failed: %w", err) + } + + ret = int64(float64(ret) * mpool.GetConfig().GasLimitOverestimation) + return ret, nil + } + + return -1, xerrors.Errorf("message execution failed: exit %s, reason: %s", res.MsgRct.ExitCode, res.Error) +} + +func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) { + msg, err := a.ethCallToFilecoinMessage(ctx, tx) + if err != nil { + return nil, xerrors.Errorf("failed to convert ethcall to filecoin message: %w", err) + } + + ts, err := a.parseBlkParam(ctx, blkParam) + if err != nil { + return nil, xerrors.Errorf("cannot parse block param: %s", blkParam) + } + + invokeResult, err := a.applyMessage(ctx, msg, ts.Key()) + if err != nil { + return nil, err + } + + if msg.To == builtintypes.EthereumAddressManagerActorAddr { + // As far as I can tell, the Eth API always returns empty on contract deployment + return ethtypes.EthBytes{}, nil + } else if len(invokeResult.MsgRct.Return) > 0 { + return cbg.ReadByteArray(bytes.NewReader(invokeResult.MsgRct.Return), uint64(len(invokeResult.MsgRct.Return))) + } + + return ethtypes.EthBytes{}, nil +} + +func (e *EthEvent) EthGetLogs(ctx context.Context, filterSpec *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) { + if e.EventFilterManager == nil { + return nil, api.ErrNotSupported + } + + // Create a temporary filter + f, err := e.installEthFilterSpec(ctx, filterSpec) + if err != nil { + return nil, err + } + ces := f.TakeCollectedEvents(ctx) + + _ = e.uninstallFilter(ctx, f) + + return ethFilterResultFromEvents(ces, e.SubManager.StateAPI) +} + +func (e *EthEvent) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if e.FilterStore == nil { + return nil, api.ErrNotSupported + } + + f, err := e.FilterStore.Get(ctx, types.FilterID(id)) + if err != nil { + return nil, err + } + + switch fc := f.(type) { + case filterEventCollector: + return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI) + case filterTipSetCollector: + return ethFilterResultFromTipSets(fc.TakeCollectedTipSets(ctx)) + case filterMessageCollector: + return ethFilterResultFromMessages(fc.TakeCollectedMessages(ctx), e.SubManager.StateAPI) + } + + return nil, xerrors.Errorf("unknown filter type") +} + +func (e *EthEvent) EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if e.FilterStore == nil { + return nil, api.ErrNotSupported + } + + f, err := e.FilterStore.Get(ctx, types.FilterID(id)) + if err != nil { + return nil, err + } + + switch fc := f.(type) { + case filterEventCollector: + return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI) + } + + return nil, xerrors.Errorf("wrong filter type") +} + +func (e *EthEvent) installEthFilterSpec(ctx context.Context, filterSpec *ethtypes.EthFilterSpec) (*filter.EventFilter, error) { + var ( + minHeight abi.ChainEpoch + maxHeight abi.ChainEpoch + tipsetCid cid.Cid + addresses []address.Address + keys = map[string][][]byte{} + ) + + if filterSpec.BlockHash != nil { + if filterSpec.FromBlock != nil || filterSpec.ToBlock != nil { + return nil, xerrors.Errorf("must not specify block hash and from/to block") + } + + // TODO: derive a tipset hash from eth hash - might need to push this down into the EventFilterManager + } else { + if filterSpec.FromBlock == nil || *filterSpec.FromBlock == "latest" { + ts := e.Chain.GetHeaviestTipSet() + minHeight = ts.Height() + } else if *filterSpec.FromBlock == "earliest" { + minHeight = 0 + } else if *filterSpec.FromBlock == "pending" { + return nil, api.ErrNotSupported + } else { + epoch, err := ethtypes.EthUint64FromHex(*filterSpec.FromBlock) + if err != nil { + return nil, xerrors.Errorf("invalid epoch") + } + minHeight = abi.ChainEpoch(epoch) + } + + if filterSpec.ToBlock == nil || *filterSpec.ToBlock == "latest" { + // here latest means the latest at the time + maxHeight = -1 + } else if *filterSpec.ToBlock == "earliest" { + maxHeight = 0 + } else if *filterSpec.ToBlock == "pending" { + return nil, api.ErrNotSupported + } else { + epoch, err := ethtypes.EthUint64FromHex(*filterSpec.ToBlock) + if err != nil { + return nil, xerrors.Errorf("invalid epoch") + } + maxHeight = abi.ChainEpoch(epoch) + } + + // Validate height ranges are within limits set by node operator + if minHeight == -1 && maxHeight > 0 { + // Here the client is looking for events between the head and some future height + ts := e.Chain.GetHeaviestTipSet() + if maxHeight-ts.Height() > e.MaxFilterHeightRange { + return nil, xerrors.Errorf("invalid epoch range: to block is too far in the future (maximum: %d)", e.MaxFilterHeightRange) + } + } else if minHeight >= 0 && maxHeight == -1 { + // Here the client is looking for events between some time in the past and the current head + ts := e.Chain.GetHeaviestTipSet() + if ts.Height()-minHeight > e.MaxFilterHeightRange { + return nil, xerrors.Errorf("invalid epoch range: from block is too far in the past (maximum: %d)", e.MaxFilterHeightRange) + } + + } else if minHeight >= 0 && maxHeight >= 0 { + if minHeight > maxHeight { + return nil, xerrors.Errorf("invalid epoch range: to block (%d) must be after from block (%d)", minHeight, maxHeight) + } else if maxHeight-minHeight > e.MaxFilterHeightRange { + return nil, xerrors.Errorf("invalid epoch range: range between to and from blocks is too large (maximum: %d)", e.MaxFilterHeightRange) + } + } + + } + + // Convert all addresses to filecoin f4 addresses + for _, ea := range filterSpec.Address { + a, err := ea.ToFilecoinAddress() + if err != nil { + return nil, xerrors.Errorf("invalid address %x", ea) + } + addresses = append(addresses, a) + } + + keys, err := parseEthTopics(filterSpec.Topics) + if err != nil { + return nil, err + } + + return e.EventFilterManager.Install(ctx, minHeight, maxHeight, tipsetCid, addresses, keys) +} + +func (e *EthEvent) EthNewFilter(ctx context.Context, filterSpec *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) { + if e.FilterStore == nil || e.EventFilterManager == nil { + return ethtypes.EthFilterID{}, api.ErrNotSupported + } + + f, err := e.installEthFilterSpec(ctx, filterSpec) + if err != nil { + return ethtypes.EthFilterID{}, err + } + + if err := e.FilterStore.Add(ctx, f); err != nil { + // Could not record in store, attempt to delete filter to clean up + err2 := e.TipSetFilterManager.Remove(ctx, f.ID()) + if err2 != nil { + return ethtypes.EthFilterID{}, xerrors.Errorf("encountered error %v while removing new filter due to %v", err2, err) + } + + return ethtypes.EthFilterID{}, err + } + return ethtypes.EthFilterID(f.ID()), nil +} + +func (e *EthEvent) EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) { + if e.FilterStore == nil || e.TipSetFilterManager == nil { + return ethtypes.EthFilterID{}, api.ErrNotSupported + } + + f, err := e.TipSetFilterManager.Install(ctx) + if err != nil { + return ethtypes.EthFilterID{}, err + } + + if err := e.FilterStore.Add(ctx, f); err != nil { + // Could not record in store, attempt to delete filter to clean up + err2 := e.TipSetFilterManager.Remove(ctx, f.ID()) + if err2 != nil { + return ethtypes.EthFilterID{}, xerrors.Errorf("encountered error %v while removing new filter due to %v", err2, err) + } + + return ethtypes.EthFilterID{}, err + } + + return ethtypes.EthFilterID(f.ID()), nil +} + +func (e *EthEvent) EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) { + if e.FilterStore == nil || e.MemPoolFilterManager == nil { + return ethtypes.EthFilterID{}, api.ErrNotSupported + } + + f, err := e.MemPoolFilterManager.Install(ctx) + if err != nil { + return ethtypes.EthFilterID{}, err + } + + if err := e.FilterStore.Add(ctx, f); err != nil { + // Could not record in store, attempt to delete filter to clean up + err2 := e.MemPoolFilterManager.Remove(ctx, f.ID()) + if err2 != nil { + return ethtypes.EthFilterID{}, xerrors.Errorf("encountered error %v while removing new filter due to %v", err2, err) + } + + return ethtypes.EthFilterID{}, err + } + + return ethtypes.EthFilterID(f.ID()), nil +} + +func (e *EthEvent) EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) { + if e.FilterStore == nil { + return false, api.ErrNotSupported + } + + f, err := e.FilterStore.Get(ctx, types.FilterID(id)) + if err != nil { + if errors.Is(err, filter.ErrFilterNotFound) { + return false, nil + } + return false, err + } + + if err := e.uninstallFilter(ctx, f); err != nil { + return false, err + } + + return true, nil +} + +func (e *EthEvent) uninstallFilter(ctx context.Context, f filter.Filter) error { + switch f.(type) { + case *filter.EventFilter: + err := e.EventFilterManager.Remove(ctx, f.ID()) + if err != nil && !errors.Is(err, filter.ErrFilterNotFound) { + return err + } + case *filter.TipSetFilter: + err := e.TipSetFilterManager.Remove(ctx, f.ID()) + if err != nil && !errors.Is(err, filter.ErrFilterNotFound) { + return err + } + case *filter.MemPoolFilter: + err := e.MemPoolFilterManager.Remove(ctx, f.ID()) + if err != nil && !errors.Is(err, filter.ErrFilterNotFound) { + return err + } + default: + return xerrors.Errorf("unknown filter type") + } + + return e.FilterStore.Remove(ctx, f.ID()) +} + +const ( + EthSubscribeEventTypeHeads = "newHeads" + EthSubscribeEventTypeLogs = "logs" + EthSubscribeEventTypePendingTransactions = "newPendingTransactions" +) + +func (e *EthEvent) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) { + params, err := jsonrpc.DecodeParams[ethtypes.EthSubscribeParams](p) + if err != nil { + return ethtypes.EthSubscriptionID{}, xerrors.Errorf("decoding params: %w", err) + } + + if e.SubManager == nil { + return ethtypes.EthSubscriptionID{}, api.ErrNotSupported + } + + ethCb, ok := jsonrpc.ExtractReverseClient[api.EthSubscriberMethods](ctx) + if !ok { + return ethtypes.EthSubscriptionID{}, xerrors.Errorf("connection doesn't support callbacks") + } + + sub, err := e.SubManager.StartSubscription(e.SubscribtionCtx, ethCb.EthSubscription) + if err != nil { + return ethtypes.EthSubscriptionID{}, err + } + + switch params.EventType { + case EthSubscribeEventTypeHeads: + f, err := e.TipSetFilterManager.Install(ctx) + if err != nil { + // clean up any previous filters added and stop the sub + _, _ = e.EthUnsubscribe(ctx, sub.id) + return ethtypes.EthSubscriptionID{}, err + } + sub.addFilter(ctx, f) + + case EthSubscribeEventTypeLogs: + keys := map[string][][]byte{} + if params.Params != nil { + var err error + keys, err = parseEthTopics(params.Params.Topics) + if err != nil { + // clean up any previous filters added and stop the sub + _, _ = e.EthUnsubscribe(ctx, sub.id) + return ethtypes.EthSubscriptionID{}, err + } + } + + var addresses []address.Address + if params.Params != nil { + for _, ea := range params.Params.Address { + a, err := ea.ToFilecoinAddress() + if err != nil { + return ethtypes.EthSubscriptionID{}, xerrors.Errorf("invalid address %x", ea) + } + addresses = append(addresses, a) + } + } + + f, err := e.EventFilterManager.Install(ctx, -1, -1, cid.Undef, addresses, keys) + if err != nil { + // clean up any previous filters added and stop the sub + _, _ = e.EthUnsubscribe(ctx, sub.id) + return ethtypes.EthSubscriptionID{}, err + } + sub.addFilter(ctx, f) + case EthSubscribeEventTypePendingTransactions: + f, err := e.MemPoolFilterManager.Install(ctx) + if err != nil { + // clean up any previous filters added and stop the sub + _, _ = e.EthUnsubscribe(ctx, sub.id) + return ethtypes.EthSubscriptionID{}, err + } + + sub.addFilter(ctx, f) + default: + return ethtypes.EthSubscriptionID{}, xerrors.Errorf("unsupported event type: %s", params.EventType) + } + + return sub.id, nil +} + +func (e *EthEvent) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) { + if e.SubManager == nil { + return false, api.ErrNotSupported + } + + filters, err := e.SubManager.StopSubscription(ctx, id) + if err != nil { + return false, nil + } + + for _, f := range filters { + if err := e.uninstallFilter(ctx, f); err != nil { + // this will leave the filter a zombie, collecting events up to the maximum allowed + log.Warnf("failed to remove filter when unsubscribing: %v", err) + } + } + + return true, nil +} + +// GC runs a garbage collection loop, deleting filters that have not been used within the ttl window +func (e *EthEvent) GC(ctx context.Context, ttl time.Duration) { + if e.FilterStore == nil { + return + } + + tt := time.NewTicker(time.Minute * 30) + defer tt.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-tt.C: + fs := e.FilterStore.NotTakenSince(time.Now().Add(-ttl)) + for _, f := range fs { + if err := e.uninstallFilter(ctx, f); err != nil { + log.Warnf("Failed to remove actor event filter during garbage collection: %v", err) + } + } + } + } +} + +type filterEventCollector interface { + TakeCollectedEvents(context.Context) []*filter.CollectedEvent +} + +type filterMessageCollector interface { + TakeCollectedMessages(context.Context) []*types.SignedMessage +} + +type filterTipSetCollector interface { + TakeCollectedTipSets(context.Context) []types.TipSetKey +} + +func ethLogFromEvent(entries []types.EventEntry) (data []byte, topics []ethtypes.EthHash, ok bool) { + var ( + topicsFound [4]bool + topicsFoundCount int + dataFound bool + ) + for _, entry := range entries { + // Drop events with non-raw topics to avoid mistakes. + if entry.Codec != cid.Raw { + log.Warnw("did not expect an event entry with a non-raw codec", "codec", entry.Codec, "key", entry.Key) + return nil, nil, false + } + // Check if the key is t1..t4 + if len(entry.Key) == 2 && "t1" <= entry.Key && entry.Key <= "t4" { + // '1' - '1' == 0, etc. + idx := int(entry.Key[1] - '1') + + // Drop events with mis-sized topics. + if len(entry.Value) != 32 { + log.Warnw("got an EVM event topic with an invalid size", "key", entry.Key, "size", len(entry.Value)) + return nil, nil, false + } + + // Drop events with duplicate topics. + if topicsFound[idx] { + log.Warnw("got a duplicate EVM event topic", "key", entry.Key) + return nil, nil, false + } + topicsFound[idx] = true + topicsFoundCount++ + + // Extend the topics array + for len(topics) <= idx { + topics = append(topics, ethtypes.EthHash{}) + } + copy(topics[idx][:], entry.Value) + } else if entry.Key == "d" { + // Drop events with duplicate data fields. + if dataFound { + log.Warnw("got duplicate EVM event data") + return nil, nil, false + } + + dataFound = true + data = entry.Value + } else { + // Skip entries we don't understand (makes it easier to extend things). + // But we warn for now because we don't expect them. + log.Warnw("unexpected event entry", "key", entry.Key) + } + + } + + // Drop events with skipped topics. + if len(topics) != topicsFoundCount { + log.Warnw("EVM event topic length mismatch", "expected", len(topics), "actual", topicsFoundCount) + return nil, nil, false + } + return data, topics, true +} + +func ethFilterResultFromEvents(evs []*filter.CollectedEvent, sa StateAPI) (*ethtypes.EthFilterResult, error) { + res := ðtypes.EthFilterResult{} + for _, ev := range evs { + log := ethtypes.EthLog{ + Removed: ev.Reverted, + LogIndex: ethtypes.EthUint64(ev.EventIdx), + TransactionIndex: ethtypes.EthUint64(ev.MsgIdx), + BlockNumber: ethtypes.EthUint64(ev.Height), + } + var ( + err error + ok bool + ) + + log.Data, log.Topics, ok = ethLogFromEvent(ev.Entries) + if !ok { + continue + } + + log.Address, err = ethtypes.EthAddressFromFilecoinAddress(ev.EmitterAddr) + if err != nil { + return nil, err + } + + log.TransactionHash, err = EthTxHashFromMessageCid(context.TODO(), ev.MsgCid, sa) + if err != nil { + return nil, err + } + c, err := ev.TipSetKey.Cid() + if err != nil { + return nil, err + } + log.BlockHash, err = ethtypes.EthHashFromCid(c) + if err != nil { + return nil, err + } + + res.Results = append(res.Results, log) + } + + return res, nil +} + +func ethFilterResultFromTipSets(tsks []types.TipSetKey) (*ethtypes.EthFilterResult, error) { + res := ðtypes.EthFilterResult{} + + for _, tsk := range tsks { + c, err := tsk.Cid() + if err != nil { + return nil, err + } + hash, err := ethtypes.EthHashFromCid(c) + if err != nil { + return nil, err + } + + res.Results = append(res.Results, hash) + } + + return res, nil +} + +func ethFilterResultFromMessages(cs []*types.SignedMessage, sa StateAPI) (*ethtypes.EthFilterResult, error) { + res := ðtypes.EthFilterResult{} + + for _, c := range cs { + hash, err := EthTxHashFromSignedMessage(context.TODO(), c, sa) + if err != nil { + return nil, err + } + + res.Results = append(res.Results, hash) + } + + return res, nil +} + +type EthSubscriptionManager struct { + Chain *store.ChainStore + StateAPI StateAPI + ChainAPI ChainAPI + mu sync.Mutex + subs map[ethtypes.EthSubscriptionID]*ethSubscription +} + +func (e *EthSubscriptionManager) StartSubscription(ctx context.Context, out ethSubscriptionCallback) (*ethSubscription, error) { // nolint + rawid, err := uuid.NewRandom() + if err != nil { + return nil, xerrors.Errorf("new uuid: %w", err) + } + id := ethtypes.EthSubscriptionID{} + copy(id[:], rawid[:]) // uuid is 16 bytes + + ctx, quit := context.WithCancel(ctx) + + sub := ðSubscription{ + Chain: e.Chain, + StateAPI: e.StateAPI, + ChainAPI: e.ChainAPI, + id: id, + in: make(chan interface{}, 200), + out: out, + quit: quit, + } + + e.mu.Lock() + if e.subs == nil { + e.subs = make(map[ethtypes.EthSubscriptionID]*ethSubscription) + } + e.subs[sub.id] = sub + e.mu.Unlock() + + go sub.start(ctx) + + return sub, nil +} + +func (e *EthSubscriptionManager) StopSubscription(ctx context.Context, id ethtypes.EthSubscriptionID) ([]filter.Filter, error) { + e.mu.Lock() + defer e.mu.Unlock() + + sub, ok := e.subs[id] + if !ok { + return nil, xerrors.Errorf("subscription not found") + } + sub.stop() + delete(e.subs, id) + + return sub.filters, nil +} + +type ethSubscriptionCallback func(context.Context, jsonrpc.RawParams) error + +type ethSubscription struct { + Chain *store.ChainStore + StateAPI StateAPI + ChainAPI ChainAPI + id ethtypes.EthSubscriptionID + in chan interface{} + out ethSubscriptionCallback + + mu sync.Mutex + filters []filter.Filter + quit func() +} + +func (e *ethSubscription) addFilter(ctx context.Context, f filter.Filter) { + e.mu.Lock() + defer e.mu.Unlock() + + f.SetSubChannel(e.in) + e.filters = append(e.filters, f) +} + +func (e *ethSubscription) send(ctx context.Context, v interface{}) { + resp := ethtypes.EthSubscriptionResponse{ + SubscriptionID: e.id, + Result: v, + } + + outParam, err := json.Marshal(resp) + if err != nil { + log.Warnw("marshaling subscription response", "sub", e.id, "error", err) + return + } + + if err := e.out(ctx, outParam); err != nil { + log.Warnw("sending subscription response", "sub", e.id, "error", err) + return + } +} + +func (e *ethSubscription) start(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + case v := <-e.in: + switch vt := v.(type) { + case *filter.CollectedEvent: + evs, err := ethFilterResultFromEvents([]*filter.CollectedEvent{vt}, e.StateAPI) + if err != nil { + continue + } + + for _, r := range evs.Results { + e.send(ctx, r) + } + case *types.TipSet: + ev, err := newEthBlockFromFilecoinTipSet(ctx, vt, true, e.Chain, e.StateAPI) + if err != nil { + break + } + + e.send(ctx, ev) + case *types.SignedMessage: // mpool txid + evs, err := ethFilterResultFromMessages([]*types.SignedMessage{vt}, e.StateAPI) + if err != nil { + continue + } + + for _, r := range evs.Results { + e.send(ctx, r) + } + default: + log.Warnf("unexpected subscription value type: %T", vt) + } + } + } +} + +func (e *ethSubscription) stop() { + e.mu.Lock() + defer e.mu.Unlock() + + if e.quit != nil { + e.quit() + e.quit = nil + } +} + +func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTxInfo bool, cs *store.ChainStore, sa StateAPI) (ethtypes.EthBlock, error) { + parent, err := cs.LoadTipSet(ctx, ts.Parents()) + if err != nil { + return ethtypes.EthBlock{}, err + } + parentKeyCid, err := parent.Key().Cid() + if err != nil { + return ethtypes.EthBlock{}, err + } + parentBlkHash, err := ethtypes.EthHashFromCid(parentKeyCid) + if err != nil { + return ethtypes.EthBlock{}, err + } + + blkCid, err := ts.Key().Cid() + if err != nil { + return ethtypes.EthBlock{}, err + } + blkHash, err := ethtypes.EthHashFromCid(blkCid) + if err != nil { + return ethtypes.EthBlock{}, err + } + + msgs, err := cs.MessagesForTipset(ctx, ts) + if err != nil { + return ethtypes.EthBlock{}, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err) + } + + block := ethtypes.NewEthBlock(len(msgs) > 0) + + // this seems to be a very expensive way to get gasUsed of the block. may need to find an efficient way to do it + gasUsed := int64(0) + for txIdx, msg := range msgs { + msgLookup, err := sa.StateSearchMsg(ctx, types.EmptyTSK, msg.Cid(), api.LookbackNoLimit, false) + if err != nil || msgLookup == nil { + return ethtypes.EthBlock{}, nil + } + gasUsed += msgLookup.Receipt.GasUsed + + tx, err := newEthTxFromMessageLookup(ctx, msgLookup, txIdx, cs, sa) + if err != nil { + return ethtypes.EthBlock{}, nil + } + + if fullTxInfo { + block.Transactions = append(block.Transactions, tx) + } else { + block.Transactions = append(block.Transactions, tx.Hash.String()) + } + } + + block.Hash = blkHash + block.Number = ethtypes.EthUint64(ts.Height()) + block.ParentHash = parentBlkHash + block.Timestamp = ethtypes.EthUint64(ts.Blocks()[0].Timestamp) + block.BaseFeePerGas = ethtypes.EthBigInt{Int: ts.Blocks()[0].ParentBaseFee.Int} + block.GasUsed = ethtypes.EthUint64(gasUsed) + return block, nil +} + +// lookupEthAddress makes its best effort at finding the Ethereum address for a +// Filecoin address. It does the following: +// +// 1. If the supplied address is an f410 address, we return its payload as the EthAddress. +// 2. Otherwise (f0, f1, f2, f3), we look up the actor on the state tree. If it has a delegated address, we return it if it's f410 address. +// 3. Otherwise, we fall back to returning a masked ID Ethereum address. If the supplied address is an f0 address, we +// use that ID to form the masked ID address. +// 4. Otherwise, we fetch the actor's ID from the state tree and form the masked ID with it. +func lookupEthAddress(ctx context.Context, addr address.Address, sa StateAPI) (ethtypes.EthAddress, error) { + // BLOCK A: We are trying to get an actual Ethereum address from an f410 address. + // Attempt to convert directly, if it's an f4 address. + ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(addr) + if err == nil && !ethAddr.IsMaskedID() { + return ethAddr, nil + } + + // Lookup on the target actor and try to get an f410 address. + if actor, err := sa.StateGetActor(ctx, addr, types.EmptyTSK); err != nil { + return ethtypes.EthAddress{}, err + } else if actor.Address != nil { + if ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(*actor.Address); err == nil && !ethAddr.IsMaskedID() { + return ethAddr, nil + } + } + + // BLOCK B: We gave up on getting an actual Ethereum address and are falling back to a Masked ID address. + // Check if we already have an ID addr, and use it if possible. + if err == nil && ethAddr.IsMaskedID() { + return ethAddr, nil + } + + // Otherwise, resolve the ID addr. + idAddr, err := sa.StateLookupID(ctx, addr, types.EmptyTSK) + if err != nil { + return ethtypes.EthAddress{}, err + } + return ethtypes.EthAddressFromFilecoinAddress(idAddr) +} + +func EthTxHashFromMessageCid(ctx context.Context, c cid.Cid, sa StateAPI) (ethtypes.EthHash, error) { + smsg, err := sa.Chain.GetSignedMessage(ctx, c) + if err == nil { + // This is an Eth Tx, Secp message, Or BLS message in the mpool + return EthTxHashFromSignedMessage(ctx, smsg, sa) + } + + _, err = sa.Chain.GetMessage(ctx, c) + if err == nil { + // This is a BLS message + return ethtypes.EthHashFromCid(c) + } + + return ethtypes.EmptyEthHash, nil +} + +func EthTxHashFromSignedMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthHash, error) { + if smsg.Signature.Type == crypto.SigTypeDelegated { + ethTx, err := newEthTxFromSignedMessage(ctx, smsg, sa) + if err != nil { + return ethtypes.EmptyEthHash, err + } + return ethTx.Hash, nil + } else if smsg.Signature.Type == crypto.SigTypeSecp256k1 { + return ethtypes.EthHashFromCid(smsg.Cid()) + } else { // BLS message + return ethtypes.EthHashFromCid(smsg.Message.Cid()) + } +} + +func newEthTxFromSignedMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthTx, error) { + var tx ethtypes.EthTx + var err error + + // This is an eth tx + if smsg.Signature.Type == crypto.SigTypeDelegated { + tx, err = ethtypes.EthTxFromSignedEthMessage(smsg) + if err != nil { + return ethtypes.EthTx{}, xerrors.Errorf("failed to convert from signed message: %w", err) + } + + tx.Hash, err = tx.TxHash() + if err != nil { + return ethtypes.EthTx{}, xerrors.Errorf("failed to calculate hash for ethTx: %w", err) + } + + fromAddr, err := lookupEthAddress(ctx, smsg.Message.From, sa) + if err != nil { + return ethtypes.EthTx{}, xerrors.Errorf("failed to resolve Ethereum address: %w", err) + } + + tx.From = fromAddr + } else if smsg.Signature.Type == crypto.SigTypeSecp256k1 { // Secp Filecoin Message + tx = ethTxFromNativeMessage(ctx, smsg.VMMessage(), sa) + tx.Hash, err = ethtypes.EthHashFromCid(smsg.Cid()) + if err != nil { + return tx, err + } + } else { // BLS Filecoin message + tx = ethTxFromNativeMessage(ctx, smsg.VMMessage(), sa) + tx.Hash, err = ethtypes.EthHashFromCid(smsg.Message.Cid()) + if err != nil { + return tx, err + } + } + + return tx, nil +} + +// ethTxFromNativeMessage does NOT populate: +// - BlockHash +// - BlockNumber +// - TransactionIndex +// - Hash +func ethTxFromNativeMessage(ctx context.Context, msg *types.Message, sa StateAPI) ethtypes.EthTx { + // We don't care if we error here, conversion is best effort for non-eth transactions + from, _ := lookupEthAddress(ctx, msg.From, sa) + to, _ := lookupEthAddress(ctx, msg.To, sa) + return ethtypes.EthTx{ + To: &to, + From: from, + Nonce: ethtypes.EthUint64(msg.Nonce), + ChainID: ethtypes.EthUint64(build.Eip155ChainId), + Value: ethtypes.EthBigInt(msg.Value), + Type: ethtypes.Eip1559TxType, + Gas: ethtypes.EthUint64(msg.GasLimit), + MaxFeePerGas: ethtypes.EthBigInt(msg.GasFeeCap), + MaxPriorityFeePerGas: ethtypes.EthBigInt(msg.GasPremium), + AccessList: []ethtypes.EthHash{}, + } +} + +// newEthTxFromMessageLookup creates an ethereum transaction from filecoin message lookup. If a negative txIdx is passed +// into the function, it looks up the transaction index of the message in the tipset, otherwise it uses the txIdx passed into the +// function +func newEthTxFromMessageLookup(ctx context.Context, msgLookup *api.MsgLookup, txIdx int, cs *store.ChainStore, sa StateAPI) (ethtypes.EthTx, error) { + ts, err := cs.LoadTipSet(ctx, msgLookup.TipSet) + if err != nil { + return ethtypes.EthTx{}, err + } + + // This tx is located in the parent tipset + parentTs, err := cs.LoadTipSet(ctx, ts.Parents()) + if err != nil { + return ethtypes.EthTx{}, err + } + + parentTsCid, err := parentTs.Key().Cid() + if err != nil { + return ethtypes.EthTx{}, err + } + + // lookup the transactionIndex + if txIdx < 0 { + msgs, err := cs.MessagesForTipset(ctx, parentTs) + if err != nil { + return ethtypes.EthTx{}, err + } + for i, msg := range msgs { + if msg.Cid() == msgLookup.Message { + txIdx = i + break + } + } + if txIdx < 0 { + return ethtypes.EthTx{}, fmt.Errorf("cannot find the msg in the tipset") + } + } + + blkHash, err := ethtypes.EthHashFromCid(parentTsCid) + if err != nil { + return ethtypes.EthTx{}, err + } + + smsg, err := cs.GetSignedMessage(ctx, msgLookup.Message) + if err != nil { + // We couldn't find the signed message, it might be a BLS message, so search for a regular message. + msg, err := cs.GetMessage(ctx, msgLookup.Message) + if err != nil { + return ethtypes.EthTx{}, err + } + smsg = &types.SignedMessage{ + Message: *msg, + Signature: crypto.Signature{ + Type: crypto.SigTypeBLS, + Data: nil, + }, + } + } + + tx, err := newEthTxFromSignedMessage(ctx, smsg, sa) + if err != nil { + return ethtypes.EthTx{}, err + } + + var ( + bn = ethtypes.EthUint64(parentTs.Height()) + ti = ethtypes.EthUint64(txIdx) + ) + + tx.ChainID = ethtypes.EthUint64(build.Eip155ChainId) + tx.BlockHash = &blkHash + tx.BlockNumber = &bn + tx.TransactionIndex = &ti + return tx, nil +} + +func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLookup, replay *api.InvocResult, events []types.Event, sa StateAPI) (api.EthTxReceipt, error) { + var ( + transactionIndex ethtypes.EthUint64 + blockHash ethtypes.EthHash + blockNumber ethtypes.EthUint64 + ) + + if tx.TransactionIndex != nil { + transactionIndex = *tx.TransactionIndex + } + if tx.BlockHash != nil { + blockHash = *tx.BlockHash + } + if tx.BlockNumber != nil { + blockNumber = *tx.BlockNumber + } + + receipt := api.EthTxReceipt{ + TransactionHash: tx.Hash, + From: tx.From, + To: tx.To, + TransactionIndex: transactionIndex, + BlockHash: blockHash, + BlockNumber: blockNumber, + Type: ethtypes.EthUint64(2), + Logs: []ethtypes.EthLog{}, // empty log array is compulsory when no logs, or libraries like ethers.js break + LogsBloom: ethtypes.EmptyEthBloom[:], + } + + if lookup.Receipt.ExitCode.IsSuccess() { + receipt.Status = 1 + } + if lookup.Receipt.ExitCode.IsError() { + receipt.Status = 0 + } + + receipt.GasUsed = ethtypes.EthUint64(lookup.Receipt.GasUsed) + + // TODO: handle CumulativeGasUsed + receipt.CumulativeGasUsed = ethtypes.EmptyEthInt + + effectiveGasPrice := big.Div(replay.GasCost.TotalCost, big.NewInt(lookup.Receipt.GasUsed)) + receipt.EffectiveGasPrice = ethtypes.EthBigInt(effectiveGasPrice) + + if receipt.To == nil && lookup.Receipt.ExitCode.IsSuccess() { + // Create and Create2 return the same things. + var ret eam.CreateExternalReturn + if err := ret.UnmarshalCBOR(bytes.NewReader(lookup.Receipt.Return)); err != nil { + return api.EthTxReceipt{}, xerrors.Errorf("failed to parse contract creation result: %w", err) + } + addr := ethtypes.EthAddress(ret.EthAddress) + receipt.ContractAddress = &addr + } + + if len(events) > 0 { + receipt.Logs = make([]ethtypes.EthLog, 0, len(events)) + for i, evt := range events { + l := ethtypes.EthLog{ + Removed: false, + LogIndex: ethtypes.EthUint64(i), + TransactionHash: tx.Hash, + TransactionIndex: transactionIndex, + BlockHash: blockHash, + BlockNumber: blockNumber, + } + + data, topics, ok := ethLogFromEvent(evt.Entries) + if !ok { + // not an eth event. + continue + } + for _, topic := range topics { + ethtypes.EthBloomSet(receipt.LogsBloom, topic[:]) + } + l.Data = data + l.Topics = topics + + addr, err := address.NewIDAddress(uint64(evt.Emitter)) + if err != nil { + return api.EthTxReceipt{}, xerrors.Errorf("failed to create ID address: %w", err) + } + + l.Address, err = lookupEthAddress(ctx, addr, sa) + if err != nil { + return api.EthTxReceipt{}, xerrors.Errorf("failed to resolve Ethereum address: %w", err) + } + + ethtypes.EthBloomSet(receipt.LogsBloom, l.Address[:]) + receipt.Logs = append(receipt.Logs, l) + } + } + + return receipt, nil +} + +func (m *EthTxHashManager) Apply(ctx context.Context, from, to *types.TipSet) error { + for _, blk := range to.Blocks() { + _, smsgs, err := m.StateAPI.Chain.MessagesForBlock(ctx, blk) + if err != nil { + return err + } + + for _, smsg := range smsgs { + if smsg.Signature.Type != crypto.SigTypeDelegated { + continue + } + + hash, err := EthTxHashFromSignedMessage(ctx, smsg, m.StateAPI) + if err != nil { + return err + } + + err = m.TransactionHashLookup.UpsertHash(hash, smsg.Cid()) + if err != nil { + return err + } + } + } + + return nil +} + +type EthTxHashManager struct { + StateAPI StateAPI + TransactionHashLookup *ethhashlookup.EthTxHashLookup +} + +func (m *EthTxHashManager) Revert(ctx context.Context, from, to *types.TipSet) error { + return nil +} + +func (m *EthTxHashManager) PopulateExistingMappings(ctx context.Context, minHeight abi.ChainEpoch) error { + if minHeight < build.UpgradeHyggeHeight { + minHeight = build.UpgradeHyggeHeight + } + + ts := m.StateAPI.Chain.GetHeaviestTipSet() + for ts.Height() > minHeight { + for _, block := range ts.Blocks() { + msgs, err := m.StateAPI.Chain.SecpkMessagesForBlock(ctx, block) + if err != nil { + // If we can't find the messages, we've either imported from snapshot or pruned the store + log.Debug("exiting message mapping population at epoch ", ts.Height()) + return nil + } + + for _, msg := range msgs { + m.ProcessSignedMessage(ctx, msg) + } + } + + var err error + ts, err = m.StateAPI.Chain.GetTipSetFromKey(ctx, ts.Parents()) + if err != nil { + return err + } + } + + return nil +} + +func (m *EthTxHashManager) ProcessSignedMessage(ctx context.Context, msg *types.SignedMessage) { + if msg.Signature.Type != crypto.SigTypeDelegated { + return + } + + ethTx, err := newEthTxFromSignedMessage(ctx, msg, m.StateAPI) + if err != nil { + log.Errorf("error converting filecoin message to eth tx: %s", err) + return + } + + err = m.TransactionHashLookup.UpsertHash(ethTx.Hash, msg.Cid()) + if err != nil { + log.Errorf("error inserting tx mapping to db: %s", err) + return + } +} + +func WaitForMpoolUpdates(ctx context.Context, ch <-chan api.MpoolUpdate, manager *EthTxHashManager) { + for { + select { + case <-ctx.Done(): + return + case u := <-ch: + if u.Type != api.MpoolAdd { + continue + } + + manager.ProcessSignedMessage(ctx, u.Message) + } + } +} + +func EthTxHashGC(ctx context.Context, retentionDays int, manager *EthTxHashManager) { + if retentionDays == 0 { + return + } + + gcPeriod := 1 * time.Hour + for { + entriesDeleted, err := manager.TransactionHashLookup.DeleteEntriesOlderThan(retentionDays) + if err != nil { + log.Errorf("error garbage collecting eth transaction hash database: %s", err) + } + log.Info("garbage collection run on eth transaction hash lookup database. %d entries deleted", entriesDeleted) + time.Sleep(gcPeriod) + } +} + +func parseEthTopics(topics ethtypes.EthTopicSpec) (map[string][][]byte, error) { + keys := map[string][][]byte{} + for idx, vals := range topics { + if len(vals) == 0 { + continue + } + // Ethereum topics are emitted using `LOG{0..4}` opcodes resulting in topics1..4 + key := fmt.Sprintf("t%d", idx+1) + for _, v := range vals { + v := v // copy the ethhash to avoid repeatedly referencing the same one. + keys[key] = append(keys[key], v[:]) + } + } + return keys, nil +} + +const errorFunctionSelector = "\x08\xc3\x79\xa0" // Error(string) +const panicFunctionSelector = "\x4e\x48\x7b\x71" // Panic(uint256) +// Eth ABI (solidity) panic codes. +var panicErrorCodes map[uint64]string = map[uint64]string{ + 0x00: "Panic()", + 0x01: "Assert()", + 0x11: "ArithmeticOverflow()", + 0x12: "DivideByZero()", + 0x21: "InvalidEnumVariant()", + 0x22: "InvalidStorageArray()", + 0x31: "PopEmptyArray()", + 0x32: "ArrayIndexOutOfBounds()", + 0x41: "OutOfMemory()", + 0x51: "CalledUninitializedFunction()", +} + +// Parse an ABI encoded revert reason. This reason should be encoded as if it were the parameters to +// an `Error(string)` function call. +// +// See https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require +func parseEthRevert(ret []byte) string { + if len(ret) == 0 { + return "none" + } + var cbytes abi.CborBytes + if err := cbytes.UnmarshalCBOR(bytes.NewReader(ret)); err != nil { + return "ERROR: revert reason is not cbor encoded bytes" + } + if len(cbytes) == 0 { + return "none" + } + // If it's not long enough to contain an ABI encoded response, return immediately. + if len(cbytes) < 4+32 { + return ethtypes.EthBytes(cbytes).String() + } + switch string(cbytes[:4]) { + case panicFunctionSelector: + cbytes := cbytes[4 : 4+32] + // Read the and check the code. + code, err := ethtypes.EthUint64FromBytes(cbytes) + if err != nil { + // If it's too big, just return the raw value. + codeInt := big.PositiveFromUnsignedBytes(cbytes) + return fmt.Sprintf("Panic(%s)", ethtypes.EthBigInt(codeInt).String()) + } + if s, ok := panicErrorCodes[uint64(code)]; ok { + return s + } + return fmt.Sprintf("Panic(0x%x)", code) + case errorFunctionSelector: + cbytes := cbytes[4:] + cbytesLen := ethtypes.EthUint64(len(cbytes)) + // Read the and check the offset. + offset, err := ethtypes.EthUint64FromBytes(cbytes[:32]) + if err != nil { + break + } + if cbytesLen < offset { + break + } + + // Read and check the length. + if cbytesLen-offset < 32 { + break + } + start := offset + 32 + length, err := ethtypes.EthUint64FromBytes(cbytes[offset : offset+32]) + if err != nil { + break + } + if cbytesLen-start < length { + break + } + // Slice the error message. + return fmt.Sprintf("Error(%s)", cbytes[start:start+length]) + } + return ethtypes.EthBytes(cbytes).String() +} + +func calculateRewardsAndGasUsed(rewardPercentiles []float64, txGasRewards gasRewardSorter) ([]ethtypes.EthBigInt, uint64) { + var totalGasUsed uint64 + for _, tx := range txGasRewards { + totalGasUsed += tx.gas + } + + rewards := make([]ethtypes.EthBigInt, len(rewardPercentiles)) + for i := range rewards { + rewards[i] = ethtypes.EthBigIntZero + } + + if len(txGasRewards) == 0 { + return rewards, totalGasUsed + } + + sort.Stable(txGasRewards) + + var idx int + var sum uint64 + for i, percentile := range rewardPercentiles { + threshold := uint64(float64(totalGasUsed) * percentile / 100) + for sum < threshold && idx < len(txGasRewards)-1 { + sum += txGasRewards[idx].gas + idx++ + } + rewards[i] = txGasRewards[idx].reward + } + + return rewards, totalGasUsed +} + +type gasRewardTuple struct { + gas uint64 + reward ethtypes.EthBigInt +} + +// sorted in ascending order +type gasRewardSorter []gasRewardTuple + +func (g gasRewardSorter) Len() int { return len(g) } +func (g gasRewardSorter) Swap(i, j int) { + g[i], g[j] = g[j], g[i] +} +func (g gasRewardSorter) Less(i, j int) bool { + return g[i].reward.Int.Cmp(g[j].reward.Int) == -1 +} diff --git a/node/impl/full/eth_test.go b/node/impl/full/eth_test.go new file mode 100644 index 000000000..67a8b0500 --- /dev/null +++ b/node/impl/full/eth_test.go @@ -0,0 +1,166 @@ +package full + +import ( + "testing" + + "github.com/ipfs/go-cid" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" +) + +func TestEthLogFromEvent(t *testing.T) { + // basic empty + data, topics, ok := ethLogFromEvent(nil) + require.True(t, ok) + require.Nil(t, data) + require.Nil(t, topics) + + // basic topic + data, topics, ok = ethLogFromEvent([]types.EventEntry{{ + Flags: 0, + Key: "t1", + Codec: cid.Raw, + Value: make([]byte, 32), + }}) + require.True(t, ok) + require.Nil(t, data) + require.Len(t, topics, 1) + require.Equal(t, topics[0], ethtypes.EthHash{}) + + // basic topic with data + data, topics, ok = ethLogFromEvent([]types.EventEntry{{ + Flags: 0, + Key: "t1", + Codec: cid.Raw, + Value: make([]byte, 32), + }, { + Flags: 0, + Key: "d", + Codec: cid.Raw, + Value: []byte{0x0}, + }}) + require.True(t, ok) + require.Equal(t, data, []byte{0x0}) + require.Len(t, topics, 1) + require.Equal(t, topics[0], ethtypes.EthHash{}) + + // skip topic + _, _, ok = ethLogFromEvent([]types.EventEntry{{ + Flags: 0, + Key: "t2", + Codec: cid.Raw, + Value: make([]byte, 32), + }}) + require.False(t, ok) + + // duplicate topic + _, _, ok = ethLogFromEvent([]types.EventEntry{{ + Flags: 0, + Key: "t1", + Codec: cid.Raw, + Value: make([]byte, 32), + }, { + Flags: 0, + Key: "t1", + Codec: cid.Raw, + Value: make([]byte, 32), + }}) + require.False(t, ok) + + // duplicate data + _, _, ok = ethLogFromEvent([]types.EventEntry{{ + Flags: 0, + Key: "d", + Codec: cid.Raw, + Value: make([]byte, 32), + }, { + Flags: 0, + Key: "d", + Codec: cid.Raw, + Value: make([]byte, 32), + }}) + require.False(t, ok) + + // unknown key is fine + data, topics, ok = ethLogFromEvent([]types.EventEntry{{ + Flags: 0, + Key: "t5", + Codec: cid.Raw, + Value: make([]byte, 32), + }, { + Flags: 0, + Key: "t1", + Codec: cid.Raw, + Value: make([]byte, 32), + }}) + require.True(t, ok) + require.Nil(t, data) + require.Len(t, topics, 1) + require.Equal(t, topics[0], ethtypes.EthHash{}) +} + +func TestReward(t *testing.T) { + baseFee := big.NewInt(100) + testcases := []struct { + maxFeePerGas, maxPriorityFeePerGas big.Int + answer big.Int + }{ + {maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(200), answer: big.NewInt(200)}, + {maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(300), answer: big.NewInt(300)}, + {maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(500), answer: big.NewInt(500)}, + {maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(600), answer: big.NewInt(500)}, + {maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(1000), answer: big.NewInt(500)}, + {maxFeePerGas: big.NewInt(50), maxPriorityFeePerGas: big.NewInt(200), answer: big.NewInt(-50)}, + } + for _, tc := range testcases { + tx := ethtypes.EthTx{ + MaxFeePerGas: ethtypes.EthBigInt(tc.maxFeePerGas), + MaxPriorityFeePerGas: ethtypes.EthBigInt(tc.maxPriorityFeePerGas), + } + reward := tx.Reward(baseFee) + require.Equal(t, 0, reward.Int.Cmp(tc.answer.Int), reward, tc.answer) + } +} + +func TestRewardPercentiles(t *testing.T) { + testcases := []struct { + percentiles []float64 + txGasRewards gasRewardSorter + answer []int64 + }{ + { + percentiles: []float64{25, 50, 75}, + txGasRewards: []gasRewardTuple{}, + answer: []int64{0, 0, 0}, + }, + { + percentiles: []float64{25, 50, 75, 100}, + txGasRewards: []gasRewardTuple{ + {gas: uint64(0), reward: ethtypes.EthBigInt(big.NewInt(300))}, + {gas: uint64(100), reward: ethtypes.EthBigInt(big.NewInt(200))}, + {gas: uint64(350), reward: ethtypes.EthBigInt(big.NewInt(100))}, + {gas: uint64(500), reward: ethtypes.EthBigInt(big.NewInt(600))}, + {gas: uint64(300), reward: ethtypes.EthBigInt(big.NewInt(700))}, + }, + answer: []int64{200, 700, 700, 700}, + }, + } + for _, tc := range testcases { + rewards, totalGasUsed := calculateRewardsAndGasUsed(tc.percentiles, tc.txGasRewards) + gasUsed := uint64(0) + for _, tx := range tc.txGasRewards { + gasUsed += tx.gas + } + ans := []ethtypes.EthBigInt{} + for _, bi := range tc.answer { + ans = append(ans, ethtypes.EthBigInt(big.NewInt(bi))) + } + require.Equal(t, totalGasUsed, gasUsed) + require.Equal(t, len(ans), len(tc.percentiles)) + require.Equal(t, ans, rewards) + } +} diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 8cbe9ea1c..cd3cb0156 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -248,22 +248,23 @@ func (m *GasModule) GasEstimateGasLimit(ctx context.Context, msgIn *types.Messag } return gasEstimateGasLimit(ctx, m.Chain, m.Stmgr, m.Mpool, msgIn, ts) } -func gasEstimateGasLimit( + +// gasEstimateCallWithGas invokes a message "msgIn" on the earliest available tipset with pending +// messages in the message pool. The function returns the result of the message invocation, the +// pending messages, the tipset used for the invocation, and an error if occurred. +// The returned information can be used to make subsequent calls to CallWithGas with the same parameters. +func gasEstimateCallWithGas( ctx context.Context, cstore *store.ChainStore, smgr *stmgr.StateManager, mpool *messagepool.MessagePool, msgIn *types.Message, currTs *types.TipSet, -) (int64, error) { +) (*api.InvocResult, []types.ChainMsg, *types.TipSet, error) { msg := *msgIn - msg.GasLimit = build.BlockGasLimit - msg.GasFeeCap = big.Zero() - msg.GasPremium = big.Zero() - - fromA, err := smgr.ResolveToKeyAddress(ctx, msgIn.From, currTs) + fromA, err := smgr.ResolveToDeterministicAddress(ctx, msgIn.From, currTs) if err != nil { - return -1, xerrors.Errorf("getting key address: %w", err) + return nil, []types.ChainMsg{}, nil, xerrors.Errorf("getting key address: %w", err) } pending, ts := mpool.PendingFor(ctx, fromA) @@ -284,12 +285,34 @@ func gasEstimateGasLimit( } ts, err = cstore.GetTipSetFromKey(ctx, ts.Parents()) if err != nil { - return -1, xerrors.Errorf("getting parent tipset: %w", err) + return nil, []types.ChainMsg{}, nil, xerrors.Errorf("getting parent tipset: %w", err) } } if err != nil { - return -1, xerrors.Errorf("CallWithGas failed: %w", err) + return nil, []types.ChainMsg{}, nil, xerrors.Errorf("CallWithGas failed: %w", err) } + + return res, priorMsgs, ts, nil +} + +func gasEstimateGasLimit( + ctx context.Context, + cstore *store.ChainStore, + smgr *stmgr.StateManager, + mpool *messagepool.MessagePool, + msgIn *types.Message, + currTs *types.TipSet, +) (int64, error) { + msg := *msgIn + msg.GasLimit = build.BlockGasLimit + msg.GasFeeCap = big.Zero() + msg.GasPremium = big.Zero() + + res, _, ts, err := gasEstimateCallWithGas(ctx, cstore, smgr, mpool, &msg, currTs) + if err != nil { + return -1, xerrors.Errorf("gas estimation failed: %w", err) + } + if res.MsgRct.ExitCode == exitcode.SysErrOutOfGas { return -1, &api.ErrOutOfGas{} } @@ -300,12 +323,19 @@ func gasEstimateGasLimit( ret := res.MsgRct.GasUsed + log.Infow("GasEstimateMessageGas CallWithGas Result", "GasUsed", ret, "ExitCode", res.MsgRct.ExitCode) + transitionalMulti := 1.0 // Overestimate gas around the upgrade - if ts.Height() <= build.UpgradeSkyrHeight && (build.UpgradeSkyrHeight-ts.Height() <= 20) { - transitionalMulti = 2.0 - + if ts.Height() <= build.UpgradeHyggeHeight && (build.UpgradeHyggeHeight-ts.Height() <= 20) { func() { + + // Bare transfers get about 3x more expensive: https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0057.md#product-considerations + if msgIn.Method == builtin.MethodSend { + transitionalMulti = 3.0 + return + } + st, err := smgr.ParentState(ts) if err != nil { return @@ -317,26 +347,27 @@ func gasEstimateGasLimit( if lbuiltin.IsStorageMinerActor(act.Code) { switch msgIn.Method { - case 5: - transitionalMulti = 3.954 + case 3: + transitionalMulti = 1.92 + case 4: + transitionalMulti = 1.72 case 6: - transitionalMulti = 4.095 + transitionalMulti = 1.06 case 7: - // skip, stay at 2.0 - //transitionalMulti = 1.289 - case 11: - transitionalMulti = 17.8758 + transitionalMulti = 1.2 case 16: - transitionalMulti = 2.1704 - case 25: - transitionalMulti = 3.1177 + transitionalMulti = 1.19 + case 18: + transitionalMulti = 1.73 + case 23: + transitionalMulti = 1.73 case 26: - transitionalMulti = 2.3322 + transitionalMulti = 1.15 + case 27: + transitionalMulti = 1.18 default: } } - - // skip storage market, 80th percentie for everything ~1.9, leave it at 2.0 }() } ret = (ret * int64(transitionalMulti*1024)) >> 10 diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index 31d134dac..addcc41be 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -175,7 +175,7 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spe } } - fromA, err := a.Stmgr.ResolveToKeyAddress(ctx, msg.From, nil) + fromA, err := a.Stmgr.ResolveToDeterministicAddress(ctx, msg.From, nil) if err != nil { return nil, xerrors.Errorf("getting key address: %w", err) } diff --git a/node/impl/full/state.go b/node/impl/full/state.go index f9b4f741c..e6142a36f 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "strconv" @@ -507,7 +508,7 @@ func (m *StateModule) StateAccountKey(ctx context.Context, addr address.Address, return address.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - return m.StateManager.ResolveToKeyAddress(ctx, addr, ts) + return m.StateManager.ResolveToDeterministicAddress(ctx, addr, ts) } func (a *StateAPI) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) { @@ -615,16 +616,22 @@ func (m *StateModule) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence vmsg := cmsg.VMMessage() - t, err := stmgr.GetReturnType(ctx, m.StateManager, vmsg.To, vmsg.Method, ts) - if err != nil { + switch t, err := stmgr.GetReturnType(ctx, m.StateManager, vmsg.To, vmsg.Method, ts); { + case errors.Is(err, stmgr.ErrMetadataNotFound): + // This is not necessarily an error -- EVM methods (and in the future native actors) may + // return just bytes, and in the not so distant future we'll have native wasm actors + // that are by definition not in the registry. + // So in this case, log a debug message and retun the raw bytes. + log.Debugf("failed to get return type: %s", err) + returndec = recpt.Return + case err != nil: return nil, xerrors.Errorf("failed to get return type: %w", err) + default: + if err := t.UnmarshalCBOR(bytes.NewReader(recpt.Return)); err != nil { + return nil, err + } + returndec = t } - - if err := t.UnmarshalCBOR(bytes.NewReader(recpt.Return)); err != nil { - return nil, err - } - - returndec = t } return &api.MsgLookup{ @@ -771,7 +778,7 @@ func (m *StateModule) StateMarketStorageDeal(ctx context.Context, dealId abi.Dea return stmgr.GetStorageDeal(ctx, m.StateManager, dealId, ts) } -func (a *StateAPI) StateGetAllocationForPendingDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*verifregtypes.Allocation, error) { +func (a *StateAPI) StateGetAllocationForPendingDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*verifreg.Allocation, error) { ts, err := a.Chain.GetTipSetFromKey(ctx, tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) @@ -798,7 +805,7 @@ func (a *StateAPI) StateGetAllocationForPendingDeal(ctx context.Context, dealId return a.StateGetAllocation(ctx, dealState.Proposal.Client, allocationId, tsk) } -func (a *StateAPI) StateGetAllocation(ctx context.Context, clientAddr address.Address, allocationId verifregtypes.AllocationId, tsk types.TipSetKey) (*verifregtypes.Allocation, error) { +func (a *StateAPI) StateGetAllocation(ctx context.Context, clientAddr address.Address, allocationId verifreg.AllocationId, tsk types.TipSetKey) (*verifreg.Allocation, error) { idAddr, err := a.StateLookupID(ctx, clientAddr, tsk) if err != nil { return nil, err @@ -825,7 +832,7 @@ func (a *StateAPI) StateGetAllocation(ctx context.Context, clientAddr address.Ad return allocation, nil } -func (a *StateAPI) StateGetAllocations(ctx context.Context, clientAddr address.Address, tsk types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) { +func (a *StateAPI) StateGetAllocations(ctx context.Context, clientAddr address.Address, tsk types.TipSetKey) (map[verifreg.AllocationId]verifreg.Allocation, error) { idAddr, err := a.StateLookupID(ctx, clientAddr, tsk) if err != nil { return nil, err @@ -849,7 +856,7 @@ func (a *StateAPI) StateGetAllocations(ctx context.Context, clientAddr address.A return allocations, nil } -func (a *StateAPI) StateGetClaim(ctx context.Context, providerAddr address.Address, claimId verifregtypes.ClaimId, tsk types.TipSetKey) (*verifregtypes.Claim, error) { +func (a *StateAPI) StateGetClaim(ctx context.Context, providerAddr address.Address, claimId verifreg.ClaimId, tsk types.TipSetKey) (*verifreg.Claim, error) { idAddr, err := a.StateLookupID(ctx, providerAddr, tsk) if err != nil { return nil, err @@ -876,7 +883,7 @@ func (a *StateAPI) StateGetClaim(ctx context.Context, providerAddr address.Addre return claim, nil } -func (a *StateAPI) StateGetClaims(ctx context.Context, providerAddr address.Address, tsk types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) { +func (a *StateAPI) StateGetClaims(ctx context.Context, providerAddr address.Address, tsk types.TipSetKey) (map[verifreg.ClaimId]verifreg.Claim, error) { idAddr, err := a.StateLookupID(ctx, providerAddr, tsk) if err != nil { return nil, err @@ -1046,6 +1053,7 @@ func (a *StateAPI) StateSectorPreCommitInfo(ctx context.Context, maddr address.A return pci, err } +// Returns nil, nil if sector is not found func (m *StateModule) StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) { ts, err := m.Chain.GetTipSetFromKey(ctx, tsk) if err != nil { @@ -1799,6 +1807,7 @@ func (a *StateAPI) StateGetNetworkParams(ctx context.Context) (*api.NetworkParam UpgradeOhSnapHeight: build.UpgradeOhSnapHeight, UpgradeSkyrHeight: build.UpgradeSkyrHeight, UpgradeSharkHeight: build.UpgradeSharkHeight, + UpgradeHyggeHeight: build.UpgradeHyggeHeight, }, }, nil } diff --git a/node/impl/full/wallet.go b/node/impl/full/wallet.go index ae2550d77..fdf00e086 100644 --- a/node/impl/full/wallet.go +++ b/node/impl/full/wallet.go @@ -11,6 +11,7 @@ import ( "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/messagesigner" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" @@ -36,7 +37,7 @@ func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (ty } func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error) { - keyAddr, err := a.StateManagerAPI.ResolveToKeyAddress(ctx, k, nil) + keyAddr, err := a.StateManagerAPI.ResolveToDeterministicAddress(ctx, k, nil) if err != nil { return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr) } @@ -46,17 +47,21 @@ func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byt } func (a *WalletAPI) WalletSignMessage(ctx context.Context, k address.Address, msg *types.Message) (*types.SignedMessage, error) { - keyAddr, err := a.StateManagerAPI.ResolveToKeyAddress(ctx, k, nil) + keyAddr, err := a.StateManagerAPI.ResolveToDeterministicAddress(ctx, k, nil) if err != nil { return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr) } + sb, err := messagesigner.SigningBytes(msg, keyAddr.Protocol()) + if err != nil { + return nil, err + } mb, err := msg.ToStorageBlock() if err != nil { return nil, xerrors.Errorf("serializing message: %w", err) } - sig, err := a.Wallet.WalletSign(ctx, keyAddr, mb.Cid().Bytes(), api.MsgMeta{ + sig, err := a.Wallet.WalletSign(ctx, keyAddr, sb, api.MsgMeta{ Type: api.MTChainMsg, Extra: mb.RawData(), }) diff --git a/node/modules/actorevent.go b/node/modules/actorevent.go new file mode 100644 index 000000000..55a79a59a --- /dev/null +++ b/node/modules/actorevent.go @@ -0,0 +1,153 @@ +package modules + +import ( + "context" + "path/filepath" + "time" + + "github.com/multiformats/go-varint" + "go.uber.org/fx" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + builtintypes "github.com/filecoin-project/go-state-types/builtin" + + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/chain/events/filter" + "github.com/filecoin-project/lotus/chain/messagepool" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/node/impl/full" + "github.com/filecoin-project/lotus/node/modules/helpers" + "github.com/filecoin-project/lotus/node/repo" +) + +type EventAPI struct { + fx.In + + full.ChainAPI + full.StateAPI +} + +var _ events.EventAPI = &EventAPI{} + +func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI) (*full.EthEvent, error) { + return func(mctx helpers.MetricsCtx, r repo.LockedRepo, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI) (*full.EthEvent, error) { + ctx := helpers.LifecycleCtx(mctx, lc) + + ee := &full.EthEvent{ + Chain: cs, + MaxFilterHeightRange: abi.ChainEpoch(cfg.Events.MaxFilterHeightRange), + SubscribtionCtx: ctx, + } + + if !cfg.EnableEthRPC || cfg.Events.DisableRealTimeFilterAPI { + // all event functionality is disabled + // the historic filter API relies on the real time one + return ee, nil + } + + ee.SubManager = &full.EthSubscriptionManager{ + Chain: cs, + StateAPI: stateapi, + ChainAPI: chainapi, + } + ee.FilterStore = filter.NewMemFilterStore(cfg.Events.MaxFilters) + + // Start garbage collection for filters + lc.Append(fx.Hook{ + OnStart: func(context.Context) error { + go ee.GC(ctx, time.Duration(cfg.Events.FilterTTL)) + return nil + }, + }) + + // Enable indexing of actor events + var eventIndex *filter.EventIndex + if !cfg.Events.DisableHistoricFilterAPI { + var dbPath string + if cfg.Events.DatabasePath == "" { + sqlitePath, err := r.SqlitePath() + if err != nil { + return nil, err + } + dbPath = filepath.Join(sqlitePath, "events.db") + } else { + dbPath = cfg.Events.DatabasePath + } + + var err error + eventIndex, err = filter.NewEventIndex(dbPath) + if err != nil { + return nil, err + } + + lc.Append(fx.Hook{ + OnStop: func(context.Context) error { + return eventIndex.Close() + }, + }) + } + + ee.EventFilterManager = &filter.EventFilterManager{ + ChainStore: cs, + EventIndex: eventIndex, // will be nil unless EnableHistoricFilterAPI is true + AddressResolver: func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool) { + // we only want to match using f4 addresses + idAddr, err := address.NewIDAddress(uint64(emitter)) + if err != nil { + return address.Undef, false + } + + actor, err := sm.LoadActor(ctx, idAddr, ts) + if err != nil || actor.Address == nil { + return address.Undef, false + } + + // if robust address is not f4 then we won't match against it so bail early + if actor.Address.Protocol() != address.Delegated { + return address.Undef, false + } + // we have an f4 address, make sure it's assigned by the EAM + if namespace, _, err := varint.FromUvarint(actor.Address.Payload()); err != nil || namespace != builtintypes.EthereumAddressManagerActorID { + return address.Undef, false + } + return *actor.Address, true + }, + + MaxFilterResults: cfg.Events.MaxFilterResults, + } + ee.TipSetFilterManager = &filter.TipSetFilterManager{ + MaxFilterResults: cfg.Events.MaxFilterResults, + } + ee.MemPoolFilterManager = &filter.MemPoolFilterManager{ + MaxFilterResults: cfg.Events.MaxFilterResults, + } + + const ChainHeadConfidence = 1 + + lc.Append(fx.Hook{ + OnStart: func(context.Context) error { + ev, err := events.NewEventsWithConfidence(ctx, &evapi, ChainHeadConfidence) + if err != nil { + return err + } + // ignore returned tipsets + _ = ev.Observe(ee.EventFilterManager) + _ = ev.Observe(ee.TipSetFilterManager) + + ch, err := mp.Updates(ctx) + if err != nil { + return err + } + go ee.MemPoolFilterManager.WaitForMpoolUpdates(ctx, ch) + + return nil + }, + }) + + return ee, nil + } +} diff --git a/node/modules/chain.go b/node/modules/chain.go index 22a1d618a..f304ab135 100644 --- a/node/modules/chain.go +++ b/node/modules/chain.go @@ -4,9 +4,9 @@ import ( "context" "time" - "github.com/ipfs/go-bitswap" - "github.com/ipfs/go-bitswap/network" "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-libipfs/bitswap" + "github.com/ipfs/go-libipfs/bitswap/network" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/routing" "go.uber.org/fx" @@ -69,7 +69,7 @@ func MessagePool(lc fx.Lifecycle, mctx helpers.MetricsCtx, us stmgr.UpgradeSched return mp.Close() }, }) - protector.AddProtector(mp.ForEachPendingMessage) + protector.AddProtector(mp.TryForEachPendingMessage) return mp, nil } @@ -181,3 +181,7 @@ func NewSlashFilter(ds dtypes.MetadataDS) *slashfilter.SlashFilter { func UpgradeSchedule() stmgr.UpgradeSchedule { return filcns.DefaultUpgradeSchedule() } + +func EnableStoringEvents(cs *store.ChainStore) { + cs.StoreEvents(true) +} diff --git a/node/modules/ethmodule.go b/node/modules/ethmodule.go new file mode 100644 index 000000000..eba6c54d1 --- /dev/null +++ b/node/modules/ethmodule.go @@ -0,0 +1,93 @@ +package modules + +import ( + "context" + "os" + "path/filepath" + + "go.uber.org/fx" + + "github.com/filecoin-project/lotus/chain/ethhashlookup" + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/chain/messagepool" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/node/impl/full" + "github.com/filecoin-project/lotus/node/modules/helpers" + "github.com/filecoin-project/lotus/node/repo" +) + +func EthModuleAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI, full.MpoolAPI) (*full.EthModule, error) { + return func(mctx helpers.MetricsCtx, r repo.LockedRepo, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI, mpoolapi full.MpoolAPI) (*full.EthModule, error) { + sqlitePath, err := r.SqlitePath() + if err != nil { + return nil, err + } + + dbPath := filepath.Join(sqlitePath, "txhash.db") + + // Check if the db exists, if not, we'll back-fill some entries + _, err = os.Stat(dbPath) + dbAlreadyExists := err == nil + + transactionHashLookup, err := ethhashlookup.NewTransactionHashLookup(dbPath) + if err != nil { + return nil, err + } + + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + return transactionHashLookup.Close() + }, + }) + + ethTxHashManager := full.EthTxHashManager{ + StateAPI: stateapi, + TransactionHashLookup: transactionHashLookup, + } + + if !dbAlreadyExists { + err = ethTxHashManager.PopulateExistingMappings(mctx, 0) + if err != nil { + return nil, err + } + } + + const ChainHeadConfidence = 1 + + ctx := helpers.LifecycleCtx(mctx, lc) + lc.Append(fx.Hook{ + OnStart: func(context.Context) error { + ev, err := events.NewEventsWithConfidence(ctx, &evapi, ChainHeadConfidence) + if err != nil { + return err + } + + // Tipset listener + _ = ev.Observe(ðTxHashManager) + + ch, err := mp.Updates(ctx) + if err != nil { + return err + } + go full.WaitForMpoolUpdates(ctx, ch, ðTxHashManager) + go full.EthTxHashGC(ctx, cfg.EthTxHashMappingLifetimeDays, ðTxHashManager) + + return nil + }, + }) + + return &full.EthModule{ + Chain: cs, + Mpool: mp, + StateManager: sm, + + ChainAPI: chainapi, + MpoolAPI: mpoolapi, + StateAPI: stateapi, + + EthTxHashManager: ðTxHashManager, + }, nil + } +} diff --git a/node/modules/lp2p/host.go b/node/modules/lp2p/host.go index 6ba9cdb79..2d441eb3f 100644 --- a/node/modules/lp2p/host.go +++ b/node/modules/lp2p/host.go @@ -7,11 +7,11 @@ import ( nilrouting "github.com/ipfs/go-ipfs-routing/none" "github.com/libp2p/go-libp2p" dht "github.com/libp2p/go-libp2p-kad-dht" - "github.com/libp2p/go-libp2p-peerstore/pstoremem" record "github.com/libp2p/go-libp2p-record" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peerstore" + "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" routedhost "github.com/libp2p/go-libp2p/p2p/host/routed" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" "go.uber.org/fx" diff --git a/node/modules/lp2p/pubsub.go b/node/modules/lp2p/pubsub.go index 9f1b58c2b..5376d93c8 100644 --- a/node/modules/lp2p/pubsub.go +++ b/node/modules/lp2p/pubsub.go @@ -21,6 +21,7 @@ import ( "github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/modules/helpers" + "github.com/filecoin-project/lotus/node/modules/tracer" ) func init() { @@ -49,6 +50,30 @@ func ScoreKeeper() *dtypes.ScoreKeeper { return new(dtypes.ScoreKeeper) } +type PeerScoreTracker interface { + UpdatePeerScore(scores map[peer.ID]*pubsub.PeerScoreSnapshot) +} + +type peerScoreTracker struct { + sk *dtypes.ScoreKeeper + lt tracer.LotusTracer +} + +func newPeerScoreTracker(lt tracer.LotusTracer, sk *dtypes.ScoreKeeper) PeerScoreTracker { + return &peerScoreTracker{ + sk: sk, + lt: lt, + } +} + +func (pst *peerScoreTracker) UpdatePeerScore(scores map[peer.ID]*pubsub.PeerScoreSnapshot) { + if pst.lt != nil { + pst.lt.PeerScores(scores) + } + + pst.sk.Update(scores) +} + type GossipIn struct { fx.In Mctx helpers.MetricsCtx @@ -291,7 +316,6 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { OpportunisticGraftThreshold: OpportunisticGraftScoreThreshold, }, ), - pubsub.WithPeerScoreInspect(in.Sk.Update, 10*time.Second), } // enable Peer eXchange on bootstrappers @@ -361,6 +385,27 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { pubsub.NewAllowlistSubscriptionFilter(allowTopics...), 100))) + var transports []tracer.TracerTransport + if in.Cfg.JsonTracer != "" { + jsonTransport, err := tracer.NewJsonTracerTransport(in.Cfg.JsonTracer) + if err != nil { + return nil, err + } + + transports = append(transports, jsonTransport) + } + if in.Cfg.ElasticSearchTracer != "" { + elasticSearchTransport, err := tracer.NewElasticSearchTransport( + in.Cfg.ElasticSearchTracer, + in.Cfg.ElasticSearchIndex, + ) + if err != nil { + return nil, err + } + transports = append(transports, elasticSearchTransport) + } + lt := tracer.NewLotusTracer(transports, in.Host.ID(), in.Cfg.TracerSourceAuth) + // tracer if in.Cfg.RemoteTracer != "" { a, err := ma.NewMultiaddr(in.Cfg.RemoteTracer) @@ -378,12 +423,18 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { return nil, err } - trw := newTracerWrapper(tr, build.BlocksTopic(in.Nn)) + pst := newPeerScoreTracker(lt, in.Sk) + trw := newTracerWrapper(tr, lt, build.BlocksTopic(in.Nn)) + options = append(options, pubsub.WithEventTracer(trw)) + options = append(options, pubsub.WithPeerScoreInspect(pst.UpdatePeerScore, 10*time.Second)) } else { // still instantiate a tracer for collecting metrics - trw := newTracerWrapper(nil) + trw := newTracerWrapper(nil, lt) options = append(options, pubsub.WithEventTracer(trw)) + + pst := newPeerScoreTracker(lt, in.Sk) + options = append(options, pubsub.WithPeerScoreInspect(pst.UpdatePeerScore, 10*time.Second)) } return pubsub.NewGossipSub(helpers.LifecycleCtx(in.Mctx, in.Lc), in.Host, options...) @@ -394,7 +445,11 @@ func HashMsgId(m *pubsub_pb.Message) string { return string(hash[:]) } -func newTracerWrapper(tr pubsub.EventTracer, topics ...string) pubsub.EventTracer { +func newTracerWrapper( + lp2pTracer pubsub.EventTracer, + lotusTracer pubsub.EventTracer, + topics ...string, +) pubsub.EventTracer { var topicsMap map[string]struct{} if len(topics) > 0 { topicsMap = make(map[string]struct{}) @@ -403,12 +458,13 @@ func newTracerWrapper(tr pubsub.EventTracer, topics ...string) pubsub.EventTrace } } - return &tracerWrapper{tr: tr, topics: topicsMap} + return &tracerWrapper{lp2pTracer: lp2pTracer, lotusTracer: lotusTracer, topics: topicsMap} } type tracerWrapper struct { - tr pubsub.EventTracer - topics map[string]struct{} + lp2pTracer pubsub.EventTracer + lotusTracer pubsub.EventTracer + topics map[string]struct{} } func (trw *tracerWrapper) traceMessage(topic string) bool { @@ -426,33 +482,70 @@ func (trw *tracerWrapper) Trace(evt *pubsub_pb.TraceEvent) { switch evt.GetType() { case pubsub_pb.TraceEvent_PUBLISH_MESSAGE: stats.Record(context.TODO(), metrics.PubsubPublishMessage.M(1)) - if trw.tr != nil && trw.traceMessage(evt.GetPublishMessage().GetTopic()) { - trw.tr.Trace(evt) + if trw.traceMessage(evt.GetPublishMessage().GetTopic()) { + if trw.lp2pTracer != nil { + trw.lp2pTracer.Trace(evt) + } + + if trw.lotusTracer != nil { + trw.lotusTracer.Trace(evt) + } } case pubsub_pb.TraceEvent_DELIVER_MESSAGE: stats.Record(context.TODO(), metrics.PubsubDeliverMessage.M(1)) - if trw.tr != nil && trw.traceMessage(evt.GetDeliverMessage().GetTopic()) { - trw.tr.Trace(evt) + if trw.traceMessage(evt.GetDeliverMessage().GetTopic()) { + if trw.lp2pTracer != nil { + trw.lp2pTracer.Trace(evt) + } + + if trw.lotusTracer != nil { + trw.lotusTracer.Trace(evt) + } } case pubsub_pb.TraceEvent_REJECT_MESSAGE: stats.Record(context.TODO(), metrics.PubsubRejectMessage.M(1)) + if trw.traceMessage(evt.GetRejectMessage().GetTopic()) { + if trw.lp2pTracer != nil { + trw.lp2pTracer.Trace(evt) + } + + if trw.lotusTracer != nil { + trw.lotusTracer.Trace(evt) + } + } case pubsub_pb.TraceEvent_DUPLICATE_MESSAGE: stats.Record(context.TODO(), metrics.PubsubDuplicateMessage.M(1)) case pubsub_pb.TraceEvent_JOIN: - if trw.tr != nil { - trw.tr.Trace(evt) + if trw.lp2pTracer != nil { + trw.lp2pTracer.Trace(evt) + } + + if trw.lotusTracer != nil { + trw.lotusTracer.Trace(evt) } case pubsub_pb.TraceEvent_LEAVE: - if trw.tr != nil { - trw.tr.Trace(evt) + if trw.lp2pTracer != nil { + trw.lp2pTracer.Trace(evt) + } + + if trw.lotusTracer != nil { + trw.lotusTracer.Trace(evt) } case pubsub_pb.TraceEvent_GRAFT: - if trw.tr != nil { - trw.tr.Trace(evt) + if trw.lp2pTracer != nil { + trw.lp2pTracer.Trace(evt) + } + + if trw.lotusTracer != nil { + trw.lotusTracer.Trace(evt) } case pubsub_pb.TraceEvent_PRUNE: - if trw.tr != nil { - trw.tr.Trace(evt) + if trw.lp2pTracer != nil { + trw.lp2pTracer.Trace(evt) + } + + if trw.lotusTracer != nil { + trw.lotusTracer.Trace(evt) } case pubsub_pb.TraceEvent_RECV_RPC: stats.Record(context.TODO(), metrics.PubsubRecvRPC.M(1)) diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index 04814ffdc..dff9c1415 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -233,7 +233,7 @@ func PreflightChecks(mctx helpers.MetricsCtx, lc fx.Lifecycle, api v1api.FullNod return xerrors.New("key for worker not found in local wallet") } - log.Infof("starting up miner %s, worker addr %s", maddr, workerKey) + log.Infof("starting up miner %s, worker addr %s", address.Address(maddr), workerKey) return nil }}) diff --git a/node/modules/storageminer_idxprov.go b/node/modules/storageminer_idxprov.go index 5f6cf69f0..92a6a6a54 100644 --- a/node/modules/storageminer_idxprov.go +++ b/node/modules/storageminer_idxprov.go @@ -46,7 +46,7 @@ func IndexProvider(cfg config.IndexProviderConfig) func(params IdxProv, marketHo engine.WithHost(marketHost), engine.WithRetrievalAddrs(marketHost.Addrs()...), engine.WithEntriesCacheCapacity(cfg.EntriesCacheCapacity), - engine.WithEntriesChunkSize(cfg.EntriesChunkSize), + engine.WithChainedEntries(cfg.EntriesChunkSize), engine.WithTopicName(topicName), engine.WithPurgeCacheOnStart(cfg.PurgeCacheOnStart), } diff --git a/node/modules/storageminer_idxprov_test.go b/node/modules/storageminer_idxprov_test.go index 125d5b82c..8d5717b66 100644 --- a/node/modules/storageminer_idxprov_test.go +++ b/node/modules/storageminer_idxprov_test.go @@ -78,8 +78,9 @@ func Test_IndexProviderTopic(t *testing.T) { func() *pubsub.PubSub { return ps }, func() dtypes.MetadataDS { return datastore.NewMapDatastore() }, modules.IndexProvider(config.IndexProviderConfig{ - Enable: true, - TopicName: test.givenConfiguredTopic, + Enable: true, + TopicName: test.givenConfiguredTopic, + EntriesChunkSize: 16384, }), ), fx.Invoke(func(p provider.Interface) {}), diff --git a/node/modules/tracer/elasticsearch_transport.go b/node/modules/tracer/elasticsearch_transport.go new file mode 100644 index 000000000..1f6f9a157 --- /dev/null +++ b/node/modules/tracer/elasticsearch_transport.go @@ -0,0 +1,97 @@ +package tracer + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "strings" + + "github.com/elastic/go-elasticsearch/v7" + "github.com/elastic/go-elasticsearch/v7/esapi" +) + +const ( + ElasticSearchDefaultIndex = "lotus-pubsub" +) + +func NewElasticSearchTransport(connectionString string, elasticsearchIndex string) (TracerTransport, error) { + conUrl, err := url.Parse(connectionString) + + if err != nil { + return nil, err + } + + username := conUrl.User.Username() + password, _ := conUrl.User.Password() + cfg := elasticsearch.Config{ + Addresses: []string{ + conUrl.Scheme + "://" + conUrl.Host, + }, + Username: username, + Password: password, + } + + es, err := elasticsearch.NewClient(cfg) + + if err != nil { + return nil, err + } + + var esIndex string + if elasticsearchIndex != "" { + esIndex = elasticsearchIndex + } else { + esIndex = ElasticSearchDefaultIndex + } + + return &elasticSearchTransport{ + cl: es, + esIndex: esIndex, + }, nil +} + +type elasticSearchTransport struct { + cl *elasticsearch.Client + esIndex string +} + +func (est *elasticSearchTransport) Transport(evt TracerTransportEvent) error { + var e interface{} + + if evt.lotusTraceEvent != nil { + e = *evt.lotusTraceEvent + } else if evt.pubsubTraceEvent != nil { + e = *evt.pubsubTraceEvent + } else { + return nil + } + + jsonEvt, err := json.Marshal(e) + if err != nil { + return fmt.Errorf("error while marshaling event: %s", err) + } + + req := esapi.IndexRequest{ + Index: est.esIndex, + Body: strings.NewReader(string(jsonEvt)), + Refresh: "true", + } + + // Perform the request with the client. + res, err := req.Do(context.Background(), est.cl) + if err != nil { + return err + } + + err = res.Body.Close() + if err != nil { + return err + } + + if res.IsError() { + return fmt.Errorf("[%s] Error indexing document ID=%s", res.Status(), req.DocumentID) + } + + return nil +} diff --git a/node/modules/tracer/json_transport.go b/node/modules/tracer/json_transport.go new file mode 100644 index 000000000..ca8535f4b --- /dev/null +++ b/node/modules/tracer/json_transport.go @@ -0,0 +1,41 @@ +package tracer + +import ( + "encoding/json" + "fmt" + "os" +) + +type jsonTracerTransport struct { + out *os.File +} + +func NewJsonTracerTransport(file string) (TracerTransport, error) { + out, err := os.OpenFile(file, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0660) + if err != nil { + return nil, err + } + + return &jsonTracerTransport{ + out: out, + }, nil +} + +func (jtt *jsonTracerTransport) Transport(evt TracerTransportEvent) error { + var e interface{} + if evt.lotusTraceEvent != nil { + e = *evt.lotusTraceEvent + } else if evt.pubsubTraceEvent != nil { + e = *evt.pubsubTraceEvent + } else { + return nil + } + + jsonEvt, err := json.Marshal(e) + if err != nil { + return fmt.Errorf("error while marshaling event: %s", err) + } + + _, err = jtt.out.WriteString(string(jsonEvt) + "\n") + return err +} diff --git a/node/modules/tracer/tracer.go b/node/modules/tracer/tracer.go new file mode 100644 index 000000000..0d0a156d9 --- /dev/null +++ b/node/modules/tracer/tracer.go @@ -0,0 +1,120 @@ +package tracer + +import ( + "time" + + logging "github.com/ipfs/go-log/v2" + pubsub "github.com/libp2p/go-libp2p-pubsub" + pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb" + "github.com/libp2p/go-libp2p/core/peer" +) + +var log = logging.Logger("lotus-tracer") + +func NewLotusTracer(tt []TracerTransport, pid peer.ID, sourceAuth string) LotusTracer { + return &lotusTracer{ + tt: tt, + pid: pid, + sa: sourceAuth, + } +} + +type lotusTracer struct { + tt []TracerTransport + pid peer.ID + sa string +} + +const ( + TraceEventPeerScores pubsub_pb.TraceEvent_Type = 100 +) + +type LotusTraceEvent struct { + Type pubsub_pb.TraceEvent_Type `json:"type,omitempty"` + PeerID string `json:"peerID,omitempty"` + Timestamp *int64 `json:"timestamp,omitempty"` + PeerScore TraceEventPeerScore `json:"peerScore,omitempty"` + SourceAuth string `json:"sourceAuth,omitempty"` +} + +type TopicScore struct { + Topic string `json:"topic"` + TimeInMesh time.Duration `json:"timeInMesh"` + FirstMessageDeliveries float64 `json:"firstMessageDeliveries"` + MeshMessageDeliveries float64 `json:"meshMessageDeliveries"` + InvalidMessageDeliveries float64 `json:"invalidMessageDeliveries"` +} + +type TraceEventPeerScore struct { + PeerID string `json:"peerID"` + Score float64 `json:"score"` + AppSpecificScore float64 `json:"appSpecificScore"` + IPColocationFactor float64 `json:"ipColocationFactor"` + BehaviourPenalty float64 `json:"behaviourPenalty"` + Topics []TopicScore `json:"topics"` +} + +type LotusTracer interface { + Trace(evt *pubsub_pb.TraceEvent) + TraceLotusEvent(evt *LotusTraceEvent) + + PeerScores(scores map[peer.ID]*pubsub.PeerScoreSnapshot) +} + +func (lt *lotusTracer) PeerScores(scores map[peer.ID]*pubsub.PeerScoreSnapshot) { + now := time.Now().UnixNano() + for pid, score := range scores { + var topics []TopicScore + for topic, snapshot := range score.Topics { + topics = append(topics, TopicScore{ + Topic: topic, + TimeInMesh: snapshot.TimeInMesh, + FirstMessageDeliveries: snapshot.FirstMessageDeliveries, + MeshMessageDeliveries: snapshot.MeshMessageDeliveries, + InvalidMessageDeliveries: snapshot.InvalidMessageDeliveries, + }) + } + + evt := &LotusTraceEvent{ + Type: *TraceEventPeerScores.Enum(), + PeerID: lt.pid.Pretty(), + Timestamp: &now, + SourceAuth: lt.sa, + PeerScore: TraceEventPeerScore{ + PeerID: pid.Pretty(), + Score: score.Score, + AppSpecificScore: score.AppSpecificScore, + IPColocationFactor: score.IPColocationFactor, + BehaviourPenalty: score.BehaviourPenalty, + Topics: topics, + }, + } + + lt.TraceLotusEvent(evt) + } +} + +func (lt *lotusTracer) TraceLotusEvent(evt *LotusTraceEvent) { + for _, t := range lt.tt { + err := t.Transport(TracerTransportEvent{ + lotusTraceEvent: evt, + pubsubTraceEvent: nil, + }) + if err != nil { + log.Errorf("error while transporting peer scores: %s", err) + } + } + +} + +func (lt *lotusTracer) Trace(evt *pubsub_pb.TraceEvent) { + for _, t := range lt.tt { + err := t.Transport(TracerTransportEvent{ + lotusTraceEvent: nil, + pubsubTraceEvent: evt, + }) + if err != nil { + log.Errorf("error while transporting trace event: %s", err) + } + } +} diff --git a/node/modules/tracer/tracer_test.go b/node/modules/tracer/tracer_test.go new file mode 100644 index 000000000..7ade67861 --- /dev/null +++ b/node/modules/tracer/tracer_test.go @@ -0,0 +1,109 @@ +package tracer + +import ( + "testing" + "time" + + pubsub "github.com/libp2p/go-libp2p-pubsub" + pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/stretchr/testify/require" +) + +type testTracerTransport struct { + t *testing.T + executeTest func(t *testing.T, evt TracerTransportEvent) +} + +const peerIDA peer.ID = "12D3KooWAbSVMgRejb6ECg6fRTkCPGCfu8396msZVryu8ivcz44G" + +func NewTestTraceTransport(t *testing.T, executeTest func(t *testing.T, evt TracerTransportEvent)) TracerTransport { + return &testTracerTransport{ + t: t, + executeTest: executeTest, + } +} + +func (ttt *testTracerTransport) Transport(evt TracerTransportEvent) error { + ttt.executeTest(ttt.t, evt) + return nil +} + +func TestTracer_PeerScores(t *testing.T) { + + testTransport := NewTestTraceTransport(t, func(t *testing.T, evt TracerTransportEvent) { + require.Equal(t, peerIDA.Pretty(), evt.lotusTraceEvent.PeerID) + require.Equal(t, "source-auth-token-test", evt.lotusTraceEvent.SourceAuth) + require.Equal(t, float64(32), evt.lotusTraceEvent.PeerScore.Score) + + n := time.Now().UnixNano() + require.LessOrEqual(t, *evt.lotusTraceEvent.Timestamp, n) + + require.Equal(t, peerIDA.Pretty(), evt.lotusTraceEvent.PeerScore.PeerID) + require.Equal(t, 1, len(evt.lotusTraceEvent.PeerScore.Topics)) + + topic := evt.lotusTraceEvent.PeerScore.Topics[0] + require.Equal(t, "topicA", topic.Topic) + require.Equal(t, float64(100), topic.FirstMessageDeliveries) + }) + + lt := NewLotusTracer( + []TracerTransport{testTransport}, + peerIDA, + "source-auth-token-test", + ) + + topics := make(map[string]*pubsub.TopicScoreSnapshot) + topics["topicA"] = &pubsub.TopicScoreSnapshot{ + FirstMessageDeliveries: float64(100), + } + + m := make(map[peer.ID]*pubsub.PeerScoreSnapshot) + m[peerIDA] = &pubsub.PeerScoreSnapshot{ + Score: float64(32), + Topics: topics, + } + + lt.PeerScores(m) +} + +func TestTracer_PubSubTrace(t *testing.T) { + n := time.Now().Unix() + + testTransport := NewTestTraceTransport(t, func(t *testing.T, evt TracerTransportEvent) { + require.Equal(t, []byte(peerIDA), evt.pubsubTraceEvent.PeerID) + require.Equal(t, &n, evt.pubsubTraceEvent.Timestamp) + }) + + lt := NewLotusTracer( + []TracerTransport{testTransport}, + "pid", + "source-auth", + ) + + lt.Trace(&pubsub_pb.TraceEvent{ + PeerID: []byte(peerIDA), + Timestamp: &n, + }) + +} + +func TestTracer_MultipleTransports(t *testing.T) { + testTransportA := NewTestTraceTransport(t, func(t *testing.T, evt TracerTransportEvent) { + require.Equal(t, []byte(peerIDA), evt.pubsubTraceEvent.PeerID) + }) + + testTransportB := NewTestTraceTransport(t, func(t *testing.T, evt TracerTransportEvent) { + require.Equal(t, []byte(peerIDA), evt.pubsubTraceEvent.PeerID) + }) + + executeTest := NewLotusTracer( + []TracerTransport{testTransportA, testTransportB}, + "pid", + "source-auth", + ) + + executeTest.Trace(&pubsub_pb.TraceEvent{ + PeerID: []byte(peerIDA), + }) +} diff --git a/node/modules/tracer/transport.go b/node/modules/tracer/transport.go new file mode 100644 index 000000000..56d926afc --- /dev/null +++ b/node/modules/tracer/transport.go @@ -0,0 +1,12 @@ +package tracer + +import pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb" + +type TracerTransport interface { + Transport(evt TracerTransportEvent) error +} + +type TracerTransportEvent struct { + lotusTraceEvent *LotusTraceEvent + pubsubTraceEvent *pubsub_pb.TraceEvent +} diff --git a/node/repo/fsrepo.go b/node/repo/fsrepo.go index 68550e389..bd387babf 100644 --- a/node/repo/fsrepo.go +++ b/node/repo/fsrepo.go @@ -37,6 +37,7 @@ const ( fsDatastore = "datastore" fsLock = "repo.lock" fsKeystore = "keystore" + fsSqlite = "sqlite" ) func NewRepoTypeFromString(t string) RepoType { @@ -411,6 +412,10 @@ type fsLockedRepo struct { ssErr error ssOnce sync.Once + sqlPath string + sqlErr error + sqlOnce sync.Once + storageLk sync.Mutex configLk sync.Mutex } @@ -515,6 +520,21 @@ func (fsr *fsLockedRepo) SplitstorePath() (string, error) { return fsr.ssPath, fsr.ssErr } +func (fsr *fsLockedRepo) SqlitePath() (string, error) { + fsr.sqlOnce.Do(func() { + path := fsr.join(fsSqlite) + + if err := os.MkdirAll(path, 0755); err != nil { + fsr.sqlErr = err + return + } + + fsr.sqlPath = path + }) + + return fsr.sqlPath, fsr.sqlErr +} + // join joins path elements with fsr.path func (fsr *fsLockedRepo) join(paths ...string) string { return filepath.Join(append([]string{fsr.path}, paths...)...) diff --git a/node/repo/interface.go b/node/repo/interface.go index dd0839559..328862b92 100644 --- a/node/repo/interface.go +++ b/node/repo/interface.go @@ -69,6 +69,9 @@ type LockedRepo interface { // SplitstorePath returns the path for the SplitStore SplitstorePath() (string, error) + // SqlitePath returns the path for the Sqlite database + SqlitePath() (string, error) + // Returns config in this repo Config() (interface{}, error) SetConfig(func(interface{})) error diff --git a/node/repo/memrepo.go b/node/repo/memrepo.go index 61d960872..7817776a9 100644 --- a/node/repo/memrepo.go +++ b/node/repo/memrepo.go @@ -277,6 +277,14 @@ func (lmem *lockedMemRepo) SplitstorePath() (string, error) { return splitstorePath, nil } +func (lmem *lockedMemRepo) SqlitePath() (string, error) { + sqlitePath := filepath.Join(lmem.Path(), "sqlite") + if err := os.MkdirAll(sqlitePath, 0755); err != nil { + return "", err + } + return sqlitePath, nil +} + func (lmem *lockedMemRepo) ListDatastores(ns string) ([]int64, error) { return nil, nil } diff --git a/node/rpc.go b/node/rpc.go index 96a81a383..cacd33526 100644 --- a/node/rpc.go +++ b/node/rpc.go @@ -9,6 +9,7 @@ import ( _ "net/http/pprof" "runtime" "strconv" + "time" "github.com/google/uuid" "github.com/gorilla/mux" @@ -51,7 +52,8 @@ func ServeRPC(h http.Handler, id string, addr multiaddr.Multiaddr) (StopFunc, er // Instantiate the server and start listening. srv := &http.Server{ - Handler: h, + Handler: h, + ReadHeaderTimeout: 30 * time.Second, BaseContext: func(listener net.Listener) context.Context { ctx, _ := tag.New(context.Background(), tag.Upsert(metrics.APIInterface, id)) return ctx @@ -73,10 +75,12 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server m := mux.NewRouter() serveRpc := func(path string, hnd interface{}) { - rpcServer := jsonrpc.NewServer(append(opts, jsonrpc.WithServerErrors(api.RPCErrors))...) + rpcServer := jsonrpc.NewServer(append(opts, jsonrpc.WithReverseClient[api.EthSubscriberMethods]("Filecoin"), jsonrpc.WithServerErrors(api.RPCErrors))...) rpcServer.Register("Filecoin", hnd) rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover") + api.CreateEthRPCAliases(rpcServer) + var handler http.Handler = rpcServer if permissioned { handler = &auth.Handler{Verify: a.AuthVerify, Next: rpcServer.ServeHTTP} @@ -90,8 +94,9 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server fnapi = api.PermissionedFullAPI(fnapi) } + var v0 v0api.FullNode = &(struct{ v0api.FullNode }{&v0api.WrapperV1Full{FullNode: fnapi}}) serveRpc("/rpc/v1", fnapi) - serveRpc("/rpc/v0", &v0api.WrapperV1Full{FullNode: fnapi}) + serveRpc("/rpc/v0", v0) // Import handler handleImportFunc := handleImport(a.(*impl.FullNodeAPI)) @@ -103,7 +108,6 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server Next: handleImportFunc, } m.Handle("/rest/v0/import", importAH) - exportAH := &auth.Handler{ Verify: a.AuthVerify, Next: handleExportFunc, diff --git a/node/shutdown.go b/node/shutdown.go index e630031da..f44ca0857 100644 --- a/node/shutdown.go +++ b/node/shutdown.go @@ -51,6 +51,7 @@ func MonitorShutdown(triggerCh <-chan struct{}, handlers ...ShutdownHandler) <-c close(out) }() + signal.Reset(syscall.SIGTERM, syscall.SIGINT) signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT) return out } diff --git a/paychmgr/manager.go b/paychmgr/manager.go index fda9b101f..b1b6a7517 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -28,7 +28,7 @@ var errProofNotSupported = errors.New("payment channel proof parameter is not su // stateManagerAPI defines the methods needed from StateManager type stateManagerAPI interface { - ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) + ResolveToDeterministicAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) } diff --git a/paychmgr/mock_test.go b/paychmgr/mock_test.go index 739bae25a..5d36e60f0 100644 --- a/paychmgr/mock_test.go +++ b/paychmgr/mock_test.go @@ -63,7 +63,7 @@ func (sm *mockStateManager) setPaychState(a address.Address, actor *types.Actor, sm.paychState[a] = mockPchState{actor, state} } -func (sm *mockStateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { +func (sm *mockStateManager) ResolveToDeterministicAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { sm.lk.Lock() defer sm.lk.Unlock() keyAddr, ok := sm.accountState[addr] diff --git a/paychmgr/paych.go b/paychmgr/paych.go index c683aaadd..1eb496dba 100644 --- a/paychmgr/paych.go +++ b/paychmgr/paych.go @@ -211,7 +211,7 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add return nil, err } - from, err := ca.api.ResolveToKeyAddress(ctx, f, nil) + from, err := ca.api.ResolveToDeterministicAddress(ctx, f, nil) if err != nil { return nil, err } diff --git a/paychmgr/state.go b/paychmgr/state.go index 65963d2a0..0466d2d36 100644 --- a/paychmgr/state.go +++ b/paychmgr/state.go @@ -28,7 +28,7 @@ func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Ad if err != nil { return nil, err } - from, err := ca.sm.ResolveToKeyAddress(ctx, f, nil) + from, err := ca.sm.ResolveToDeterministicAddress(ctx, f, nil) if err != nil { return nil, err } @@ -36,7 +36,7 @@ func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Ad if err != nil { return nil, err } - to, err := ca.sm.ResolveToKeyAddress(ctx, t, nil) + to, err := ca.sm.ResolveToDeterministicAddress(ctx, t, nil) if err != nil { return nil, err } diff --git a/scripts/build-arch-bundle.sh b/scripts/build-arch-bundle.sh deleted file mode 100755 index 27b4218f5..000000000 --- a/scripts/build-arch-bundle.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash -set -ex - -ARCH=$1 - -REQUIRED=( - "ipfs" - "sha512sum" -) -for REQUIRE in "${REQUIRED[@]}" -do - command -v "${REQUIRE}" >/dev/null 2>&1 || echo >&2 "'${REQUIRE}' must be installed" -done - -mkdir bundle -pushd bundle - -BINARIES=( - "lotus" - "lotus-miner" - "lotus-worker" -) - -export IPFS_PATH=`mktemp -d` -ipfs init -ipfs daemon & -PID="$!" -trap "kill -9 ${PID}" EXIT -sleep 30 - -mkdir -p "${ARCH}/lotus" -pushd "${ARCH}" -for BINARY in "${BINARIES[@]}" -do - cp "../../${ARCH}/${BINARY}" "lotus/" - chmod +x "lotus/${BINARY}" -done - -tar -zcvf "../lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz" lotus -popd -rm -rf "${ARCH}" - -sha512sum "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz" > "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz.sha512" - -ipfs add -q "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz" > "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz.cid" -popd diff --git a/scripts/docker-git-state-check.sh b/scripts/docker-git-state-check.sh new file mode 100755 index 000000000..6075ebf84 --- /dev/null +++ b/scripts/docker-git-state-check.sh @@ -0,0 +1,12 @@ +set -e + +if [ -z "$(git status --porcelain)" ]; then + echo "PASSED: Working directory clean" +else + echo "FAILED: Working directory not clean." + echo "This is likely because the .dockerignore file has removed something checked into git." + echo "Add the missing files listed below to the .dockerignore to fix this issue:" + echo "$(git status)" + exit 1 +fi + diff --git a/scripts/generate-lotus-cli.py b/scripts/generate-lotus-cli.py index 7999603b2..b0d3fd19d 100644 --- a/scripts/generate-lotus-cli.py +++ b/scripts/generate-lotus-cli.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # Generate lotus command lines documents as text and markdown in folder "lotus/documentation/en". -# Python 2.7 +# Python 3 import os diff --git a/scripts/publish-arch-release.sh b/scripts/publish-arch-release.sh deleted file mode 100755 index b47ad53fe..000000000 --- a/scripts/publish-arch-release.sh +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env bash -set -e - -ARCH=$1 - -pushd bundle - -# make sure we have a token set, api requests won't work otherwise -if [ -z "${GITHUB_TOKEN}" ]; then - echo "\${GITHUB_TOKEN} not set, publish failed" - exit 1 -fi - -REQUIRED=( - "jq" - "curl" -) -for REQUIRE in "${REQUIRED[@]}" -do - command -v "${REQUIRE}" >/dev/null 2>&1 || echo >&2 "'${REQUIRE}' must be installed" -done - -#see if the release already exists by tag -RELEASE_RESPONSE=` - curl \ - --header "Authorization: token ${GITHUB_TOKEN}" \ - "https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/releases/tags/${CIRCLE_TAG}" -` -RELEASE_ID=`echo "${RELEASE_RESPONSE}" | jq '.id'` - -if [ "${RELEASE_ID}" = "null" ]; then - echo "creating release" - - COND_CREATE_DISCUSSION="" - PRERELEASE=true - if [[ ${CIRCLE_TAG} =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - COND_CREATE_DISCUSSION="\"discussion_category_name\": \"announcement\"," - PRERELEASE=false - fi - - RELEASE_DATA="{ - \"tag_name\": \"${CIRCLE_TAG}\", - \"target_commitish\": \"${CIRCLE_SHA1}\", - ${COND_CREATE_DISCUSSION} - \"name\": \"${CIRCLE_TAG}\", - \"body\": \"\", - \"prerelease\": ${PRERELEASE} - }" - - # create it if it doesn't exist yet - RELEASE_RESPONSE=` - curl \ - --request POST \ - --header "Authorization: token ${GITHUB_TOKEN}" \ - --header "Content-Type: application/json" \ - --data "${RELEASE_DATA}" \ - "https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/${CIRCLE_PROJECT_REPONAME}/releases" - ` -else - echo "release already exists" -fi - -RELEASE_UPLOAD_URL=`echo "${RELEASE_RESPONSE}" | jq -r '.upload_url' | cut -d'{' -f1` -echo "Preparing to send artifacts to ${RELEASE_UPLOAD_URL}" - -if [ $ARCH = 'linux' ]; then -artifacts=( - "lotus_${CIRCLE_TAG}_linux-amd64.tar.gz" - "lotus_${CIRCLE_TAG}_linux-amd64.tar.gz.cid" - "lotus_${CIRCLE_TAG}_linux-amd64.tar.gz.sha512" -) -elif [ $ARCH = 'darwin' ]; then -artifacts=( - "lotus_${CIRCLE_TAG}_darwin-amd64.tar.gz" - "lotus_${CIRCLE_TAG}_darwin-amd64.tar.gz.cid" - "lotus_${CIRCLE_TAG}_darwin-amd64.tar.gz.sha512" -) -elif [ $ARCH = 'appimage' ]; then -artifacts=( - "Lotus-${CIRCLE_TAG}-x86_64.AppImage" - "Lotus-${CIRCLE_TAG}-x86_64.AppImage.cid" - "Lotus-${CIRCLE_TAG}-x86_64.AppImage.sha512" -) -else - echo "$1 is not a supported architecture to publish a release for" 1>&2 - exit 1 -fi - -for RELEASE_FILE in "${artifacts[@]}" -do - echo "Uploading ${RELEASE_FILE}..." - curl \ - --request POST \ - --fail \ - --header "Authorization: token ${GITHUB_TOKEN}" \ - --header "Content-Type: application/octet-stream" \ - --data-binary "@${RELEASE_FILE}" \ - "$RELEASE_UPLOAD_URL?name=$(basename "${RELEASE_FILE}")" - - echo "Uploaded ${RELEASE_FILE}" -done - -popd - -miscellaneous=( - "README.md" - "LICENSE-MIT" - "LICENSE-APACHE" -) -for MISC in "${miscellaneous[@]}" -do - echo "Uploading release bundle: ${MISC}" - curl \ - --request POST \ - --header "Authorization: token ${GITHUB_TOKEN}" \ - --header "Content-Type: application/octet-stream" \ - --data-binary "@${MISC}" \ - "$RELEASE_UPLOAD_URL?name=$(basename "${MISC}")" - - echo "Release bundle uploaded: ${MISC}" -done diff --git a/snap/local/icon.svg b/snap/local/icon.svg deleted file mode 100644 index da992296a..000000000 --- a/snap/local/icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml deleted file mode 100644 index 8c7323a2b..000000000 --- a/snap/snapcraft.yaml +++ /dev/null @@ -1,96 +0,0 @@ -name: lotus-filecoin -base: core20 -version: latest -summary: filecoin daemon/client -icon: snap/local/icon.svg -description: | - Filecoin is a peer-to-peer network that stores files on the internet - with built-in economic incentives to ensure files are stored reliably over time - - For documentation and additional information, please see the following resources - - https://filecoin.io - - https://fil.org - - https://lotus.filecoin.io - - https://github.com/filecoin-project/lotus - -confinement: strict - -parts: - lotus: - plugin: make - source: ./ - build-snaps: - - go - - rustup - build-packages: - - git - - jq - - libhwloc-dev - - ocl-icd-opencl-dev - - pkg-config - stage-packages: - - libhwloc15 - - ocl-icd-libopencl1 - override-build: | - LDFLAGS="" make lotus lotus-miner lotus-worker - cp lotus lotus-miner lotus-worker $SNAPCRAFT_PART_INSTALL - cp scripts/snap-lotus-entrypoint.sh $SNAPCRAFT_PART_INSTALL - -layout: - /var/lib/lotus: - symlink: $SNAP_COMMON/lotus - /var/lib/lotus-miner: - symlink: $SNAP_COMMON/lotus-miner - /var/lib/lotus-worker: - symlink: $SNAP_COMMON/lotus-worker - -apps: - lotus: - command: lotus - plugs: - - network - - network-bind - - home - environment: - FIL_PROOFS_PARAMETER_CACHE: $SNAP_USER_COMMON/filecoin-proof-parameters - LOTUS_PATH: $SNAP_COMMON/lotus - LOTUS_MINER_PATH: $SNAP_COMMON/lotus-miner - LOTUS_WORKER_PATH: $SNAP_COMMON/lotus-worker - lotus-miner: - command: lotus-miner - plugs: - - network - - network-bind - - opengl - environment: - FIL_PROOFS_PARAMETER_CACHE: $SNAP_USER_COMMON/filecoin-proof-parameters - LOTUS_PATH: $SNAP_COMMON/lotus - LOTUS_MINER_PATH: $SNAP_COMMON/lotus-miner - LOTUS_WORKER_PATH: $SNAP_COMMON/lotus-worker - lotus-worker: - command: lotus-worker - plugs: - - network - - network-bind - - opengl - environment: - FIL_PROOFS_PARAMETER_CACHE: $SNAP_USER_COMMON/filecoin-proof-parameters - LOTUS_PATH: $SNAP_COMMON/lotus - LOTUS_MINER_PATH: $SNAP_COMMON/lotus-miner - LOTUS_WORKER_PATH: $SNAP_COMMON/lotus-worker - lotus-daemon: - command: snap-lotus-entrypoint.sh - daemon: simple - install-mode: disable - plugs: - - network - - network-bind - environment: - FIL_PROOFS_PARAMETER_CACHE: $SNAP_COMMON/filecoin-proof-parameters - LOTUS_PATH: $SNAP_COMMON/lotus - LOTUS_MINER_PATH: $SNAP_COMMON/lotus-miner - LOTUS_WORKER_PATH: $SNAP_COMMON/lotus-worker diff --git a/storage/paths/index.go b/storage/paths/index.go index ba387a3f7..ce11eec9c 100644 --- a/storage/paths/index.go +++ b/storage/paths/index.go @@ -324,7 +324,11 @@ func (i *Index) StorageReportHealth(ctx context.Context, id storiface.ID, report ent.lastHeartbeat = time.Now() if report.Stat.Capacity > 0 { - ctx, _ = tag.New(ctx, tag.Upsert(metrics.StorageID, string(id))) + ctx, _ = tag.New(ctx, + tag.Upsert(metrics.StorageID, string(id)), + tag.Upsert(metrics.PathStorage, fmt.Sprint(ent.info.CanStore)), + tag.Upsert(metrics.PathSeal, fmt.Sprint(ent.info.CanSeal)), + ) stats.Record(ctx, metrics.StorageFSAvailable.M(float64(report.Stat.FSAvailable)/float64(report.Stat.Capacity))) stats.Record(ctx, metrics.StorageAvailable.M(float64(report.Stat.Available)/float64(report.Stat.Capacity))) diff --git a/storage/pipeline/states_failed.go b/storage/pipeline/states_failed.go index 942f4f8dc..d952d8eda 100644 --- a/storage/pipeline/states_failed.go +++ b/storage/pipeline/states_failed.go @@ -17,6 +17,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/storage/sealer/storiface" ) var MinRetryTime = 1 * time.Minute @@ -425,16 +426,19 @@ func (m *Sealing) handleAbortUpgrade(ctx statemachine.Context, sector SectorInfo m.cleanupAssignedDeals(sector) // Remove snap deals replica if any + // This removes update / update-cache from all storage if err := m.sealer.ReleaseReplicaUpgrade(ctx.Context(), m.minerSector(sector.SectorType, sector.SectorNumber)); err != nil { return xerrors.Errorf("removing CC update files from sector storage") } - cfg, err := m.getConfig() - if err != nil { - return xerrors.Errorf("getting sealing config: %w", err) + // This removes the unsealed file from all storage + // note: we're not keeping anything unsealed because we're reverting to CC + if err := m.sealer.ReleaseUnsealed(ctx.Context(), m.minerSector(sector.SectorType, sector.SectorNumber), []storiface.Range{}); err != nil { + log.Error(err) } - if err := m.sealer.ReleaseUnsealed(ctx.Context(), m.minerSector(sector.SectorType, sector.SectorNumber), sector.keepUnsealedRanges(sector.CCPieces, true, cfg.AlwaysKeepUnsealedCopy)); err != nil { + // and makes sure sealed/cache files only exist in long-term-storage + if err := m.sealer.FinalizeSector(ctx.Context(), m.minerSector(sector.SectorType, sector.SectorNumber)); err != nil { log.Error(err) } diff --git a/storage/pipeline/states_replica_update.go b/storage/pipeline/states_replica_update.go index 6a4708379..e1b9cfc30 100644 --- a/storage/pipeline/states_replica_update.go +++ b/storage/pipeline/states_replica_update.go @@ -143,6 +143,10 @@ func (m *Sealing) handleSubmitReplicaUpdate(ctx statemachine.Context, sector Sec log.Errorf("handleSubmitReplicaUpdate: api error, not proceeding: %+v", err) return nil } + if onChainInfo == nil { + return xerrors.Errorf("sector not found %d", sector.SectorNumber) + } + sp, err := m.currentSealProof(ctx.Context()) if err != nil { log.Errorf("sealer failed to return current seal proof not proceeding: %+v", err) @@ -305,7 +309,11 @@ func (m *Sealing) handleFinalizeReplicaUpdate(ctx statemachine.Context, sector S return xerrors.Errorf("getting sealing config: %w", err) } - if err := m.sealer.FinalizeReplicaUpdate(sector.sealingCtx(ctx.Context()), m.minerSector(sector.SectorType, sector.SectorNumber), sector.keepUnsealedRanges(sector.Pieces, false, cfg.AlwaysKeepUnsealedCopy)); err != nil { + if err := m.sealer.ReleaseUnsealed(ctx.Context(), m.minerSector(sector.SectorType, sector.SectorNumber), sector.keepUnsealedRanges(sector.Pieces, false, cfg.AlwaysKeepUnsealedCopy)); err != nil { + return ctx.Send(SectorFinalizeFailed{xerrors.Errorf("release unsealed: %w", err)}) + } + + if err := m.sealer.FinalizeReplicaUpdate(sector.sealingCtx(ctx.Context()), m.minerSector(sector.SectorType, sector.SectorNumber)); err != nil { return ctx.Send(SectorFinalizeFailed{xerrors.Errorf("finalize sector: %w", err)}) } @@ -335,7 +343,7 @@ func (m *Sealing) handleUpdateActivating(ctx statemachine.Context, sector Sector lb := policy.GetWinningPoStSectorSetLookback(nv) - targetHeight := mw.Height + lb + InteractivePoRepConfidence + targetHeight := mw.Height + lb return m.events.ChainAt(context.Background(), func(context.Context, *types.TipSet, abi.ChainEpoch) error { return ctx.Send(SectorUpdateActive{}) diff --git a/storage/pipeline/states_sealing.go b/storage/pipeline/states_sealing.go index 5b5d2e372..0608ead07 100644 --- a/storage/pipeline/states_sealing.go +++ b/storage/pipeline/states_sealing.go @@ -862,7 +862,11 @@ func (m *Sealing) handleFinalizeSector(ctx statemachine.Context, sector SectorIn return xerrors.Errorf("getting sealing config: %w", err) } - if err := m.sealer.FinalizeSector(sector.sealingCtx(ctx.Context()), m.minerSector(sector.SectorType, sector.SectorNumber), sector.keepUnsealedRanges(sector.Pieces, false, cfg.AlwaysKeepUnsealedCopy)); err != nil { + if err := m.sealer.ReleaseUnsealed(ctx.Context(), m.minerSector(sector.SectorType, sector.SectorNumber), sector.keepUnsealedRanges(sector.Pieces, false, cfg.AlwaysKeepUnsealedCopy)); err != nil { + return ctx.Send(SectorFinalizeFailed{xerrors.Errorf("release unsealed: %w", err)}) + } + + if err := m.sealer.FinalizeSector(sector.sealingCtx(ctx.Context()), m.minerSector(sector.SectorType, sector.SectorNumber)); err != nil { return ctx.Send(SectorFinalizeFailed{xerrors.Errorf("finalize sector: %w", err)}) } diff --git a/storage/pipeline/upgrade_queue.go b/storage/pipeline/upgrade_queue.go index 309e59573..9d9e1ca46 100644 --- a/storage/pipeline/upgrade_queue.go +++ b/storage/pipeline/upgrade_queue.go @@ -33,6 +33,9 @@ func (m *Sealing) MarkForUpgrade(ctx context.Context, id abi.SectorNumber) error if err != nil { return xerrors.Errorf("failed to read sector on chain info: %w", err) } + if onChainInfo == nil { + return xerrors.Errorf("sector not found %d", id) + } active, err := m.sectorActive(ctx, ts.Key(), id) if err != nil { diff --git a/storage/sealer/README.md b/storage/sealer/README.md index a4661f9d8..83fa3ea5f 100644 --- a/storage/sealer/README.md +++ b/storage/sealer/README.md @@ -21,16 +21,15 @@ Please report your issues with regards to sector-storage at the [lotus issue tra Manages is the top-level piece of the storage system gluing all the other pieces together. It also implements scheduling logic. -### `package stores` +### `package paths` This package implements the sector storage subsystem. Fundamentally the storage is divided into `path`s, each path has it's UUID, and stores a set of sector -'files'. There are currently 3 types of sector files - `unsealed`, `sealed`, -and `cache`. +'files'. There are currently 5 types of sector files - `unsealed`, `sealed`, `cache`, `update` and `update-cache`. Paths can be shared between nodes by sharing the underlying filesystem. -### `stores.Local` +### `paths.Local` The Local store implements SectorProvider for paths mounted in the local filesystem. Paths can be shared between nodes, and support shared filesystems @@ -38,12 +37,12 @@ such as NFS. stores.Local implements all native filesystem-related operations -### `stores.Remote` +### `paths.Remote` The Remote store extends Local store, handles fetching sector files into a local store if needed, and handles removing sectors from non-local stores. -### `stores.Index` +### `paths.Index` The Index is a singleton holding metadata about storage paths, and a mapping of sector files to paths diff --git a/storage/sealer/docs/sector-storage.svg b/storage/sealer/docs/sector-storage.svg index 3978ef2f8..0e2ed27a7 100644 --- a/storage/sealer/docs/sector-storage.svg +++ b/storage/sealer/docs/sector-storage.svg @@ -1,3 +1,4 @@ + -
LocalWorker
LocalWorker
stores.Local
stores.Local
stores.Store
stores.Store
stores.SectorIndex
stores.SectorInd...
ffiwrapper.Sealer
ffiwrapper.Seal...
SectorProvider
SectorProvider
localProvider
localProvider
Worker
Worker
stores.Remote
stores.Remote
stores.Local
stores.Local
stores.SectorIndex
stores.SectorInd...
localPaths []string
localPaths []str...
urls []string
urls []stri...
stores.SectorIndex
stores.SectorInd...
specs-storage.Prover
specs-storage.Prover
ronlyProvider
ronlyProvider
stores.Index
stores.Index
FetchHandler
FetchHandler
ffiwrapper.Sealer
ffiwrapper.Seal...
SectorProvider
SectorProvider
specs-storage.[Sealer,Storage]
specs-storage.[Sealer,Storage]
specs-storage.Prover
specs-storage.Prover
Manager API
Manager API
Scheduler
Scheduler
[]workerHandle
[]workerHandle
Worker
Worker
WorkerInfo
Worker...
resourceInfo
resourceInfo
schedQueue
schedQueue
stores.SectorIndex
stores.SectorInd...
sector-storage.Manager
sector-storage.Manager
worker management APIs
worker management APIs
Filecoin 'Miner' Node
Filecoin 'Miner' Node
HTTP API
HTTP API
/remote
/remote
JsonRPC
JsonRPC
/rpc/v0
/rpc/v0
LocalWorker
LocalWorker
stores.Local
stores.Local
stores.Store
stores.Store
stores.SectorIndex
stores.SectorInd...
ffiwrapper.Sealer
ffiwrapper.Seal...
SectorProvider
SectorProvider
localProvider
localProvider
Worker
Worker
stores.Remote
stores.Remote
stores.Local
stores.Local
stores.SectorIndex
stores.SectorInd...
localPaths []string
localPaths []str...
urls []string
urls []stri...
stores.SectorIndex
stores.SectorInd...
Miner JsonRPC client
Miner JsonRPC client
miner.Register(remoteWorker)
miner.Register(remoteWorker)
HTTP API
HTTP API
FetchHandler
FetchHandler
/remote
/remote
RemoteWorker
RemoteWorker
/rpc/v0
/rpc/v0
JsonRPC
JsonRPC
Seal Worker Node
Seal Worker Node
Viewer does not support full SVG 1.1
\ No newline at end of file +
LocalWorker
LocalWorker
paths.Local
paths.Local
paths.Store
paths.Store
paths.SectorIndex
paths.SectorIndex
ffiwrapper.Sealer
ffiwrapper.Seal...
SectorProvider
SectorProvider
localProvider
localProvider
Worker
Worker
paths.Remote
paths.Remote
paths.Local
paths.Local
paths.SectorIndex
paths.SectorIndex
localPaths []string
localPaths []str...
urls []string
urls []stri...
paths.SectorIndex
paths.SectorIndex
storiface.Prover
storiface.Prover
ronlyProvider
ronlyProvider
paths.Index
paths.Index
FetchHandler
FetchHandler
ffiwrapper.Sealer
ffiwrapper.Seal...
SectorProvider
SectorProvider
storiface.[Sealer,Storage]
storiface.[Sealer,Storage]
storiface.Prover
storiface.Prover
Manager API
Manager API
Scheduler
Scheduler
[]workerHandle
[]workerHandle
Worker
Worker
WorkerInfo
Worker...
resourceInfo
resourceInfo
schedQueue
schedQueue
paths.SectorIndex
paths.SectorIndex
sealer.Manager
sealer.Manager
worker management APIs
worker management APIs
'Lotus-Miner' Node
'Lotus-Miner' Node
HTTP API
HTTP API
/remote
/remote
JsonRPC
JsonRPC
/rpc/v0
/rpc/v0
LocalWorker
LocalWorker
paths.Local
paths.Local
paths.Store
paths.Store
paths.SectorIndex
paths.SectorIndex
ffiwrapper.Sealer
ffiwrapper.Seal...
SectorProvider
SectorProvider
localProvider
localProvider
Worker
Worker
paths.Remote
paths.Remote
paths.Local
paths.Local
paths.SectorIndex
paths.SectorIndex
localPaths []string
localPaths []str...
urls []string
urls []stri...
paths.SectorIndex
paths.SectorIndex
Miner JsonRPC client
Miner JsonRPC client
miner.Register(remoteWorker)
miner.Register(remoteWorker)
HTTP API
HTTP API
FetchHandler
FetchHandler
/remote
/remote
RemoteWorker
RemoteWorker
/rpc/v0
/rpc/v0
JsonRPC
JsonRPC
'Lotus-Worker' node
'Lotus-Worker' node
Text is not SVG - cannot display
\ No newline at end of file diff --git a/storage/sealer/ffiwrapper/sealer_cgo.go b/storage/sealer/ffiwrapper/sealer_cgo.go index 67d519259..e9ce5746e 100644 --- a/storage/sealer/ffiwrapper/sealer_cgo.go +++ b/storage/sealer/ffiwrapper/sealer_cgo.go @@ -405,7 +405,7 @@ func (sb *Sealer) pieceCid(spt abi.RegisteredSealProof, in []byte) (cid.Cid, err } func (sb *Sealer) tryDecodeUpdatedReplica(ctx context.Context, sector storiface.SectorRef, commD cid.Cid, unsealedPath string, randomness abi.SealRandomness) (bool, error) { - replicaPath, done, err := sb.sectors.AcquireSector(ctx, sector, storiface.FTUpdate|storiface.FTUpdateCache, storiface.FTNone, storiface.PathStorage) + replicaPath, done, err := sb.sectors.AcquireSector(ctx, sector, storiface.FTUpdate|storiface.FTUpdateCache, storiface.FTNone, storiface.PathSealing) if xerrors.Is(err, storiface.ErrSectorNotFound) { return false, nil } else if err != nil { @@ -464,12 +464,12 @@ func (sb *Sealer) UnsealPiece(ctx context.Context, sector storiface.SectorRef, o maxPieceSize := abi.PaddedPieceSize(ssize) // try finding existing - unsealedPath, done, err := sb.sectors.AcquireSector(ctx, sector, storiface.FTUnsealed, storiface.FTNone, storiface.PathStorage) + unsealedPath, done, err := sb.sectors.AcquireSector(ctx, sector, storiface.FTUnsealed, storiface.FTNone, storiface.PathSealing) var pf *partialfile.PartialFile switch { case xerrors.Is(err, storiface.ErrSectorNotFound): - unsealedPath, done, err = sb.sectors.AcquireSector(ctx, sector, storiface.FTNone, storiface.FTUnsealed, storiface.PathStorage) + unsealedPath, done, err = sb.sectors.AcquireSector(ctx, sector, storiface.FTNone, storiface.FTUnsealed, storiface.PathSealing) if err != nil { return xerrors.Errorf("acquire unsealed sector path (allocate): %w", err) } @@ -516,7 +516,7 @@ func (sb *Sealer) UnsealPiece(ctx context.Context, sector storiface.SectorRef, o } // Piece data sealed in sector - srcPaths, srcDone, err := sb.sectors.AcquireSector(ctx, sector, storiface.FTCache|storiface.FTSealed, storiface.FTNone, storiface.PathStorage) + srcPaths, srcDone, err := sb.sectors.AcquireSector(ctx, sector, storiface.FTCache|storiface.FTSealed, storiface.FTNone, storiface.PathSealing) if err != nil { return xerrors.Errorf("acquire sealed sector paths: %w", err) } @@ -999,7 +999,7 @@ func (sb *Sealer) ReleaseSealed(ctx context.Context, sector storiface.SectorRef) return xerrors.Errorf("not supported at this layer") } -func (sb *Sealer) freeUnsealed(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) error { +func (sb *Sealer) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) error { ssize, err := sector.ProofType.SectorSize() if err != nil { return err @@ -1067,16 +1067,12 @@ func (sb *Sealer) freeUnsealed(ctx context.Context, sector storiface.SectorRef, return nil } -func (sb *Sealer) FinalizeSector(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) error { +func (sb *Sealer) FinalizeSector(ctx context.Context, sector storiface.SectorRef) error { ssize, err := sector.ProofType.SectorSize() if err != nil { return err } - if err := sb.freeUnsealed(ctx, sector, keepUnsealed); err != nil { - return err - } - paths, done, err := sb.sectors.AcquireSector(ctx, sector, storiface.FTCache, 0, storiface.PathStorage) if err != nil { return xerrors.Errorf("acquiring sector cache path: %w", err) @@ -1124,16 +1120,12 @@ func (sb *Sealer) FinalizeSectorInto(ctx context.Context, sector storiface.Secto return ffi.ClearCache(uint64(ssize), dest) } -func (sb *Sealer) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) error { +func (sb *Sealer) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef) error { ssize, err := sector.ProofType.SectorSize() if err != nil { return err } - if err := sb.freeUnsealed(ctx, sector, keepUnsealed); err != nil { - return err - } - { paths, done, err := sb.sectors.AcquireSector(ctx, sector, storiface.FTCache, 0, storiface.PathStorage) if err != nil { @@ -1161,16 +1153,6 @@ func (sb *Sealer) FinalizeReplicaUpdate(ctx context.Context, sector storiface.Se return nil } -func (sb *Sealer) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, safeToFree []storiface.Range) error { - // This call is meant to mark storage as 'freeable'. Given that unsealing is - // very expensive, we don't remove data as soon as we can - instead we only - // do that when we don't have free space for data that really needs it - - // This function should not be called at this layer, everything should be - // handled in localworker - return xerrors.Errorf("not supported at this layer") -} - func (sb *Sealer) ReleaseReplicaUpgrade(ctx context.Context, sector storiface.SectorRef) error { return xerrors.Errorf("not supported at this layer") } diff --git a/storage/sealer/ffiwrapper/sealer_test.go b/storage/sealer/ffiwrapper/sealer_test.go index 654caf784..dd0c1e184 100644 --- a/storage/sealer/ffiwrapper/sealer_test.go +++ b/storage/sealer/ffiwrapper/sealer_test.go @@ -327,7 +327,7 @@ func TestSealAndVerify(t *testing.T) { post(t, sb, nil, s) - if err := sb.FinalizeSector(context.TODO(), si, nil); err != nil { + if err := sb.FinalizeSector(context.TODO(), si); err != nil { t.Fatalf("%+v", err) } @@ -390,7 +390,7 @@ func TestSealPoStNoCommit(t *testing.T) { precommit := time.Now() - if err := sb.FinalizeSector(context.TODO(), si, nil); err != nil { + if err := sb.FinalizeSector(context.TODO(), si); err != nil { t.Fatal(err) } diff --git a/storage/sealer/manager.go b/storage/sealer/manager.go index b0f506539..336664ca8 100644 --- a/storage/sealer/manager.go +++ b/storage/sealer/manager.go @@ -105,7 +105,7 @@ func New(ctx context.Context, lstor *paths.Local, stor paths.Store, ls paths.Loc return nil, xerrors.Errorf("creating prover instance: %w", err) } - sh, err := newScheduler(sc.Assigner) + sh, err := newScheduler(ctx, sc.Assigner) if err != nil { return nil, err } @@ -142,7 +142,7 @@ func New(ctx context.Context, lstor *paths.Local, stor paths.Store, ls paths.Loc go m.sched.runSched() localTasks := []sealtasks.TaskType{ - sealtasks.TTCommit1, sealtasks.TTProveReplicaUpdate1, sealtasks.TTFinalize, sealtasks.TTFetch, sealtasks.TTFinalizeReplicaUpdate, + sealtasks.TTCommit1, sealtasks.TTProveReplicaUpdate1, sealtasks.TTFinalize, sealtasks.TTFetch, sealtasks.TTFinalizeUnsealed, sealtasks.TTFinalizeReplicaUpdate, } if sc.AllowSectorDownload { localTasks = append(localTasks, sealtasks.TTDownloadSector) @@ -358,6 +358,21 @@ func (m *Manager) SectorsUnsealPiece(ctx context.Context, sector storiface.Secto return xerrors.Errorf("worker UnsealPiece call: %s", err) } + // get a selector for moving unsealed sector into long-term storage + fetchSel := newMoveSelector(m.index, sector.ID, storiface.FTUnsealed, storiface.PathStorage, !m.disallowRemoteFinalize) + + // move unsealed sector to long-term storage + // Possible TODO: Add an option to not keep the unsealed sector in long term storage? + err = m.sched.Schedule(ctx, sector, sealtasks.TTFetch, fetchSel, + m.schedFetch(sector, storiface.FTUnsealed, storiface.PathStorage, storiface.AcquireMove), + func(ctx context.Context, w Worker) error { + _, err := m.waitSimpleCall(ctx)(w.MoveStorage(ctx, sector, storiface.FTUnsealed)) + return err + }) + if err != nil { + return xerrors.Errorf("moving unsealed sector to long term storage: %w", err) + } + return nil } @@ -613,7 +628,27 @@ func (m *Manager) SealCommit2(ctx context.Context, sector storiface.SectorRef, p return out, waitErr } -func (m *Manager) FinalizeSector(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) error { +// sectorStorageType tries to figure out storage type for a given sector; expects only a single copy of the file in the +// storage system +func (m *Manager) sectorStorageType(ctx context.Context, sector storiface.SectorRef, ft storiface.SectorFileType) (sectorFound bool, ptype storiface.PathType, err error) { + stores, err := m.index.StorageFindSector(ctx, sector.ID, ft, 0, false) + if err != nil { + return false, "", xerrors.Errorf("finding sector: %w", err) + } + if len(stores) == 0 { + return false, "", nil + } + + for _, store := range stores { + if store.CanSeal { + return true, storiface.PathSealing, nil + } + } + + return true, storiface.PathStorage, nil +} + +func (m *Manager) FinalizeSector(ctx context.Context, sector storiface.SectorRef) error { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -621,44 +656,38 @@ func (m *Manager) FinalizeSector(ctx context.Context, sector storiface.SectorRef return xerrors.Errorf("acquiring sector lock: %w", err) } - // first check if the unsealed file exists anywhere; If it doesn't ignore it - unsealed := storiface.FTUnsealed - { - unsealedStores, err := m.index.StorageFindSector(ctx, sector.ID, storiface.FTUnsealed, 0, false) - if err != nil { - return xerrors.Errorf("finding unsealed sector: %w", err) - } + /* + We want to: + - Trim cache + - Move stuff to long-term storage + */ - if len(unsealedStores) == 0 { // Is some edge-cases unsealed sector may not exist already, that's fine - unsealed = storiface.FTNone - } + // remove redundant copies if there are any + if err := m.storage.RemoveCopies(ctx, sector.ID, storiface.FTUnsealed); err != nil { + return xerrors.Errorf("remove copies (sealed): %w", err) + } + if err := m.storage.RemoveCopies(ctx, sector.ID, storiface.FTSealed); err != nil { + return xerrors.Errorf("remove copies (sealed): %w", err) + } + if err := m.storage.RemoveCopies(ctx, sector.ID, storiface.FTCache); err != nil { + return xerrors.Errorf("remove copies (cache): %w", err) } - // Make sure that the sealed file is still in sealing storage; In case it already - // isn't, we want to do finalize in long-term storage - pathType := storiface.PathStorage - { - sealedStores, err := m.index.StorageFindSector(ctx, sector.ID, storiface.FTSealed, 0, false) - if err != nil { - return xerrors.Errorf("finding sealed sector: %w", err) - } - - for _, store := range sealedStores { - if store.CanSeal { - pathType = storiface.PathSealing - break - } - } + // Make sure that the cache files are still in sealing storage; In case not, + // we want to do finalize in long-term storage + _, cachePathType, err := m.sectorStorageType(ctx, sector, storiface.FTCache) + if err != nil { + return xerrors.Errorf("checking cache storage type: %w", err) } // do the cache trimming wherever the likely still very large cache lives. // we really don't want to move it. selector := newExistingSelector(m.index, sector.ID, storiface.FTCache, false) - err := m.sched.Schedule(ctx, sector, sealtasks.TTFinalize, selector, - m.schedFetch(sector, storiface.FTCache|unsealed, pathType, storiface.AcquireMove), + err = m.sched.Schedule(ctx, sector, sealtasks.TTFinalize, selector, + m.schedFetch(sector, storiface.FTCache, cachePathType, storiface.AcquireMove), func(ctx context.Context, w Worker) error { - _, err := m.waitSimpleCall(ctx)(w.FinalizeSector(ctx, sector, keepUnsealed)) + _, err := m.waitSimpleCall(ctx)(w.FinalizeSector(ctx, sector)) return err }) if err != nil { @@ -669,9 +698,14 @@ func (m *Manager) FinalizeSector(ctx context.Context, sector storiface.SectorRef fetchSel := newMoveSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, storiface.PathStorage, !m.disallowRemoteFinalize) // only move the unsealed file if it still exists and needs moving - moveUnsealed := unsealed + moveUnsealed := storiface.FTUnsealed { - if len(keepUnsealed) == 0 { + found, unsealedPathType, err := m.sectorStorageType(ctx, sector, storiface.FTUnsealed) + if err != nil { + return xerrors.Errorf("checking cache storage type: %w", err) + } + + if !found || unsealedPathType == storiface.PathStorage { moveUnsealed = storiface.FTNone } } @@ -690,7 +724,7 @@ func (m *Manager) FinalizeSector(ctx context.Context, sector storiface.SectorRef return nil } -func (m *Manager) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) error { +func (m *Manager) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef) error { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -698,19 +732,6 @@ func (m *Manager) FinalizeReplicaUpdate(ctx context.Context, sector storiface.Se return xerrors.Errorf("acquiring sector lock: %w", err) } - // first check if the unsealed file exists anywhere; If it doesn't ignore it - moveUnsealed := storiface.FTUnsealed - { - unsealedStores, err := m.index.StorageFindSector(ctx, sector.ID, storiface.FTUnsealed, 0, false) - if err != nil { - return xerrors.Errorf("finding unsealed sector: %w", err) - } - - if len(unsealedStores) == 0 { // Is some edge-cases unsealed sector may not exist already, that's fine - moveUnsealed = storiface.FTNone - } - } - // Make sure that the update file is still in sealing storage; In case it already // isn't, we want to do finalize in long-term storage pathType := storiface.PathStorage @@ -733,9 +754,9 @@ func (m *Manager) FinalizeReplicaUpdate(ctx context.Context, sector storiface.Se selector := newExistingSelector(m.index, sector.ID, storiface.FTUpdateCache, false) err := m.sched.Schedule(ctx, sector, sealtasks.TTFinalizeReplicaUpdate, selector, - m.schedFetch(sector, storiface.FTCache|storiface.FTUpdateCache|moveUnsealed, pathType, storiface.AcquireMove), + m.schedFetch(sector, storiface.FTCache|storiface.FTUpdateCache, pathType, storiface.AcquireMove), func(ctx context.Context, w Worker) error { - _, err := m.waitSimpleCall(ctx)(w.FinalizeReplicaUpdate(ctx, sector, keepUnsealed)) + _, err := m.waitSimpleCall(ctx)(w.FinalizeReplicaUpdate(ctx, sector)) return err }) if err != nil { @@ -760,9 +781,15 @@ func (m *Manager) FinalizeReplicaUpdate(ctx context.Context, sector storiface.Se err = multierr.Append(move(storiface.FTUpdate|storiface.FTUpdateCache), move(storiface.FTCache)) err = multierr.Append(err, move(storiface.FTSealed)) // Sealed separate from cache just in case ReleaseSectorKey was already called - // if we found unsealed files, AND have been asked to keep at least one, move unsealed - if moveUnsealed != storiface.FTNone && len(keepUnsealed) != 0 { - err = multierr.Append(err, move(moveUnsealed)) + + { + unsealedStores, ferr := m.index.StorageFindSector(ctx, sector.ID, storiface.FTUnsealed, 0, false) + if err != nil { + err = multierr.Append(err, xerrors.Errorf("find unsealed sector before move: %w", ferr)) + } else if len(unsealedStores) > 0 { + // if we found unsealed files, AND have been asked to keep at least one piece, move unsealed + err = multierr.Append(err, move(storiface.FTUnsealed)) + } } if err != nil { @@ -772,16 +799,7 @@ func (m *Manager) FinalizeReplicaUpdate(ctx context.Context, sector storiface.Se return nil } -func (m *Manager) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, safeToFree []storiface.Range) error { - ssize, err := sector.ProofType.SectorSize() - if err != nil { - return err - } - if len(safeToFree) == 0 || safeToFree[0].Offset != 0 || safeToFree[0].Size.Padded() != abi.PaddedPieceSize(ssize) { - // todo support partial free - return nil - } - +func (m *Manager) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) error { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -789,7 +807,25 @@ func (m *Manager) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRe return xerrors.Errorf("acquiring sector lock: %w", err) } - return m.storage.Remove(ctx, sector.ID, storiface.FTUnsealed, true, nil) + found, pathType, err := m.sectorStorageType(ctx, sector, storiface.FTUnsealed) + if err != nil { + return xerrors.Errorf("checking cache storage type: %w", err) + } + if !found { + // already removed + return nil + } + + selector := newExistingSelector(m.index, sector.ID, storiface.FTUnsealed, false) + + return m.sched.Schedule(ctx, sector, sealtasks.TTFinalizeUnsealed, selector, m.schedFetch(sector, storiface.FTUnsealed, pathType, storiface.AcquireMove), func(ctx context.Context, w Worker) error { + _, err := m.waitSimpleCall(ctx)(w.ReleaseUnsealed(ctx, sector, keepUnsealed)) + if err != nil { + return err + } + + return nil + }) } func (m *Manager) ReleaseSectorKey(ctx context.Context, sector storiface.SectorRef) error { diff --git a/storage/sealer/manager_test.go b/storage/sealer/manager_test.go index 5759d0bc7..a44f69a89 100644 --- a/storage/sealer/manager_test.go +++ b/storage/sealer/manager_test.go @@ -110,7 +110,7 @@ func newTestMgr(ctx context.Context, t *testing.T, ds datastore.Datastore) (*Man stor := paths.NewRemote(lstor, si, nil, 6000, &paths.DefaultPartialFileHandler{}) - sh, err := newScheduler("") + sh, err := newScheduler(ctx, "") require.NoError(t, err) m := &Manager{ @@ -148,7 +148,7 @@ func TestSimple(t *testing.T) { defer cleanup() localTasks := []sealtasks.TaskType{ - sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFetch, + sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed, sealtasks.TTFetch, } err := m.AddWorker(ctx, newTestWorker(WorkerConfig{ @@ -207,7 +207,7 @@ func TestSnapDeals(t *testing.T) { localTasks := []sealtasks.TaskType{ sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTPreCommit2, sealtasks.TTCommit1, sealtasks.TTCommit2, sealtasks.TTFinalize, sealtasks.TTFetch, sealtasks.TTReplicaUpdate, sealtasks.TTProveReplicaUpdate1, sealtasks.TTProveReplicaUpdate2, sealtasks.TTUnseal, - sealtasks.TTRegenSectorKey, + sealtasks.TTRegenSectorKey, sealtasks.TTFinalizeUnsealed, } wds := datastore.NewMapDatastore() @@ -304,13 +304,13 @@ func TestSnapDeals(t *testing.T) { fmt.Printf("Decode\n") // Remove unsealed data and decode for retrieval - require.NoError(t, m.FinalizeSector(ctx, sid, nil)) + require.NoError(t, m.ReleaseUnsealed(ctx, sid, nil)) startDecode := time.Now() require.NoError(t, m.SectorsUnsealPiece(ctx, sid, 0, p1.Size.Unpadded(), ticket, &out.NewUnsealed)) fmt.Printf("Decode duration (%s): %s\n", ss.ShortString(), time.Since(startDecode)) // Remove just the first piece and decode for retrieval - require.NoError(t, m.FinalizeSector(ctx, sid, []storiface.Range{{Offset: p1.Size.Unpadded(), Size: p2.Size.Unpadded()}})) + require.NoError(t, m.ReleaseUnsealed(ctx, sid, []storiface.Range{{Offset: p1.Size.Unpadded(), Size: p2.Size.Unpadded()}})) require.NoError(t, m.SectorsUnsealPiece(ctx, sid, 0, p1.Size.Unpadded(), ticket, &out.NewUnsealed)) fmt.Printf("GSK\n") @@ -320,7 +320,7 @@ func TestSnapDeals(t *testing.T) { fmt.Printf("GSK duration (%s): %s\n", ss.ShortString(), time.Since(startGSK)) fmt.Printf("Remove data\n") - require.NoError(t, m.FinalizeSector(ctx, sid, nil)) + require.NoError(t, m.ReleaseUnsealed(ctx, sid, nil)) fmt.Printf("Release Sector Key\n") require.NoError(t, m.ReleaseSectorKey(ctx, sid)) fmt.Printf("Unseal Replica\n") @@ -336,7 +336,7 @@ func TestSnarkPackV2(t *testing.T) { localTasks := []sealtasks.TaskType{ sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTPreCommit2, sealtasks.TTCommit1, sealtasks.TTCommit2, sealtasks.TTFinalize, sealtasks.TTFetch, sealtasks.TTReplicaUpdate, sealtasks.TTProveReplicaUpdate1, sealtasks.TTProveReplicaUpdate2, sealtasks.TTUnseal, - sealtasks.TTRegenSectorKey, + sealtasks.TTRegenSectorKey, sealtasks.TTFinalizeUnsealed, } wds := datastore.NewMapDatastore() @@ -476,7 +476,7 @@ func TestRedoPC1(t *testing.T) { defer cleanup() localTasks := []sealtasks.TaskType{ - sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFetch, + sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed, sealtasks.TTFetch, } tw := newTestWorker(WorkerConfig{ @@ -531,7 +531,7 @@ func TestRestartManager(t *testing.T) { defer cleanup() localTasks := []sealtasks.TaskType{ - sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFetch, + sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed, sealtasks.TTFetch, } tw := newTestWorker(WorkerConfig{ @@ -702,7 +702,7 @@ func TestReenableWorker(t *testing.T) { defer cleanup() localTasks := []sealtasks.TaskType{ - sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFetch, + sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed, sealtasks.TTFetch, } wds := datastore.NewMapDatastore() diff --git a/storage/sealer/mock/mock.go b/storage/sealer/mock/mock.go index 0797bf549..6e88b86a5 100644 --- a/storage/sealer/mock/mock.go +++ b/storage/sealer/mock/mock.go @@ -497,15 +497,15 @@ func (mgr *SectorMgr) StageFakeData(mid abi.ActorID, spt abi.RegisteredSealProof return id, []abi.PieceInfo{pi}, nil } -func (mgr *SectorMgr) FinalizeSector(context.Context, storiface.SectorRef, []storiface.Range) error { +func (mgr *SectorMgr) FinalizeSector(context.Context, storiface.SectorRef) error { return nil } -func (mgr *SectorMgr) FinalizeReplicaUpdate(context.Context, storiface.SectorRef, []storiface.Range) error { +func (mgr *SectorMgr) FinalizeReplicaUpdate(context.Context, storiface.SectorRef) error { return nil } -func (mgr *SectorMgr) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, safeToFree []storiface.Range) error { +func (mgr *SectorMgr) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) error { return nil } diff --git a/storage/sealer/piece_provider_test.go b/storage/sealer/piece_provider_test.go index 3605b2597..ea2866e5d 100644 --- a/storage/sealer/piece_provider_test.go +++ b/storage/sealer/piece_provider_test.go @@ -107,7 +107,7 @@ func TestReadPieceRemoteWorkers(t *testing.T) { // the unsealed file from the miner. ppt.addRemoteWorker(t, []sealtasks.TaskType{ sealtasks.TTPreCommit1, sealtasks.TTPreCommit2, sealtasks.TTCommit1, - sealtasks.TTFetch, sealtasks.TTFinalize, + sealtasks.TTFetch, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed, }) // create a worker that can ONLY unseal and fetch @@ -352,7 +352,8 @@ func (p *pieceProviderTestHarness) readPiece(t *testing.T, offset storiface.Unpa } func (p *pieceProviderTestHarness) finalizeSector(t *testing.T, keepUnseal []storiface.Range) { - require.NoError(t, p.mgr.FinalizeSector(p.ctx, p.sector, keepUnseal)) + require.NoError(t, p.mgr.ReleaseUnsealed(p.ctx, p.sector, keepUnseal)) + require.NoError(t, p.mgr.FinalizeSector(p.ctx, p.sector)) } func (p *pieceProviderTestHarness) shutdown(t *testing.T) { diff --git a/storage/sealer/sched.go b/storage/sealer/sched.go index 335bb1249..c2b7d6a2d 100644 --- a/storage/sealer/sched.go +++ b/storage/sealer/sched.go @@ -10,6 +10,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/metrics" "github.com/filecoin-project/lotus/storage/sealer/sealtasks" "github.com/filecoin-project/lotus/storage/sealer/storiface" ) @@ -42,15 +43,23 @@ const mib = 1 << 20 type WorkerAction func(ctx context.Context, w Worker) error +type SchedWorker interface { + TaskTypes(context.Context) (map[sealtasks.TaskType]struct{}, error) + Paths(context.Context) ([]storiface.StoragePath, error) + Utilization() float64 +} + type WorkerSelector interface { // Ok is true if worker is acceptable for performing a task. // If any worker is preferred for a task, other workers won't be considered for that task. - Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, a *WorkerHandle) (ok, preferred bool, err error) + Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, a SchedWorker) (ok, preferred bool, err error) - Cmp(ctx context.Context, task sealtasks.TaskType, a, b *WorkerHandle) (bool, error) // true if a is preferred over b + Cmp(ctx context.Context, task sealtasks.TaskType, a, b SchedWorker) (bool, error) // true if a is preferred over b } type Scheduler struct { + mctx context.Context // metrics context + assigner Assigner workersLk sync.RWMutex @@ -79,10 +88,6 @@ type Scheduler struct { type WorkerHandle struct { workerRpc Worker - tasksCache map[sealtasks.TaskType]struct{} - tasksUpdate time.Time - tasksLk sync.Mutex - Info storiface.WorkerInfo preparing *ActiveResources // use with WorkerHandle.lk @@ -146,7 +151,7 @@ type rmRequest struct { res chan error } -func newScheduler(assigner string) (*Scheduler, error) { +func newScheduler(ctx context.Context, assigner string) (*Scheduler, error) { var a Assigner switch assigner { case "", "utilization": @@ -158,6 +163,7 @@ func newScheduler(assigner string) (*Scheduler, error) { } return &Scheduler{ + mctx: ctx, assigner: a, Workers: map[storiface.WorkerID]*WorkerHandle{}, @@ -366,6 +372,9 @@ func (sh *Scheduler) trySched() { sh.workersLk.RLock() defer sh.workersLk.RUnlock() + done := metrics.Timer(sh.mctx, metrics.SchedAssignerCycleDuration) + defer done() + sh.assigner.TrySched(sh) } diff --git a/storage/sealer/sched_assigner_common.go b/storage/sealer/sched_assigner_common.go index 09ff82a89..bf92dbf15 100644 --- a/storage/sealer/sched_assigner_common.go +++ b/storage/sealer/sched_assigner_common.go @@ -5,6 +5,11 @@ import ( "math/rand" "sort" "sync" + + "go.opencensus.io/stats" + + "github.com/filecoin-project/lotus/metrics" + "github.com/filecoin-project/lotus/storage/sealer/storiface" ) type WindowSelector func(sh *Scheduler, queueLen int, acceptableWindows [][]int, windows []SchedWindow) int @@ -33,9 +38,17 @@ func (a *AssignerCommon) TrySched(sh *Scheduler) { */ + cachedWorkers := &schedWorkerCache{ + Workers: sh.Workers, + cached: map[storiface.WorkerID]*cachedSchedWorker{}, + } + windowsLen := len(sh.OpenWindows) queueLen := sh.SchedQueue.Len() + stats.Record(sh.mctx, metrics.SchedCycleOpenWindows.M(int64(windowsLen))) + stats.Record(sh.mctx, metrics.SchedCycleQueueSize.M(int64(queueLen))) + log.Debugf("SCHED %d queued; %d open windows", queueLen, windowsLen) if windowsLen == 0 || queueLen == 0 { @@ -52,6 +65,12 @@ func (a *AssignerCommon) TrySched(sh *Scheduler) { // Step 1 throttle := make(chan struct{}, windowsLen) + partDone := metrics.Timer(sh.mctx, metrics.SchedAssignerCandidatesDuration) + defer func() { + // call latest value of partDone in case we error out somewhere + partDone() + }() + var wg sync.WaitGroup wg.Add(queueLen) for i := 0; i < queueLen; i++ { @@ -69,7 +88,7 @@ func (a *AssignerCommon) TrySched(sh *Scheduler) { var havePreferred bool for wnd, windowRequest := range sh.OpenWindows { - worker, ok := sh.Workers[windowRequest.Worker] + worker, ok := cachedWorkers.Get(windowRequest.Worker) if !ok { log.Errorf("worker referenced by windowRequest not found (worker: %s)", windowRequest.Worker) // TODO: How to move forward here? @@ -131,8 +150,8 @@ func (a *AssignerCommon) TrySched(sh *Scheduler) { return acceptableWindows[sqi][i] < acceptableWindows[sqi][j] // nolint:scopelint } - wi := sh.Workers[wii] - wj := sh.Workers[wji] + wi, _ := cachedWorkers.Get(wii) + wj, _ := cachedWorkers.Get(wji) rpcCtx, cancel := context.WithTimeout(task.Ctx, SelectorTimeout) defer cancel() @@ -148,13 +167,17 @@ func (a *AssignerCommon) TrySched(sh *Scheduler) { wg.Wait() - log.Debugf("SCHED windows: %+v", windows) log.Debugf("SCHED Acceptable win: %+v", acceptableWindows) // Step 2 + partDone() + partDone = metrics.Timer(sh.mctx, metrics.SchedAssignerWindowSelectionDuration) + scheduled := a.WindowSel(sh, queueLen, acceptableWindows, windows) // Step 3 + partDone() + partDone = metrics.Timer(sh.mctx, metrics.SchedAssignerSubmitDuration) if scheduled == 0 { return diff --git a/storage/sealer/sched_resources.go b/storage/sealer/sched_resources.go index 88725f6ba..487e294a2 100644 --- a/storage/sealer/sched_resources.go +++ b/storage/sealer/sched_resources.go @@ -1,9 +1,7 @@ package sealer import ( - "context" "sync" - "time" "github.com/filecoin-project/lotus/storage/sealer/sealtasks" "github.com/filecoin-project/lotus/storage/sealer/storiface" @@ -185,20 +183,3 @@ func (wh *WorkerHandle) Utilization() float64 { return u } - -var tasksCacheTimeout = 30 * time.Second - -func (wh *WorkerHandle) TaskTypes(ctx context.Context) (t map[sealtasks.TaskType]struct{}, err error) { - wh.tasksLk.Lock() - defer wh.tasksLk.Unlock() - - if wh.tasksCache == nil || time.Now().Sub(wh.tasksUpdate) > tasksCacheTimeout { - wh.tasksCache, err = wh.workerRpc.TaskTypes(ctx) - if err != nil { - return nil, err - } - wh.tasksUpdate = time.Now() - } - - return wh.tasksCache, nil -} diff --git a/storage/sealer/sched_test.go b/storage/sealer/sched_test.go index 89a286bdc..2eed1ce73 100644 --- a/storage/sealer/sched_test.go +++ b/storage/sealer/sched_test.go @@ -19,6 +19,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" prooftypes "github.com/filecoin-project/go-state-types/proof" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/storage/paths" "github.com/filecoin-project/lotus/storage/sealer/fsutil" "github.com/filecoin-project/lotus/storage/sealer/sealtasks" @@ -91,11 +92,11 @@ func (s *schedTestWorker) SealCommit2(ctx context.Context, sector storiface.Sect panic("implement me") } -func (s *schedTestWorker) FinalizeSector(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) { +func (s *schedTestWorker) FinalizeSector(ctx context.Context, sector storiface.SectorRef) (storiface.CallID, error) { panic("implement me") } -func (s *schedTestWorker) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, safeToFree []storiface.Range) (storiface.CallID, error) { +func (s *schedTestWorker) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) { panic("implement me") } @@ -127,7 +128,7 @@ func (s *schedTestWorker) GenerateSectorKeyFromData(ctx context.Context, sector panic("implement me") } -func (s *schedTestWorker) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) { +func (s *schedTestWorker) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef) (storiface.CallID, error) { panic("implement me") } @@ -226,7 +227,7 @@ func addTestWorker(t *testing.T, sched *Scheduler, index *paths.Index, name stri } func TestSchedStartStop(t *testing.T) { - sched, err := newScheduler("") + sched, err := newScheduler(context.Background(), "") require.NoError(t, err) go sched.runSched() @@ -356,7 +357,7 @@ func TestSched(t *testing.T) { return func(t *testing.T) { index := paths.NewIndex(nil) - sched, err := newScheduler("") + sched, err := newScheduler(ctx, "") require.NoError(t, err) sched.testSync = make(chan struct{}) @@ -587,18 +588,28 @@ func TestSched(t *testing.T) { type slowishSelector bool -func (s slowishSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, a *WorkerHandle) (bool, bool, error) { - time.Sleep(200 * time.Microsecond) +func (s slowishSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, a SchedWorker) (bool, bool, error) { + // note: we don't care about output here, just the time those calls take + // (selector Ok/Cmp is called in the scheduler) + _, _ = a.Paths(ctx) + _, _ = a.TaskTypes(ctx) return bool(s), false, nil } -func (s slowishSelector) Cmp(ctx context.Context, task sealtasks.TaskType, a, b *WorkerHandle) (bool, error) { - time.Sleep(100 * time.Microsecond) +func (s slowishSelector) Cmp(ctx context.Context, task sealtasks.TaskType, a, b SchedWorker) (bool, error) { + // note: we don't care about output here, just the time those calls take + // (selector Ok/Cmp is called in the scheduler) + _, _ = a.Paths(ctx) return true, nil } var _ WorkerSelector = slowishSelector(true) +type tw struct { + api.Worker + io.Closer +} + func BenchmarkTrySched(b *testing.B) { logging.SetAllLoggers(logging.LevelInfo) defer logging.SetAllLoggers(logging.LevelDebug) @@ -609,14 +620,25 @@ func BenchmarkTrySched(b *testing.B) { for i := 0; i < b.N; i++ { b.StopTimer() - sched, err := newScheduler("") + var whnd api.WorkerStruct + whnd.Internal.TaskTypes = func(p0 context.Context) (map[sealtasks.TaskType]struct{}, error) { + time.Sleep(100 * time.Microsecond) + return nil, nil + } + whnd.Internal.Paths = func(p0 context.Context) ([]storiface.StoragePath, error) { + time.Sleep(100 * time.Microsecond) + return nil, nil + } + + sched, err := newScheduler(ctx, "") require.NoError(b, err) sched.Workers[storiface.WorkerID{}] = &WorkerHandle{ - workerRpc: nil, + workerRpc: &tw{Worker: &whnd}, Info: storiface.WorkerInfo{ Hostname: "t", Resources: decentWorkerResources, }, + Enabled: true, preparing: NewActiveResources(), active: NewActiveResources(), } diff --git a/storage/sealer/sched_worker_cache.go b/storage/sealer/sched_worker_cache.go new file mode 100644 index 000000000..a17bf5674 --- /dev/null +++ b/storage/sealer/sched_worker_cache.go @@ -0,0 +1,69 @@ +package sealer + +import ( + "context" + "sync" + + "github.com/filecoin-project/lotus/lib/lazy" + "github.com/filecoin-project/lotus/storage/sealer/sealtasks" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +// schedWorkerCache caches scheduling-related calls to workers +type schedWorkerCache struct { + Workers map[storiface.WorkerID]*WorkerHandle + + lk sync.Mutex + cached map[storiface.WorkerID]*cachedSchedWorker +} + +func (s *schedWorkerCache) Get(id storiface.WorkerID) (*cachedSchedWorker, bool) { + s.lk.Lock() + defer s.lk.Unlock() + + if _, found := s.cached[id]; !found { + if _, found := s.Workers[id]; !found { + return nil, false + } + + whnd := s.Workers[id] + + s.cached[id] = &cachedSchedWorker{ + tt: lazy.MakeLazyCtx(whnd.workerRpc.TaskTypes), + paths: lazy.MakeLazyCtx(whnd.workerRpc.Paths), + utilization: lazy.MakeLazy(func() (float64, error) { + return whnd.Utilization(), nil + }), + + Enabled: whnd.Enabled, + Info: whnd.Info, + } + } + + return s.cached[id], true +} + +type cachedSchedWorker struct { + tt *lazy.LazyCtx[map[sealtasks.TaskType]struct{}] + paths *lazy.LazyCtx[[]storiface.StoragePath] + utilization *lazy.Lazy[float64] + + Enabled bool + Info storiface.WorkerInfo +} + +func (c *cachedSchedWorker) TaskTypes(ctx context.Context) (map[sealtasks.TaskType]struct{}, error) { + return c.tt.Val(ctx) +} + +func (c *cachedSchedWorker) Paths(ctx context.Context) ([]storiface.StoragePath, error) { + return c.paths.Get(ctx) +} + +func (c *cachedSchedWorker) Utilization() float64 { + // can't error + v, _ := c.utilization.Val() + return v +} + +var _ SchedWorker = &cachedSchedWorker{} diff --git a/storage/sealer/sealtasks/task.go b/storage/sealer/sealtasks/task.go index 1a06f7d34..bbf33b159 100644 --- a/storage/sealer/sealtasks/task.go +++ b/storage/sealer/sealtasks/task.go @@ -20,7 +20,8 @@ const ( TTCommit1 TaskType = "seal/v0/commit/1" TTCommit2 TaskType = "seal/v0/commit/2" - TTFinalize TaskType = "seal/v0/finalize" + TTFinalize TaskType = "seal/v0/finalize" + TTFinalizeUnsealed TaskType = "seal/v0/finalizeunsealed" TTFetch TaskType = "seal/v0/fetch" TTUnseal TaskType = "seal/v0/unseal" @@ -50,12 +51,13 @@ var order = map[TaskType]int{ TTCommit1: 2, TTUnseal: 1, - TTFetch: -1, - TTDownloadSector: -2, - TTFinalize: -3, + TTFetch: -1, + TTDownloadSector: -2, + TTFinalize: -3, + TTFinalizeUnsealed: -4, - TTGenerateWindowPoSt: -4, - TTGenerateWinningPoSt: -5, // most priority + TTGenerateWindowPoSt: -5, + TTGenerateWinningPoSt: -6, // most priority } var shortNames = map[TaskType]string{ @@ -67,7 +69,8 @@ var shortNames = map[TaskType]string{ TTCommit1: "C1", TTCommit2: "C2", - TTFinalize: "FIN", + TTFinalize: "FIN", + TTFinalizeUnsealed: "FUS", TTFetch: "GET", TTUnseal: "UNS", diff --git a/storage/sealer/selector_alloc.go b/storage/sealer/selector_alloc.go index ce64820f7..130f74461 100644 --- a/storage/sealer/selector_alloc.go +++ b/storage/sealer/selector_alloc.go @@ -26,7 +26,7 @@ func newAllocSelector(index paths.SectorIndex, alloc storiface.SectorFileType, p } } -func (s *allocSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, whnd *WorkerHandle) (bool, bool, error) { +func (s *allocSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, whnd SchedWorker) (bool, bool, error) { tasks, err := whnd.TaskTypes(ctx) if err != nil { return false, false, xerrors.Errorf("getting supported worker task types: %w", err) @@ -35,7 +35,7 @@ func (s *allocSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi return false, false, nil } - paths, err := whnd.workerRpc.Paths(ctx) + paths, err := whnd.Paths(ctx) if err != nil { return false, false, xerrors.Errorf("getting worker paths: %w", err) } @@ -71,7 +71,7 @@ func (s *allocSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi return requested == storiface.FTNone, false, nil } -func (s *allocSelector) Cmp(ctx context.Context, task sealtasks.TaskType, a, b *WorkerHandle) (bool, error) { +func (s *allocSelector) Cmp(ctx context.Context, task sealtasks.TaskType, a, b SchedWorker) (bool, error) { return a.Utilization() < b.Utilization(), nil } diff --git a/storage/sealer/selector_existing.go b/storage/sealer/selector_existing.go index 830213f1e..c1e082db8 100644 --- a/storage/sealer/selector_existing.go +++ b/storage/sealer/selector_existing.go @@ -28,7 +28,7 @@ func newExistingSelector(index paths.SectorIndex, sector abi.SectorID, alloc sto } } -func (s *existingSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, whnd *WorkerHandle) (bool, bool, error) { +func (s *existingSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, whnd SchedWorker) (bool, bool, error) { tasks, err := whnd.TaskTypes(ctx) if err != nil { return false, false, xerrors.Errorf("getting supported worker task types: %w", err) @@ -37,7 +37,7 @@ func (s *existingSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt return false, false, nil } - paths, err := whnd.workerRpc.Paths(ctx) + paths, err := whnd.Paths(ctx) if err != nil { return false, false, xerrors.Errorf("getting worker paths: %w", err) } @@ -78,7 +78,7 @@ func (s *existingSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt return requested == storiface.FTNone, false, nil } -func (s *existingSelector) Cmp(ctx context.Context, task sealtasks.TaskType, a, b *WorkerHandle) (bool, error) { +func (s *existingSelector) Cmp(ctx context.Context, task sealtasks.TaskType, a, b SchedWorker) (bool, error) { return a.Utilization() < b.Utilization(), nil } diff --git a/storage/sealer/selector_move.go b/storage/sealer/selector_move.go index c1f402456..fde4b3c59 100644 --- a/storage/sealer/selector_move.go +++ b/storage/sealer/selector_move.go @@ -30,7 +30,7 @@ func newMoveSelector(index paths.SectorIndex, sector abi.SectorID, alloc storifa } } -func (s *moveSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, whnd *WorkerHandle) (bool, bool, error) { +func (s *moveSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, whnd SchedWorker) (bool, bool, error) { tasks, err := whnd.TaskTypes(ctx) if err != nil { return false, false, xerrors.Errorf("getting supported worker task types: %w", err) @@ -39,7 +39,7 @@ func (s *moveSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi. return false, false, nil } - paths, err := whnd.workerRpc.Paths(ctx) + paths, err := whnd.Paths(ctx) if err != nil { return false, false, xerrors.Errorf("getting worker paths: %w", err) } @@ -99,7 +99,7 @@ func (s *moveSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi. return (ok && s.allowRemote) || pref, pref, nil } -func (s *moveSelector) Cmp(ctx context.Context, task sealtasks.TaskType, a, b *WorkerHandle) (bool, error) { +func (s *moveSelector) Cmp(ctx context.Context, task sealtasks.TaskType, a, b SchedWorker) (bool, error) { return a.Utilization() < b.Utilization(), nil } diff --git a/storage/sealer/selector_task.go b/storage/sealer/selector_task.go index cc12b514e..805fcbbd0 100644 --- a/storage/sealer/selector_task.go +++ b/storage/sealer/selector_task.go @@ -19,7 +19,7 @@ func newTaskSelector() *taskSelector { return &taskSelector{} } -func (s *taskSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, whnd *WorkerHandle) (bool, bool, error) { +func (s *taskSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, whnd SchedWorker) (bool, bool, error) { tasks, err := whnd.TaskTypes(ctx) if err != nil { return false, false, xerrors.Errorf("getting supported worker task types: %w", err) @@ -29,7 +29,7 @@ func (s *taskSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi. return supported, false, nil } -func (s *taskSelector) Cmp(ctx context.Context, _ sealtasks.TaskType, a, b *WorkerHandle) (bool, error) { +func (s *taskSelector) Cmp(ctx context.Context, _ sealtasks.TaskType, a, b SchedWorker) (bool, error) { atasks, err := a.TaskTypes(ctx) if err != nil { return false, xerrors.Errorf("getting supported worker task types: %w", err) diff --git a/storage/sealer/storiface/filetype.go b/storage/sealer/storiface/filetype.go index 4660dd2a7..ec3c5450c 100644 --- a/storage/sealer/storiface/filetype.go +++ b/storage/sealer/storiface/filetype.go @@ -83,7 +83,7 @@ func (t SectorFileType) String() string { case FTUpdateCache: return "update-cache" default: - return fmt.Sprintf("", t) + return fmt.Sprintf("", t, (t & ((1 << FileTypes) - 1)).Strings()) } } diff --git a/storage/sealer/storiface/storage.go b/storage/sealer/storiface/storage.go index a5aa8907a..b63c0480d 100644 --- a/storage/sealer/storiface/storage.go +++ b/storage/sealer/storiface/storage.go @@ -63,13 +63,17 @@ type Sealer interface { SealCommit1(ctx context.Context, sector SectorRef, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, cids SectorCids) (Commit1Out, error) SealCommit2(ctx context.Context, sector SectorRef, c1o Commit1Out) (Proof, error) - FinalizeSector(ctx context.Context, sector SectorRef, keepUnsealed []Range) error + FinalizeSector(ctx context.Context, sector SectorRef) error // ReleaseUnsealed marks parts of the unsealed sector file as safe to drop // (called by the fsm on restart, allows storage to keep no persistent // state about unsealed fast-retrieval copies) - ReleaseUnsealed(ctx context.Context, sector SectorRef, safeToFree []Range) error + ReleaseUnsealed(ctx context.Context, sector SectorRef, keepUnsealed []Range) error + // ReleaseSectorKey removes `sealed` from all storage + // called after successful sector upgrade ReleaseSectorKey(ctx context.Context, sector SectorRef) error + // ReleaseReplicaUpgrade removes `update` / `update-cache` from all storage + // called when aborting sector upgrade ReleaseReplicaUpgrade(ctx context.Context, sector SectorRef) error // Removes all data associated with the specified sector @@ -85,7 +89,7 @@ type Sealer interface { // GenerateSectorKeyFromData computes sector key given unsealed data and updated replica GenerateSectorKeyFromData(ctx context.Context, sector SectorRef, unsealed cid.Cid) error - FinalizeReplicaUpdate(ctx context.Context, sector SectorRef, keepUnsealed []Range) error + FinalizeReplicaUpdate(ctx context.Context, sector SectorRef) error DownloadSectorData(ctx context.Context, sector SectorRef, finalized bool, src map[SectorFileType]SectorLocation) error } diff --git a/storage/sealer/storiface/worker.go b/storage/sealer/storiface/worker.go index 51a7901b0..3cbf9f737 100644 --- a/storage/sealer/storiface/worker.go +++ b/storage/sealer/storiface/worker.go @@ -124,8 +124,8 @@ type WorkerCalls interface { SealPreCommit2(ctx context.Context, sector SectorRef, pc1o PreCommit1Out) (CallID, error) SealCommit1(ctx context.Context, sector SectorRef, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, cids SectorCids) (CallID, error) SealCommit2(ctx context.Context, sector SectorRef, c1o Commit1Out) (CallID, error) - FinalizeSector(ctx context.Context, sector SectorRef, keepUnsealed []Range) (CallID, error) - FinalizeReplicaUpdate(ctx context.Context, sector SectorRef, keepUnsealed []Range) (CallID, error) + FinalizeSector(ctx context.Context, sector SectorRef) (CallID, error) + FinalizeReplicaUpdate(ctx context.Context, sector SectorRef) (CallID, error) ReleaseUnsealed(ctx context.Context, sector SectorRef, safeToFree []Range) (CallID, error) ReplicaUpdate(ctx context.Context, sector SectorRef, pieces []abi.PieceInfo) (CallID, error) ProveReplicaUpdate1(ctx context.Context, sector SectorRef, sectorKey, newSealed, newUnsealed cid.Cid) (CallID, error) diff --git a/storage/sealer/tarutil/systar.go b/storage/sealer/tarutil/systar.go index e13e5ff21..4372cc8c7 100644 --- a/storage/sealer/tarutil/systar.go +++ b/storage/sealer/tarutil/systar.go @@ -90,7 +90,7 @@ func ExtractTar(body io.Reader, dir string, buf []byte) (int64, error) { sz, found := CacheFileConstraints[header.Name] if !found { - return read, xerrors.Errorf("tar file %#v isn't expected") + return read, xerrors.Errorf("tar file %#v isn't expected", header.Name) } if header.Size > sz { return read, xerrors.Errorf("tar file %#v is bigger than expected: %d > %d", header.Name, header.Size, sz) diff --git a/storage/sealer/teststorage_test.go b/storage/sealer/teststorage_test.go index 4b30d5fff..a074dc20a 100644 --- a/storage/sealer/teststorage_test.go +++ b/storage/sealer/teststorage_test.go @@ -61,11 +61,11 @@ func (t *testExec) SealCommit2(ctx context.Context, sector storiface.SectorRef, panic("implement me") } -func (t *testExec) FinalizeSector(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) error { +func (t *testExec) FinalizeSector(ctx context.Context, sector storiface.SectorRef) error { panic("implement me") } -func (t *testExec) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, safeToFree []storiface.Range) error { +func (t *testExec) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) error { panic("implement me") } @@ -101,7 +101,7 @@ func (t *testExec) GenerateSectorKeyFromData(ctx context.Context, sector storifa panic("implement me") } -func (t *testExec) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) error { +func (t *testExec) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef) error { panic("implement me") } diff --git a/storage/sealer/worker_local.go b/storage/sealer/worker_local.go index 326f38366..7f141780c 100644 --- a/storage/sealer/worker_local.go +++ b/storage/sealer/worker_local.go @@ -481,35 +481,36 @@ func (l *LocalWorker) GenerateSectorKeyFromData(ctx context.Context, sector stor }) } -func (l *LocalWorker) FinalizeSector(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) { +func (l *LocalWorker) FinalizeSector(ctx context.Context, sector storiface.SectorRef) (storiface.CallID, error) { sb, err := l.executor() if err != nil { return storiface.UndefCall, err } return l.asyncCall(ctx, sector, FinalizeSector, func(ctx context.Context, ci storiface.CallID) (interface{}, error) { - if err := sb.FinalizeSector(ctx, sector, keepUnsealed); err != nil { - return nil, xerrors.Errorf("finalizing sector: %w", err) - } - - if len(keepUnsealed) == 0 { - if err := l.storage.Remove(ctx, sector.ID, storiface.FTUnsealed, true, nil); err != nil { - return nil, xerrors.Errorf("removing unsealed data: %w", err) - } - } - - return nil, err + return nil, sb.FinalizeSector(ctx, sector) }) } -func (l *LocalWorker) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) { +func (l *LocalWorker) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef) (storiface.CallID, error) { sb, err := l.executor() if err != nil { return storiface.UndefCall, err } return l.asyncCall(ctx, sector, FinalizeReplicaUpdate, func(ctx context.Context, ci storiface.CallID) (interface{}, error) { - if err := sb.FinalizeReplicaUpdate(ctx, sector, keepUnsealed); err != nil { + return nil, sb.FinalizeReplicaUpdate(ctx, sector) + }) +} + +func (l *LocalWorker) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) { + sb, err := l.executor() + if err != nil { + return storiface.UndefCall, err + } + + return l.asyncCall(ctx, sector, ReleaseUnsealed, func(ctx context.Context, ci storiface.CallID) (interface{}, error) { + if err := sb.ReleaseUnsealed(ctx, sector, keepUnsealed); err != nil { return nil, xerrors.Errorf("finalizing sector: %w", err) } @@ -523,10 +524,6 @@ func (l *LocalWorker) FinalizeReplicaUpdate(ctx context.Context, sector storifac }) } -func (l *LocalWorker) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, safeToFree []storiface.Range) (storiface.CallID, error) { - return storiface.UndefCall, xerrors.Errorf("implement me") -} - func (l *LocalWorker) Remove(ctx context.Context, sector abi.SectorID) error { var err error diff --git a/storage/sealer/worker_tracked.go b/storage/sealer/worker_tracked.go index 970ba9a69..7fce400a0 100644 --- a/storage/sealer/worker_tracked.go +++ b/storage/sealer/worker_tracked.go @@ -183,8 +183,12 @@ func (t *trackedWorker) SealCommit2(ctx context.Context, sector storiface.Sector return t.tracker.track(ctx, t.execute, t.wid, t.workerInfo, sector, sealtasks.TTCommit2, func() (storiface.CallID, error) { return t.Worker.SealCommit2(ctx, sector, c1o) }) } -func (t *trackedWorker) FinalizeSector(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) { - return t.tracker.track(ctx, t.execute, t.wid, t.workerInfo, sector, sealtasks.TTFinalize, func() (storiface.CallID, error) { return t.Worker.FinalizeSector(ctx, sector, keepUnsealed) }) +func (t *trackedWorker) FinalizeSector(ctx context.Context, sector storiface.SectorRef) (storiface.CallID, error) { + return t.tracker.track(ctx, t.execute, t.wid, t.workerInfo, sector, sealtasks.TTFinalize, func() (storiface.CallID, error) { return t.Worker.FinalizeSector(ctx, sector) }) +} + +func (t *trackedWorker) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) { + return t.tracker.track(ctx, t.execute, t.wid, t.workerInfo, sector, sealtasks.TTFinalizeUnsealed, func() (storiface.CallID, error) { return t.Worker.ReleaseUnsealed(ctx, sector, keepUnsealed) }) } func (t *trackedWorker) DataCid(ctx context.Context, pieceSize abi.UnpaddedPieceSize, pieceData storiface.Data) (storiface.CallID, error) { @@ -225,8 +229,8 @@ func (t *trackedWorker) ProveReplicaUpdate2(ctx context.Context, sector storifac }) } -func (t *trackedWorker) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef, keepUnsealed []storiface.Range) (storiface.CallID, error) { - return t.tracker.track(ctx, t.execute, t.wid, t.workerInfo, sector, sealtasks.TTFinalizeReplicaUpdate, func() (storiface.CallID, error) { return t.Worker.FinalizeReplicaUpdate(ctx, sector, keepUnsealed) }) +func (t *trackedWorker) FinalizeReplicaUpdate(ctx context.Context, sector storiface.SectorRef) (storiface.CallID, error) { + return t.tracker.track(ctx, t.execute, t.wid, t.workerInfo, sector, sealtasks.TTFinalizeReplicaUpdate, func() (storiface.CallID, error) { return t.Worker.FinalizeReplicaUpdate(ctx, sector) }) } var _ Worker = &trackedWorker{} diff --git a/storage/wdpost/wdpost_run_test.go b/storage/wdpost/wdpost_run_test.go index 140e0886e..64d470dba 100644 --- a/storage/wdpost/wdpost_run_test.go +++ b/storage/wdpost/wdpost_run_test.go @@ -19,6 +19,7 @@ import ( minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/go-state-types/network" prooftypes "github.com/filecoin-project/go-state-types/proof" tutils "github.com/filecoin-project/specs-actors/v2/support/testing" @@ -570,7 +571,7 @@ func (m *mockStorageMinerAPI) StateMinerProvingDeadline(ctx context.Context, add } func (m *mockStorageMinerAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) { - code, ok := actors.GetActorCodeID(actorstypes.Version7, actors.MinerKey) + code, ok := actors.GetActorCodeID(actorstypes.Version7, manifest.MinerKey) if !ok { return nil, xerrors.Errorf("failed to get miner actor code ID for actors version %d", actors.Version7) } diff --git a/tools/kibana/README.md b/tools/kibana/README.md new file mode 100644 index 000000000..c556ae10c --- /dev/null +++ b/tools/kibana/README.md @@ -0,0 +1,20 @@ +## Lotus Kibana Dashboard + +This folder contains configuration files to create Kibana dashboards to track peer scores and block propagation +throughout Filecoin network. + +### Importing index template + +Index template needs to be imported into Elasticsearch for score weights and to +prevent Elasticsearch from infering wrong field type. + +The [template](./index-template.json) is loaded via [Kibana Index Management](https://www.elastic.co/guide/en/elasticsearch/reference/current/index-mgmt.html) and pasted +into newly created Index Template. + +### Importing dashboard + +The peer score and block propagation dashboard configuration is imported via Kibana import saved object [functionality](https://www.elastic.co/guide/en/kibana/current/managing-saved-objects.html#managing-saved-objects-export-objects). + +#### Custom index + +By default, the dashboards and index template target `lotus-pubsub` index which is the default one when running node. The index can be customised via edit on dashboard visualizations and also index template needs to be updated to target new index. diff --git a/tools/kibana/block-propagation-dashboard.ndjson b/tools/kibana/block-propagation-dashboard.ndjson new file mode 100644 index 000000000..c7b14c0c3 --- /dev/null +++ b/tools/kibana/block-propagation-dashboard.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"Force layout vega graph where link force distance between peers is block propagation","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"syncColors\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"version\":\"7.14.1\",\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":0,\"w\":48,\"h\":42,\"i\":\"c7e4001d-38c9-4fa0-a488-e069dd50d274\"},\"panelIndex\":\"c7e4001d-38c9-4fa0-a488-e069dd50d274\",\"embeddableConfig\":{\"savedVis\":{\"title\":\"Block propagation\",\"description\":\"\",\"type\":\"vega\",\"params\":{\"spec\":\"{\\n $schema: https://vega.github.io/schema/vega/v5.json\\n title: Node block propagation\\n\\n\\n \\\"signals\\\": [\\n { \\\"name\\\": \\\"cx\\\", \\\"update\\\": \\\"width / 2\\\" },\\n { \\\"name\\\": \\\"cy\\\", \\\"update\\\": \\\"height / 2\\\" },\\n { \\\"name\\\": \\\"nodeRadius\\\", \\\"value\\\": 10,\\n \\\"bind\\\": {\\\"input\\\": \\\"range\\\", \\\"min\\\": 1, \\\"max\\\": 20, \\\"step\\\": 1} },\\n { \\\"name\\\": \\\"propagationMultiplier\\\", \\\"value\\\": 1,\\n \\\"bind\\\": {\\\"input\\\": \\\"range\\\", \\\"min\\\": 1, \\\"max\\\": 100, \\\"step\\\": 1} },\\n ],\\n\\n data: [\\n {\\n \\n name: \\\"node-data\\\",\\n url: {\\n index: lotus-pubsub\\n body: {\\n size: 0,\\n aggs: {\\n unique_peerID: {\\n terms: { \\n field: \\\"peerID\\\",\\n size: 10000\\n },\\n }\\n }\\n }\\n },\\n format: {\\\"property\\\": \\\"aggregations.unique_peerID.buckets\\\"},\\n transform: [\\n {\\n \\\"type\\\": \\\"project\\\",\\n \\\"fields\\\": [\\\"key\\\"],\\n \\\"as\\\": [\\\"peerID\\\"]\\n },\\n {\\n type: \\\"identifier\\\",\\n as: \\\"id\\\"\\n },\\n {\\n type: \\\"formula\\\",\\n expr: \\\"datum.id - 1\\\",\\n as: \\\"index\\\"\\n }\\n ]\\n },\\n {\\n name: \\\"published-message-data\\\",\\n url: {\\n index: lotus-pubsub\\n body: {\\n size: 10000,\\n query: {\\n bool: {\\n must: [\\n {\\n match: {\\n type: 0\\n }\\n }\\n ]\\n }\\n }\\n }\\n },\\n format: {\\\"property\\\": \\\"hits.hits\\\"},\\n },\\n {\\n name: \\\"link-data\\\",\\n url: {\\n index: lotus-pubsub\\n body: {\\n size: 10000,\\n query: {\\n bool: {\\n must: [\\n {\\n match: {\\n type: 1\\n }\\n }\\n ]\\n }\\n }\\n }\\n },\\n format: {\\\"property\\\": \\\"hits.hits\\\"},\\n transform: [\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"published-message-data\\\",\\n \\\"key\\\": \\\"_source.publishMessage.messageID\\\",\\n \\\"fields\\\": [\\\"_source.deliverMessage.messageID\\\"],\\n \\\"as\\\": [\\\"publishedMessage\\\"],\\n },\\n {\\n \\\"type\\\": \\\"filter\\\",\\n \\\"expr\\\": \\\"datum.publishedMessage != null\\\"\\n },\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"node-data\\\",\\n \\\"key\\\": \\\"peerID\\\",\\n \\\"fields\\\": [\\\"_source.peerID\\\"],\\n \\\"as\\\": [\\\"source\\\"],\\n },\\n {\\n \\\"type\\\": \\\"lookup\\\",\\n \\\"from\\\": \\\"node-data\\\",\\n \\\"key\\\": \\\"peerID\\\",\\n \\\"fields\\\": [\\\"publishedMessage._source.peerID\\\"],\\n \\\"as\\\": [\\\"target\\\"],\\n },\\n {\\n \\\"type\\\": \\\"formula\\\",\\n \\\"expr\\\": \\\"(datum._source.timestamp - datum.publishedMessage._source.timestamp) * propagationMultiplier\\\",\\n \\\"as\\\": \\\"distance\\\"\\n },\\n {\\n \\\"type\\\": \\\"project\\\",\\n \\\"fields\\\": [\\\"source.index\\\", \\\"target.index\\\", \\\"distance\\\"]\\n \\\"as\\\": [\\\"source\\\", \\\"target\\\", \\\"distance\\\"]\\n },\\n {\\n \\\"type\\\": \\\"aggregate\\\",\\n \\\"ops\\\": [\\\"average\\\"],\\n \\\"fields\\\": [\\\"distance\\\"],\\n \\\"groupby\\\": [\\\"source\\\", \\\"target\\\"],\\n \\\"as\\\": [\\\"distance\\\"]\\n }\\n ]\\n }\\n ]\\n\\n scales: [\\n {\\n \\\"name\\\": \\\"color\\\",\\n \\\"type\\\": \\\"ordinal\\\",\\n \\\"domain\\\": {\\\"data\\\": \\\"node-data\\\", \\\"field\\\": \\\"id\\\"},\\n \\\"range\\\": {\\\"scheme\\\": \\\"category20c\\\"}\\n }\\n ]\\n\\n marks: [\\n {\\n \\\"name\\\": \\\"nodes\\\",\\n \\\"type\\\": \\\"symbol\\\",\\n \\\"zindex\\\": 1,\\n \\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"fill\\\": {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"id\\\"},\\n \\\"stroke\\\": {\\\"value\\\": \\\"black\\\"},\\n \\\"tooltip\\\": {\\\"signal\\\": \\\"{'PeerID': datum.peerID}\\\"}\\n },\\n \\\"update\\\": {\\n \\\"size\\\": {\\\"signal\\\": \\\"2 * nodeRadius * nodeRadius\\\"},\\n \\\"fill\\\": {\\\"scale\\\": \\\"color\\\", \\\"field\\\": \\\"id\\\"},\\n },\\n \\\"hover\\\": { \\\"fill\\\": {\\\"value\\\": \\\"red\\\"} },\\n },\\n\\n \\\"from\\\": {\\\"data\\\": \\\"node-data\\\"},\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"force\\\",\\n \\\"restart\\\": false,\\n \\\"static\\\": true,\\n \\\"signal\\\": \\\"force\\\",\\n \\\"forces\\\": [\\n {\\\"force\\\": \\\"link\\\", \\\"links\\\": \\\"link-data\\\", distance: {field: \\\"distance\\\"}},\\n {\\\"force\\\": \\\"center\\\", \\\"x\\\": {\\\"signal\\\": \\\"cx\\\"}, \\\"y\\\": {\\\"signal\\\": \\\"cy\\\"}},\\n ]\\n }\\n ]\\n },\\n {\\n \\\"type\\\": \\\"path\\\",\\n \\\"from\\\": {\\\"data\\\": \\\"link-data\\\"},\\n \\\"encode\\\": {\\n \\\"enter\\\": {\\n \\\"tooltip\\\": {\\\"signal\\\": \\\"{'Block propagation': datum.distance}\\\"}\\n },\\n \\\"update\\\": {\\n \\\"stroke\\\": {\\\"value\\\": \\\"#ccc\\\"},\\n \\\"strokeWidth\\\": {\\\"value\\\": 1.5}\\n },\\n \\\"hover\\\": { \\\"stroke\\\": { \\\"value\\\": \\\"#0B33A0\\\" }}\\n },\\n \\\"transform\\\": [\\n {\\n \\\"type\\\": \\\"linkpath\\\",\\n \\\"require\\\": {\\\"signal\\\": \\\"force\\\"},\\n \\\"shape\\\": \\\"line\\\",\\n \\\"sourceX\\\": \\\"datum.source.x\\\", \\\"sourceY\\\": \\\"datum.source.y\\\",\\n \\\"targetX\\\": \\\"datum.target.x\\\", \\\"targetY\\\": \\\"datum.target.y\\\"\\n }\\n ]\\n }\\n ]\\n}\\n\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}}},\"enhancements\":{}}}]","timeRestore":false,"title":"Peer block propagation","version":1},"coreMigrationVersion":"7.14.1","id":"937b1470-212b-11ec-99f4-75d57f0cd0d8","migrationVersion":{"dashboard":"7.14.0"},"references":[],"type":"dashboard","updated_at":"2021-09-29T13:45:58.342Z","version":"Wzg4NzMsMV0="} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} diff --git a/tools/kibana/index-template.json b/tools/kibana/index-template.json new file mode 100644 index 000000000..f08298ad1 --- /dev/null +++ b/tools/kibana/index-template.json @@ -0,0 +1,66 @@ +{ + "template": { + "settings": {}, + "mappings": { + "runtime": { + "peerScore.weightedScore": { + "type": "double", + "script": { + "source": "if (doc['type'].value == 100) {\n def score = doc['peerScore.score'].value;\n if (doc['sourceAuth'] == \"\") {\n\n emit(score * 1.2)\n } else {\n emit(score)\n }\n}\n", + "lang": "painless" + } + } + }, + "properties": { + "peerScore": { + "properties": { + "appSpecificScore": { + "type": "double" + }, + "behaviourPenalty": { + "type": "double" + }, + "ipColocationFactor": { + "type": "double" + }, + "score": { + "type": "double" + }, + "topics": { + "type": "nested", + "properties": { + "firstMessageDeliveries": { + "type": "double", + "ignore_malformed": false, + "coerce": true + }, + "invalidMessageDeliveries": { + "type": "double", + "ignore_malformed": false, + "coerce": true + }, + "meshMessageDeliveries": { + "type": "double", + "ignore_malformed": false, + "coerce": true + }, + "timeInMesh": { + "type": "double", + "ignore_malformed": false, + "coerce": true + }, + "topic": { + "type": "keyword" + } + } + } + } + }, + "sourceAuth": { + "type": "keyword" + } + } + }, + "aliases": {} + } +} diff --git a/tools/kibana/peer-scores-dashboard.ndjson b/tools/kibana/peer-scores-dashboard.ndjson new file mode 100644 index 000000000..4df376ab3 --- /dev/null +++ b/tools/kibana/peer-scores-dashboard.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"description":"Average peer score table per node peerID","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"syncColors\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"version\":\"7.14.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":48,\"h\":43,\"i\":\"cddc98a5-45f3-4ba7-a7c6-6b9d216b19da\"},\"panelIndex\":\"cddc98a5-45f3-4ba7-a7c6-6b9d216b19da\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"type\":\"lens\",\"visualizationType\":\"lnsDatatable\",\"state\":{\"datasourceStates\":{\"indexpattern\":{\"layers\":{\"666e2f39-8868-45ad-b747-fe124830b0ae\":{\"columns\":{\"504c50bd-14c1-4119-820e-c961866fc3b4\":{\"label\":\"peerID\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"peerScore.peerID.keyword\",\"isBucketed\":true,\"params\":{\"size\":100,\"orderBy\":{\"type\":\"column\",\"columnId\":\"ec82c5f7-b3c4-4715-8646-a8fe584400fc\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false},\"customLabel\":true},\"ec82c5f7-b3c4-4715-8646-a8fe584400fc\":{\"label\":\"Score\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"peerScore.score\",\"isBucketed\":false,\"scale\":\"ratio\",\"customLabel\":true},\"e22a19e8-1d71-43d6-9ca0-b30ddd423447\":{\"label\":\"Weighted Score\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"peerScore.weightedScore\",\"isBucketed\":false,\"scale\":\"ratio\",\"customLabel\":true}},\"columnOrder\":[\"504c50bd-14c1-4119-820e-c961866fc3b4\",\"ec82c5f7-b3c4-4715-8646-a8fe584400fc\",\"e22a19e8-1d71-43d6-9ca0-b30ddd423447\"],\"incompleteColumns\":{}}}}},\"visualization\":{\"columns\":[{\"isTransposed\":false,\"columnId\":\"504c50bd-14c1-4119-820e-c961866fc3b4\"},{\"isTransposed\":false,\"columnId\":\"ec82c5f7-b3c4-4715-8646-a8fe584400fc\",\"colorMode\":\"cell\",\"palette\":{\"type\":\"palette\",\"name\":\"positive\",\"params\":{\"stops\":[{\"color\":\"#d6e9e4\",\"stop\":20},{\"color\":\"#aed3ca\",\"stop\":40},{\"color\":\"#85bdb1\",\"stop\":60},{\"color\":\"#5aa898\",\"stop\":80},{\"color\":\"#209280\",\"stop\":100}]}}},{\"columnId\":\"e22a19e8-1d71-43d6-9ca0-b30ddd423447\",\"isTransposed\":false,\"colorMode\":\"cell\",\"palette\":{\"type\":\"palette\",\"name\":\"positive\",\"params\":{\"stops\":[{\"color\":\"#d6e9e4\",\"stop\":20},{\"color\":\"#aed3ca\",\"stop\":40},{\"color\":\"#85bdb1\",\"stop\":60},{\"color\":\"#5aa898\",\"stop\":80},{\"color\":\"#209280\",\"stop\":100}]}}}],\"layerId\":\"666e2f39-8868-45ad-b747-fe124830b0ae\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[]},\"references\":[{\"type\":\"index-pattern\",\"id\":\"9890c040-17b7-11ec-99f4-75d57f0cd0d8\",\"name\":\"indexpattern-datasource-current-indexpattern\"},{\"type\":\"index-pattern\",\"id\":\"2c407db0-1acb-11ec-99f4-75d57f0cd0d8\",\"name\":\"indexpattern-datasource-layer-666e2f39-8868-45ad-b747-fe124830b0ae\"}]},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Peer Scores\"}]","timeRestore":false,"title":"Peer Scores","version":1},"coreMigrationVersion":"7.14.1","id":"e7e4fd70-1acb-11ec-99f4-75d57f0cd0d8","migrationVersion":{"dashboard":"7.14.0"},"references":[{"id":"2c407db0-1acb-11ec-99f4-75d57f0cd0d8","name":"cddc98a5-45f3-4ba7-a7c6-6b9d216b19da:indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"2c407db0-1acb-11ec-99f4-75d57f0cd0d8","name":"cddc98a5-45f3-4ba7-a7c6-6b9d216b19da:indexpattern-datasource-layer-666e2f39-8868-45ad-b747-fe124830b0ae","type":"index-pattern"}],"type":"dashboard","updated_at":"2021-09-24T12:06:00.625Z","version":"WzczNDgsMV0="} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":1,"missingRefCount":0,"missingReferences":[]} diff --git a/tools/packer/etc/motd b/tools/packer/etc/motd deleted file mode 100644 index 892b156e1..000000000 --- a/tools/packer/etc/motd +++ /dev/null @@ -1,64 +0,0 @@ -Your lotus node is up and running! - -This image contains the two most important pieces of the lotus filecoin suite, the -daemon and the miner. The daemon is is configured to download a snapshot and start -running. In fact, by the time you read this, the daemon may already be in sync. -Go ahead and make sure everything is working correctly with the following commands. - - - -To check if the daemon is running: - - systemctl status lotus-daemon - - - -To check if the daemon is in sync: - - lotus sync status - - **note: When starting lotus for the first time, it will download a chain snapshot. - This is a large download and will take several minutes to complete. During - this time, the lotus API will not be up yet. Give it time! You can see - progress by looking at the systemd journal. - - -To check if the daemon is connecting to other lotus nodes: - - lotus net peers - - - -No wallets are crated by default. You can view, create, and delete wallets with -the lotus command. On this image, lotus is running as the user `fc`. -Be careful, now. Don't delete a wallet with funds! - - sudo -E -u fc lotus wallet list - sudo -E -u fc lotus wallet new bls - - - -The lotus miner is also installed, but it's not running by default. If you have no -special disk or worker requirements, you can initialize the lotus-miner repo like this: - - sudo -E -u fc lotus-miner init -o - - - -You only need to do this once, after which, you can enable and start the miner. - - sudo systemctl enable lotus-miner - sudo systemctl start lotus-miner - - - -Do you want to access your lotus daemon remotely? Learn how to setup token authentication -and use client libraries from lotus docs. - -https://lotus.filecoin.io/reference/basics/api-access/ - - - -For more information, see https://lotus.filecoin.io/ -Found a bug? let us know! https://github.com/filecoin-project/lotus -Chat with us on slack! https://filecoinproject.slack.com/archives/CEGN061C5 diff --git a/tools/packer/homedir/bashrc b/tools/packer/homedir/bashrc deleted file mode 100644 index db4dbd0b6..000000000 --- a/tools/packer/homedir/bashrc +++ /dev/null @@ -1,12 +0,0 @@ -PS1="[\h \w] ⨎ " - -export PROMT_DIRTRIM=1 - -# Where to find the lotus repo -export LOTUS_PATH=/var/lib/lotus - -# The miner is not running in this image by default. -# export LOTUS_MINER_PATH=/var/lib/lotus-miner - -# To access the lotus node remotely, the following environment variable may be used. -# export FULLNODE_API_INFO=:/ip4//tcp/1234/http diff --git a/tools/packer/lotus-snap.pkr.hcl b/tools/packer/lotus-snap.pkr.hcl deleted file mode 100644 index b42272c20..000000000 --- a/tools/packer/lotus-snap.pkr.hcl +++ /dev/null @@ -1,90 +0,0 @@ -variable "ci_workspace_bins" { - type = string - default = "./linux" -} - -variable "lotus_network" { - type = string - default = "mainnet" -} - -locals { - timestamp = regex_replace(timestamp(), "[- TZ:]", "") -} - -source "amazon-ebs" "lotus" { - ami_name = "lotus-${var.lotus_network}-snap-${local.timestamp}" - ami_regions = [ - "ap-east-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-northeast-3", - "ap-south-1", - "ap-southeast-1", - "ap-southeast-2", - "ca-central-1", - "eu-central-1", - "eu-north-1", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "sa-east-1", - "us-east-1", - "us-east-2", - "us-west-1", - "us-west-2", - ] - ami_groups = [ - # This causes the ami to be publicly-accessable. - "all", - ] - ami_description = "Lotus Filecoin AMI" - launch_block_device_mappings { - device_name = "/dev/sda1" - volume_size = 100 - delete_on_termination = true - } - - instance_type = "t2.micro" - source_ami_filter { - filters = { - name = "ubuntu/images/*ubuntu-focal-20.04-amd64-server-*" - root-device-type = "ebs" - virtualization-type = "hvm" - } - most_recent = true - owners = ["099720109477"] - } - ssh_username = "ubuntu" - - aws_polling { - delay_seconds = 60 - max_attempts = 60 - } -} - -source "digitalocean" "lotus" { - droplet_name = "lotus-snap" - size = "s-1vcpu-1gb" - region = "nyc3" - image = "ubuntu-20-04-x64" - snapshot_name = "lotus-${var.lotus_network}-snap-${local.timestamp}" - ssh_username = "root" -} - -build { - sources = [ - "source.amazon-ebs.lotus", - "source.digitalocean.lotus", - ] - - provisioner "file" { - source = "./tools/packer/etc/motd" - destination = "motd" - } - # build it. - provisioner "shell" { - script = "./tools/packer/setup-snap.sh" - } -} - diff --git a/tools/packer/lotus.pkr.hcl b/tools/packer/lotus.pkr.hcl deleted file mode 100644 index cfaca8398..000000000 --- a/tools/packer/lotus.pkr.hcl +++ /dev/null @@ -1,110 +0,0 @@ -variable "ci_workspace_bins" { - type = string - default = "./linux" -} - -variable "lotus_network" { - type = string - default = "mainnet" -} - -variable "git_tag" { - type = string - default = "" -} - -locals { - timestamp = regex_replace(timestamp(), "[- TZ:]", "") -} - -source "amazon-ebs" "lotus" { - ami_name = "lotus-${var.lotus_network}-${var.git_tag}-${local.timestamp}" - ami_regions = [ - "ap-east-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-northeast-3", - "ap-south-1", - "ap-southeast-1", - "ap-southeast-2", - "ca-central-1", - "eu-central-1", - "eu-north-1", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "sa-east-1", - "us-east-1", - "us-east-2", - "us-west-1", - "us-west-2", - ] - ami_groups = [ - # This causes the ami to be publicly-accessable. - "all", - ] - ami_description = "Lotus Filecoin AMI" - launch_block_device_mappings { - device_name = "/dev/sda1" - volume_size = 100 - delete_on_termination = true - } - - instance_type = "t2.micro" - source_ami_filter { - filters = { - name = "ubuntu/images/*ubuntu-focal-20.04-amd64-server-*" - root-device-type = "ebs" - virtualization-type = "hvm" - } - most_recent = true - owners = ["099720109477"] - } - ssh_username = "ubuntu" -} - -build { - sources = [ - "source.amazon-ebs.lotus", - ] - - # Lotus software (from CI workspace) - provisioner "file" { - source = "${var.ci_workspace_bins}/lotus" - destination = "lotus" - } - provisioner "file" { - source = "${var.ci_workspace_bins}/lotus-miner" - destination = "lotus-miner" - } - # First run script - provisioner "file" { - source = "./tools/packer/scripts/${var.lotus_network}/lotus-init.sh" - destination = "lotus-init.sh" - } - # Systemd service units. - provisioner "file" { - source = "./tools/packer/systemd/lotus-daemon.service" - destination = "lotus-daemon.service" - } - provisioner "file" { - source = "./tools/packer/systemd/lotus-miner.service" - destination = "lotus-miner.service" - } - provisioner "file" { - source = "./tools/packer/repo/config.toml" - destination = "config.toml" - } - provisioner "file" { - source = "./tools/packer/etc/motd" - destination = "motd" - } - provisioner "file" { - source = "./tools/packer/homedir/bashrc" - destination = ".bashrc" - } - # build it. - provisioner "shell" { - script = "./tools/packer/setup.sh" - } -} diff --git a/tools/packer/repo/config.toml b/tools/packer/repo/config.toml deleted file mode 100644 index 380d5a28f..000000000 --- a/tools/packer/repo/config.toml +++ /dev/null @@ -1,38 +0,0 @@ -[API] -ListenAddress = "/ip4/0.0.0.0/tcp/1234/http" -# RemoteListenAddress = "" -# Timeout = "30s" -# -[Libp2p] -ListenAddresses = ["/ip4/0.0.0.0/tcp/5678", "/ip6/::/tcp/5678"] -# AnnounceAddresses = [] -# NoAnnounceAddresses = [] -# ConnMgrLow = 150 -# ConnMgrHigh = 180 -# ConnMgrGrace = "20s" -# -[Pubsub] -# Bootstrapper = false -# RemoteTracer = "" -# -[Client] -# UseIpfs = false -# IpfsOnlineMode = false -# IpfsMAddr = "" -# IpfsUseForRetrieval = false -# SimultaneousTransfersForStorage = 20 -# SimultaneousTransfersForStoragePerClient = 0 -# SimultaneousTransfersForRetrieval = 20 -# -[Metrics] -# Nickname = "" -# HeadNotifs = false -# -[Wallet] -# RemoteBackend = "" -# EnableLedger = false -# DisableLocal = false -# -[Fees] -# DefaultMaxFee = "0.007 FIL" -# diff --git a/tools/packer/scripts/butterflynet/lotus-init.sh b/tools/packer/scripts/butterflynet/lotus-init.sh deleted file mode 100755 index cfbf93f78..000000000 --- a/tools/packer/scripts/butterflynet/lotus-init.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -# This script sets up an initial configuraiton for the lotus daemon and miner -# It will only run once. - -GATE="$LOTUS_PATH"/date_initialized - -# Don't init if already initialized. -if [ -f "$GATE" ]; then - echo lotus already initialized. - exit 0 -fi - -# Not importing snapshot on butterflynet -# -# echo importing minimal snapshot -# lotus daemon --import-snapshot https://fil-chain-snapshots-fallback.s3.amazonaws.com/mainnet/minimal_finality_stateroots_latest.car --halt-after-import - -# Block future inits -date > "$GATE" diff --git a/tools/packer/scripts/calibrationnet/lotus-init.sh b/tools/packer/scripts/calibrationnet/lotus-init.sh deleted file mode 100755 index 77260fa29..000000000 --- a/tools/packer/scripts/calibrationnet/lotus-init.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -# This script sets up an initial configuraiton for the lotus daemon and miner -# It will only run once. - -GATE="$LOTUS_PATH"/date_initialized - -# Don't init if already initialized. -if [ -f "$GATE" ]; then - echo lotus already initialized. - exit 0 -fi - -# Not importing snapshot on calibrationnet. -# -# echo importing minimal snapshot -# lotus daemon --import-snapshot https://fil-chain-snapshots-fallback.s3.amazonaws.com/mainnet/minimal_finality_stateroots_latest.car --halt-after-import - -# Block future inits -date > "$GATE" diff --git a/tools/packer/scripts/mainnet/lotus-init.sh b/tools/packer/scripts/mainnet/lotus-init.sh deleted file mode 100755 index b22853365..000000000 --- a/tools/packer/scripts/mainnet/lotus-init.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -# This script sets up an initial configuraiton for the lotus daemon and miner -# It will only run once. - -GATE="$LOTUS_PATH"/date_initialized - -# Don't init if already initialized. -if [ -f "$GATE" ]; then - echo lotus already initialized. - exit 0 -fi - -echo importing minimal snapshot -lotus daemon --import-snapshot https://fil-chain-snapshots-fallback.s3.amazonaws.com/mainnet/minimal_finality_stateroots_latest.car --halt-after-import - -# Block future inits -date > "$GATE" diff --git a/tools/packer/setup-snap.sh b/tools/packer/setup-snap.sh deleted file mode 100644 index 615877f83..000000000 --- a/tools/packer/setup-snap.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash - -# This script is executed by packer to setup the image. -# When this script is run, packer will have already copied binaries into the home directory of -# whichever user it has access too. This script is executed from within the home directory of that -# user. Bear in mind that different cloud providers, and different images on the same cloud -# provider will have a different initial user account. - -set -x - -# Become root, if we aren't already. -# Docker images will already be root. AMIs will have an SSH user account. -if [ x$UID != x0 ] -then - printf -v cmd_str '%q ' "$0" "$@" - exec sudo su -c "$cmd_str" -fi - -set -e - -MANAGED_FILES=( - /etc/motd -) - -# this is required on digitalocean, which does not have snap seeded correctly at this phase. -apt-get -y -o DPkg::Lock::Timeout=3 update \ - && apt-get -y -o DPkg::Lock::Timeout=3 reinstall snapd - -snap install lotus - -snap alias lotus.lotus-miner lotus-miner -snap alias lotus.lotus-worker lotus-worker - -# Setup firewall -yes | ufw enable -ufw default deny incoming -ufw default allow outgoing -ufw allow ssh - -set +e - -curl -L https://raw.githubusercontent.com/digitalocean/marketplace-partners/master/scripts/90-cleanup.sh | bash diff --git a/tools/packer/setup.sh b/tools/packer/setup.sh deleted file mode 100644 index 2b190045e..000000000 --- a/tools/packer/setup.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env bash - -# This script is executed by packer to setup the image. -# When this script is run, packer will have already copied binaries into the home directory of -# whichever user it has access too. This script is executed from within the home directory of that -# user. Bear in mind that different cloud providers, and different images on the same cloud -# provider will have a different initial user account. - -set -x - -# Become root, if we aren't already. -# Docker images will already be root. AMIs will have an SSH user account. -UID=$(id -u) -if [ x$UID != x0 ] -then - printf -v cmd_str '%q ' "$0" "$@" - exec sudo su -c "$cmd_str" -fi - -MANAGED_BINS=( lotus lotus-miner lotus-init.sh ) -MANAGED_FILES=( - /lib/systemd/system/lotus-daemon.service - /lib/systemd/system/lotus-miner.service - /etc/motd - /var/lib/lotus/config.toml -) - -# install libs. -export DEBIAN_FRONTEND=noninteractive -apt-get update -apt-get -y install libhwloc15 ocl-icd-libopencl1 ufw -apt-get -y upgrade -q -y -u -o Dpkg::Options::="--force-confold" -ln -s /usr/lib/x86_64-linux-gnu/libhwloc.so.15 /usr/lib/x86_64-linux-gnu/libhwloc.so.5 - -# Create lotus user -useradd -c "lotus system account" -r fc -install -o fc -g fc -d /var/lib/lotus -install -o fc -g fc -d /var/lib/lotus-miner - -# Install software -for i in "${MANAGED_BINS[@]}" -do - install -o root -g root -m 755 -t /usr/local/bin $i - rm $i -done - -# Install systemd and other files. -# Because packer doesn't copy files with root permisison, -# files are in the home directory of the ssh user. Copy -# these files into the right position. -for i in "${MANAGED_FILES[@]}" -do - fn=$(basename $i) - install -o root -g root -m 644 $fn $i - rm $fn -done - -# Enable services -systemctl daemon-reload -systemctl enable lotus-daemon - -# Setup firewall -yes | ufw enable -ufw default deny incoming -ufw default allow outgoing -ufw allow ssh -ufw allow 5678 #libp2p - -curl -L https://raw.githubusercontent.com/digitalocean/marketplace-partners/master/scripts/90-cleanup.sh | bash diff --git a/tools/packer/systemd/lotus-daemon.service b/tools/packer/systemd/lotus-daemon.service deleted file mode 100644 index edbc91151..000000000 --- a/tools/packer/systemd/lotus-daemon.service +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=Lotus Daemon -After=network.target - -[Service] -User=fc -Group=fc -ExecStartPre=/usr/local/bin/lotus-init.sh -ExecStart=/usr/local/bin/lotus daemon -ExecStop=/usr/local/bin/lotus daemon stop -Environment=LOTUS_PATH=/var/lib/lotus -Restart=always -RestartSec=30 -TimeoutSec=infinity - -[Install] -WantedBy=multi-user.target diff --git a/tools/packer/systemd/lotus-miner.service b/tools/packer/systemd/lotus-miner.service deleted file mode 100644 index d7289c888..000000000 --- a/tools/packer/systemd/lotus-miner.service +++ /dev/null @@ -1,15 +0,0 @@ -[Unit] -Description=Lotus Miner -After=network.target - -[Service] -User=fc -Group=fc -ExecStart=/usr/local/bin/lotus-miner run -Environment=LOTUS_PATH=/var/lib/lotus -Environment=LOTUS_MINER_PATH=/var/lib/lotus-miner -Restart=always -RestartSec=30 - -[Install] -WantedBy=multi-user.target